summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichal Strehovský <michals@microsoft.com>2017-11-02 21:58:31 +0100
committerMichal Strehovský <michals@microsoft.com>2017-11-02 21:58:31 +0100
commitfc7225790db730e411e98c7e74f5d979b4b224f1 (patch)
treeb38440f8f1bb0ae71c749dc0b2a0aee0e1ae4755 /src
parent24f5c553ba96ece53fbc20cab0d7abe860f410bc (diff)
parent96f1a89a2bb007b7dbe5ccc613a0fa3f8dd323dd (diff)
downloadcoreclr-fc7225790db730e411e98c7e74f5d979b4b224f1.tar.gz
coreclr-fc7225790db730e411e98c7e74f5d979b4b224f1.tar.bz2
coreclr-fc7225790db730e411e98c7e74f5d979b4b224f1.zip
Merge branch 'master' into master-merge
Diffstat (limited to 'src')
-rw-r--r--src/.nuget/dir.traversal.targets11
-rw-r--r--src/.nuget/optdata/optdata.csproj8
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp76
-rw-r--r--src/ToolBox/SOS/lldbplugin/CMakeLists.txt11
-rw-r--r--src/ToolBox/SOS/lldbplugin/services.cpp42
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/coreclrcommoncallbacks.h4
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/errorhandling.h2
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h15
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/lwmlist.h5
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp167
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontext.h34
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp13
-rw-r--r--src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h24
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp2
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp261
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h2
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp36
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h2
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp3
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp33
-rw-r--r--src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h2
-rw-r--r--src/ToolBox/superpmi/superpmi/commandline.cpp32
-rw-r--r--src/ToolBox/superpmi/superpmi/commandline.h10
-rw-r--r--src/ToolBox/superpmi/superpmi/icorjitinfo.cpp46
-rw-r--r--src/ToolBox/superpmi/superpmi/iexecutionengine.cpp6
-rw-r--r--src/ToolBox/superpmi/superpmi/jitdebugger.cpp6
-rw-r--r--src/ToolBox/superpmi/superpmi/jithost.cpp5
-rw-r--r--src/ToolBox/superpmi/superpmi/jithost.h2
-rw-r--r--src/ToolBox/superpmi/superpmi/jitinstance.cpp11
-rw-r--r--src/ToolBox/superpmi/superpmi/jitinstance.h7
-rw-r--r--src/ToolBox/superpmi/superpmi/neardiffer.cpp54
-rw-r--r--src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp16
-rw-r--r--src/ToolBox/superpmi/superpmi/superpmi.cpp11
-rw-r--r--src/build.proj2
-rw-r--r--src/classlibnative/bcltype/number.cpp6
-rw-r--r--src/classlibnative/bcltype/stringnative.cpp232
-rw-r--r--src/classlibnative/bcltype/stringnative.h4
-rw-r--r--src/classlibnative/bcltype/system.cpp80
-rw-r--r--src/classlibnative/bcltype/system.h2
-rw-r--r--src/debug/daccess/dacdbiimpl.cpp11
-rw-r--r--src/debug/daccess/enummem.cpp5
-rw-r--r--src/debug/daccess/request.cpp4
-rw-r--r--src/debug/di/rspriv.h3
-rw-r--r--src/debug/di/rsthread.cpp203
-rw-r--r--src/debug/di/valuehome.cpp36
-rw-r--r--src/debug/ee/controller.cpp187
-rw-r--r--src/debug/ee/controller.h46
-rw-r--r--src/debug/ee/debugger.cpp40
-rw-r--r--src/debug/ee/debugger.h17
-rw-r--r--src/debug/ee/functioninfo.cpp144
-rw-r--r--src/debug/ee/rcthread.cpp5
-rw-r--r--src/debug/inc/dbgipcevents.h1
-rw-r--r--src/debug/shim/debugshim.cpp4
-rw-r--r--src/dlls/mscordbi/mscordbi.cpp2
-rw-r--r--src/dlls/mscoree/mscoree.cpp54
-rw-r--r--src/dlls/mscorrc/mscorrc.rc39
-rw-r--r--src/dlls/mscorrc/resource.h43
-rw-r--r--src/gc/CMakeLists.txt26
-rw-r--r--src/gc/env/gcenv.base.h24
-rw-r--r--src/gc/env/gcenv.ee.h2
-rw-r--r--src/gc/gc.cpp54
-rw-r--r--src/gc/gccommon.cpp103
-rw-r--r--src/gc/gcenv.ee.standalone.inl12
-rw-r--r--src/gc/gcinterface.ee.h11
-rw-r--r--src/gc/gcinterface.h51
-rw-r--r--src/gc/gcload.cpp120
-rw-r--r--src/gc/sample/CMakeLists.txt3
-rw-r--r--src/gc/sample/GCSample.cpp4
-rw-r--r--src/gc/sample/gcenv.ee.cpp10
-rw-r--r--src/ildasm/dasm.cpp26
-rw-r--r--src/inc/CMakeLists.txt3
-rw-r--r--src/inc/CrstTypes.def6
-rw-r--r--src/inc/MSCOREE.IDL6
-rw-r--r--src/inc/assemblyusagelog.idl51
-rw-r--r--src/inc/assemblyusagelogmanager.h53
-rw-r--r--src/inc/binderngen.idl254
-rw-r--r--src/inc/clrconfigvalues.h137
-rw-r--r--src/inc/clrnt.h2
-rw-r--r--src/inc/compatibilityflags.h17
-rw-r--r--src/inc/compatibilityflagsdef.h48
-rw-r--r--src/inc/corhost.h2
-rw-r--r--src/inc/corinfo.h40
-rw-r--r--src/inc/corjit.h8
-rw-r--r--src/inc/corpriv.h20
-rw-r--r--src/inc/corprof.idl22
-rw-r--r--src/inc/crsttypes.h133
-rw-r--r--src/inc/dacvars.h7
-rw-r--r--src/inc/ex.h25
-rw-r--r--src/inc/ivalidator.idl116
-rw-r--r--src/inc/ivehandler.idl72
-rw-r--r--src/inc/jithelpers.h5
-rw-r--r--src/inc/metahost_mktlb.rc11
-rw-r--r--src/inc/metahostpriv.idl212
-rw-r--r--src/inc/mscorcfg.h34
-rw-r--r--src/inc/mscoree_tlb.idl15
-rw-r--r--src/inc/profilepriv.inl16
-rw-r--r--src/inc/switches.h7
-rw-r--r--src/inc/sxshelpers.h141
-rw-r--r--src/inc/sxshelpers.inl76
-rw-r--r--src/inc/tlbimpexp.idl72
-rw-r--r--src/inc/tls.h57
-rw-r--r--src/inc/warningcontrol.h1
-rw-r--r--src/inc/winsqmevents.h84
-rw-r--r--src/inc/xmlparser.h1385
-rw-r--r--src/inc/xmlparser_i.cpp86
-rw-r--r--src/jit/CMakeLists.txt9
-rw-r--r--src/jit/DIRS.proj1
-rw-r--r--src/jit/ICorJitInfo_API_names.h1
-rw-r--r--src/jit/ICorJitInfo_API_wrapper.hpp11
-rw-r--r--src/jit/armelnonjit/.gitmirror1
-rw-r--r--src/jit/armelnonjit/CMakeLists.txt90
-rw-r--r--src/jit/armelnonjit/SOURCES10
-rw-r--r--src/jit/armelnonjit/armelnonjit.def7
-rw-r--r--src/jit/armelnonjit/armelnonjit.nativeproj86
-rw-r--r--src/jit/armelnonjit/makefile7
-rw-r--r--src/jit/assertionprop.cpp6
-rw-r--r--src/jit/codegen.h4
-rw-r--r--src/jit/codegenarm.cpp13
-rw-r--r--src/jit/codegenarm64.cpp1453
-rw-r--r--src/jit/codegenarmarch.cpp52
-rw-r--r--src/jit/codegencommon.cpp299
-rw-r--r--src/jit/codegeninterface.h2
-rw-r--r--src/jit/codegenlegacy.cpp22
-rw-r--r--src/jit/codegenlinear.cpp13
-rw-r--r--src/jit/codegenlinear.h24
-rw-r--r--src/jit/codegenxarch.cpp181
-rw-r--r--src/jit/compiler.cpp198
-rw-r--r--src/jit/compiler.h240
-rw-r--r--src/jit/compiler.hpp110
-rw-r--r--src/jit/decomposelongs.cpp77
-rw-r--r--src/jit/decomposelongs.h1
-rw-r--r--src/jit/dll/jit.nativeproj2
-rw-r--r--src/jit/earlyprop.cpp117
-rw-r--r--src/jit/ee_il_dll.cpp22
-rw-r--r--src/jit/eeinterface.cpp2
-rw-r--r--src/jit/emit.cpp12
-rw-r--r--src/jit/emit.h48
-rw-r--r--src/jit/emitarm.cpp34
-rw-r--r--src/jit/emitarm.h9
-rw-r--r--src/jit/emitarm64.cpp316
-rw-r--r--src/jit/emitarm64.h9
-rw-r--r--src/jit/emitfmtsarm64.h5
-rw-r--r--src/jit/emitxarch.cpp183
-rw-r--r--src/jit/emitxarch.h48
-rw-r--r--src/jit/flowgraph.cpp347
-rw-r--r--src/jit/gentree.cpp1046
-rw-r--r--src/jit/gentree.h288
-rw-r--r--src/jit/gtlist.h17
-rw-r--r--src/jit/gtstructs.h8
-rw-r--r--src/jit/hashbv.cpp1
-rw-r--r--src/jit/hwintrinsiccodegenxarch.cpp220
-rw-r--r--src/jit/hwintrinsiclistxarch.h7
-rw-r--r--src/jit/hwintrinsicxarch.cpp98
-rw-r--r--src/jit/importer.cpp974
-rw-r--r--src/jit/inline.def7
-rw-r--r--src/jit/inlinepolicy.cpp16
-rw-r--r--src/jit/inlinepolicy.h6
-rw-r--r--src/jit/instr.cpp62
-rw-r--r--src/jit/instr.h16
-rw-r--r--src/jit/instrsarm64.h161
-rw-r--r--src/jit/instrsxarch.h9
-rw-r--r--src/jit/jit.h3
-rw-r--r--src/jit/jit.settings.targets2
-rw-r--r--src/jit/jitconfigvalues.h22
-rw-r--r--src/jit/jitee.h13
-rw-r--r--src/jit/lclvars.cpp21
-rw-r--r--src/jit/legacyjit/CMakeLists.txt4
-rw-r--r--src/jit/legacynonjit/CMakeLists.txt3
-rw-r--r--src/jit/linuxnonjit/CMakeLists.txt2
-rw-r--r--src/jit/lir.cpp13
-rw-r--r--src/jit/liveness.cpp6
-rw-r--r--src/jit/lower.cpp438
-rw-r--r--src/jit/lower.h20
-rw-r--r--src/jit/lowerarmarch.cpp137
-rw-r--r--src/jit/lowerxarch.cpp115
-rw-r--r--src/jit/lsra.cpp970
-rw-r--r--src/jit/lsra.h51
-rw-r--r--src/jit/lsraarm.cpp41
-rw-r--r--src/jit/lsraarm64.cpp202
-rw-r--r--src/jit/lsraarmarch.cpp69
-rw-r--r--src/jit/lsraxarch.cpp344
-rw-r--r--src/jit/morph.cpp4589
-rw-r--r--src/jit/namedintrinsiclist.h2
-rw-r--r--src/jit/nodeinfo.h4
-rw-r--r--src/jit/optcse.cpp3
-rw-r--r--src/jit/optimizer.cpp98
-rw-r--r--src/jit/protojit/protojit.nativeproj2
-rw-r--r--src/jit/protononjit/CMakeLists.txt3
-rw-r--r--src/jit/rangecheck.cpp23
-rw-r--r--src/jit/regset.cpp33
-rw-r--r--src/jit/regset.h25
-rw-r--r--src/jit/sideeffects.cpp4
-rw-r--r--src/jit/simd.cpp125
-rw-r--r--src/jit/simd.h37
-rw-r--r--src/jit/simdcodegenxarch.cpp177
-rw-r--r--src/jit/simdintrinsiclist.h26
-rw-r--r--src/jit/stackfp.cpp2
-rw-r--r--src/jit/target.h13
-rw-r--r--src/jit/unwind.cpp293
-rw-r--r--src/jit/unwindamd64.cpp177
-rw-r--r--src/jit/unwindarm.cpp275
-rw-r--r--src/jit/unwindarm64.cpp11
-rw-r--r--src/jit/unwindx86.cpp11
-rw-r--r--src/jit/utils.cpp10
-rw-r--r--src/jit/valuenum.cpp13
-rw-r--r--src/jit/vartype.h2
-rw-r--r--src/md/compiler/mdvalidator.cpp7589
-rw-r--r--src/md/compiler/regmeta.cpp4
-rw-r--r--src/md/compiler/regmeta.h40
-rw-r--r--src/mscorlib/Common/System/SR.cs3
-rw-r--r--src/mscorlib/Resources/Strings.resx18
-rw-r--r--src/mscorlib/System.Private.CoreLib.csproj15
-rw-r--r--src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs (renamed from src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs)0
-rw-r--r--src/mscorlib/shared/Interop/Windows/Interop.Errors.cs1
-rw-r--r--src/mscorlib/shared/System.Private.CoreLib.Shared.projitems9
-rw-r--r--src/mscorlib/shared/System/AccessViolationException.cs3
-rw-r--r--src/mscorlib/shared/System/ApplicationException.cs4
-rw-r--r--src/mscorlib/shared/System/ArgumentException.cs6
-rw-r--r--src/mscorlib/shared/System/ArgumentNullException.cs4
-rw-r--r--src/mscorlib/shared/System/ArgumentOutOfRangeException.cs7
-rw-r--r--src/mscorlib/shared/System/ArithmeticException.cs4
-rw-r--r--src/mscorlib/shared/System/ArrayTypeMismatchException.cs4
-rw-r--r--src/mscorlib/shared/System/BadImageFormatException.cs7
-rw-r--r--src/mscorlib/shared/System/Buffers/MemoryHandle.cs8
-rw-r--r--src/mscorlib/shared/System/Byte.cs20
-rw-r--r--src/mscorlib/shared/System/Char.cs22
-rw-r--r--src/mscorlib/shared/System/Collections/Generic/Dictionary.cs (renamed from src/mscorlib/src/System/Collections/Generic/Dictionary.cs)79
-rw-r--r--src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs38
-rw-r--r--src/mscorlib/shared/System/Collections/HashHelpers.cs108
-rw-r--r--src/mscorlib/shared/System/Convert.cs129
-rw-r--r--src/mscorlib/shared/System/DataMisalignedException.cs6
-rw-r--r--src/mscorlib/shared/System/DateTime.cs86
-rw-r--r--src/mscorlib/shared/System/DateTimeOffset.cs101
-rw-r--r--src/mscorlib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs12
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs7
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs14
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs7
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs174
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs9
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs1
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs15
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs9
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs6
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs6
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs9
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs13
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs6
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs5
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs13
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs11
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs8
-rw-r--r--src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs8
-rw-r--r--src/mscorlib/shared/System/DivideByZeroException.cs3
-rw-r--r--src/mscorlib/shared/System/DllNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/DuplicateWaitObjectException.cs4
-rw-r--r--src/mscorlib/shared/System/EntryPointNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/ExecutionEngineException.cs6
-rw-r--r--src/mscorlib/shared/System/FieldAccessException.cs3
-rw-r--r--src/mscorlib/shared/System/FormatException.cs3
-rw-r--r--src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs2
-rw-r--r--src/mscorlib/shared/System/Globalization/CalendarData.cs2
-rw-r--r--src/mscorlib/shared/System/Globalization/CalendricalCalculationsHelper.cs2
-rw-r--r--src/mscorlib/shared/System/Globalization/CompareInfo.Invariant.cs (renamed from src/mscorlib/src/System/Globalization/CompareInfo.Invariant.cs)0
-rw-r--r--src/mscorlib/shared/System/Globalization/CompareInfo.cs (renamed from src/mscorlib/src/System/Globalization/CompareInfo.cs)125
-rw-r--r--src/mscorlib/shared/System/Globalization/CultureData.Unix.cs8
-rw-r--r--src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs7
-rw-r--r--src/mscorlib/shared/System/Globalization/DateTimeFormat.cs43
-rw-r--r--src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs163
-rw-r--r--src/mscorlib/shared/System/Globalization/DateTimeParse.cs209
-rw-r--r--src/mscorlib/shared/System/Globalization/GregorianCalendar.cs16
-rw-r--r--src/mscorlib/shared/System/Globalization/PersianCalendar.cs1
-rw-r--r--src/mscorlib/shared/System/Globalization/TimeSpanParse.cs19
-rw-r--r--src/mscorlib/shared/System/Guid.cs7
-rw-r--r--src/mscorlib/shared/System/IO/BinaryWriter.cs18
-rw-r--r--src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/IO/DriveNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/IO/EndOfStreamException.cs3
-rw-r--r--src/mscorlib/shared/System/IO/FileLoadException.cs7
-rw-r--r--src/mscorlib/shared/System/IO/FileNotFoundException.cs7
-rw-r--r--src/mscorlib/shared/System/IO/IOException.cs3
-rw-r--r--src/mscorlib/shared/System/IO/PathTooLongException.cs3
-rw-r--r--src/mscorlib/shared/System/IndexOutOfRangeException.cs6
-rw-r--r--src/mscorlib/shared/System/InsufficientExecutionStackException.cs6
-rw-r--r--src/mscorlib/shared/System/Int16.cs10
-rw-r--r--src/mscorlib/shared/System/Int32.cs10
-rw-r--r--src/mscorlib/shared/System/Int64.cs10
-rw-r--r--src/mscorlib/shared/System/InvalidCastException.cs3
-rw-r--r--src/mscorlib/shared/System/InvalidOperationException.cs3
-rw-r--r--src/mscorlib/shared/System/InvalidProgramException.cs4
-rw-r--r--src/mscorlib/shared/System/InvalidTimeZoneException.cs3
-rw-r--r--src/mscorlib/shared/System/Lazy.cs4
-rw-r--r--src/mscorlib/shared/System/Math.cs1
-rw-r--r--src/mscorlib/shared/System/MemberAccessException.cs4
-rw-r--r--src/mscorlib/shared/System/Memory.cs14
-rw-r--r--src/mscorlib/shared/System/MethodAccessException.cs3
-rw-r--r--src/mscorlib/shared/System/MissingMethodException.cs3
-rw-r--r--src/mscorlib/shared/System/MulticastNotSupportedException.cs6
-rw-r--r--src/mscorlib/shared/System/NotFiniteNumberException.cs13
-rw-r--r--src/mscorlib/shared/System/NotImplementedException.cs3
-rw-r--r--src/mscorlib/shared/System/NotSupportedException.cs3
-rw-r--r--src/mscorlib/shared/System/NullReferenceException.cs3
-rw-r--r--src/mscorlib/shared/System/ObjectDisposedException.cs5
-rw-r--r--src/mscorlib/shared/System/OperationCanceledException.cs3
-rw-r--r--src/mscorlib/shared/System/OverflowException.cs3
-rw-r--r--src/mscorlib/shared/System/ParseNumbers.cs14
-rw-r--r--src/mscorlib/shared/System/PlatformNotSupportedException.cs3
-rw-r--r--src/mscorlib/shared/System/RankException.cs3
-rw-r--r--src/mscorlib/shared/System/ReadOnlyMemory.cs7
-rw-r--r--src/mscorlib/shared/System/ReadOnlySpan.cs4
-rw-r--r--src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs6
-rw-r--r--src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs3
-rw-r--r--src/mscorlib/shared/System/Reflection/IntrospectionExtensions.cs5
-rw-r--r--src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs3
-rw-r--r--src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs10
-rw-r--r--src/mscorlib/shared/System/Reflection/SignatureConstructedGenericType.cs1
-rw-r--r--src/mscorlib/shared/System/Reflection/SignatureGenericMethodParameterType.cs3
-rw-r--r--src/mscorlib/shared/System/Reflection/SignatureHasElementType.cs1
-rw-r--r--src/mscorlib/shared/System/Reflection/SignatureType.cs3
-rw-r--r--src/mscorlib/shared/System/Reflection/SignatureTypeExtensions.cs2
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetException.cs3
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetInvocationException.cs7
-rw-r--r--src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs7
-rw-r--r--src/mscorlib/shared/System/Reflection/TypeDelegator.cs2
-rw-r--r--src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs3
-rw-r--r--src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs3
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs8
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs16
-rw-r--r--src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs9
-rw-r--r--src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs4
-rw-r--r--src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs3
-rw-r--r--src/mscorlib/shared/System/Security/CryptographicException.cs3
-rw-r--r--src/mscorlib/shared/System/Security/SecurityException.cs27
-rw-r--r--src/mscorlib/shared/System/Security/VerificationException.cs3
-rw-r--r--src/mscorlib/shared/System/Span.cs4
-rw-r--r--src/mscorlib/shared/System/StackOverflowException.cs6
-rw-r--r--src/mscorlib/shared/System/String.Searching.cs (renamed from src/mscorlib/src/System/String.Searching.cs)208
-rw-r--r--src/mscorlib/shared/System/StringSpanHelpers.cs23
-rw-r--r--src/mscorlib/shared/System/SystemException.cs3
-rw-r--r--src/mscorlib/shared/System/Text/DecoderExceptionFallback.cs8
-rw-r--r--src/mscorlib/shared/System/Text/EncoderExceptionFallback.cs7
-rw-r--r--src/mscorlib/shared/System/Text/StringBuilder.cs2
-rw-r--r--src/mscorlib/shared/System/Threading/AbandonedMutexException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/LockRecursionException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/ReaderWriterLockSlim.cs73
-rw-r--r--src/mscorlib/shared/System/Threading/SemaphoreFullException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/SynchronizationLockException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs9
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadAbortException.cs7
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadStartException.cs7
-rw-r--r--src/mscorlib/shared/System/Threading/ThreadStateException.cs3
-rw-r--r--src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs3
-rw-r--r--src/mscorlib/shared/System/TimeZoneNotFoundException.cs3
-rw-r--r--src/mscorlib/shared/System/TimeoutException.cs3
-rw-r--r--src/mscorlib/shared/System/Tuple.cs (renamed from src/mscorlib/src/System/Tuple.cs)51
-rw-r--r--src/mscorlib/shared/System/Type.cs2
-rw-r--r--src/mscorlib/shared/System/TypeAccessException.cs3
-rw-r--r--src/mscorlib/shared/System/TypeInitializationException.cs9
-rw-r--r--src/mscorlib/shared/System/TypeUnloadedException.cs3
-rw-r--r--src/mscorlib/shared/System/UInt16.cs9
-rw-r--r--src/mscorlib/shared/System/UInt32.cs10
-rw-r--r--src/mscorlib/shared/System/UInt64.cs9
-rw-r--r--src/mscorlib/shared/System/UnauthorizedAccessException.cs5
-rw-r--r--src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs6
-rw-r--r--src/mscorlib/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs23
-rw-r--r--src/mscorlib/src/Microsoft/Win32/OAVariantLib.cs4
-rw-r--r--src/mscorlib/src/Microsoft/Win32/Registry.cs3
-rw-r--r--src/mscorlib/src/Microsoft/Win32/RegistryKey.cs16
-rw-r--r--src/mscorlib/src/Microsoft/Win32/Win32Native.cs13
-rw-r--r--src/mscorlib/src/System/AppDomainUnloadedException.cs6
-rw-r--r--src/mscorlib/src/System/Array.cs2
-rw-r--r--src/mscorlib/src/System/Attribute.cs2
-rw-r--r--src/mscorlib/src/System/BCLDebug.cs110
-rw-r--r--src/mscorlib/src/System/Buffer.cs4
-rw-r--r--src/mscorlib/src/System/Collections/Generic/Comparer.cs30
-rw-r--r--src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs8
-rw-r--r--src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs135
-rw-r--r--src/mscorlib/src/System/Collections/Hashtable.cs107
-rw-r--r--src/mscorlib/src/System/Delegate.cs2
-rw-r--r--src/mscorlib/src/System/Diagnostics/Contracts/Contracts.cs1
-rw-r--r--src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs43
-rw-r--r--src/mscorlib/src/System/Diagnostics/Stacktrace.cs9
-rw-r--r--src/mscorlib/src/System/Enum.cs8
-rw-r--r--src/mscorlib/src/System/Environment.Windows.cs34
-rw-r--r--src/mscorlib/src/System/Environment.cs48
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.Unix.cs27
-rw-r--r--src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs51
-rw-r--r--src/mscorlib/src/System/IO/BinaryReader.cs8
-rw-r--r--src/mscorlib/src/System/IO/File.cs2
-rw-r--r--src/mscorlib/src/System/IO/MemoryStream.cs1
-rw-r--r--src/mscorlib/src/System/InsufficientMemoryException.cs6
-rw-r--r--src/mscorlib/src/System/MissingFieldException.cs3
-rw-r--r--src/mscorlib/src/System/MissingMemberException.cs12
-rw-r--r--src/mscorlib/src/System/OutOfMemoryException.cs3
-rw-r--r--src/mscorlib/src/System/Reflection/CustomAttribute.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/AssemblyBuilder.cs3
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderData.cs1
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/CustomAttributeBuilder.cs6
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs4
-rw-r--r--src/mscorlib/src/System/Reflection/Emit/MethodBuilder.cs2
-rw-r--r--src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs2
-rw-r--r--src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs14
-rw-r--r--src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs8
-rw-r--r--src/mscorlib/src/System/Resources/ResourceManager.cs4
-rw-r--r--src/mscorlib/src/System/Resources/ResourceReader.cs76
-rw-r--r--src/mscorlib/src/System/RtType.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs195
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs29
-rw-r--r--src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs8
-rw-r--r--src/mscorlib/src/System/Runtime/ExceptionServices/ExceptionServicesCommon.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/COMException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs8
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs10
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs3
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs16
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs6
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs4
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs2
-rw-r--r--src/mscorlib/src/System/Runtime/MemoryFailPoint.cs8
-rw-r--r--src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs2
-rw-r--r--src/mscorlib/src/System/SharedStatics.cs2
-rw-r--r--src/mscorlib/src/System/String.Comparison.cs22
-rw-r--r--src/mscorlib/src/System/String.Manipulation.cs91
-rw-r--r--src/mscorlib/src/System/String.cs3
-rw-r--r--src/mscorlib/src/System/StubHelpers.cs22
-rw-r--r--src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs2
-rw-r--r--src/mscorlib/src/System/Threading/Mutex.cs252
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs27
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/Task.cs68
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs8
-rw-r--r--src/mscorlib/src/System/Threading/Tasks/future.cs2
-rw-r--r--src/mscorlib/src/System/Threading/ThreadInterruptedException.cs3
-rw-r--r--src/mscorlib/src/System/Threading/Timer.cs88
-rw-r--r--src/mscorlib/src/System/Threading/WaitHandle.cs4
-rw-r--r--src/mscorlib/src/System/ThrowHelper.cs1
-rw-r--r--src/mscorlib/src/System/TypeLoadException.cs12
-rw-r--r--src/mscorlib/src/System/ValueType.cs1
-rw-r--r--src/mscorlib/src/System/WeakReference.cs2
-rw-r--r--src/pal/CMakeLists.txt1
-rw-r--r--src/pal/inc/pal.h4
-rw-r--r--src/pal/prebuilt/idl/corprof_i.cpp3
-rw-r--r--src/pal/prebuilt/idl/fusionpriv_i.cpp121
-rw-r--r--src/pal/prebuilt/idl/ivalidator_i.cpp76
-rw-r--r--src/pal/prebuilt/idl/ivehandler_i.cpp79
-rw-r--r--src/pal/prebuilt/idl/tlbimpexp_i.cpp82
-rw-r--r--src/pal/prebuilt/inc/corprof.h941
-rw-r--r--src/pal/prebuilt/inc/ivalidator.h334
-rw-r--r--src/pal/prebuilt/inc/ivehandler.h220
-rw-r--r--src/pal/prebuilt/inc/mscoree.h1
-rw-r--r--src/pal/src/CMakeLists.txt6
-rw-r--r--src/pal/src/cruntime/mbstring.cpp3
-rw-r--r--src/pal/src/cruntime/printf.cpp77
-rw-r--r--src/pal/src/cruntime/printfcpp.cpp77
-rw-r--r--src/pal/src/cruntime/wchar.cpp3
-rw-r--r--src/pal/src/exception/seh.cpp32
-rw-r--r--src/pal/src/include/pal/cruntime.h18
-rw-r--r--src/pal/src/include/pal/malloc.hpp4
-rw-r--r--src/pal/src/include/pal/palinternal.h8
-rw-r--r--src/pal/src/init/pal.cpp4
-rw-r--r--src/pal/src/misc/cgroup.cpp7
-rw-r--r--src/pal/src/misc/sysinfo.cpp21
-rw-r--r--src/pal/src/numa/numa.cpp6
-rw-r--r--src/pal/src/numa/numashim.h2
-rw-r--r--src/pal/src/synchmgr/synchmanager.cpp10
-rw-r--r--src/publish.proj82
-rw-r--r--src/strongname/api/common.h4
-rw-r--r--src/syncAzure.proj10
-rw-r--r--src/tools/metainfo/mdinfo.cpp302
-rw-r--r--src/tools/metainfo/mdinfo.h2
-rw-r--r--src/utilcode/CMakeLists.txt13
-rw-r--r--src/utilcode/sxshelpers.cpp1508
-rw-r--r--src/utilcode/tls.cpp271
-rw-r--r--src/utilcode/util.cpp344
-rw-r--r--src/vm/CMakeLists.txt31
-rw-r--r--src/vm/amd64/AsmMacros.inc30
-rw-r--r--src/vm/amd64/InstantiatingStub.asm8
-rw-r--r--src/vm/amd64/JitHelpers_Fast.asm59
-rw-r--r--src/vm/amd64/JitHelpers_InlineGetAppDomain.asm123
-rw-r--r--src/vm/amd64/JitHelpers_InlineGetThread.asm49
-rw-r--r--src/vm/amd64/JitHelpers_Slow.asm481
-rw-r--r--src/vm/amd64/RedirectedHandledJITCase.asm3
-rw-r--r--src/vm/amd64/TlsGetters.asm120
-rw-r--r--src/vm/amd64/UMThunkStub.asm8
-rw-r--r--src/vm/amd64/asmconstants.h17
-rw-r--r--src/vm/amd64/cgencpu.h19
-rw-r--r--src/vm/amd64/jitinterfaceamd64.cpp92
-rw-r--r--src/vm/appdomain.cpp41
-rw-r--r--src/vm/appdomainconfigfactory.hpp240
-rw-r--r--src/vm/arm/asmconstants.h3
-rw-r--r--src/vm/arm/asmhelpers.S53
-rw-r--r--src/vm/arm/asmhelpers.asm2
-rw-r--r--src/vm/arm/cgencpu.h17
-rw-r--r--src/vm/arm/patchedcode.S16
-rw-r--r--src/vm/arm/patchedcode.asm515
-rw-r--r--src/vm/arm/stubs.cpp437
-rw-r--r--src/vm/arm/unixstubs.cpp5
-rw-r--r--src/vm/arm64/cgencpu.h10
-rw-r--r--src/vm/arm64/stubs.cpp56
-rw-r--r--src/vm/ceeload.cpp34
-rw-r--r--src/vm/ceeload.h12
-rw-r--r--src/vm/ceemain.cpp134
-rw-r--r--src/vm/ceemain.h8
-rw-r--r--src/vm/clsload.cpp133
-rw-r--r--src/vm/clsload.hpp21
-rw-r--r--src/vm/codeman.cpp8
-rw-r--r--src/vm/comdelegate.cpp140
-rw-r--r--src/vm/comdelegate.h3
-rw-r--r--src/vm/common.h27
-rw-r--r--src/vm/compile.cpp40
-rw-r--r--src/vm/comsynchronizable.cpp8
-rw-r--r--src/vm/comthreadpool.cpp30
-rw-r--r--src/vm/comthreadpool.h2
-rw-r--r--src/vm/comutilnative.cpp7
-rw-r--r--src/vm/comutilnative.h2
-rw-r--r--src/vm/corhost.cpp151
-rw-r--r--src/vm/crossgencompile.cpp21
-rw-r--r--src/vm/dbginterface.h2
-rw-r--r--src/vm/domainfile.cpp14
-rw-r--r--src/vm/ecalllist.h2
-rw-r--r--src/vm/eeconfig.cpp1
-rw-r--r--src/vm/eeconfig.h2
-rw-r--r--src/vm/eedbginterface.h1
-rw-r--r--src/vm/eedbginterfaceimpl.cpp11
-rw-r--r--src/vm/eedbginterfaceimpl.h1
-rw-r--r--src/vm/eetoprofinterfaceimpl.cpp18
-rw-r--r--src/vm/excep.cpp3
-rw-r--r--src/vm/excep.h3
-rw-r--r--src/vm/gcenv.ee.cpp70
-rw-r--r--src/vm/gcenv.ee.h2
-rw-r--r--src/vm/gcheaputilities.cpp198
-rw-r--r--src/vm/gcheaputilities.h5
-rw-r--r--src/vm/gchelpers.h9
-rw-r--r--src/vm/gdbjit.cpp213
-rw-r--r--src/vm/gdbjit.h8
-rw-r--r--src/vm/hillclimbing.cpp2
-rw-r--r--src/vm/i386/asmconstants.h3
-rw-r--r--src/vm/i386/asmhelpers.asm63
-rw-r--r--src/vm/i386/cgencpu.h15
-rw-r--r--src/vm/i386/cgenx86.cpp2
-rw-r--r--src/vm/i386/jithelp.asm51
-rw-r--r--src/vm/i386/jitinterfacex86.cpp92
-rw-r--r--src/vm/i386/stublinkerx86.cpp222
-rw-r--r--src/vm/i386/stublinkerx86.h6
-rw-r--r--src/vm/jithelpers.cpp18
-rw-r--r--src/vm/jitinterface.cpp258
-rw-r--r--src/vm/jitinterface.h39
-rw-r--r--src/vm/jitinterfacegen.cpp183
-rw-r--r--src/vm/method.hpp12
-rw-r--r--src/vm/mscorlib.h13
-rw-r--r--src/vm/object.h13
-rw-r--r--src/vm/peimagelayout.cpp4
-rw-r--r--src/vm/prestub.cpp4
-rw-r--r--src/vm/proftoeeinterfaceimpl.cpp328
-rw-r--r--src/vm/proftoeeinterfaceimpl.h25
-rw-r--r--src/vm/readytoruninfo.cpp14
-rw-r--r--src/vm/safehandle.cpp9
-rw-r--r--src/vm/siginfo.cpp2
-rw-r--r--src/vm/stubmgr.h16
-rw-r--r--src/vm/synch.cpp42
-rw-r--r--src/vm/synch.h14
-rw-r--r--src/vm/threads.cpp461
-rw-r--r--src/vm/threads.h104
-rw-r--r--src/vm/threads.inl11
-rw-r--r--src/vm/threadstatics.h4
-rw-r--r--src/vm/tieredcompilation.cpp54
-rw-r--r--src/vm/vars.cpp50
-rw-r--r--src/vm/vars.hpp23
-rw-r--r--src/vm/vertable.h380
-rw-r--r--src/vm/win32threadpool.cpp13
-rw-r--r--src/vm/win32threadpool.h8
-rw-r--r--src/vm/yieldprocessornormalized.cpp105
-rw-r--r--src/vm/yieldprocessornormalized.h103
-rw-r--r--src/zap/zapinfo.cpp20
-rw-r--r--src/zap/zapinfo.h13
-rw-r--r--src/zap/zapper.cpp15
599 files changed, 17029 insertions, 27401 deletions
diff --git a/src/.nuget/dir.traversal.targets b/src/.nuget/dir.traversal.targets
index 686ae749a7..e0bcdb8cbb 100644
--- a/src/.nuget/dir.traversal.targets
+++ b/src/.nuget/dir.traversal.targets
@@ -3,11 +3,20 @@
<Import Project="$(MSBuildThisFileDirectory)..\..\dir.traversal.targets" />
+ <PropertyGroup Condition="'$(OfficialBuildId)' != ''">
+ <!-- During an official build, only build identity packages in the AllConfigurations build -->
+ <BuildIdentityPackage Condition="'$(BuildIdentityPackage)' == '' AND '$(OS)' == 'Windows_NT' AND '$(BuildArch)' == 'x64'">true</BuildIdentityPackage>
+ </PropertyGroup>
+
<Target Name="FilterProjects" BeforeTargets="Build">
<Error Condition="'$(PackageRID)' == ''" Text="'PackageRID' property must be specified."/>
<!-- Only build packages for current RID or non-RID-specific -->
- <ItemGroup>
+ <ItemGroup Condition="$(BuildIdentityPackage)!='true'">
+ <_projectsToBuild Include="@(Project)" Condition="'%(Project.PackageTargetRuntime)' == '$(PackageRID)'" />
+ </ItemGroup>
+
+ <ItemGroup Condition="$(BuildIdentityPackage)=='true'" >
<_projectsToBuild Include="@(Project)" Condition="'%(Project.PackageTargetRuntime)' == '$(PackageRID)' OR '%(Project.PackageTargetRuntime)' == ''" />
</ItemGroup>
diff --git a/src/.nuget/optdata/optdata.csproj b/src/.nuget/optdata/optdata.csproj
index 20e2a40ada..76b5b97789 100644
--- a/src/.nuget/optdata/optdata.csproj
+++ b/src/.nuget/optdata/optdata.csproj
@@ -8,6 +8,14 @@
<RuntimeIdentifiers>win7-x64;win7-x86;linux-x64</RuntimeIdentifiers>
</PropertyGroup>
+ <!-- Add optimization data package restore source. -->
+ <PropertyGroup>
+ <RestoreSources Condition="'$(DotNetBuildOffline)' != 'true'">
+ https://dotnet.myget.org/F/dotnet-core-optimization-data/api/v3/index.json;
+ $(RestoreSources)
+ </RestoreSources>
+ </PropertyGroup>
+
<ItemGroup>
<PackageReference Include="optimization.PGO.CoreCLR" Version="$(PgoDataPackageVersion)" Condition="'$(PgoDataPackageVersion)'!=''" />
<PackageReference Include="optimization.IBC.CoreCLR" Version="$(IbcDataPackageVersion)" Condition="'$(IbcDataPackageVersion)'!=''" />
diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp
index b621023d1f..def0af31e4 100644
--- a/src/ToolBox/SOS/Strike/strike.cpp
+++ b/src/ToolBox/SOS/Strike/strike.cpp
@@ -324,7 +324,9 @@ DECLARE_API(IP2MD)
#define DEBUG_STACK_CONTEXT AMD64_CONTEXT
#elif defined(_TARGET_ARM_) // _TARGET_WIN64_
#define DEBUG_STACK_CONTEXT ARM_CONTEXT
-#endif // _TARGET_ARM_
+#elif defined(_TARGET_X86_) // _TARGET_ARM_
+#define DEBUG_STACK_CONTEXT X86_CONTEXT
+#endif // _TARGET_X86_
#ifdef DEBUG_STACK_CONTEXT
// I use a global set of frames for stack walking on win64 because the debugger's
@@ -774,7 +776,7 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
if (objData.Request(g_sos, TO_CDADDR(DynamicMethodObj)) != S_OK)
return bRet;
- iOffset = GetObjFieldOffset(DynamicMethodObj, objData.MethodTable, W("m_resolver"));
+ iOffset = GetObjFieldOffset(TO_CDADDR(DynamicMethodObj), objData.MethodTable, W("m_resolver"));
if (iOffset <= 0)
return bRet;
@@ -785,7 +787,7 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
if (objData.Request(g_sos, TO_CDADDR(resolverPtr)) != S_OK)
return bRet;
- iOffset = GetObjFieldOffset(resolverPtr, objData.MethodTable, W("m_code"));
+ iOffset = GetObjFieldOffset(TO_CDADDR(resolverPtr), objData.MethodTable, W("m_code"));
if (iOffset <= 0)
return bRet;
@@ -800,7 +802,7 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
return bRet;
// We also need the resolution table
- iOffset = GetObjFieldOffset (resolverPtr, objData.MethodTable, W("m_scope"));
+ iOffset = GetObjFieldOffset (TO_CDADDR(resolverPtr), objData.MethodTable, W("m_scope"));
if (iOffset <= 0)
return bRet;
@@ -811,7 +813,7 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
if (objData.Request(g_sos, TO_CDADDR(scopePtr)) != S_OK)
return bRet;
- iOffset = GetObjFieldOffset (scopePtr, objData.MethodTable, W("m_tokens"));
+ iOffset = GetObjFieldOffset (TO_CDADDR(scopePtr), objData.MethodTable, W("m_tokens"));
if (iOffset <= 0)
return bRet;
@@ -822,7 +824,7 @@ BOOL GatherDynamicInfo(TADDR DynamicMethodObj, DacpObjectData *codeArray,
if (objData.Request(g_sos, TO_CDADDR(tokensPtr)) != S_OK)
return bRet;
- iOffset = GetObjFieldOffset(tokensPtr, objData.MethodTable, W("_items"));
+ iOffset = GetObjFieldOffset(TO_CDADDR(tokensPtr), objData.MethodTable, W("_items"));
if (iOffset <= 0)
return bRet;
@@ -1469,7 +1471,7 @@ HRESULT PrintVC(TADDR taMT, TADDR taObject, BOOL bPrintFields = TRUE)
void PrintRuntimeTypeInfo(TADDR p_rtObject, const DacpObjectData & rtObjectData)
{
// Get the method table
- int iOffset = GetObjFieldOffset(p_rtObject, rtObjectData.MethodTable, W("m_handle"));
+ int iOffset = GetObjFieldOffset(TO_CDADDR(p_rtObject), rtObjectData.MethodTable, W("m_handle"));
if (iOffset > 0)
{
TADDR mtPtr;
@@ -1541,7 +1543,7 @@ HRESULT PrintObj(TADDR taObj, BOOL bPrintFields = TRUE)
if (_wcscmp(obj.GetTypeName(), W("System.RuntimeType+RuntimeTypeCache")) == 0)
{
// Get the method table
- int iOffset = GetObjFieldOffset (taObj, objData.MethodTable, W("m_runtimeType"));
+ int iOffset = GetObjFieldOffset (TO_CDADDR(taObj), objData.MethodTable, W("m_runtimeType"));
if (iOffset > 0)
{
TADDR rtPtr;
@@ -1712,7 +1714,7 @@ HRESULT PrintPermissionSet (TADDR p_PermSet)
// Walk the fields, printing some fields in a special way.
- int iOffset = GetObjFieldOffset (p_PermSet, PermSetData.MethodTable, W("m_Unrestricted"));
+ int iOffset = GetObjFieldOffset (TO_CDADDR(p_PermSet), PermSetData.MethodTable, W("m_Unrestricted"));
if (iOffset > 0)
{
@@ -1724,7 +1726,7 @@ HRESULT PrintPermissionSet (TADDR p_PermSet)
ExtOut("Unrestricted: FALSE\n");
}
- iOffset = GetObjFieldOffset (p_PermSet, PermSetData.MethodTable, W("m_permSet"));
+ iOffset = GetObjFieldOffset (TO_CDADDR(p_PermSet), PermSetData.MethodTable, W("m_permSet"));
if (iOffset > 0)
{
TADDR tbSetPtr;
@@ -1738,7 +1740,7 @@ HRESULT PrintPermissionSet (TADDR p_PermSet)
return Status;
}
- iOffset = GetObjFieldOffset (tbSetPtr, tbSetData.MethodTable, W("m_Set"));
+ iOffset = GetObjFieldOffset (TO_CDADDR(tbSetPtr), tbSetData.MethodTable, W("m_Set"));
if (iOffset > 0)
{
DWORD_PTR PermsArrayPtr;
@@ -1758,7 +1760,7 @@ HRESULT PrintPermissionSet (TADDR p_PermSet)
}
}
- iOffset = GetObjFieldOffset (tbSetPtr, tbSetData.MethodTable, W("m_Obj"));
+ iOffset = GetObjFieldOffset (TO_CDADDR(tbSetPtr), tbSetData.MethodTable, W("m_Obj"));
if (iOffset > 0)
{
DWORD_PTR PermObjPtr;
@@ -1967,7 +1969,7 @@ HRESULT PrintArray(DacpObjectData& objData, DumpArrayFlags& flags, BOOL isPermSe
if (isElementValueType)
{
- DMLOut( " %s\n", DMLValueClass(objData.MethodTable, p_Element));
+ DMLOut( " %s\n", DMLValueClass(objData.ElementTypeHandle, p_Element));
}
else
{
@@ -2188,7 +2190,7 @@ static const HRESULT AsyncHResultValues[] =
COR_E_DATAMISALIGNED, // kDataMisalignedException
};
-BOOL IsAsyncException(TADDR taObj, TADDR mtObj)
+BOOL IsAsyncException(CLRDATA_ADDRESS taObj, CLRDATA_ADDRESS mtObj)
{
// by default we'll treat exceptions as synchronous
UINT32 xcode = EXCEPTION_COMPLUS;
@@ -2382,12 +2384,12 @@ void SosExtOutLargeString(__inout_z __inout_ecount_opt(len) WCHAR * pwszLargeStr
ExtOut("%S", pwsz);
}
-HRESULT FormatException(TADDR taObj, BOOL bLineNumbers = FALSE)
+HRESULT FormatException(CLRDATA_ADDRESS taObj, BOOL bLineNumbers = FALSE)
{
HRESULT Status = S_OK;
DacpObjectData objData;
- if ((Status=objData.Request(g_sos, TO_CDADDR(taObj))) != S_OK)
+ if ((Status=objData.Request(g_sos, taObj)) != S_OK)
{
ExtOut("Invalid object\n");
return Status;
@@ -2416,7 +2418,7 @@ HRESULT FormatException(TADDR taObj, BOOL bLineNumbers = FALSE)
// First try to get exception object data using ISOSDacInterface2
DacpExceptionObjectData excData;
- BOOL bGotExcData = SUCCEEDED(excData.Request(g_sos, TO_CDADDR(taObj)));
+ BOOL bGotExcData = SUCCEEDED(excData.Request(g_sos, taObj));
// Walk the fields, printing some fields in a special way.
// HR, InnerException, Message, StackTrace, StackTraceString
@@ -2486,7 +2488,7 @@ HRESULT FormatException(TADDR taObj, BOOL bLineNumbers = FALSE)
}
BOOL bAsync = bGotExcData ? IsAsyncException(excData)
- : IsAsyncException(taObj, TO_TADDR(objData.MethodTable));
+ : IsAsyncException(taObj, objData.MethodTable);
{
TADDR taStackTrace = 0;
@@ -2720,7 +2722,7 @@ DECLARE_API(PrintException)
if (p_Object)
{
- FormatException(p_Object, bLineNumbers);
+ FormatException(TO_CDADDR(p_Object), bLineNumbers);
}
// Are there nested exceptions?
@@ -2760,7 +2762,7 @@ DECLARE_API(PrintException)
}
ExtOut("\nNested exception -------------------------------------------------------------\n");
- Status = FormatException((DWORD_PTR) obj, bLineNumbers);
+ Status = FormatException(obj, bLineNumbers);
if (Status != S_OK)
{
return Status;
@@ -3173,7 +3175,7 @@ DECLARE_API(DumpPermissionSet)
{
INIT_API();
MINIDUMP_NOT_SUPPORTED();
-
+
DWORD_PTR p_Object = NULL;
CMDValue arg[] =
@@ -3522,7 +3524,7 @@ void PrintRuntimeTypes(DWORD_PTR objAddr,size_t Size,DWORD_PTR methodTable,LPVOI
if (_wcscmp(g_mdName, W("System.RuntimeType")) == 0)
{
pArgs->mtOfRuntimeType = methodTable;
- pArgs->handleFieldOffset = GetObjFieldOffset(objAddr, methodTable, W("m_handle"));
+ pArgs->handleFieldOffset = GetObjFieldOffset(TO_CDADDR(objAddr), TO_CDADDR(methodTable), W("m_handle"));
if (pArgs->handleFieldOffset <= 0)
ExtOut("Error getting System.RuntimeType.m_handle offset\n");
@@ -5776,7 +5778,6 @@ HRESULT PrintSpecialThreads()
TADDR CLRTLSDataAddr = 0;
-#ifdef FEATURE_IMPLICIT_TLS
TADDR tlsArrayAddr = NULL;
if (!SafeReadMemory (TO_TADDR(cdaTeb) + WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer , &tlsArrayAddr, sizeof (void**), NULL))
{
@@ -5786,36 +5787,13 @@ HRESULT PrintSpecialThreads()
TADDR moduleTlsDataAddr = 0;
- if (!SafeReadMemory (tlsArrayAddr + sizeof (void*) * dwCLRTLSDataIndex, &moduleTlsDataAddr, sizeof (void**), NULL))
+ if (!SafeReadMemory (tlsArrayAddr + sizeof (void*) * (dwCLRTLSDataIndex & 0xFFFF), &moduleTlsDataAddr, sizeof (void**), NULL))
{
PrintLn("Failed to get Tls expansion slots for thread ", ThreadID(SysId));
continue;
}
- CLRTLSDataAddr = moduleTlsDataAddr + OFFSETOF__TLS__tls_EETlsData;
-#else
- if (dwCLRTLSDataIndex < TLS_MINIMUM_AVAILABLE)
- {
- CLRTLSDataAddr = TO_TADDR(cdaTeb) + offsetof(TEB, TlsSlots) + sizeof (void*) * dwCLRTLSDataIndex;
- }
- else
- {
- //if TLS index is bigger than TLS_MINIMUM_AVAILABLE, the TLS slot lives in ExpansionSlots
- TADDR TebExpsionAddr = NULL;
- if (!SafeReadMemory (TO_TADDR(cdaTeb) + offsetof(TEB, TlsExpansionSlots) , &TebExpsionAddr, sizeof (void**), NULL))
- {
- PrintLn("Failed to get Tls expansion slots for thread ", ThreadID(SysId));
- continue;
- }
-
- if (TebExpsionAddr == NULL)
- {
- continue;
- }
-
- CLRTLSDataAddr = TebExpsionAddr + sizeof (void*) * (dwCLRTLSDataIndex - TLS_MINIMUM_AVAILABLE);
- }
-#endif // FEATURE_IMPLICIT_TLS
+ CLRTLSDataAddr = moduleTlsDataAddr + ((dwCLRTLSDataIndex & 0x7FFF0000) >> 16) + OFFSETOF__TLS__tls_EETlsData;
TADDR CLRTLSData = NULL;
if (!SafeReadMemory (CLRTLSDataAddr, &CLRTLSData, sizeof (TADDR), NULL))
@@ -13796,7 +13774,7 @@ HRESULT AppendExceptionInfo(CLRDATA_ADDRESS cdaObj,
}
BOOL bAsync = bGotExcData ? IsAsyncException(excData)
- : IsAsyncException(TO_TADDR(cdaObj), TO_TADDR(objData.MethodTable));
+ : IsAsyncException(cdaObj, objData.MethodTable);
DWORD_PTR arrayPtr;
if (bGotExcData)
diff --git a/src/ToolBox/SOS/lldbplugin/CMakeLists.txt b/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
index db2516a93e..d780cb2e85 100644
--- a/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
+++ b/src/ToolBox/SOS/lldbplugin/CMakeLists.txt
@@ -63,7 +63,8 @@ if (CLR_CMAKE_PLATFORM_DARWIN)
else()
set(MESSAGE_MODE WARNING)
endif()
- message(${MESSAGE_MODE} "Cannot find lldb-3.5, lldb-3.6, lldb-3.8, lldb-3.9 or lldb-4.0. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ message(${MESSAGE_MODE} "Cannot find lldb-3.5, lldb-3.6, lldb-3.8, lldb-3.9 or lldb-4.0. Try installing liblldb-3.9-dev (or the appropriate package for your platform). You may need to set LLVM_HOME if the build still can't find it.")
+
return()
endif()
@@ -81,13 +82,17 @@ find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.8/include")
find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.7/include")
find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.6/include")
find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/lib/llvm-3.5/include")
+#FreeBSD
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/local/llvm39/include")
+find_path(LLDB_H "lldb/API/LLDB.h" PATHS "/usr/local/llvm38/include")
if(LLDB_H STREQUAL LLDB_H-NOTFOUND)
if(REQUIRE_LLDBPLUGIN)
- message(FATAL_ERROR "Cannot find LLDB.h. Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ set(MESSAGE_MODE FATAL_ERROR)
else()
- message(WARNING "Cannot find LLDB.h Try installing lldb-3.6-dev (or the appropriate package for your platform)")
+ set(MESSAGE_MODE WARNING)
endif()
+ message(${MESSAGE_MODE} "Cannot find LLDB.h Try installing lldb-3.9-dev (or the appropriate package for your platform). You may need to set LLVM_HOME if the build still can't find it.")
return()
endif()
diff --git a/src/ToolBox/SOS/lldbplugin/services.cpp b/src/ToolBox/SOS/lldbplugin/services.cpp
index e3eee4fc59..3186920eb0 100644
--- a/src/ToolBox/SOS/lldbplugin/services.cpp
+++ b/src/ToolBox/SOS/lldbplugin/services.cpp
@@ -8,6 +8,8 @@
#include <string.h>
#include <string>
+#define CONVERT_FROM_SIGN_EXTENDED(offset) ((ULONG_PTR)(offset))
+
ULONG g_currentThreadIndex = -1;
ULONG g_currentThreadSystemId = -1;
char *g_coreclrDirectory;
@@ -545,6 +547,9 @@ LLDBServices::Disassemble(
uint8_t byte;
int cch;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
if (buffer == NULL)
{
hr = E_INVALIDARG;
@@ -750,6 +755,9 @@ LLDBServices::ReadVirtual(
lldb::SBError error;
size_t read = 0;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
lldb::SBProcess process = GetCurrentProcess();
if (!process.IsValid())
{
@@ -776,6 +784,9 @@ LLDBServices::WriteVirtual(
lldb::SBError error;
size_t written = 0;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
lldb::SBProcess process = GetCurrentProcess();
if (!process.IsValid())
{
@@ -822,6 +833,9 @@ LLDBServices::GetNameByOffset(
lldb::SBSymbol symbol;
std::string str;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
@@ -1012,6 +1026,9 @@ LLDBServices::GetModuleByOffset(
lldb::SBTarget target;
int numModules;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
@@ -1076,6 +1093,9 @@ LLDBServices::GetModuleNames(
lldb::SBFileSpec fileSpec;
HRESULT hr = S_OK;
+ // lldb doesn't expect sign-extended address
+ base = CONVERT_FROM_SIGN_EXTENDED(base);
+
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
@@ -1167,6 +1187,9 @@ LLDBServices::GetLineByOffset(
lldb::SBLineEntry lineEntry;
std::string str;
+ // lldb doesn't expect sign-extended address
+ offset = CONVERT_FROM_SIGN_EXTENDED(offset);
+
target = m_debugger.GetSelectedTarget();
if (!target.IsValid())
{
@@ -1554,6 +1577,25 @@ LLDBServices::GetContextFromFrame(
dtcontext->R10 = GetRegister(frame, "r10");
dtcontext->R11 = GetRegister(frame, "r11");
dtcontext->R12 = GetRegister(frame, "r12");
+#elif DBG_TARGET_X86
+ dtcontext->Eip = frame.GetPC();
+ dtcontext->Esp = frame.GetSP();
+ dtcontext->Ebp = frame.GetFP();
+ dtcontext->EFlags = GetRegister(frame, "eflags");
+
+ dtcontext->Edi = GetRegister(frame, "edi");
+ dtcontext->Esi = GetRegister(frame, "esi");
+ dtcontext->Ebx = GetRegister(frame, "ebx");
+ dtcontext->Edx = GetRegister(frame, "edx");
+ dtcontext->Ecx = GetRegister(frame, "ecx");
+ dtcontext->Eax = GetRegister(frame, "eax");
+
+ dtcontext->SegCs = GetRegister(frame, "cs");
+ dtcontext->SegSs = GetRegister(frame, "ss");
+ dtcontext->SegDs = GetRegister(frame, "ds");
+ dtcontext->SegEs = GetRegister(frame, "es");
+ dtcontext->SegFs = GetRegister(frame, "fs");
+ dtcontext->SegGs = GetRegister(frame, "gs");
#endif
}
diff --git a/src/ToolBox/superpmi/superpmi-shared/coreclrcommoncallbacks.h b/src/ToolBox/superpmi/superpmi-shared/coreclrcommoncallbacks.h
index 254981cada..98c44c5dec 100644
--- a/src/ToolBox/superpmi/superpmi-shared/coreclrcommoncallbacks.h
+++ b/src/ToolBox/superpmi/superpmi-shared/coreclrcommoncallbacks.h
@@ -14,7 +14,7 @@ LPVOID STDMETHODCALLTYPE EEHeapAllocInProcessHeap(DWORD dwFlags, SIZE_T dwBytes)
BOOL STDMETHODCALLTYPE EEHeapFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem);
void* STDMETHODCALLTYPE GetCLRFunction(LPCSTR functionName);
-typedef LPVOID (STDMETHODCALLTYPE *pfnEEHeapAllocInProcessHeap)(DWORD dwFlags, SIZE_T dwBytes);
-typedef BOOL (STDMETHODCALLTYPE *pfnEEHeapFreeInProcessHeap)(DWORD dwFlags, LPVOID lpMem);
+typedef LPVOID(STDMETHODCALLTYPE* pfnEEHeapAllocInProcessHeap)(DWORD dwFlags, SIZE_T dwBytes);
+typedef BOOL(STDMETHODCALLTYPE* pfnEEHeapFreeInProcessHeap)(DWORD dwFlags, LPVOID lpMem);
#endif
diff --git a/src/ToolBox/superpmi/superpmi-shared/errorhandling.h b/src/ToolBox/superpmi/superpmi-shared/errorhandling.h
index 8c0cadd8b8..bd4a8990d2 100644
--- a/src/ToolBox/superpmi/superpmi-shared/errorhandling.h
+++ b/src/ToolBox/superpmi/superpmi-shared/errorhandling.h
@@ -11,7 +11,7 @@
#include "logging.h"
-// EXCEPTIONCODE_DebugBreakorAV is just the base exception number; calls to DebugBreakorAV()
+// EXCEPTIONCODE_DebugBreakorAV is just the base exception number; calls to DebugBreakorAV()
// pass a unique number to add to this. EXCEPTIONCODE_DebugBreakorAV_MAX is the maximum number
// of this exception range.
#define EXCEPTIONCODE_DebugBreakorAV 0xe0421000
diff --git a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
index 29baaa8a39..5c6dc4fc04 100644
--- a/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
+++ b/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h
@@ -15,6 +15,8 @@
// interface declaration (with the "virtual" and "= 0" syntax removed). This is to make it easy to compare
// against the interface declaration.
+// clang-format off
+
public:
/**********************************************************************************/
//
@@ -119,6 +121,11 @@ CORINFO_METHOD_HANDLE resolveVirtualMethod(CORINFO_METHOD_HANDLE virtualMethod,
CORINFO_CLASS_HANDLE implementingClass,
CORINFO_CONTEXT_HANDLE ownerType);
+// Get the unboxed entry point for a method, if possible.
+CORINFO_METHOD_HANDLE getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg /* OUT */);
+
// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE elemType);
@@ -428,6 +435,14 @@ BOOL canCast(CORINFO_CLASS_HANDLE child, // subtype (extends parent)
// TRUE if cls1 and cls2 are considered equivalent types.
BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
diff --git a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
index 21f7906510..b0cb7ad3c8 100644
--- a/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
+++ b/src/ToolBox/superpmi/superpmi-shared/lwmlist.h
@@ -31,6 +31,8 @@ LWM(CanInlineTypeCheckWithObjectVTable, DWORDLONG, DWORD)
LWM(CanSkipMethodVerification, DLD, DWORD)
LWM(CanTailCall, Agnostic_CanTailCall, DWORD)
LWM(CheckMethodModifier, Agnostic_CheckMethodModifier, DWORD)
+LWM(CompareTypesForCast, DLDL, DWORD)
+LWM(CompareTypesForEquality, DLDL, DWORD)
LWM(CompileMethod, DWORD, Agnostic_CompileMethod)
LWM(ConstructStringLiteral, DLD, DLD)
LWM(EmbedClassHandle, DWORDLONG, DLDL)
@@ -69,7 +71,7 @@ LWM(GetClassName, DWORDLONG, DWORD)
LWM(GetClassNumInstanceFields, DWORDLONG, DWORD)
LWM(GetClassSize, DWORDLONG, DWORD)
LWM(GetCookieForPInvokeCalliSig, GetCookieForPInvokeCalliSigValue, DLDL)
-LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG)
+LWM(GetDefaultEqualityComparerClass, DWORDLONG, DWORDLONG)
LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut)
LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO)
LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE)
@@ -122,6 +124,7 @@ LWM(GetThreadTLSIndex, DWORD, DLD)
LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG)
LWM(GetTypeForBox, DWORDLONG, DWORDLONG)
LWM(GetTypeForPrimitiveValueClass, DWORDLONG, DWORD)
+LWM(GetUnboxedEntry, DWORDLONG, DLD);
LWM(GetUnBoxHelper, DWORDLONG, DWORD)
LWM(GetUnmanagedCallConv, DWORDLONG, DWORD)
LWM(GetVarArgsHandle, GetVarArgsHandleValue, DLDL)
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 0bf288d196..3326a49937 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -985,7 +985,7 @@ void MethodContext::recGetMethodName(CORINFO_METHOD_HANDLE ftn, char* methodname
else
value.A = (DWORD)-1;
- if (moduleName != nullptr)
+ if ((moduleName != nullptr) && (*moduleName != nullptr))
value.B = GetMethodName->AddBuffer((unsigned char*)*moduleName, (DWORD)strlen(*moduleName) + 1);
else
value.B = (DWORD)-1;
@@ -1029,9 +1029,10 @@ const char* MethodContext::repGetMethodName(CORINFO_METHOD_HANDLE ftn, const cha
return result;
}
-
-void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
- char* methodName, const char** className, const char **namespaceName)
+void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
+ char* methodName,
+ const char** className,
+ const char** namespaceName)
{
if (GetMethodNameFromMetadata == nullptr)
GetMethodNameFromMetadata = new LightWeightMap<DLDD, DDD>();
@@ -1046,13 +1047,14 @@ void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
else
value.A = (DWORD)-1;
- if (className != nullptr)
+ if ((className != nullptr) && (*className != nullptr))
value.B = GetMethodNameFromMetadata->AddBuffer((unsigned char*)*className, (DWORD)strlen(*className) + 1);
else
value.B = (DWORD)-1;
- if (namespaceName != nullptr)
- value.C = GetMethodNameFromMetadata->AddBuffer((unsigned char*)*namespaceName, (DWORD)strlen(*namespaceName) + 1);
+ if ((namespaceName != nullptr) && (*namespaceName != nullptr))
+ value.C =
+ GetMethodNameFromMetadata->AddBuffer((unsigned char*)*namespaceName, (DWORD)strlen(*namespaceName) + 1);
else
value.C = (DWORD)-1;
@@ -1062,15 +1064,18 @@ void MethodContext::recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
void MethodContext::dmpGetMethodNameFromMetadata(DLDD key, DDD value)
{
- unsigned char* methodName = (unsigned char*)GetMethodName->GetBuffer(value.A);
- unsigned char* className = (unsigned char*)GetMethodName->GetBuffer(value.B);
+ unsigned char* methodName = (unsigned char*)GetMethodName->GetBuffer(value.A);
+ unsigned char* className = (unsigned char*)GetMethodName->GetBuffer(value.B);
unsigned char* namespaceName = (unsigned char*)GetMethodName->GetBuffer(value.C);
- printf("GetMethodNameFromMetadata key - ftn-%016llX classNonNull-%u namespaceNonNull-%u, value meth-'%s', class-'%s', namespace-'%s'",
- key.A, key.B, key.C, methodName, className, namespaceName);
+ printf("GetMethodNameFromMetadata key - ftn-%016llX classNonNull-%u namespaceNonNull-%u, value meth-'%s', "
+ "class-'%s', namespace-'%s'",
+ key.A, key.B, key.C, methodName, className, namespaceName);
GetMethodNameFromMetadata->Unlock();
}
-const char* MethodContext::repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char** moduleName, const char** namespaceName)
+const char* MethodContext::repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
+ const char** moduleName,
+ const char** namespaceName)
{
const char* result = nullptr;
DDD value;
@@ -1091,16 +1096,16 @@ const char* MethodContext::repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ft
}
else
{
- value = GetMethodNameFromMetadata->Get(key);
+ value = GetMethodNameFromMetadata->Get(key);
result = (const char*)GetMethodNameFromMetadata->GetBuffer(value.A);
if (moduleName != nullptr)
- {
+ {
*moduleName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.B);
}
if (namespaceName != nullptr)
- {
+ {
*namespaceName = (const char*)GetMethodNameFromMetadata->GetBuffer(value.C);
}
}
@@ -1464,7 +1469,8 @@ void MethodContext::repGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
pResult->stubLookup.runtimeLookup.testForNull = value.stubLookup.runtimeLookup.testForNull != 0;
pResult->stubLookup.runtimeLookup.testForFixup = value.stubLookup.runtimeLookup.testForFixup != 0;
pResult->stubLookup.runtimeLookup.indirectFirstOffset = value.stubLookup.runtimeLookup.indirectFirstOffset != 0;
- pResult->stubLookup.runtimeLookup.indirectSecondOffset = value.stubLookup.runtimeLookup.indirectSecondOffset != 0;
+ pResult->stubLookup.runtimeLookup.indirectSecondOffset =
+ value.stubLookup.runtimeLookup.indirectSecondOffset != 0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
pResult->stubLookup.runtimeLookup.offsets[i] = (SIZE_T)value.stubLookup.runtimeLookup.offsets[i];
}
@@ -3012,6 +3018,55 @@ CORINFO_METHOD_HANDLE MethodContext::repResolveVirtualMethod(CORINFO_METHOD_HAND
return (CORINFO_METHOD_HANDLE)result;
}
+void MethodContext::recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn,
+ bool *requiresInstMethodTableArg,
+ CORINFO_METHOD_HANDLE result)
+{
+ if (GetUnboxedEntry == nullptr)
+ {
+ GetUnboxedEntry = new LightWeightMap<DWORDLONG, DLD>();
+ }
+
+ DWORDLONG key = (DWORDLONG) ftn;
+ DLD value;
+ value.A = (DWORDLONG) result;
+ if (requiresInstMethodTableArg != nullptr)
+ {
+ value.B = (DWORD) *requiresInstMethodTableArg ? 1 : 0;
+ }
+ else
+ {
+ value.B = 0;
+ }
+ GetUnboxedEntry->Add(key, value);
+ DEBUG_REC(dmpGetUnboxedEntry(key, value));
+}
+
+void MethodContext::dmpGetUnboxedEntry(DWORDLONG key, DLD value)
+{
+ printf("GetUnboxedEntry ftn-%016llX, result-%016llX, requires-inst-%u",
+ key, value.A, value.B);
+}
+
+CORINFO_METHOD_HANDLE MethodContext::repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg)
+{
+ DWORDLONG key = (DWORDLONG)ftn;
+
+ AssertCodeMsg(GetUnboxedEntry != nullptr, EXCEPTIONCODE_MC, "No GetUnboxedEntry map for %016llX", key);
+ AssertCodeMsg(GetUnboxedEntry->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX", key);
+ DLD result = GetUnboxedEntry->Get(key);
+
+ DEBUG_REP(dmpGetUnboxedEntry(key, result));
+
+ if (requiresInstMethodTableArg != nullptr)
+ {
+ *requiresInstMethodTableArg = (result.B == 1);
+ }
+
+ return (CORINFO_METHOD_HANDLE)(result.A);
+}
+
void MethodContext::recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result)
{
if (GetDefaultEqualityComparerClass == nullptr)
@@ -4197,7 +4252,7 @@ void MethodContext::recGetFieldName(CORINFO_FIELD_HANDLE ftn, const char** modul
else
value.A = (DWORD)-1;
- if (moduleName != nullptr) // protect strlen
+ if ((moduleName != nullptr) && (*moduleName != nullptr)) // protect strlen
value.B = (DWORD)GetFieldName->AddBuffer((unsigned char*)*moduleName, (DWORD)strlen(*moduleName) + 1);
else
value.B = (DWORD)-1;
@@ -5288,6 +5343,76 @@ BOOL MethodContext::repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return value;
}
+void MethodContext::recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass,
+ TypeCompareState result)
+{
+ if (CompareTypesForCast == nullptr)
+ CompareTypesForCast = new LightWeightMap<DLDL, DWORD>();
+
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)fromClass;
+ key.B = (DWORDLONG)toClass;
+
+ CompareTypesForCast->Add(key, (DWORD)result);
+}
+void MethodContext::dmpCompareTypesForCast(DLDL key, DWORD value)
+{
+ printf("CompareTypesForCast key fromClas=%016llX, toClass=%016llx, result=%d", key.A, key.B, value);
+}
+TypeCompareState MethodContext::repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)fromClass;
+ key.B = (DWORDLONG)toClass;
+
+ AssertCodeMsg(CompareTypesForCast->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX",
+ (DWORDLONG)fromClass, (DWORDLONG)toClass);
+ TypeCompareState value = (TypeCompareState)CompareTypesForCast->Get(key);
+ return value;
+}
+
+void MethodContext::recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2,
+ TypeCompareState result)
+{
+ if (CompareTypesForEquality == nullptr)
+ CompareTypesForEquality = new LightWeightMap<DLDL, DWORD>();
+
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ CompareTypesForEquality->Add(key, (DWORD)result);
+}
+void MethodContext::dmpCompareTypesForEquality(DLDL key, DWORD value)
+{
+ printf("CompareTypesForEquality key cls1=%016llX, cls2=%016llx, result=%d", key.A, key.B, value);
+}
+TypeCompareState MethodContext::repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ DLDL key;
+ ZeroMemory(&key, sizeof(DLDL)); // We use the input structs as a key and use memcmp to compare.. so we need to zero
+ // out padding too
+
+ key.A = (DWORDLONG)cls1;
+ key.B = (DWORDLONG)cls2;
+
+ AssertCodeMsg(CompareTypesForEquality->GetIndex(key) != -1, EXCEPTIONCODE_MC, "Didn't find %016llX %016llX",
+ (DWORDLONG)cls1, (DWORDLONG)cls2);
+ TypeCompareState value = (TypeCompareState)CompareTypesForEquality->Get(key);
+ return value;
+}
+
void MethodContext::recFindNameOfToken(
CORINFO_MODULE_HANDLE module, mdToken metaTOK, char* szFQName, size_t FQNameCapacity, size_t result)
{
@@ -6008,12 +6133,12 @@ bool MethodContext::wasEnviromentChanged()
for (unsigned int i = 0; i < Environment->GetCount(); i++)
{
Agnostic_Environment currEnvValue = Environment->Get(i);
- LPCSTR currKey = (LPCSTR)Environment->GetBuffer(currEnvValue.name_index);
- LPCSTR currVal = (LPCSTR)Environment->GetBuffer(currEnvValue.val_index);
+ LPCSTR currKey = (LPCSTR)Environment->GetBuffer(currEnvValue.name_index);
+ LPCSTR currVal = (LPCSTR)Environment->GetBuffer(currEnvValue.val_index);
Agnostic_Environment prevEnvValue = prevEnviroment->Get(i);
- LPCSTR prevKey = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.name_index);
- LPCSTR prevVal = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.val_index);
+ LPCSTR prevKey = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.name_index);
+ LPCSTR prevVal = (LPCSTR)prevEnviroment->GetBuffer(prevEnvValue.val_index);
if (strcmp(currKey, prevKey) != 0 || strcmp(currVal, prevVal) != 0)
{
changed = true;
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 52515733d3..450831d114 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -617,9 +617,14 @@ public:
void dmpGetMethodName(DLD key, DD value);
const char* repGetMethodName(CORINFO_METHOD_HANDLE ftn, const char** moduleName);
- void recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, char* methodname, const char** moduleName, const char** namespaceName);
+ void recGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
+ char* methodname,
+ const char** moduleName,
+ const char** namespaceName);
void dmpGetMethodNameFromMetadata(DLDD key, DDD value);
- const char* repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, const char** className, const char** namespaceName);
+ const char* repGetMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn,
+ const char** className,
+ const char** namespaceName);
void recGetJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes, DWORD result);
void dmpGetJitFlags(DWORD key, DD value);
@@ -872,11 +877,17 @@ public:
CORINFO_CLASS_HANDLE implClass,
CORINFO_CONTEXT_HANDLE ownerType);
+ void recGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg,
+ CORINFO_METHOD_HANDLE result);
+ void dmpGetUnboxedEntry(DWORDLONG key, DLD value);
+ CORINFO_METHOD_HANDLE repGetUnboxedEntry(CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg);
+
void recGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls, CORINFO_CLASS_HANDLE result);
void dmpGetDefaultEqualityComparerClass(DWORDLONG key, DWORDLONG value);
CORINFO_CLASS_HANDLE repGetDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls);
-
void recGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_CLASS_HANDLE result);
void dmpGetTokenTypeAsHandle(const GetTokenTypeAsHandleValue& key, DWORDLONG value);
CORINFO_CLASS_HANDLE repGetTokenTypeAsHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken);
@@ -1176,6 +1187,14 @@ public:
void dmpAreTypesEquivalent(DLDL key, DWORD value);
BOOL repAreTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ void recCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass, TypeCompareState result);
+ void dmpCompareTypesForCast(DLDL key, DWORD value);
+ TypeCompareState repCompareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+
+ void recCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, TypeCompareState result);
+ void dmpCompareTypesForEquality(DLDL key, DWORD value);
+ TypeCompareState repCompareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
void recFindNameOfToken(
CORINFO_MODULE_HANDLE module, mdToken metaTOK, char* szFQName, size_t FQNameCapacity, size_t result);
void dmpFindNameOfToken(DLD key, DLD value);
@@ -1243,7 +1262,7 @@ public:
void dmpGetStringConfigValue(DWORD nameIndex, DWORD result);
const wchar_t* repGetStringConfigValue(const wchar_t* name);
- bool wasEnviromentChanged();
+ bool wasEnviromentChanged();
static DenseLightWeightMap<Agnostic_Environment>* prevEnviroment;
CompileResult* cr;
@@ -1257,7 +1276,7 @@ private:
};
// ********************* Please keep this up-to-date to ease adding more ***************
-// Highest packet number: 162
+// Highest packet number: 165
// *************************************************************************************
enum mcPackets
{
@@ -1279,6 +1298,8 @@ enum mcPackets
Packet_CheckMethodModifier = 142, // retired as 13 on 2013/07/04
Retired3 = 14,
Retired5 = 141, // retired as 14 on 2013/07/03
+ Packet_CompareTypesForCast = 163, // Added 10/4/17
+ Packet_CompareTypesForEquality = 164, // Added 10/4/17
Packet_CompileMethod = 143, // retired as 141 on 2013/07/09
Packet_ConstructStringLiteral = 15,
Packet_EmbedClassHandle = 16,
@@ -1353,7 +1374,7 @@ enum mcPackets
Packet_GetMethodHash = 73,
Packet_GetMethodInfo = 74,
Packet_GetMethodName = 75,
- Packet_GetMethodNameFromMetadata = 161, // Added 9/6/17
+ Packet_GetMethodNameFromMetadata = 161, // Added 9/6/17
Packet_GetMethodSig = 76,
Packet_GetMethodSync = 77,
Packet_GetMethodVTableOffset = 78,
@@ -1370,6 +1391,7 @@ enum mcPackets
Packet_GetTokenTypeAsHandle = 89,
Packet_GetTypeForBox = 90,
Packet_GetTypeForPrimitiveValueClass = 91,
+ Packet_GetUnboxedEntry = 165, // Added 10/26/17
Packet_GetUnBoxHelper = 92,
Packet_GetReadyToRunHelper = 150, // Added 10/10/2014
Packet_GetReadyToRunDelegateCtorHelper = 157, // Added 3/30/2016
diff --git a/src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp b/src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp
index 8d1930fb57..beadcffc25 100644
--- a/src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp
+++ b/src/ToolBox/superpmi/superpmi-shared/methodcontextreader.cpp
@@ -110,9 +110,8 @@ MethodContextReader::MethodContextReader(
this->tocFile.LoadToc(tocFileName.c_str());
// we'll get here even if we don't have a valid index file
- this->fileHandle =
- OpenFile(mchFile.c_str(),
- (this->hasTOC() && this->hasIndex()) ? FILE_ATTRIBUTE_NORMAL : FILE_FLAG_SEQUENTIAL_SCAN);
+ this->fileHandle = OpenFile(mchFile.c_str(), (this->hasTOC() && this->hasIndex()) ? FILE_ATTRIBUTE_NORMAL
+ : FILE_FLAG_SEQUENTIAL_SCAN);
if (this->fileHandle != INVALID_HANDLE_VALUE)
{
GetFileSizeEx(this->fileHandle, (PLARGE_INTEGER) & this->fileSize);
@@ -308,7 +307,7 @@ MethodContextBuffer MethodContextReader::GetNextMethodContextFromHash()
if (this->hasTOC())
{
// We have a TOC so lets go through the TOCElements
- //one-by-one till we find a matching hash
+ // one-by-one till we find a matching hash
for (; curTOCIndex < (int)this->tocFile.GetTocCount(); curTOCIndex++)
{
if (_strnicmp(this->Hash, this->tocFile.GetElementPtr(curTOCIndex)->Hash, MD5_HASH_BUFFER_SIZE) == 0)
@@ -324,7 +323,7 @@ MethodContextBuffer MethodContextReader::GetNextMethodContextFromHash()
else
{
// Keep reading all MCs until we hit a match
- //or we reach the end or hit an error
+ // or we reach the end or hit an error
while (true)
{
// Read a method context
@@ -336,7 +335,7 @@ MethodContextBuffer MethodContextReader::GetNextMethodContextFromHash()
char mcHash[MD5_HASH_BUFFER_SIZE];
// Create a temporary copy of mcb.buff plus ending 2-byte canary
- //this will get freed up by MethodContext constructor
+ // this will get freed up by MethodContext constructor
unsigned char* buff = new unsigned char[mcb.size + 2];
memcpy(buff, mcb.buff, mcb.size + 2);
@@ -466,7 +465,7 @@ MethodContextBuffer MethodContextReader::GetSpecificMethodContext(unsigned int m
MethodContextBuffer mcb = this->ReadMethodContext(false);
// The curMCIndex value updated by ReadMethodContext() is incorrect
- //since we are repositioning the file pointer we need to update it
+ // since we are repositioning the file pointer we need to update it
curMCIndex = methodNumber;
return mcb;
diff --git a/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h b/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h
index c3988f8487..40fcd462dc 100644
--- a/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h
+++ b/src/ToolBox/superpmi/superpmi-shared/spmirecordhelper.h
@@ -291,12 +291,12 @@ inline MethodContext::Agnostic_CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::StoreAg
{
MethodContext::Agnostic_CORINFO_RUNTIME_LOOKUP runtimeLookup;
ZeroMemory(&runtimeLookup, sizeof(runtimeLookup));
- runtimeLookup.signature = (DWORDLONG)pLookup->signature;
- runtimeLookup.helper = (DWORD)pLookup->helper;
- runtimeLookup.indirections = (DWORD)pLookup->indirections;
- runtimeLookup.testForNull = (DWORD)pLookup->testForNull;
- runtimeLookup.testForFixup = (DWORD)pLookup->testForFixup;
- runtimeLookup.indirectFirstOffset = (DWORD)pLookup->indirectFirstOffset;
+ runtimeLookup.signature = (DWORDLONG)pLookup->signature;
+ runtimeLookup.helper = (DWORD)pLookup->helper;
+ runtimeLookup.indirections = (DWORD)pLookup->indirections;
+ runtimeLookup.testForNull = (DWORD)pLookup->testForNull;
+ runtimeLookup.testForFixup = (DWORD)pLookup->testForFixup;
+ runtimeLookup.indirectFirstOffset = (DWORD)pLookup->indirectFirstOffset;
runtimeLookup.indirectSecondOffset = (DWORD)pLookup->indirectSecondOffset;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
runtimeLookup.offsets[i] = (DWORDLONG)pLookup->offsets[i];
@@ -307,12 +307,12 @@ inline CORINFO_RUNTIME_LOOKUP SpmiRecordsHelper::RestoreCORINFO_RUNTIME_LOOKUP(
MethodContext::Agnostic_CORINFO_RUNTIME_LOOKUP& lookup)
{
CORINFO_RUNTIME_LOOKUP runtimeLookup;
- runtimeLookup.signature = (LPVOID)lookup.signature;
- runtimeLookup.helper = (CorInfoHelpFunc)lookup.helper;
- runtimeLookup.indirections = (WORD)lookup.indirections;
- runtimeLookup.testForNull = lookup.testForNull != 0;
- runtimeLookup.testForFixup = lookup.testForFixup != 0;
- runtimeLookup.indirectFirstOffset = lookup.indirectFirstOffset != 0;
+ runtimeLookup.signature = (LPVOID)lookup.signature;
+ runtimeLookup.helper = (CorInfoHelpFunc)lookup.helper;
+ runtimeLookup.indirections = (WORD)lookup.indirections;
+ runtimeLookup.testForNull = lookup.testForNull != 0;
+ runtimeLookup.testForFixup = lookup.testForFixup != 0;
+ runtimeLookup.indirectFirstOffset = lookup.indirectFirstOffset != 0;
runtimeLookup.indirectSecondOffset = lookup.indirectSecondOffset != 0;
for (int i = 0; i < CORINFO_MAXINDIRECTIONS; i++)
runtimeLookup.offsets[i] = (size_t)lookup.offsets[i];
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp
index 19f96385e4..13254dc46c 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitcompiler.cpp
@@ -38,7 +38,7 @@ CorJitResult __stdcall interceptor_ICJC::compileMethod(ICorJitInfo*
our_ICorJitInfo.mc->recCompileMethod(info, flags);
// force some extra data into our tables..
- //data probably not needed with RyuJIT, but needed in 4.5 and 4.5.1 to help with catching cached values
+ // data probably not needed with RyuJIT, but needed in 4.5 and 4.5.1 to help with catching cached values
our_ICorJitInfo.getBuiltinClass(CLASSID_SYSTEM_OBJECT);
our_ICorJitInfo.getBuiltinClass(CLASSID_TYPED_BYREF);
our_ICorJitInfo.getBuiltinClass(CLASSID_TYPE_HANDLE);
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
index 6051de8840..3477baca77 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp
@@ -76,22 +76,25 @@ bool interceptor_ICJI::getMethodInfo(CORINFO_METHOD_HANDLE ftn, /* IN */
param.info = info;
param.temp = false;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("getMethodInfo");
- pParam->temp = pParam->pThis->original_ICorJitInfo->getMethodInfo(pParam->ftn, pParam->info);
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recGetMethodInfo(ftn, info, param.temp, param.exceptionCode);
-}
-PAL_ENDTRY
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("getMethodInfo");
+ pParam->temp = pParam->pThis->original_ICorJitInfo->getMethodInfo(pParam->ftn, pParam->info);
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recGetMethodInfo(ftn, info, param.temp, param.exceptionCode);
+ }
+ PAL_ENDTRY
-return param.temp;
+ return param.temp;
}
// Decides if you have any limitations for inlining. If everything's OK, it will return
@@ -122,23 +125,26 @@ CorInfoInline interceptor_ICJI::canInline(CORINFO_METHOD_HANDLE callerHnd, /*
param.pRestrictions = pRestrictions;
param.temp = INLINE_NEVER;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("canInline");
- pParam->temp =
- pParam->pThis->original_ICorJitInfo->canInline(pParam->callerHnd, pParam->calleeHnd, pParam->pRestrictions);
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recCanInline(callerHnd, calleeHnd, pRestrictions, param.temp, param.exceptionCode);
-}
-PAL_ENDTRY
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("canInline");
+ pParam->temp = pParam->pThis->original_ICorJitInfo->canInline(pParam->callerHnd, pParam->calleeHnd,
+ pParam->pRestrictions);
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recCanInline(callerHnd, calleeHnd, pRestrictions, param.temp, param.exceptionCode);
+ }
+ PAL_ENDTRY
-return param.temp;
+ return param.temp;
}
// Reports whether or not a method can be inlined, and why. canInline is responsible for reporting all
@@ -212,10 +218,10 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me
// This function returns the offset of the specified method in the
// vtable of it's owning class or interface.
-void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
- unsigned* offsetOfIndirection, /* OUT */
- unsigned* offsetAfterIndirection,/* OUT */
- bool* isRelative /* OUT */
+void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
+ unsigned* offsetOfIndirection, /* OUT */
+ unsigned* offsetAfterIndirection, /* OUT */
+ bool* isRelative /* OUT */
)
{
mc->cr->AddCall("getMethodVTableOffset");
@@ -236,6 +242,21 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HAND
return result;
}
+// Get the unboxed entry point for a method, if possible.
+CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
+{
+ mc->cr->AddCall("getUnboxedEntry");
+ bool localRequiresInstMethodTableArg = false;
+ CORINFO_METHOD_HANDLE result =
+ original_ICorJitInfo->getUnboxedEntry(ftn, &localRequiresInstMethodTableArg);
+ mc->recGetUnboxedEntry(ftn, &localRequiresInstMethodTableArg, result);
+ if (requiresInstMethodTableArg != nullptr)
+ {
+ *requiresInstMethodTableArg = localRequiresInstMethodTableArg;
+ }
+ return result;
+}
+
// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
@@ -246,9 +267,8 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_C
return result;
}
-void interceptor_ICJI::expandRawHandleIntrinsic(
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_GENERICHANDLE_RESULT * pResult)
+void interceptor_ICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ CORINFO_GENERICHANDLE_RESULT* pResult)
{
mc->cr->AddCall("expandRawHandleIntrinsic");
original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, pResult);
@@ -398,20 +418,23 @@ void interceptor_ICJI::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN* pResol
param.pThis = this;
param.pResolvedToken = pResolvedToken;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("resolveToken");
- pParam->pThis->original_ICorJitInfo->resolveToken(pParam->pResolvedToken);
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recResolveToken(param.pResolvedToken, param.exceptionCode);
-}
-PAL_ENDTRY
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("resolveToken");
+ pParam->pThis->original_ICorJitInfo->resolveToken(pParam->pResolvedToken);
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recResolveToken(param.pResolvedToken, param.exceptionCode);
+ }
+ PAL_ENDTRY
}
bool interceptor_ICJI::tryResolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN* pResolvedToken)
@@ -889,6 +912,26 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return temp;
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ mc->cr->AddCall("compareTypesForCast");
+ TypeCompareState temp = original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+ mc->recCompareTypesForCast(fromClass, toClass, temp);
+ return temp;
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mc->cr->AddCall("compareTypesForEquality");
+ TypeCompareState temp = original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+ mc->recCompareTypesForEquality(cls1, cls2, temp);
+ return temp;
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
@@ -1087,7 +1130,7 @@ void interceptor_ICJI::getBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] m
// Note that debugger (and profiler) is assuming that all of the
// offsets form a contiguous block of memory, and that the
// OffsetMapping is sorted in order of increasing native offset.
- //Note - Ownership of pMap is transfered with this call. We need to record it before its passed on to the EE.
+// Note - Ownership of pMap is transfered with this call. We need to record it before its passed on to the EE.
void interceptor_ICJI::setBoundaries(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest
ULONG32 cMap, // [IN] size of pMap
ICorDebugInfo::OffsetMapping* pMap // [IN] map including all points of interest.
@@ -1124,7 +1167,7 @@ void interceptor_ICJI::getVars(CORINFO_METHOD_HANDLE ftn, // [IN] method
// Report back to the EE the location of every variable.
// note that the JIT might split lifetimes into different
// locations etc.
- //Note - Ownership of vars is transfered with this call. We need to record it before its passed on to the EE.
+// Note - Ownership of vars is transfered with this call. We need to record it before its passed on to the EE.
void interceptor_ICJI::setVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest
ULONG32 cVars, // [IN] size of 'vars'
ICorDebugInfo::NativeVarInfo* vars // [IN] map telling where local vars are stored at
@@ -1201,26 +1244,30 @@ CorInfoTypeWithMod interceptor_ICJI::getArgType(CORINFO_SIG_INFO* sig,
param.vcTypeRet = vcTypeRet;
param.temp = (CorInfoTypeWithMod)CORINFO_TYPE_UNDEF;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("getArgType");
- pParam->temp = pParam->pThis->original_ICorJitInfo->getArgType(pParam->sig, pParam->args, pParam->vcTypeRet);
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("getArgType");
+ pParam->temp =
+ pParam->pThis->original_ICorJitInfo->getArgType(pParam->sig, pParam->args, pParam->vcTypeRet);
#ifdef fatMC
- CORINFO_CLASS_HANDLE temp3 = pParam->pThis->getArgClass(pParam->sig, pParam->args);
+ CORINFO_CLASS_HANDLE temp3 = pParam->pThis->getArgClass(pParam->sig, pParam->args);
#endif
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recGetArgType(sig, args, vcTypeRet, param.temp, param.exceptionCode);
-}
-PAL_ENDTRY
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recGetArgType(sig, args, vcTypeRet, param.temp, param.exceptionCode);
+ }
+ PAL_ENDTRY
-return param.temp;
+ return param.temp;
}
// If the Arg is a CORINFO_TYPE_CLASS fetch the class handle associated with it
@@ -1240,25 +1287,28 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getArgClass(CORINFO_SIG_INFO* sig,
param.args = args;
param.temp = 0;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("getArgClass");
- pParam->temp = pParam->pThis->original_ICorJitInfo->getArgClass(pParam->sig, pParam->args);
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recGetArgClass(sig, args, param.temp, param.exceptionCode);
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("getArgClass");
+ pParam->temp = pParam->pThis->original_ICorJitInfo->getArgClass(pParam->sig, pParam->args);
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recGetArgClass(sig, args, param.temp, param.exceptionCode);
- // to build up a fat mc
- getClassName(param.temp);
-}
-PAL_ENDTRY
+ // to build up a fat mc
+ getClassName(param.temp);
+ }
+ PAL_ENDTRY
-return param.temp;
+ return param.temp;
}
// Returns type of HFA for valuetype
@@ -1379,7 +1429,7 @@ const char* interceptor_ICJI::getMethodName(CORINFO_METHOD_HANDLE ftn, /*
const char* interceptor_ICJI::getMethodNameFromMetadata(CORINFO_METHOD_HANDLE ftn, /* IN */
const char** className, /* OUT */
- const char** namespaceName /* OUT */
+ const char** namespaceName /* OUT */
)
{
mc->cr->AddCall("getMethodNameFromMetadata");
@@ -1663,22 +1713,25 @@ void interceptor_ICJI::getCallInfo(
param.flags = flags;
param.pResult = pResult;
- PAL_TRY(Param*, pOuterParam,
- &param){PAL_TRY(Param*, pParam, pOuterParam){pParam->pThis->mc->cr->AddCall("getCallInfo");
- pParam->pThis->original_ICorJitInfo->getCallInfo(pParam->pResolvedToken, pParam->pConstrainedResolvedToken,
- pParam->callerHandle, pParam->flags, pParam->pResult);
-}
-PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
-{
-}
-PAL_ENDTRY
-}
-PAL_FINALLY
-{
- this->mc->recGetCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult,
- param.exceptionCode);
-}
-PAL_ENDTRY
+ PAL_TRY(Param*, pOuterParam, &param)
+ {
+ PAL_TRY(Param*, pParam, pOuterParam)
+ {
+ pParam->pThis->mc->cr->AddCall("getCallInfo");
+ pParam->pThis->original_ICorJitInfo->getCallInfo(pParam->pResolvedToken, pParam->pConstrainedResolvedToken,
+ pParam->callerHandle, pParam->flags, pParam->pResult);
+ }
+ PAL_EXCEPT_FILTER(FilterSuperPMIExceptions_CaptureExceptionAndContinue)
+ {
+ }
+ PAL_ENDTRY
+ }
+ PAL_FINALLY
+ {
+ this->mc->recGetCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult,
+ param.exceptionCode);
+ }
+ PAL_ENDTRY
}
BOOL interceptor_ICJI::canAccessFamily(CORINFO_METHOD_HANDLE hCaller, CORINFO_CLASS_HANDLE hInstanceType)
diff --git a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h
index b582866a89..af2c866fd6 100644
--- a/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h
+++ b/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.h
@@ -20,7 +20,7 @@ private:
public:
// Added to help us track the original icji and be able to easily indirect
- //to it. And a simple way to keep one memory manager instance per instance.
+ // to it. And a simple way to keep one memory manager instance per instance.
ICorJitInfo* original_ICorJitInfo;
MethodContext* mc;
};
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
index 17da100dac..a9e5761c34 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp
@@ -143,10 +143,10 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me
// This function returns the offset of the specified method in the
// vtable of it's owning class or interface.
-void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
- unsigned* offsetOfIndirection, /* OUT */
- unsigned* offsetAfterIndirection,/* OUT */
- bool* isRelative /* OUT */
+void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
+ unsigned* offsetOfIndirection, /* OUT */
+ unsigned* offsetAfterIndirection, /* OUT */
+ bool* isRelative /* OUT */
)
{
mcs->AddCall("getMethodVTableOffset");
@@ -163,6 +163,13 @@ CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HAND
return original_ICorJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
+// Get the unboxed entry point for a method, if possible.
+CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
+{
+ mcs->AddCall("getUnboxedEntry");
+ return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg);
+}
+
// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
@@ -171,9 +178,8 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_C
return original_ICorJitInfo->getDefaultEqualityComparerClass(cls);
}
-void interceptor_ICJI::expandRawHandleIntrinsic(
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_GENERICHANDLE_RESULT * pResult)
+void interceptor_ICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ CORINFO_GENERICHANDLE_RESULT* pResult)
{
mcs->AddCall("expandRawHandleIntrinsic");
original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, pResult);
@@ -703,6 +709,22 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return original_ICorJitInfo->areTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ mcs->AddCall("compareTypesForCast");
+ return original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ mcs->AddCall("compareTypesForEquality");
+ return original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h
index ce269cc06c..f4c13ee2c9 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.h
@@ -17,7 +17,7 @@ class interceptor_ICJI : public ICorJitInfo
public:
// Added to help us track the original icji and be able to easily indirect
- //to it. And a simple way to keep one memory manager instance per instance.
+ // to it. And a simple way to keep one memory manager instance per instance.
ICorJitInfo* original_ICorJitInfo;
MethodCallSummarizer* mcs;
};
diff --git a/src/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp b/src/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp
index e22c060271..423007afcb 100644
--- a/src/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-counter/methodcallsummarizer.cpp
@@ -75,7 +75,8 @@ MethodCallSummarizer::MethodCallSummarizer(WCHAR* logPath)
}
// lots of ways will be faster.. this happens to be decently simple and good enough for the task at hand and nicely
-// sorts the output. in this approach the most commonly added items are at the top of the list... 60% landed in the first
+// sorts the output. in this approach the most commonly added items are at the top of the list... 60% landed in the
+// first
// three slots in short runs
void MethodCallSummarizer::AddCall(const char* name)
{
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
index df4cfcfbcd..d7ca029fae 100644
--- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp
@@ -132,15 +132,21 @@ CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE me
// This function returns the offset of the specified method in the
// vtable of it's owning class or interface.
-void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
- unsigned* offsetOfIndirection, /* OUT */
- unsigned* offsetAfterIndirection,/* OUT */
- bool* isRelative /* OUT */
+void interceptor_ICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
+ unsigned* offsetOfIndirection, /* OUT */
+ unsigned* offsetAfterIndirection, /* OUT */
+ bool* isRelative /* OUT */
)
{
original_ICorJitInfo->getMethodVTableOffset(method, offsetOfIndirection, offsetAfterIndirection, isRelative);
}
+// Get the unboxed entry point for a method, if possible.
+CORINFO_METHOD_HANDLE interceptor_ICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
+{
+ return original_ICorJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg);
+}
+
// Find the virtual method in implementingClass that overrides virtualMethod.
// Return null if devirtualization is not possible.
CORINFO_METHOD_HANDLE interceptor_ICJI::resolveVirtualMethod(CORINFO_METHOD_HANDLE virtualMethod,
@@ -157,9 +163,8 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getDefaultEqualityComparerClass(CORINFO_C
return original_ICorJitInfo->getDefaultEqualityComparerClass(cls);
}
-void interceptor_ICJI::expandRawHandleIntrinsic(
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_GENERICHANDLE_RESULT * pResult)
+void interceptor_ICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+ CORINFO_GENERICHANDLE_RESULT* pResult)
{
return original_ICorJitInfo->expandRawHandleIntrinsic(pResolvedToken, pResult);
}
@@ -629,6 +634,20 @@ BOOL interceptor_ICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLA
return original_ICorJitInfo->areTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ return original_ICorJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState interceptor_ICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return original_ICorJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE interceptor_ICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
diff --git a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h
index 01ccbe6cf0..4d01de9b77 100644
--- a/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h
+++ b/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.h
@@ -16,7 +16,7 @@ class interceptor_ICJI : public ICorJitInfo
public:
// Added to help us track the original icji and be able to easily indirect
- //to it. And a simple way to keep one memory manager instance per instance.
+ // to it. And a simple way to keep one memory manager instance per instance.
ICorJitInfo* original_ICorJitInfo;
};
diff --git a/src/ToolBox/superpmi/superpmi/commandline.cpp b/src/ToolBox/superpmi/superpmi/commandline.cpp
index 5394cf22e7..78af8cbb13 100644
--- a/src/ToolBox/superpmi/superpmi/commandline.cpp
+++ b/src/ToolBox/superpmi/superpmi/commandline.cpp
@@ -121,11 +121,13 @@ void CommandLine::DumpHelp(const char* program)
printf("\n");
printf(" -jitoption [force] key=value\n");
printf(" Set the JIT option named \"key\" to \"value\" for JIT 1 if the option was not set.");
- printf(" With optional force flag overwrites the existing value if it was already set. NOTE: do not use a \"COMPlus_\" prefix!\n");
+ printf(" With optional force flag overwrites the existing value if it was already set. NOTE: do not use a "
+ "\"COMPlus_\" prefix!\n");
printf("\n");
printf(" -jit2option [force] key=value\n");
printf(" Set the JIT option named \"key\" to \"value\" for JIT 2 if the option was not set.");
- printf(" With optional force flag overwrites the existing value if it was already set. NOTE: do not use a \"COMPlus_\" prefix!\n");
+ printf(" With optional force flag overwrites the existing value if it was already set. NOTE: do not use a "
+ "\"COMPlus_\" prefix!\n");
printf("\n");
printf("Inputs are case sensitive.\n");
printf("\n");
@@ -149,7 +151,7 @@ void CommandLine::DumpHelp(const char* program)
printf(" ; if there are any failures, record their MC numbers in the file fail.mcl\n");
}
-static bool ParseJitOption(const char* optionString, wchar_t** key, wchar_t **value)
+static bool ParseJitOption(const char* optionString, wchar_t** key, wchar_t** value)
{
char tempKey[1024];
@@ -167,14 +169,14 @@ static bool ParseJitOption(const char* optionString, wchar_t** key, wchar_t **va
const char* tempVal = &optionString[i + 1];
const unsigned keyLen = i;
- wchar_t* keyBuf = new wchar_t[keyLen + 1];
+ wchar_t* keyBuf = new wchar_t[keyLen + 1];
MultiByteToWideChar(CP_UTF8, 0, tempKey, keyLen + 1, keyBuf, keyLen + 1);
const unsigned valLen = (unsigned)strlen(tempVal);
- wchar_t* valBuf = new wchar_t[valLen + 1];
+ wchar_t* valBuf = new wchar_t[valLen + 1];
MultiByteToWideChar(CP_UTF8, 0, tempVal, valLen + 1, valBuf, valLen + 1);
- *key = keyBuf;
+ *key = keyBuf;
*value = valBuf;
return true;
}
@@ -530,12 +532,11 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
}
else if (_strnicmp(&argv[i][1], "jit2option", argLen) == 0)
{
- i++;
+ i++;
if (!AddJitOption(i, argc, argv, &o->jit2Options, &o->forceJit2Options))
{
return false;
}
-
}
else
{
@@ -545,7 +546,7 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
}
}
// Process an input filename
- //String comparisons on file extensions must be case-insensitive since we run on Windows
+ // String comparisons on file extensions must be case-insensitive since we run on Windows
else
{
char* lastdot = strrchr(argv[i], '.');
@@ -620,7 +621,11 @@ bool CommandLine::Parse(int argc, char* argv[], /* OUT */ Options* o)
//
// Returns:
// False if an error occurred, true if the option was parsed and added.
-bool CommandLine::AddJitOption(int& currArgument, int argc, char* argv[], LightWeightMap<DWORD, DWORD>** pJitOptions, LightWeightMap<DWORD, DWORD>** pForceJitOptions)
+bool CommandLine::AddJitOption(int& currArgument,
+ int argc,
+ char* argv[],
+ LightWeightMap<DWORD, DWORD>** pJitOptions,
+ LightWeightMap<DWORD, DWORD>** pForceJitOptions)
{
if (currArgument >= argc)
{
@@ -630,7 +635,6 @@ bool CommandLine::AddJitOption(int& currArgument, int argc, char* argv[], LightW
LightWeightMap<DWORD, DWORD>* targetjitOptions = nullptr;
-
if (_strnicmp(argv[currArgument], "force", strlen(argv[currArgument])) == 0)
{
if (*pForceJitOptions == nullptr)
@@ -657,8 +661,10 @@ bool CommandLine::AddJitOption(int& currArgument, int argc, char* argv[], LightW
return false;
}
- DWORD keyIndex = (DWORD)targetjitOptions->AddBuffer((unsigned char*)key, sizeof(wchar_t) * ((unsigned int)wcslen(key) + 1));
- DWORD valueIndex = (DWORD)targetjitOptions->AddBuffer((unsigned char*)value, sizeof(wchar_t) * ((unsigned int)wcslen(value) + 1));
+ DWORD keyIndex =
+ (DWORD)targetjitOptions->AddBuffer((unsigned char*)key, sizeof(wchar_t) * ((unsigned int)wcslen(key) + 1));
+ DWORD valueIndex =
+ (DWORD)targetjitOptions->AddBuffer((unsigned char*)value, sizeof(wchar_t) * ((unsigned int)wcslen(value) + 1));
targetjitOptions->Add(keyIndex, valueIndex);
delete[] key;
diff --git a/src/ToolBox/superpmi/superpmi/commandline.h b/src/ToolBox/superpmi/superpmi/commandline.h
index cf9d79cf6c..3d6cb88bfe 100644
--- a/src/ToolBox/superpmi/superpmi/commandline.h
+++ b/src/ToolBox/superpmi/superpmi/commandline.h
@@ -26,9 +26,9 @@ public:
, applyDiff(false)
, parallel(false)
#if !defined(USE_MSVCDIS) && defined(USE_COREDISTOOLS)
- , useCoreDisTools(true) // if CoreDisTools is available (but MSVCDIS is not), use it.
+ , useCoreDisTools(true) // if CoreDisTools is available (but MSVCDIS is not), use it.
#else
- , useCoreDisTools(false) // Otherwise, use MSVCDIS if that is available (else no diffs are available).
+ , useCoreDisTools(false) // Otherwise, use MSVCDIS if that is available (else no diffs are available).
#endif
, skipCleanup(false)
, workerCount(-1)
@@ -79,7 +79,11 @@ public:
static bool Parse(int argc, char* argv[], /* OUT */ Options* o);
- static bool AddJitOption(int& currArgument, int argc, char* argv[], LightWeightMap<DWORD, DWORD>** pJitOptions, LightWeightMap<DWORD, DWORD>** pForceJitOptions);
+ static bool AddJitOption(int& currArgument,
+ int argc,
+ char* argv[],
+ LightWeightMap<DWORD, DWORD>** pJitOptions,
+ LightWeightMap<DWORD, DWORD>** pForceJitOptions);
private:
static void DumpHelp(const char* program);
diff --git a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
index 7c119b86dd..e8f86cedbd 100644
--- a/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
+++ b/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp
@@ -163,10 +163,10 @@ CORINFO_MODULE_HANDLE MyICJI::getMethodModule(CORINFO_METHOD_HANDLE method)
// This function returns the offset of the specified method in the
// vtable of it's owning class or interface.
-void MyICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
- unsigned* offsetOfIndirection, /* OUT */
- unsigned* offsetAfterIndirection,/* OUT */
- bool* isRelative /* OUT */
+void MyICJI::getMethodVTableOffset(CORINFO_METHOD_HANDLE method, /* IN */
+ unsigned* offsetOfIndirection, /* OUT */
+ unsigned* offsetAfterIndirection, /* OUT */
+ bool* isRelative /* OUT */
)
{
jitInstance->mc->cr->AddCall("getMethodVTableOffset");
@@ -185,6 +185,15 @@ CORINFO_METHOD_HANDLE MyICJI::resolveVirtualMethod(CORINFO_METHOD_HANDLE virtua
return result;
}
+// Get the unboxed entry point for a method, if possible.
+CORINFO_METHOD_HANDLE MyICJI::getUnboxedEntry(CORINFO_METHOD_HANDLE ftn, bool* requiresInstMethodTableArg)
+{
+ jitInstance->mc->cr->AddCall("getUnboxedEntry");
+ CORINFO_METHOD_HANDLE result =
+ jitInstance->mc->repGetUnboxedEntry(ftn, requiresInstMethodTableArg);
+ return result;
+}
+
// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
CORINFO_CLASS_HANDLE MyICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDLE cls)
@@ -194,9 +203,7 @@ CORINFO_CLASS_HANDLE MyICJI::getDefaultEqualityComparerClass(CORINFO_CLASS_HANDL
return result;
}
-void MyICJI::expandRawHandleIntrinsic(
- CORINFO_RESOLVED_TOKEN * pResolvedToken,
- CORINFO_GENERICHANDLE_RESULT * pResult)
+void MyICJI::expandRawHandleIntrinsic(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_GENERICHANDLE_RESULT* pResult)
{
jitInstance->mc->cr->AddCall("expandRawHandleIntrinsic");
LogError("Hit unimplemented expandRawHandleIntrinsic");
@@ -760,6 +767,22 @@ BOOL MyICJI::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE
return jitInstance->mc->repAreTypesEquivalent(cls1, cls2);
}
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState MyICJI::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ jitInstance->mc->cr->AddCall("compareTypesForCast");
+ return jitInstance->mc->repCompareTypesForCast(fromClass, toClass);
+}
+
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState MyICJI::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ jitInstance->mc->cr->AddCall("compareTypesForEquality");
+ return jitInstance->mc->repCompareTypesForEquality(cls1, cls2);
+}
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE MyICJI::mergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
{
@@ -818,7 +841,8 @@ void* MyICJI::getArrayInitializationData(CORINFO_FIELD_HANDLE field, DWORD size)
CorInfoIsAccessAllowedResult MyICJI::canAccessClass(CORINFO_RESOLVED_TOKEN* pResolvedToken,
CORINFO_METHOD_HANDLE callerHandle,
CORINFO_HELPER_DESC* pAccessHelper /* If canAccessMethod returns
- something other than ALLOWED,
+ something other than
+ ALLOWED,
then this is filled in. */
)
{
@@ -991,7 +1015,7 @@ void MyICJI::getVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of intere
void MyICJI::setVars(CORINFO_METHOD_HANDLE ftn, // [IN] method of interest
ULONG32 cVars, // [IN] size of 'vars'
ICorDebugInfo::NativeVarInfo* vars // [IN] map telling where local vars are stored at what points
- // jit allocated with allocateArray, EE frees
+ // jit allocated with allocateArray, EE frees
)
{
jitInstance->mc->cr->AddCall("setVars");
@@ -1684,8 +1708,8 @@ BOOL MyICJI::logMsg(unsigned level, const char* fmt, va_list args)
// if(level<=2)
// {
- //jitInstance->mc->cr->recMessageLog(fmt, args);
- //DebugBreakorAV(0x99);
+ // jitInstance->mc->cr->recMessageLog(fmt, args);
+ // DebugBreakorAV(0x99);
//}
jitInstance->mc->cr->recMessageLog(fmt, args);
return 0;
diff --git a/src/ToolBox/superpmi/superpmi/iexecutionengine.cpp b/src/ToolBox/superpmi/superpmi/iexecutionengine.cpp
index 7a39734500..8a82406ec1 100644
--- a/src/ToolBox/superpmi/superpmi/iexecutionengine.cpp
+++ b/src/ToolBox/superpmi/superpmi/iexecutionengine.cpp
@@ -48,9 +48,9 @@ VOID STDMETHODCALLTYPE MyIEE::TLS_AssociateCallback(DWORD slot, PTLS_CALLBACK_FU
LPVOID* STDMETHODCALLTYPE MyIEE::TLS_GetDataBlock()
{
// We were previously allocating a TlsIndex with
- //the master slot index set to a nullptr
- //so in the new version we just return nullptr
- //and it seems to be working for now
+ // the master slot index set to a nullptr
+ // so in the new version we just return nullptr
+ // and it seems to be working for now
return nullptr;
}
diff --git a/src/ToolBox/superpmi/superpmi/jitdebugger.cpp b/src/ToolBox/superpmi/superpmi/jitdebugger.cpp
index b4b4ede20f..80038647af 100644
--- a/src/ToolBox/superpmi/superpmi/jitdebugger.cpp
+++ b/src/ToolBox/superpmi/superpmi/jitdebugger.cpp
@@ -124,7 +124,7 @@ BOOL GetRegistryLongValue(HKEY hKeyParent, LPCWSTR szKey, LPCWSTR szName, long*
//----------------------------------------------------------------------------
//
-// GetCurrentModuleFileName - Retrieve the current module's filename
+// GetCurrentModuleFileName - Retrieve the current module's filename
//
// Arguments:
// pBuffer - output string buffer
@@ -174,7 +174,7 @@ HRESULT GetCurrentModuleFileName(__out_ecount(*pcchBuffer) LPWSTR pBuffer, __ino
//----------------------------------------------------------------------------
//
-// IsCurrentModuleFileNameInAutoExclusionList - decide if the current module's filename
+// IsCurrentModuleFileNameInAutoExclusionList - decide if the current module's filename
// is in the AutoExclusionList list
//
// Arguments:
@@ -347,7 +347,7 @@ HRESULT GetDebuggerSettingInfoWorker(__out_ecount_part_opt(*pcchDebuggerString,
&valueSize);
// The OS's behavior is to consider Auto to be FALSE unless the first character is set
- // to 1. They don't take into consideration the following characters. Also if the value
+ // to 1. They don't take into consideration the following characters. Also if the value
// isn't present they assume an Auto value of FALSE.
if ((wzAutoKey[0] == L'1') && !IsCurrentModuleFileNameInAutoExclusionList())
{
diff --git a/src/ToolBox/superpmi/superpmi/jithost.cpp b/src/ToolBox/superpmi/superpmi/jithost.cpp
index f92c6f442a..1b9b9a338d 100644
--- a/src/ToolBox/superpmi/superpmi/jithost.cpp
+++ b/src/ToolBox/superpmi/superpmi/jithost.cpp
@@ -72,7 +72,7 @@ int JitHost::getIntConfigValue(const wchar_t* key, int defaultValue)
if (forceValue != nullptr)
{
wchar_t* endPtr;
- result = static_cast<int>(wcstoul(forceValue, &endPtr, 16));
+ result = static_cast<int>(wcstoul(forceValue, &endPtr, 16));
bool succeeded = (errno != ERANGE) && (endPtr != forceValue);
if (succeeded)
{
@@ -127,7 +127,8 @@ const wchar_t* JitHost::getStringConfigValue(const wchar_t* key)
const wchar_t* result = nullptr;
- // First check the force options, then mc value. If value is not presented there, probe the JIT options and then the environment.
+ // First check the force options, then mc value. If value is not presented there, probe the JIT options and then the
+ // environment.
result = jitInstance.getForceOption(key);
diff --git a/src/ToolBox/superpmi/superpmi/jithost.h b/src/ToolBox/superpmi/superpmi/jithost.h
index 9e31e4362d..6391fc1974 100644
--- a/src/ToolBox/superpmi/superpmi/jithost.h
+++ b/src/ToolBox/superpmi/superpmi/jithost.h
@@ -6,7 +6,7 @@
#ifndef _JITHOST
#define _JITHOST
-class JitHost final: public ICorJitHost
+class JitHost final : public ICorJitHost
{
public:
JitHost(JitInstance& jitInstance);
diff --git a/src/ToolBox/superpmi/superpmi/jitinstance.cpp b/src/ToolBox/superpmi/superpmi/jitinstance.cpp
index 37cb54debd..52f2b90d22 100644
--- a/src/ToolBox/superpmi/superpmi/jitinstance.cpp
+++ b/src/ToolBox/superpmi/superpmi/jitinstance.cpp
@@ -12,7 +12,12 @@
#include "errorhandling.h"
#include "spmiutil.h"
-JitInstance* JitInstance::InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext, LightWeightMap<DWORD, DWORD>* forceOptions, LightWeightMap<DWORD, DWORD>* options)
+JitInstance* JitInstance::InitJit(char* nameOfJit,
+ bool breakOnAssert,
+ SimpleTimer* st1,
+ MethodContext* firstContext,
+ LightWeightMap<DWORD, DWORD>* forceOptions,
+ LightWeightMap<DWORD, DWORD>* options)
{
JitInstance* jit = new JitInstance();
if (jit == nullptr)
@@ -58,7 +63,7 @@ HRESULT JitInstance::StartUp(char* PathToJit,
char szTempFileName[MAX_PATH];
// Get an allocator instance
- //Note: we do this to keep cleanup somewhat simple...
+ // Note: we do this to keep cleanup somewhat simple...
ourHeap = ::HeapCreate(0, 0, 0);
if (ourHeap == nullptr)
{
@@ -465,7 +470,7 @@ bool JitInstance::resetConfig(MethodContext* firstContext)
{
if (pnjitStartup != nullptr)
{
- mc = firstContext;
+ mc = firstContext;
ICorJitHost* newHost = new JitHost(*this);
pnjitStartup(newHost);
delete static_cast<JitHost*>(jitHost);
diff --git a/src/ToolBox/superpmi/superpmi/jitinstance.h b/src/ToolBox/superpmi/superpmi/jitinstance.h
index 1172b9ce69..eeb2ff7081 100644
--- a/src/ToolBox/superpmi/superpmi/jitinstance.h
+++ b/src/ToolBox/superpmi/superpmi/jitinstance.h
@@ -44,7 +44,12 @@ public:
ICorJitCompiler* pJitInstance;
// Allocate and initialize the jit provided
- static JitInstance* InitJit(char* nameOfJit, bool breakOnAssert, SimpleTimer* st1, MethodContext* firstContext, LightWeightMap<DWORD, DWORD>* forceOptions, LightWeightMap<DWORD, DWORD>* options);
+ static JitInstance* InitJit(char* nameOfJit,
+ bool breakOnAssert,
+ SimpleTimer* st1,
+ MethodContext* firstContext,
+ LightWeightMap<DWORD, DWORD>* forceOptions,
+ LightWeightMap<DWORD, DWORD>* options);
HRESULT StartUp(char* PathToJit, bool copyJit, bool breakOnDebugBreakorAV, MethodContext* firstContext);
bool reLoad(MethodContext* firstContext);
diff --git a/src/ToolBox/superpmi/superpmi/neardiffer.cpp b/src/ToolBox/superpmi/superpmi/neardiffer.cpp
index d31a4066b6..627e43a09b 100644
--- a/src/ToolBox/superpmi/superpmi/neardiffer.cpp
+++ b/src/ToolBox/superpmi/superpmi/neardiffer.cpp
@@ -20,7 +20,7 @@
//
// Helper functions to print messages from CoreDisTools Library
-// The file/linenumber information is from this helper itself,
+// The file/linenumber information is from this helper itself,
// since we are only linking with the CoreDisTools library.
//
static void LogFromCoreDisToolsHelper(LogLevel level, const char* msg, va_list argList)
@@ -29,32 +29,36 @@ static void LogFromCoreDisToolsHelper(LogLevel level, const char* msg, va_list a
}
#define LOGGER(L) \
+ \
static void __cdecl CorDisToolsLog##L(const char* msg, ...) \
-{ \
- va_list argList; \
- va_start(argList, msg); \
- LogFromCoreDisToolsHelper(LOGLEVEL_##L, msg, argList); \
- va_end(argList); \
+ \
+{ \
+ va_list argList; \
+ va_start(argList, msg); \
+ LogFromCoreDisToolsHelper(LOGLEVEL_##L, msg, argList); \
+ va_end(argList); \
+ \
}
LOGGER(VERBOSE)
LOGGER(ERROR)
LOGGER(WARNING)
-const PrintControl CorPrinter = {CorDisToolsLogERROR, CorDisToolsLogWARNING, CorDisToolsLogVERBOSE, CorDisToolsLogVERBOSE};
+const PrintControl CorPrinter = {CorDisToolsLogERROR, CorDisToolsLogWARNING, CorDisToolsLogVERBOSE,
+ CorDisToolsLogVERBOSE};
#endif // USE_COREDISTOOLS
#ifdef USE_COREDISTOOLS
-NewDiffer_t* g_PtrNewDiffer = nullptr;
-FinishDiff_t* g_PtrFinishDiff = nullptr;
+NewDiffer_t* g_PtrNewDiffer = nullptr;
+FinishDiff_t* g_PtrFinishDiff = nullptr;
NearDiffCodeBlocks_t* g_PtrNearDiffCodeBlocks = nullptr;
-DumpDiffBlocks_t* g_PtrDumpDiffBlocks = nullptr;
+DumpDiffBlocks_t* g_PtrDumpDiffBlocks = nullptr;
#endif // USE_COREDISTOOLS
//
// The NearDiff Disassembler initialization.
-//
+//
// Returns true on success, false on failure.
//
bool NearDiffer::InitAsmDiff()
@@ -106,7 +110,7 @@ bool NearDiffer::InitAsmDiff()
#ifdef USE_COREDISTOOLS
// static
bool __cdecl NearDiffer::CoreDisCompareOffsetsCallback(
- const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2)
+ const void* payload, size_t blockOffset, size_t instrLen, uint64_t offset1, uint64_t offset2)
{
return compareOffsets(payload, blockOffset, instrLen, offset1, offset2);
}
@@ -265,7 +269,7 @@ struct DiffData
//
// NearDiff Offset Comparator.
-// Determine whether two syntactically different constants are
+// Determine whether two syntactically different constants are
// semantically equivalent, using certain heuristics.
//
bool NearDiffer::compareOffsets(
@@ -297,7 +301,7 @@ bool NearDiffer::compareOffsets(
(roOffset1a < data->datablockSize1)) // Confirm its an offset that fits inside our RoRegion
return true;
- // This case is written to catch IP-relative offsets to the RO data-section
+ // This case is written to catch IP-relative offsets to the RO data-section
// For example:
//
size_t roOffset1b = ipRelOffset1 - data->originalDataBlock1;
@@ -329,7 +333,7 @@ bool NearDiffer::compareOffsets(
if (data->cr->CallTargetTypes->GetIndex((DWORDLONG)Offset1) != (DWORD)-1)
{
// This logging is too noisy, so disable it.
- //LogVerbose("Found VSD callsite, did softer compare than ideal");
+ // LogVerbose("Found VSD callsite, did softer compare than ideal");
return true;
}
@@ -339,24 +343,24 @@ bool NearDiffer::compareOffsets(
if (data->cr->CallTargetTypes->GetIndex((DWORDLONG)Offset1b) != (DWORD)-1)
{
// This logging is too noisy, so disable it.
- //LogVerbose("Found VSD callsite, did softer compare than ideal");
+ // LogVerbose("Found VSD callsite, did softer compare than ideal");
return true;
}
if (data->cr->CallTargetTypes->GetIndex((DWORDLONG)Offset2b) != (DWORD)-1)
{
// This logging is too noisy, so disable it.
- //LogVerbose("Found VSD callsite, did softer compare than ideal");
+ // LogVerbose("Found VSD callsite, did softer compare than ideal");
return true;
}
// Case might be a field address that we handed out to handle inlined values being loaded into
- //a register as an immediate value (and where the address is encoded as an indirect immediate load)
+ // a register as an immediate value (and where the address is encoded as an indirect immediate load)
size_t realTargetAddr = (size_t)data->cr->searchAddressMap((void*)gOffset2);
if (realTargetAddr == gOffset1)
return true;
// Case might be a field address that we handed out to handle inlined values being loaded into
- //a register as an immediate value (and where the address is encoded and loaded by immediate into a register)
+ // a register as an immediate value (and where the address is encoded and loaded by immediate into a register)
realTargetAddr = (size_t)data->cr->searchAddressMap((void*)offset2);
if (realTargetAddr == offset1)
return true;
@@ -455,12 +459,12 @@ bool NearDiffer::compareCodeSection(MethodContext* mc,
if (UseCoreDisTools)
{
bool areSame = (*g_PtrNearDiffCodeBlocks)(corAsmDiff, &data, (const uint8_t*)originalBlock1, block1, blocksize1,
- (const uint8_t*)originalBlock2, block2, blocksize2);
+ (const uint8_t*)originalBlock2, block2, blocksize2);
if (!areSame)
{
(*g_PtrDumpDiffBlocks)(corAsmDiff, (const uint8_t*)originalBlock1, block1, blocksize1,
- (const uint8_t*)originalBlock2, block2, blocksize2);
+ (const uint8_t*)originalBlock2, block2, blocksize2);
}
return areSame;
@@ -507,7 +511,7 @@ bool NearDiffer::compareCodeSection(MethodContext* mc,
if (haveSeenRet)
{
// This logging is pretty noisy, so disable it.
- //LogVerbose("instruction size of zero after seeing a ret (soft issue?).");
+ // LogVerbose("instruction size of zero after seeing a ret (soft issue?).");
break;
}
LogWarning("instruction size of zero.");
@@ -604,13 +608,13 @@ bool NearDiffer::compareCodeSection(MethodContext* mc,
}
//
- // These are special.. we can often reason out exactly why these values
+ // These are special.. we can often reason out exactly why these values
// are different using heuristics.
//
// Why is Instruction size passed as zero?
// Ans: Because the implementation of areOffsetsEquivalent() uses
- // the instruction size to compute absolute offsets in the case of
- // PC-relative addressing, and MSVCDis already reports the
+ // the instruction size to compute absolute offsets in the case of
+ // PC-relative addressing, and MSVCDis already reports the
// absolute offsets! For example:
// 0F 2E 05 67 00 9A FD ucomiss xmm0, dword ptr[FFFFFFFFFD9A006Eh]
//
diff --git a/src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp b/src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
index f4c305d0d1..596f1b66b1 100644
--- a/src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
+++ b/src/ToolBox/superpmi/superpmi/parallelsuperpmi.cpp
@@ -282,7 +282,7 @@ Cleanup:
BOOL WINAPI CtrlHandler(DWORD fdwCtrlType)
{
// Since the child SuperPMI.exe processes share the same console
- //We don't need to kill them individually as they also receive the Ctrl-C
+ // We don't need to kill them individually as they also receive the Ctrl-C
closeRequested = true; // set a flag to indicate we need to quit
return TRUE;
@@ -334,15 +334,19 @@ void MergeWorkerMCLs(char* mclFilename, char** arrWorkerMCLPath, int workerCount
// spmiArgs - pointer to the argument string
// optionName - the jitOption name, can include [force] flag.
//
-void addJitOptionArgument(LightWeightMap<DWORD, DWORD>* jitOptions, int &bytesWritten, char * spmiArgs, const char* optionName)
+void addJitOptionArgument(LightWeightMap<DWORD, DWORD>* jitOptions,
+ int& bytesWritten,
+ char* spmiArgs,
+ const char* optionName)
{
if (jitOptions != nullptr)
{
for (unsigned i = 0; i < jitOptions->GetCount(); i++)
{
- wchar_t* key = (wchar_t*)jitOptions->GetBuffer(jitOptions->GetKey(i));
+ wchar_t* key = (wchar_t*)jitOptions->GetBuffer(jitOptions->GetKey(i));
wchar_t* value = (wchar_t*)jitOptions->GetBuffer(jitOptions->GetItem(i));
- bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -%s %S=%S", optionName, key, value);
+ bytesWritten += sprintf_s(spmiArgs + bytesWritten, MAX_CMDLINE_SIZE - bytesWritten, " -%s %S=%S",
+ optionName, key, value);
}
}
}
@@ -432,7 +436,7 @@ int doParallelSuperPMI(CommandLine::Options& o)
o.workerCount = sysinfo.dwNumberOfProcessors;
// If we ever execute on a machine which has more than MAXIMUM_WAIT_OBJECTS(64) CPU cores
- //we still can't spawn more than the max supported by WaitForMultipleObjects()
+ // we still can't spawn more than the max supported by WaitForMultipleObjects()
if (o.workerCount > MAXIMUM_WAIT_OBJECTS)
o.workerCount = MAXIMUM_WAIT_OBJECTS;
}
@@ -583,7 +587,7 @@ int doParallelSuperPMI(CommandLine::Options& o)
int loaded = 0, jitted = 0, failed = 0, diffs = 0;
// Read the stderr files and log them as errors
- //Read the stdout files and parse them for counts and log any MISSING or ISSUE errors
+ // Read the stdout files and parse them for counts and log any MISSING or ISSUE errors
for (int i = 0; i < o.workerCount; i++)
{
ProcessChildStdErr(arrStdErrorPath[i]);
diff --git a/src/ToolBox/superpmi/superpmi/superpmi.cpp b/src/ToolBox/superpmi/superpmi/superpmi.cpp
index 89f1d58004..b844d58c91 100644
--- a/src/ToolBox/superpmi/superpmi/superpmi.cpp
+++ b/src/ToolBox/superpmi/superpmi/superpmi.cpp
@@ -95,8 +95,8 @@ void InvokeNearDiffer(NearDiffer* nearDiffer,
(*pParam->mc)->methodSize);
// This is a difference in ASM outputs from Jit1 & Jit2 and not a playback failure
- //We will add this MC to the diffMCList if one is requested
- //Otherwise this will end up in failingMCList
+ // We will add this MC to the diffMCList if one is requested
+ // Otherwise this will end up in failingMCList
if ((*pParam->o).diffMCLFilename != nullptr)
(*pParam->diffMCL).AddMethodToMCL((*pParam->reader)->GetMethodContextIndex());
else if ((*pParam->o).mclFilename != nullptr)
@@ -107,8 +107,8 @@ void InvokeNearDiffer(NearDiffer* nearDiffer,
{
SpmiException e(&param.exceptionPointers);
- LogError("main method %d of size %d failed to load and compile correctly.",
- (*reader)->GetMethodContextIndex(), (*mc)->methodSize);
+ LogError("main method %d of size %d failed to load and compile correctly.", (*reader)->GetMethodContextIndex(),
+ (*mc)->methodSize);
e.ShowAndDeleteMessage();
if ((*o).mclFilename != nullptr)
(*failingMCL).AddMethodToMCL((*reader)->GetMethodContextIndex());
@@ -296,7 +296,8 @@ int __cdecl main(int argc, char* argv[])
if (o.nameOfJit2 != nullptr)
{
- jit2 = JitInstance::InitJit(o.nameOfJit2, o.breakOnAssert, &stInitJit, mc, o.forceJit2Options, o.jit2Options);
+ jit2 = JitInstance::InitJit(o.nameOfJit2, o.breakOnAssert, &stInitJit, mc, o.forceJit2Options,
+ o.jit2Options);
if (jit2 == nullptr)
{
// InitJit already printed a failure message
diff --git a/src/build.proj b/src/build.proj
index b59b00c00f..fce6571717 100644
--- a/src/build.proj
+++ b/src/build.proj
@@ -3,7 +3,7 @@
<!-- List the projects that need to be built -->
<ItemGroup>
- <Project Include="ToolBox\SOS\NETCore\SOS.NETCore.csproj" />
+ <Project Condition="$(SkipSOS) != 'true'" Include="ToolBox\SOS\NETCore\SOS.NETCore.csproj" />
<Project Include="mscorlib\System.Private.CoreLib.csproj" />
</ItemGroup>
diff --git a/src/classlibnative/bcltype/number.cpp b/src/classlibnative/bcltype/number.cpp
index a4497a50d3..c45260d05b 100644
--- a/src/classlibnative/bcltype/number.cpp
+++ b/src/classlibnative/bcltype/number.cpp
@@ -286,12 +286,12 @@ void DoubleToNumberWorker( double value, int count, int* dec, int* sign, wchar_t
// Following are the Scheme code from the paper:
// --------------------------------------------------------------------------------
// (if (>= est 0)
- // (fixup r (∗ s (exptt B est)) m+ m− est B low-ok? high-ok? )
+ // (fixup r (* s (exptt B est)) m+ m− est B low-ok? high-ok? )
// (let ([scale (exptt B (− est))])
- // (fixup (∗ r scale) s (∗ m+ scale) (∗ m− scale) est B low-ok? high-ok? ))))
+ // (fixup (* r scale) s (* m+ scale) (* m− scale) est B low-ok? high-ok? ))))
// --------------------------------------------------------------------------------
//
- // If est is 0, (∗ s (exptt B est)) = s, (∗ r scale) = (* r (exptt B (− est)))) = r.
+ // If est is 0, (* s (exptt B est)) = s, (* r scale) = (* r (exptt B (− est)))) = r.
//
// So we just skip when k = 0.
diff --git a/src/classlibnative/bcltype/stringnative.cpp b/src/classlibnative/bcltype/stringnative.cpp
index 34fbf1eb34..dc9be01680 100644
--- a/src/classlibnative/bcltype/stringnative.cpp
+++ b/src/classlibnative/bcltype/stringnative.cpp
@@ -31,22 +31,6 @@
#pragma optimize("tgy", on)
#endif
-
-#define PROBABILISTICMAP_BLOCK_INDEX_MASK 0X7
-#define PROBABILISTICMAP_BLOCK_INDEX_SHIFT 0x3
-#define PROBABILISTICMAP_SIZE 0X8
-
-//
-//
-// FORWARD DECLARATIONS
-//
-//
-int ArrayContains(WCHAR searchChar, __in_ecount(length) const WCHAR *begin, int length);
-void InitializeProbabilisticMap(int* charMap, __in_ecount(length) const WCHAR* charArray, int length);
-bool ProbablyContains(const int* charMap, WCHAR searchChar);
-bool IsBitSet(int value, int bitPos);
-void SetBit(int* value, int bitPos);
-
//
//
// CONSTRUCTORS
@@ -295,116 +279,6 @@ FCIMPL6(INT32, COMString::CompareOrdinalEx, StringObject* strA, INT32 indexA, IN
}
FCIMPLEND
-/*===============================IndexOfCharArray===============================
-**Action:
-**Returns:
-**Arguments:
-**Exceptions:
-==============================================================================*/
-FCIMPL4(INT32, COMString::IndexOfCharArray, StringObject* thisRef, CHARArray* valueRef, INT32 startIndex, INT32 count )
-{
- FCALL_CONTRACT;
-
- VALIDATEOBJECT(thisRef);
- VALIDATEOBJECT(valueRef);
-
- if (thisRef == NULL)
- FCThrow(kNullReferenceException);
-
- WCHAR *thisChars;
- WCHAR *valueChars;
- int valueLength;
- int thisLength;
-
- thisRef->RefInterpretGetStringValuesDangerousForGC(&thisChars, &thisLength);
-
- int endIndex = startIndex + count;
-
- valueLength = valueRef->GetNumComponents();
- valueChars = (WCHAR *)valueRef->GetDataPtr();
-
- // use probabilistic map, see (code:InitializeProbabilisticMap)
- int charMap[PROBABILISTICMAP_SIZE] = {0};
-
- InitializeProbabilisticMap(charMap, valueChars, valueLength);
-
- for(int i = startIndex; i < endIndex; i++) {
- WCHAR thisChar = thisChars[i];
- if (ProbablyContains(charMap, thisChar))
- if (ArrayContains(thisChars[i], valueChars, valueLength) >= 0) {
- FC_GC_POLL_RET();
- return i;
- }
- }
-
- FC_GC_POLL_RET();
- return -1;
-}
-FCIMPLEND
-
-/*=============================LastIndexOfCharArray=============================
-**Action:
-**Returns:
-**Arguments:
-**Exceptions:
-==============================================================================*/
-
-FCIMPL4(INT32, COMString::LastIndexOfCharArray, StringObject* thisRef, CHARArray* valueRef, INT32 startIndex, INT32 count )
-{
- FCALL_CONTRACT;
-
- VALIDATEOBJECT(thisRef);
- VALIDATEOBJECT(valueRef);
- WCHAR *thisChars, *valueChars;
- int thisLength, valueLength;
-
- if (thisRef==NULL) {
- FCThrow(kNullReferenceException);
- }
-
- if (valueRef == NULL)
- FCThrowArgumentNull(W("anyOf"));
-
- thisRef->RefInterpretGetStringValuesDangerousForGC(&thisChars, &thisLength);
-
- if (thisLength == 0) {
- return -1;
- }
-
- if (startIndex < 0 || startIndex >= thisLength) {
- FCThrowArgumentOutOfRange(W("startIndex"), W("ArgumentOutOfRange_Index"));
- }
-
- if (count<0 || count - 1 > startIndex) {
- FCThrowArgumentOutOfRange(W("count"), W("ArgumentOutOfRange_Count"));
- }
-
-
- valueLength = valueRef->GetNumComponents();
- valueChars = (WCHAR *)valueRef->GetDataPtr();
-
- int endIndex = startIndex - count + 1;
-
- // use probabilistic map, see (code:InitializeProbabilisticMap)
- int charMap[PROBABILISTICMAP_SIZE] = {0};
-
- InitializeProbabilisticMap(charMap, valueChars, valueLength);
-
- //We search [startIndex..EndIndex]
- for (int i=startIndex; i>=endIndex; i--) {
- WCHAR thisChar = thisChars[i];
- if (ProbablyContains(charMap, thisChar))
- if (ArrayContains(thisChars[i],valueChars, valueLength) >= 0) {
- FC_GC_POLL_RET();
- return i;
- }
- }
-
- FC_GC_POLL_RET();
- return -1;
-
-}
-FCIMPLEND
/*==================================GETCHARAT===================================
**Returns the character at position index. Thows IndexOutOfRangeException as
@@ -447,112 +321,6 @@ FCIMPL1(INT32, COMString::Length, StringObject* str) {
FCIMPLEND
-// HELPER METHODS
-//
-//
-// A probabilistic map is an optimization that is used in IndexOfAny/
-// LastIndexOfAny methods. The idea is to create a bit map of the characters we
-// are searching for and use this map as a "cheap" check to decide if the
-// current character in the string exists in the array of input characters.
-// There are 256 bits in the map, with each character mapped to 2 bits. Every
-// character is divided into 2 bytes, and then every byte is mapped to 1 bit.
-// The character map is an array of 8 integers acting as map blocks. The 3 lsb
-// in each byte in the character is used to index into this map to get the
-// right block, the value of the remaining 5 msb are used as the bit position
-// inside this block.
-void InitializeProbabilisticMap(int* charMap, __in_ecount(length) const WCHAR* charArray, int length) {
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE(charMap != NULL);
- _ASSERTE(charArray != NULL);
- _ASSERTE(length >= 0);
-
- bool hasAscii = false;
-
- for(int i = 0; i < length; ++i) {
- int hi,lo;
-
- int c = charArray[i];
-
- lo = c & 0xFF;
- hi = (c >> 8) & 0xFF;
-
- int* value = &charMap[lo & PROBABILISTICMAP_BLOCK_INDEX_MASK];
- SetBit(value, lo >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT);
-
- if (hi > 0) {
- value = &charMap[hi & PROBABILISTICMAP_BLOCK_INDEX_MASK];
- SetBit(value, hi >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT);
- }
- else {
- hasAscii = true;
- }
- }
-
- if (hasAscii) {
- // Common to search for ASCII symbols. Just the high value once.
- charMap[0] |= 1;
- }
-}
-
-// Use the probabilistic map to decide if the character value exists in the
-// map. When this method return false, we are certain the character doesn't
-// exist, however a true return means it *may* exist.
-inline bool ProbablyContains(const int* charMap, WCHAR searchValue) {
- LIMITED_METHOD_CONTRACT;
-
- int lo, hi;
-
- lo = searchValue & 0xFF;
- int value = charMap[lo & PROBABILISTICMAP_BLOCK_INDEX_MASK];
-
- if (IsBitSet(value, lo >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT)) {
- hi = (searchValue >> 8) & 0xFF;
- value = charMap[hi & PROBABILISTICMAP_BLOCK_INDEX_MASK];
-
- return IsBitSet(value, hi >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT);
- }
-
- return false;
-}
-
-inline void SetBit(int* value, int bitPos) {
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE(bitPos <= 31);
-
- *value |= (1 << bitPos);
-}
-
-inline bool IsBitSet(int value, int bitPos) {
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE(bitPos <= 31);
-
- return (value & (1 << bitPos)) != 0;
-}
-
-
-/*================================ArrayContains=================================
-**Action:
-**Returns:
-**Arguments:
-**Exceptions:
-==============================================================================*/
-int ArrayContains(WCHAR searchChar, __in_ecount(length) const WCHAR *begin, int length) {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(begin != NULL);
- _ASSERTE(length >= 0);
-
- for(int i = 0; i < length; i++) {
- if(begin[i] == searchChar) {
- return i;
- }
- }
- return -1;
-}
-
-
/*================================ReplaceString=================================
**Action:
**Returns:
diff --git a/src/classlibnative/bcltype/stringnative.h b/src/classlibnative/bcltype/stringnative.h
index a8409826c6..24326ed818 100644
--- a/src/classlibnative/bcltype/stringnative.h
+++ b/src/classlibnative/bcltype/stringnative.h
@@ -61,10 +61,6 @@ public:
static FCDECL6(INT32, CompareOrdinalEx, StringObject* strA, INT32 indexA, INT32 countA, StringObject* strB, INT32 indexB, INT32 countB);
- static FCDECL4(INT32, LastIndexOfCharArray, StringObject* thisRef, CHARArray* valueRef, INT32 startIndex, INT32 count );
-
- static FCDECL4(INT32, IndexOfCharArray, StringObject* vThisRef, CHARArray* value, INT32 startIndex, INT32 count );
-
static FCDECL2(FC_CHAR_RET, GetCharAt, StringObject* pThisRef, INT32 index);
static FCDECL1(INT32, Length, StringObject* pThisRef);
diff --git a/src/classlibnative/bcltype/system.cpp b/src/classlibnative/bcltype/system.cpp
index 4e13bd1876..bb06ceceeb 100644
--- a/src/classlibnative/bcltype/system.cpp
+++ b/src/classlibnative/bcltype/system.cpp
@@ -31,16 +31,6 @@
#include "array.h"
#include "eepolicy.h"
-
-#ifdef FEATURE_WINDOWSPHONE
-Volatile<BOOL> g_fGetPhoneVersionInitialized;
-
-// This is the API to query the phone version information
-typedef BOOL (*pfnGetPhoneVersion)(LPOSVERSIONINFO lpVersionInformation);
-
-pfnGetPhoneVersion g_pfnGetPhoneVersion = NULL;
-#endif
-
typedef void(WINAPI *pfnGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime);
extern pfnGetSystemTimeAsFileTime g_pfnGetSystemTimeAsFileTime;
@@ -53,6 +43,33 @@ void WINAPI InitializeGetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
if (hKernel32 != NULL)
{
func = (pfnGetSystemTimeAsFileTime)GetProcAddress(hKernel32, "GetSystemTimePreciseAsFileTime");
+ if (func != NULL)
+ {
+ // GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
+ // misconfigured systems, it's possible for the "precise" time to be inaccurate:
+ // https://github.com/dotnet/coreclr/issues/14187
+ // If it's inaccurate, though, we expect it to be wildly inaccurate, so as a
+ // workaround/heuristic, we get both the "normal" and "precise" times, and as
+ // long as they're close, we use the precise one. This workaround can be removed
+ // when we better understand what's causing the drift and the issue is no longer
+ // a problem or can be better worked around on all targeted OSes.
+
+ FILETIME systemTimeResult;
+ ::GetSystemTimeAsFileTime(&systemTimeResult);
+
+ FILETIME preciseSystemTimeResult;
+ func(&preciseSystemTimeResult);
+
+ LONG64 systemTimeLong100ns = (LONG64)((((ULONG64)systemTimeResult.dwHighDateTime) << 32) | (ULONG64)systemTimeResult.dwLowDateTime);
+ LONG64 preciseSystemTimeLong100ns = (LONG64)((((ULONG64)preciseSystemTimeResult.dwHighDateTime) << 32) | (ULONG64)preciseSystemTimeResult.dwLowDateTime);
+
+ const INT32 THRESHOLD_100NS = 1000000; // 100ms
+ if (abs(preciseSystemTimeLong100ns - systemTimeLong100ns) > THRESHOLD_100NS)
+ {
+ // Too much difference. Don't use GetSystemTimePreciseAsFileTime.
+ func = NULL;
+ }
+ }
}
if (func == NULL)
#endif
@@ -212,49 +229,6 @@ FCIMPL0(Object*, SystemNative::GetCommandLineArgs)
}
FCIMPLEND
-
-FCIMPL1(FC_BOOL_RET, SystemNative::_GetCompatibilityFlag, int flag)
-{
- FCALL_CONTRACT;
-
- FC_RETURN_BOOL(GetCompatibilityFlag((CompatibilityFlag)flag));
-}
-FCIMPLEND
-
-// Note: Arguments checked in IL.
-FCIMPL1(Object*, SystemNative::_GetEnvironmentVariable, StringObject* strVarUNSAFE)
-{
- FCALL_CONTRACT;
-
- STRINGREF refRetVal;
- STRINGREF strVar;
-
- refRetVal = NULL;
- strVar = ObjectToSTRINGREF(strVarUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, strVar);
-
- int len;
-
- // Get the length of the environment variable.
- PathString envPath; // prefix complains if pass a null ptr in, so rely on the final length parm instead
- len = WszGetEnvironmentVariable(strVar->GetBuffer(), envPath);
-
- if (len != 0)
- {
- // Allocate the string.
- refRetVal = StringObject::NewString(len);
-
- wcscpy_s(refRetVal->GetBuffer(), len + 1, envPath);
-
- }
-
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(refRetVal);
-}
-FCIMPLEND
-
// Return a method info for the method were the exception was thrown
FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE)
{
diff --git a/src/classlibnative/bcltype/system.h b/src/classlibnative/bcltype/system.h
index da5674f4f1..87dde89bcd 100644
--- a/src/classlibnative/bcltype/system.h
+++ b/src/classlibnative/bcltype/system.h
@@ -52,12 +52,10 @@ public:
void QCALLTYPE _GetCommandLine(QCall::StringHandleOnStack retString);
static FCDECL0(Object*, GetCommandLineArgs);
- static FCDECL1(FC_BOOL_RET, _GetCompatibilityFlag, int flag);
static FCDECL1(VOID, FailFast, StringObject* refMessageUNSAFE);
static FCDECL2(VOID, FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode);
static FCDECL2(VOID, FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE);
- static FCDECL1(Object*, _GetEnvironmentVariable, StringObject* strVar);
static FCDECL0(StringObject*, _GetModuleFileName);
static FCDECL0(StringObject*, GetRuntimeDirectory);
diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp
index 38f52adc1b..4f15297f03 100644
--- a/src/debug/daccess/dacdbiimpl.cpp
+++ b/src/debug/daccess/dacdbiimpl.cpp
@@ -7221,7 +7221,16 @@ HRESULT DacDbiInterfaceImpl::GetILCodeVersionNode(VMPTR_NativeCodeVersionNode vm
return E_INVALIDARG;
#ifdef FEATURE_REJIT
NativeCodeVersionNode* pNativeCodeVersionNode = vmNativeCodeVersionNode.GetDacPtr();
- pVmILCodeVersionNode->SetDacTargetPtr(PTR_TO_TADDR(pNativeCodeVersionNode->GetILCodeVersion().AsNode()));
+ ILCodeVersion ilCodeVersion = pNativeCodeVersionNode->GetILCodeVersion();
+ if (ilCodeVersion.IsDefaultVersion())
+ {
+ pVmILCodeVersionNode->SetDacTargetPtr(0);
+ }
+ else
+ {
+ pVmILCodeVersionNode->SetDacTargetPtr(PTR_TO_TADDR(ilCodeVersion.AsNode()));
+ }
+
#else
_ASSERTE(!"You shouldn't be calling this - rejit is not supported in this build");
pVmILCodeVersionNode->SetDacTargetPtr(0);
diff --git a/src/debug/daccess/enummem.cpp b/src/debug/daccess/enummem.cpp
index c1155d9e36..007af0ba4b 100644
--- a/src/debug/daccess/enummem.cpp
+++ b/src/debug/daccess/enummem.cpp
@@ -256,11 +256,6 @@ HRESULT ClrDataAccess::EnumMemCLRStatic(IN CLRDataEnumMemoryFlags flags)
// see synblk.cpp, the pointer is pointed to a static byte[]
SyncBlockCache::s_pSyncBlockCache.EnumMem();
-#ifndef FEATURE_IMPLICIT_TLS
- ReportMem(m_globalBase + g_dacGlobals.dac__gThreadTLSIndex, sizeof(DWORD));
- ReportMem(m_globalBase + g_dacGlobals.dac__gAppDomainTLSIndex, sizeof(DWORD));
-#endif
-
ReportMem(m_globalBase + g_dacGlobals.dac__g_FCDynamicallyAssignedImplementations,
sizeof(TADDR)*ECall::NUM_DYNAMICALLY_ASSIGNED_FCALL_IMPLEMENTATIONS);
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
index 08136f39e1..6d6e3589be 100644
--- a/src/debug/daccess/request.cpp
+++ b/src/debug/daccess/request.cpp
@@ -4041,14 +4041,14 @@ HRESULT ClrDataAccess::GetTLSIndex(ULONG *pIndex)
return E_INVALIDARG;
SOSDacEnter();
- if (CExecutionEngine::GetTlsIndex() == TLS_OUT_OF_INDEXES)
+ if (g_TlsIndex == TLS_OUT_OF_INDEXES)
{
*pIndex = 0;
hr = S_FALSE;
}
else
{
- *pIndex = CExecutionEngine::GetTlsIndex();
+ *pIndex = g_TlsIndex;
}
SOSDacLeave();
diff --git a/src/debug/di/rspriv.h b/src/debug/di/rspriv.h
index e0489c53ad..de821f26a6 100644
--- a/src/debug/di/rspriv.h
+++ b/src/debug/di/rspriv.h
@@ -10609,11 +10609,10 @@ private:
void CacheEEDebuggerWord();
HRESULT SetEEThreadValue(REMOTE_PTR EETlsValue);
-#ifdef FEATURE_IMPLICIT_TLS
+
DWORD_PTR GetEEThreadValue();
REMOTE_PTR GetClrModuleTlsDataAddress();
REMOTE_PTR GetEETlsDataBlock();
-#endif
public:
HRESULT GetEEDebuggerWord(REMOTE_PTR *pValue);
diff --git a/src/debug/di/rsthread.cpp b/src/debug/di/rsthread.cpp
index 02fae00b0f..cd5e62932a 100644
--- a/src/debug/di/rsthread.cpp
+++ b/src/debug/di/rsthread.cpp
@@ -1471,7 +1471,15 @@ void CordbThread::Get32bitFPRegisters(CONTEXT * pContext)
FLOATING_SAVE_AREA currentFPUState;
+#ifdef _MSC_VER
__asm fnsave currentFPUState // save the current FPU state.
+#else
+ __asm__ __volatile__
+ (
+ " fnsave %0\n" \
+ : "=m"(currentFPUState)
+ );
+#endif
floatarea.StatusWord &= 0xFF00; // remove any error codes.
floatarea.ControlWord |= 0x3F; // mask all exceptions.
@@ -1482,12 +1490,22 @@ void CordbThread::Get32bitFPRegisters(CONTEXT * pContext)
// @dbgtodo Microsoft crossplat: the conversion from a series of bytes to a floating
// point value will need to be done with an explicit conversion routine to unpack
// the IEEE format and compute the real number value represented.
-
+
+#ifdef _MSC_VER
__asm
{
fninit
frstor floatarea ;; reload the threads FPU state.
}
+#else
+ __asm__
+ (
+ " fninit\n" \
+ " frstor %0\n" \
+ : /* no outputs */
+ : "m"(floatarea)
+ );
+#endif
unsigned int i;
@@ -1498,11 +1516,21 @@ void CordbThread::Get32bitFPRegisters(CONTEXT * pContext)
m_floatValues[i] = td;
}
+#ifdef _MSC_VER
__asm
{
fninit
frstor currentFPUState ;; restore our saved FPU state.
}
+#else
+ __asm__
+ (
+ " fninit\n" \
+ " frstor %0\n" \
+ : /* no outputs */
+ : "m"(currentFPUState)
+ );
+#endif
m_fFloatStateValid = true;
m_floatStackTop = floatStackTop;
@@ -2968,12 +2996,7 @@ HRESULT CordbUnmanagedThread::RestoreLeafSeh()
// return value == 0 (assumed default, *pRead = false
REMOTE_PTR CordbUnmanagedThread::GetPreDefTlsSlot(SIZE_T slot, bool * pRead)
{
-#ifdef FEATURE_IMPLICIT_TLS
REMOTE_PTR pBlock = (REMOTE_PTR) GetEETlsDataBlock();
-#else
- DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
- REMOTE_PTR pBlock = (REMOTE_PTR) GetTlsSlot(pRO->m_TLSIndexOfPredefs);
-#endif
REMOTE_PTR data = 0;
@@ -3008,164 +3031,6 @@ REMOTE_PTR CordbUnmanagedThread::GetPreDefTlsSlot(SIZE_T slot, bool * pRead)
return 0;
}
-#ifndef FEATURE_IMPLICIT_TLS
-
-// Read the contents from a LS threads's TLS slot.
-DWORD_PTR CordbUnmanagedThread::GetTlsSlot(SIZE_T slot)
-{
- DWORD_PTR ret = 0;
-
- // Compute the address of the necessary TLS value.
- if (FAILED(LoadTLSArrayPtr()))
- {
- return NULL;
- }
-
-
- void * pBase = NULL;
- SIZE_T slotAdjusted = slot;
-
- if (slot < TLS_MINIMUM_AVAILABLE)
- {
- pBase = m_pTLSArray;
- }
- else if (slot < TLS_MINIMUM_AVAILABLE + TLS_EXPANSION_SLOTS)
- {
- pBase = m_pTLSExtendedArray;
- slotAdjusted -= TLS_MINIMUM_AVAILABLE;
-
- // Expansion slot is lazily allocated. If we're trying to read from it, but hasn't been allocated,
- // then the TLS slot is still the default value, which is 0 (NULL).
- if (pBase == NULL)
- {
- return NULL;
- }
- }
- else
- {
- // Slot is out of range. Shouldn't happen unless debuggee is corrupted.
- _ASSERTE(!"Invalid TLS slot");
- return NULL;
- }
-
- void *pEEThreadTLS = (BYTE*) pBase + (slotAdjusted * sizeof(void*));
-
-
- // Read the thread's TLS value.
- HRESULT hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS(pEEThreadTLS), &ret);
- if (FAILED(hr))
- {
- LOG((LF_CORDB, LL_INFO1000, "CUT::GEETV: failed to read TLS value: computed addr=0x%p index=%d, err=%x\n",
- pEEThreadTLS, slot, hr));
-
- return NULL;
- }
-
- LOG((LF_CORDB, LL_INFO1000000, "CUT::GEETV: EE Thread TLS value is 0x%p for thread 0x%x, slot 0x%x\n", ret, m_id, slot));
-
- return ret;
-}
-
-// This does a WriteProcessMemory to write to the debuggee's TLS slot allotted to EEThread
-//
-// Arguments:
-// EETlsValue - the value to write to the remote TLS slot.
-//
-// Notes:
-// The TLS slot is m_TLSIndex.
-//
-// This is very brittle because the OS can lazily allocates storage for TLS slots.
-// In order to gaurantee the storage is available, it must have been written to by the debuggee.
-// For managed threads, that's easy because the Thread* is already written to the slot.
-// But for pure native threads where GetThread() == NULL, the storage may not yet be allocated.
-//
-// The saving grace is that the debuggee's hijack filters will force the TLS to be allocated before it
-// sends a flare.
-//
-// Therefore, this function can only be called:
-// 1) on a managed thread
-// 2) on a native thread after that thread has been hijacked and sent a flare.
-//
-// This is brittle reasoning, but so is the rest of interop-debugging.
-//
-HRESULT CordbUnmanagedThread::SetEEThreadValue(REMOTE_PTR EETlsValue)
-{
- FAIL_IF_NEUTERED(this);
-
- // Compute the address of the necessary TLS value.
- DebuggerIPCRuntimeOffsets *pRO = &(GetProcess()->m_runtimeOffsets);
-
- // Compute the address of the necessary TLS value.
- HRESULT hr = LoadTLSArrayPtr();
- if (FAILED(hr))
- {
- return hr;
- }
-
-
- DWORD slot = (DWORD) pRO->m_TLSIndex;
-
- void * pBase = NULL;
- SIZE_T slotAdjusted = slot;
- if (slot < TLS_MINIMUM_AVAILABLE)
- {
- pBase = m_pTLSArray;
- }
- else if (slot < TLS_MINIMUM_AVAILABLE+TLS_EXPANSION_SLOTS)
- {
- pBase = m_pTLSExtendedArray;
- slotAdjusted -= TLS_MINIMUM_AVAILABLE;
-
- // Expansion slot is lazily allocated. If we're trying to read from it, but hasn't been allocated,
- // then the TLS slot is still the default value, which is 0.
- if (pBase == NULL)
- {
- // See reasoning in header for why this should succeed.
- _ASSERTE(!"Can't set to expansion slots because they haven't been allocated");
- return E_FAIL;
- }
- }
- else
- {
- // Slot is out of range. Shouldn't happen unless debuggee is corrupted.
- _ASSERTE(!"Invalid TLS slot");
- return E_INVALIDARG;
- }
-
-
- void *pEEThreadTLS = (BYTE*) pBase + (slotAdjusted * sizeof(void*));
-
-
- // Write the thread's TLS value.
- hr = GetProcess()->SafeWriteStruct(PTR_TO_CORDB_ADDRESS(pEEThreadTLS), &EETlsValue);
-
- if (FAILED(hr))
- {
- LOG((LF_CORDB, LL_INFO1000, "CUT::SEETV: failed to set TLS value: "
- "computed addr=0x%p index=%d, err=%x\n",
- pEEThreadTLS, pRO->m_TLSIndex, hr));
-
- return hr;
- }
-
- LOG((LF_CORDB, LL_INFO1000000,
- "CUT::SEETV: EE Thread TLS value is now 0x%p for thread 0x%x\n",
- EETlsValue, m_id));
-
- return S_OK;
-}
-#else // FEATURE_IMPLICIT_TLS
-
-#ifdef DBG_TARGET_X86
-#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x2c
-#elif defined(DBG_TARGET_AMD64)
-#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x58
-#elif defined(DBG_TARGET_ARM)
-#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x2c
-#elif defined(DBG_TARGET_ARM64)
-#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x58
-#endif
-
// sets the value of gCurrentThreadInfo.m_pThread
HRESULT CordbUnmanagedThread::SetEEThreadValue(REMOTE_PTR EETlsValue)
{
@@ -3247,7 +3112,7 @@ REMOTE_PTR CordbUnmanagedThread::GetClrModuleTlsDataAddress()
DWORD slot = (DWORD)(GetProcess()->m_runtimeOffsets.m_TLSIndex);
REMOTE_PTR clrModuleTlsDataAddr;
- hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)tlsArrayAddr + slot * sizeof(void*)), &clrModuleTlsDataAddr);
+ hr = GetProcess()->SafeReadStruct(PTR_TO_CORDB_ADDRESS((BYTE*)tlsArrayAddr + (slot & 0xFFFF) * sizeof(void*)), &clrModuleTlsDataAddr);
if (FAILED(hr))
{
return NULL;
@@ -3259,7 +3124,7 @@ REMOTE_PTR CordbUnmanagedThread::GetClrModuleTlsDataAddress()
return NULL;
}
- return clrModuleTlsDataAddr;
+ return (BYTE*) clrModuleTlsDataAddr + ((slot & 0x7FFF0000) >> 16);
}
// gets the value of gCurrentThreadInfo.m_EETlsData
@@ -3284,8 +3149,6 @@ REMOTE_PTR CordbUnmanagedThread::GetEETlsDataBlock()
return ret;
}
-#endif // FEATURE_IMPLICIT_TLS
-
/*
* CacheEEDebuggerWord
*
@@ -3309,11 +3172,7 @@ void CordbUnmanagedThread::CacheEEDebuggerWord()
{
LOG((LF_CORDB, LL_INFO1000, "CacheEEDW: Entered\n"));
-#ifdef FEATURE_IMPLICIT_TLS
REMOTE_PTR value = (REMOTE_PTR)GetEEThreadValue();
-#else
- REMOTE_PTR value = (REMOTE_PTR)GetTlsSlot(GetProcess()->m_runtimeOffsets.m_TLSIndex);
-#endif
if ((((DWORD)value) & 0x1) == 1)
{
diff --git a/src/debug/di/valuehome.cpp b/src/debug/di/valuehome.cpp
index 837afd5f8b..6cae8c1f3a 100644
--- a/src/debug/di/valuehome.cpp
+++ b/src/debug/di/valuehome.cpp
@@ -481,18 +481,36 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue,
// restore our original state.
DT_FLOATING_SAVE_AREA currentFPUState;
+ #ifdef _MSC_VER
__asm fnsave currentFPUState // save the current FPU state.
+ #else
+ __asm__ __volatile__
+ (
+ " fnsave %0\n" \
+ : "=m"(currentFPUState)
+ );
+ #endif
// Copy the state out of the context.
DT_FLOATING_SAVE_AREA floatarea = pContext->FloatSave;
floatarea.StatusWord &= 0xFF00; // remove any error codes.
floatarea.ControlWord |= 0x3F; // mask all exceptions.
+ #ifdef _MSC_VER
__asm
{
fninit
frstor floatarea ;; reload the threads FPU state.
}
+ #else
+ __asm__
+ (
+ " fninit\n" \
+ " frstor %0\n" \
+ : /* no outputs */
+ : "m"(floatarea)
+ );
+ #endif
double td; // temp double
double popArea[DebuggerIPCE_FloatCount];
@@ -519,17 +537,35 @@ void FloatRegValueHome::SetEnregisteredValue(MemoryRange newValue,
}
// Save out the modified float area.
+ #ifdef _MSC_VER
__asm fnsave floatarea
+ #else
+ __asm__ __volatile__
+ (
+ " fnsave %0\n" \
+ : "=m"(floatarea)
+ );
+ #endif
// Put it into the context.
pContext->FloatSave= floatarea;
// Restore our FPU state
+ #ifdef _MSC_VER
__asm
{
fninit
frstor currentFPUState ;; restore our saved FPU state.
}
+ #else
+ __asm__
+ (
+ " fninit\n" \
+ " frstor %0\n" \
+ : /* no outputs */
+ : "m"(currentFPUState)
+ );
+ #endif
#endif // DBG_TARGET_X86
// update the thread's floating point stack
diff --git a/src/debug/ee/controller.cpp b/src/debug/ee/controller.cpp
index 3a87fdf166..55e9936866 100644
--- a/src/debug/ee/controller.cpp
+++ b/src/debug/ee/controller.cpp
@@ -466,7 +466,9 @@ StackWalkAction ControllerStackInfo::WalkStack(FrameInfo *pInfo, void *data)
DebuggerControllerPatch *DebuggerPatchTable::AddPatchForMethodDef(DebuggerController *controller,
Module *module,
mdMethodDef md,
+ MethodDesc* pMethodDescFilter,
size_t offset,
+ BOOL offsetIsIL,
DebuggerPatchKind kind,
FramePointer fp,
AppDomain *pAppDomain,
@@ -481,6 +483,8 @@ DebuggerControllerPatch *DebuggerPatchTable::AddPatchForMethodDef(DebuggerContro
}
CONTRACTL_END;
+
+
LOG( (LF_CORDB,LL_INFO10000,"DCP:AddPatchForMethodDef unbound "
"relative in methodDef 0x%x with dji 0x%x "
"controller:0x%x AD:0x%x\n", md,
@@ -507,8 +511,9 @@ DebuggerControllerPatch *DebuggerPatchTable::AddPatchForMethodDef(DebuggerContro
patch->controller = controller;
patch->key.module = module;
patch->key.md = md;
+ patch->pMethodDescFilter = pMethodDescFilter;
patch->offset = offset;
- patch->offsetIsIL = (kind == PATCH_KIND_IL_MASTER);
+ patch->offsetIsIL = offsetIsIL;
patch->address = NULL;
patch->fp = fp;
patch->trace.Bad_SetTraceType(DPT_DEFAULT_TRACE_TYPE); // TRACE_OTHER
@@ -544,6 +549,17 @@ DebuggerControllerPatch *DebuggerPatchTable::AddPatchForMethodDef(DebuggerContro
// The only kind of patch with IL offset is the IL master patch.
_ASSERTE(patch->IsILMasterPatch() || patch->offsetIsIL == FALSE);
+
+ // The only kind of patch that allows a MethodDescFilter is the IL master patch
+ _ASSERTE(patch->IsILMasterPatch() || patch->pMethodDescFilter == NULL);
+
+ // Zero is the only native offset that we allow to bind across different jitted
+ // code bodies. There isn't any sensible meaning to binding at some other native offset.
+ // Even if all the code bodies had an instruction that started at that offset there is
+ // no guarantee those instructions represent a semantically equivalent point in the
+ // method's execution.
+ _ASSERTE(!(patch->IsILMasterPatch() && !patch->offsetIsIL && patch->offset != 0));
+
return patch;
}
@@ -604,6 +620,7 @@ DebuggerControllerPatch *DebuggerPatchTable::AddPatchForAddress(DebuggerControll
patch->key.module = g_pEEInterface->MethodDescGetModule(fd);
patch->key.md = fd->GetMemberDef();
}
+ patch->pMethodDescFilter = NULL;
patch->offset = offset;
patch->offsetIsIL = FALSE;
patch->address = address;
@@ -1795,7 +1812,9 @@ void DebuggerController::DeactivatePatch(DebuggerControllerPatch *patch)
// optimization.</REVISIT_TODO>
DebuggerControllerPatch *DebuggerController::AddILMasterPatch(Module *module,
mdMethodDef md,
+ MethodDesc *pMethodDescFilter,
SIZE_T offset,
+ BOOL offsetIsIL,
SIZE_T encVersion)
{
CONTRACTL
@@ -1814,7 +1833,9 @@ DebuggerControllerPatch *DebuggerController::AddILMasterPatch(Module *module,
DebuggerControllerPatch *patch = g_patches->AddPatchForMethodDef(this,
module,
md,
+ pMethodDescFilter,
offset,
+ offsetIsIL,
PATCH_KIND_IL_MASTER,
LEAF_MOST_FRAME,
NULL,
@@ -1822,7 +1843,8 @@ DebuggerControllerPatch *DebuggerController::AddILMasterPatch(Module *module,
NULL);
LOG((LF_CORDB, LL_INFO10000,
- "DC::AP: Added IL master patch 0x%x for md 0x%x at offset %d encVersion %d\n", patch, md, offset, encVersion));
+ "DC::AP: Added IL master patch 0x%p for mdTok 0x%x, desc 0x%p at %s offset %d encVersion %d\n",
+ patch, md, pMethodDescFilter, offsetIsIL ? "il" : "native", offset, encVersion));
return patch;
}
@@ -1835,40 +1857,56 @@ BOOL DebuggerController::AddBindAndActivateILSlavePatch(DebuggerControllerPatch
_ASSERTE(master->IsILMasterPatch());
_ASSERTE(dji != NULL);
- // Do not dereference the "master" pointer in the loop! The loop may add more patches,
- // causing the patch table to grow and move.
- BOOL result = FALSE;
- SIZE_T masterILOffset = master->offset;
+ BOOL result = FALSE;
- // Loop through all the native offsets mapped to the given IL offset. On x86 the mapping
- // should be 1:1. On WIN64, because there are funclets, we have have an 1:N mapping.
- DebuggerJitInfo::ILToNativeOffsetIterator it;
- for (dji->InitILToNativeOffsetIterator(it, masterILOffset); !it.IsAtEnd(); it.Next())
+ if (!master->offsetIsIL)
+ {
+ // Zero is the only native offset that we allow to bind across different jitted
+ // code bodies.
+ _ASSERTE(master->offset == 0);
+ INDEBUG(BOOL fOk = )
+ AddBindAndActivatePatchForMethodDesc(dji->m_fd, dji,
+ 0, PATCH_KIND_IL_SLAVE,
+ LEAF_MOST_FRAME, m_pAppDomain);
+ _ASSERTE(fOk);
+ result = TRUE;
+ }
+ else // bind by IL offset
{
- BOOL fExact;
- SIZE_T offsetNative = it.Current(&fExact);
+ // Do not dereference the "master" pointer in the loop! The loop may add more patches,
+ // causing the patch table to grow and move.
+ SIZE_T masterILOffset = master->offset;
- // We special case offset 0, which is when a breakpoint is set
- // at the beginning of a method that hasn't been jitted yet. In
- // that case it's possible that offset 0 has been optimized out,
- // but we still want to set the closest breakpoint to that.
- if (!fExact && (masterILOffset != 0))
+ // Loop through all the native offsets mapped to the given IL offset. On x86 the mapping
+ // should be 1:1. On WIN64, because there are funclets, we have have an 1:N mapping.
+ DebuggerJitInfo::ILToNativeOffsetIterator it;
+ for (dji->InitILToNativeOffsetIterator(it, masterILOffset); !it.IsAtEnd(); it.Next())
{
- LOG((LF_CORDB, LL_INFO10000, "DC::BP:Failed to bind patch at IL offset 0x%p in %s::%s\n",
- masterILOffset, dji->m_fd->m_pszDebugClassName, dji->m_fd->m_pszDebugMethodName));
+ BOOL fExact;
+ SIZE_T offsetNative = it.Current(&fExact);
- continue;
- }
- else
- {
- result = TRUE;
- }
+ // We special case offset 0, which is when a breakpoint is set
+ // at the beginning of a method that hasn't been jitted yet. In
+ // that case it's possible that offset 0 has been optimized out,
+ // but we still want to set the closest breakpoint to that.
+ if (!fExact && (masterILOffset != 0))
+ {
+ LOG((LF_CORDB, LL_INFO10000, "DC::BP:Failed to bind patch at IL offset 0x%p in %s::%s\n",
+ masterILOffset, dji->m_fd->m_pszDebugClassName, dji->m_fd->m_pszDebugMethodName));
- INDEBUG(BOOL fOk = )
- AddBindAndActivatePatchForMethodDesc(dji->m_fd, dji,
- offsetNative, PATCH_KIND_IL_SLAVE,
- LEAF_MOST_FRAME, m_pAppDomain);
- _ASSERTE(fOk);
+ continue;
+ }
+ else
+ {
+ result = TRUE;
+ }
+
+ INDEBUG(BOOL fOk = )
+ AddBindAndActivatePatchForMethodDesc(dji->m_fd, dji,
+ offsetNative, PATCH_KIND_IL_SLAVE,
+ LEAF_MOST_FRAME, m_pAppDomain);
+ _ASSERTE(fOk);
+ }
}
// As long as we have successfully bound at least one patch, we consider the operation successful.
@@ -1890,8 +1928,10 @@ BOOL DebuggerController::AddBindAndActivateILSlavePatch(DebuggerControllerPatch
// that have debugging information
BOOL DebuggerController::AddILPatch(AppDomain * pAppDomain, Module *module,
mdMethodDef md,
+ MethodDesc *pMethodDescFilter,
SIZE_T encVersion, // what encVersion does this apply to?
- SIZE_T offset)
+ SIZE_T offset,
+ BOOL offsetIsIL)
{
_ASSERTE(g_patches != NULL);
_ASSERTE(md != NULL);
@@ -1913,7 +1953,7 @@ BOOL DebuggerController::AddILPatch(AppDomain * pAppDomain, Module *module,
//
// MapAndBindFunctionPatches will take care of any instantiations that haven't
// finished JITting, by making a copy of the master breakpoint.
- DebuggerControllerPatch *master = AddILMasterPatch(module, md, offset, encVersion);
+ DebuggerControllerPatch *master = AddILMasterPatch(module, md, pMethodDescFilter, offset, offsetIsIL, encVersion);
// We have to keep the index here instead of the pointer. The loop below adds more patches,
// which may cause the patch table to grow and move.
@@ -1922,7 +1962,7 @@ BOOL DebuggerController::AddILPatch(AppDomain * pAppDomain, Module *module,
// Iterate through every existing NativeCodeBlob (with the same EnC version).
// This includes generics + prejitted code.
DebuggerMethodInfo::DJIIterator it;
- dmi->IterateAllDJIs(pAppDomain, NULL /* module filter */, &it);
+ dmi->IterateAllDJIs(pAppDomain, NULL /* module filter */, pMethodDescFilter, &it);
if (it.IsAtEnd())
{
@@ -1941,7 +1981,8 @@ BOOL DebuggerController::AddILPatch(AppDomain * pAppDomain, Module *module,
{
DebuggerJitInfo *dji = it.Current();
_ASSERTE(dji->m_jitComplete);
- if (dji->m_encVersion == encVersion)
+ if (dji->m_encVersion == encVersion &&
+ (pMethodDescFilter == NULL || pMethodDescFilter == dji->m_fd))
{
fVersionMatch = TRUE;
@@ -1992,7 +2033,10 @@ void DebuggerController::AddPatchToStartOfLatestMethod(MethodDesc * fd)
CONTRACTL_END;
_ASSERTE(g_patches != NULL);
- DebuggerController::AddBindAndActivatePatchForMethodDesc(fd, NULL, 0, PATCH_KIND_NATIVE_MANAGED, LEAF_MOST_FRAME, NULL);
+ Module* pModule = fd->GetModule();
+ mdToken defToken = fd->GetMemberDef();
+ DebuggerMethodInfo* pDMI = g_pDebugger->GetOrCreateMethodInfo(pModule, defToken);
+ DebuggerController::AddILPatch(GetAppDomain(), pModule, defToken, fd, pDMI->GetCurrentEnCVersion(), 0, FALSE);
return;
}
@@ -2023,10 +2067,10 @@ BOOL DebuggerController::AddBindAndActivateNativeManagedPatch(MethodDesc * fd,
return DebuggerController::AddBindAndActivatePatchForMethodDesc(fd, dji, offsetNative, PATCH_KIND_NATIVE_MANAGED, fp, pAppDomain);
}
-
+// Adds a breakpoint at a specific native offset in a particular jitted code version
BOOL DebuggerController::AddBindAndActivatePatchForMethodDesc(MethodDesc *fd,
DebuggerJitInfo *dji,
- SIZE_T offset,
+ SIZE_T nativeOffset,
DebuggerPatchKind kind,
FramePointer fp,
AppDomain *pAppDomain)
@@ -2039,6 +2083,7 @@ BOOL DebuggerController::AddBindAndActivatePatchForMethodDesc(MethodDesc *fd,
MODE_ANY; // don't really care what mode we're in.
PRECONDITION(ThisMaybeHelperThread());
+ PRECONDITION(kind != PATCH_KIND_IL_MASTER);
}
CONTRACTL_END;
@@ -2048,13 +2093,15 @@ BOOL DebuggerController::AddBindAndActivatePatchForMethodDesc(MethodDesc *fd,
LOG((LF_CORDB|LF_ENC,LL_INFO10000,"DC::AP: Add to %s::%s, at offs 0x%x "
"fp:0x%x AD:0x%x\n", fd->m_pszDebugClassName,
fd->m_pszDebugMethodName,
- offset, fp.GetSPValue(), pAppDomain));
+ nativeOffset, fp.GetSPValue(), pAppDomain));
DebuggerControllerPatch *patch = g_patches->AddPatchForMethodDef(
this,
g_pEEInterface->MethodDescGetModule(fd),
fd->GetMemberDef(),
- offset,
+ NULL,
+ nativeOffset,
+ FALSE,
kind,
fp,
pAppDomain,
@@ -2285,6 +2332,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace,
}
CONTRACTL_END;
DebuggerControllerPatch *dcp = NULL;
+ SIZE_T nativeOffset = 0;
switch (trace->GetTraceType())
{
@@ -2321,11 +2369,25 @@ bool DebuggerController::PatchTrace(TraceDestination *trace,
dji = g_pDebugger->GetJitInfoFromAddr(trace->GetAddress());
//_ASSERTE(dji); //we'd like to assert this, but attach won't work
- AddBindAndActivateNativeManagedPatch(fd,
- dji,
- CodeRegionInfo::GetCodeRegionInfo(dji, fd).AddressToOffset((const BYTE *)trace->GetAddress()),
- fp,
- NULL);
+ nativeOffset = CodeRegionInfo::GetCodeRegionInfo(dji, fd).AddressToOffset((const BYTE *)trace->GetAddress());
+
+ // Code versioning allows calls to be redirected to alternate code potentially after this trace is complete but before
+ // execution reaches the call target. Rather than bind the breakpoint to a specific jitted code instance that is currently
+ // configured to receive execution we need to prepare for that potential retargetting by binding all jitted code instances.
+ //
+ // Triggering this based of the native offset is a little subtle, but all of the stubmanagers follow a rule that if they
+ // trace across a call boundary into jitted code they either stop at offset zero of the new method, or they continue tracing
+ // out of that jitted code.
+ if (nativeOffset == 0)
+ {
+ AddPatchToStartOfLatestMethod(fd);
+ }
+ else
+ {
+ AddBindAndActivateNativeManagedPatch(fd, dji, nativeOffset, fp, NULL);
+ }
+
+
return true;
case TRACE_UNJITTED_METHOD:
@@ -4893,14 +4955,39 @@ DebuggerBreakpoint::DebuggerBreakpoint(Module *module,
_ASSERTE(native || nativeJITInfo == NULL);
_ASSERTE(!nativeJITInfo || nativeJITInfo->m_jitComplete); // this is sent by the left-side, and it couldn't have got the code if the JIT wasn't complete
- if (native)
+ BOOL bindAcrossAllJittedInstances = !native;
+ MethodDesc* pGenericInstanceFilter = NULL;
+#ifdef DEBUG
+ // Normally any breakpoint specified as a native offset only binds in one jitted instance of a method, however
+ // to better test the breakpoint binding logic in debug builds we allow the behavior to change. The test behavior
+ // binds native breakpoints in every code version of the same generic instance. Currently the only way to get more
+ // than one such version is to use tiered compilation, but even with only one version the code path is a little different.
+ //
+ // This covers the same code paths used to add a step-in breakpoint, because step-in needs to handle code version changes
+ // transparently but it is challenging to create a test case that ensures the code version will change exactly during the
+ // tiny window of time that the step-in breakpoint exists.
+ static ConfigDWORD config;
+ if(config.val(CLRConfig::INTERNAL_DbgNativeCodeBpBindsAcrossVersions))
+ {
+ LOG((LF_CORDB, LL_INFO1000, "DB::DB Test hook COMPLUS_DbgNativeCodeBpBindsAcrossVersions is active\n"));
+ if (native && offset == 0 && nativeMethodDesc)
+ {
+ LOG((LF_CORDB, LL_INFO1000, "DB::DB Test hook modification: native breakpoint at offset 0 binding to all code versions\n"));
+ bindAcrossAllJittedInstances = TRUE;
+ pGenericInstanceFilter = nativeMethodDesc;
+ }
+ }
+#endif
+
+ if (!bindAcrossAllJittedInstances)
{
(*pSucceed) = AddBindAndActivateNativeManagedPatch(nativeMethodDesc, nativeJITInfo, offset, LEAF_MOST_FRAME, pAppDomain);
return;
}
else
{
- (*pSucceed) = AddILPatch(pAppDomain, module, md, ilEnCVersion, offset);
+ _ASSERTE(!native || offset == 0);
+ (*pSucceed) = AddILPatch(pAppDomain, module, md, pGenericInstanceFilter, ilEnCVersion, offset, !native);
}
}
@@ -5582,7 +5669,9 @@ bool DebuggerStepper::TrapStepInHelper(
_ASSERTE( g_pEEInterface->IsManagedNativeCode((const BYTE *)td.GetAddress()) );
md = g_pEEInterface->GetNativeCodeMethodDesc(td.GetAddress());
- if ( g_pEEInterface->GetFunctionAddress(md) == td.GetAddress())
+ DebuggerJitInfo* pDJI = g_pDebugger->GetJitInfoFromAddr(td.GetAddress());
+ CodeRegionInfo code = CodeRegionInfo::GetCodeRegionInfo(pDJI, md);
+ if (code.AddressToOffset((const BYTE *)td.GetAddress()) == 0)
{
LOG((LF_CORDB,LL_INFO1000,"\tDS::TS 0x%x m_reason = STEP_CALL"
@@ -5592,9 +5681,9 @@ bool DebuggerStepper::TrapStepInHelper(
else
{
LOG((LF_CORDB, LL_INFO1000, "Didn't step: md:0x%x"
- "td.type:%s td.address:0x%x, gfa:0x%x\n",
+ "td.type:%s td.address:0x%p, hot code address:0x%p\n",
md, GetTType(td.GetTraceType()), td.GetAddress(),
- g_pEEInterface->GetFunctionAddress(md)));
+ code.getAddrOfHotCode()));
}
}
else
diff --git a/src/debug/ee/controller.h b/src/debug/ee/controller.h
index 95569b55c7..bac635e2f7 100644
--- a/src/debug/ee/controller.h
+++ b/src/debug/ee/controller.h
@@ -276,16 +276,32 @@ struct DebuggerFunctionKey1
typedef DebuggerFunctionKey1 UNALIGNED DebuggerFunctionKey;
-// ILMaster: Breakpoints on IL code may need to be applied to multiple
-// copies of code, because generics mean code gets JITTed multiple times.
-// The "master" is a patch we keep to record the IL offset, and is used to
-// create new "slave"patches.
-
+// IL Master: Breakpoints on IL code may need to be applied to multiple
+// copies of code. Historically generics was the only way IL code was JITTed
+// multiple times but more recently the CodeVersionManager and tiered compilation
+// provide more open-ended mechanisms to have multiple native code bodies derived
+// from a single IL method body.
+// The "master" is a patch we keep to record the IL offset or native offset, and
+// is used to create new "slave"patches. For native offsets only offset 0 is allowed
+// because that is the only one that we think would have a consistent semantic
+// meaning across different code bodies.
+// There can also be multiple IL bodies for the same method given EnC or ReJIT.
+// A given master breakpoint is tightly bound to one particular IL body determined
+// by encVersion. ReJIT + breakpoints isn't currently supported.
+//
+//
+// IL Slave: The slaves created from Master patches. If the master used an IL offset
+// then the slave also initially has an IL offset that will later become a native offset.
+// If the master uses a native offset (0) then the slave will also have a native offset (0).
+// These patches always resolve to addresses in jitted code.
//
-// ILSlave: The slaves created from ILMaster patches. The offset for
-// these is initially an IL offset and later becomes a native offset.
//
-// NativeManaged: A patch we apply to managed code, usually for walkers etc.
+// NativeManaged: A patch we apply to managed code, usually for walkers etc. If this code
+// is jitted then these patches are always bound to one exact jitted code body.
+// If you need to be 100% sure I suggest you do more code review but I believe we also
+// use this for managed code from other code generators such as a stub or statically compiled
+// code that executes in cooperative mode.
+//
//
// NativeUnmanaged: A patch applied to any kind of native code.
@@ -361,6 +377,8 @@ struct DebuggerControllerPatch
PRD_TYPE opcodeSaved;//also a misnomer
BOOL offsetIsIL;
TraceDestination trace;
+ MethodDesc* pMethodDescFilter; // used for IL Master patches that should only bind to jitted
+ // code versions for a single generic instantiation
private:
int refCount;
union
@@ -663,7 +681,9 @@ public:
DebuggerControllerPatch *AddPatchForMethodDef(DebuggerController *controller,
Module *module,
mdMethodDef md,
- size_t offset,
+ MethodDesc *pMethodDescFilter,
+ size_t offset,
+ BOOL offsetIsIL,
DebuggerPatchKind kind,
FramePointer fp,
AppDomain *pAppDomain,
@@ -1170,8 +1190,10 @@ public:
BOOL AddILPatch(AppDomain * pAppDomain, Module *module,
mdMethodDef md,
+ MethodDesc* pMethodFilter,
SIZE_T encVersion, // what encVersion does this apply to?
- SIZE_T offset);
+ SIZE_T offset,
+ BOOL offsetIsIL);
// The next two are very similar. Both work on offsets,
// but one takes a "patch id". I don't think these are really needed: the
@@ -1244,12 +1266,14 @@ public:
DebuggerControllerPatch *AddILMasterPatch(Module *module,
mdMethodDef md,
+ MethodDesc *pMethodDescFilter,
SIZE_T offset,
+ BOOL offsetIsIL,
SIZE_T encVersion);
BOOL AddBindAndActivatePatchForMethodDesc(MethodDesc *fd,
DebuggerJitInfo *dji,
- SIZE_T offset,
+ SIZE_T nativeOffset,
DebuggerPatchKind kind,
FramePointer fp,
AppDomain *pAppDomain);
diff --git a/src/debug/ee/debugger.cpp b/src/debug/ee/debugger.cpp
index 01833b3730..f41ce63375 100644
--- a/src/debug/ee/debugger.cpp
+++ b/src/debug/ee/debugger.cpp
@@ -2670,6 +2670,10 @@ void Debugger::JITComplete(MethodDesc* fd, TADDR newAddress)
}
CONTRACTL_END;
+ LOG((LF_CORDB, LL_INFO100000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x.\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress));
+
#ifdef _TARGET_ARM_
newAddress = newAddress|THUMB_CODE;
#endif
@@ -2690,7 +2694,24 @@ void Debugger::JITComplete(MethodDesc* fd, TADDR newAddress)
{
goto Exit;
}
- DebuggerJitInfo * ji = dmi->CreateInitAndAddJitInfo(fd, newAddress);
+ BOOL jiWasCreated = FALSE;
+ DebuggerJitInfo * ji = dmi->CreateInitAndAddJitInfo(fd, newAddress, &jiWasCreated);
+ if (!jiWasCreated)
+ {
+ // we've already been notified about this code, no work remains.
+ // The JIT is occasionally asked to generate code for the same
+ // method on two threads. When this occurs both threads will
+ // return the same code pointer and this callback is invoked
+ // multiple times.
+ LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x. Already created\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress));
+ goto Exit;
+ }
+
+ LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x. Created ji:0x%x\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress, ji));
// Bind any IL patches to the newly jitted native code.
HRESULT hr;
@@ -3008,7 +3029,7 @@ DebuggerMethodInfo *Debugger::GetOrCreateMethodInfo(Module *pModule, mdMethodDef
* structs will be returned, and some of the ilOffsets in this array
* may be the values specified in CorDebugIlToNativeMappingTypes.
******************************************************************************/
-HRESULT Debugger::GetILToNativeMapping(MethodDesc *pMD, ULONG32 cMap,
+HRESULT Debugger::GetILToNativeMapping(UINT_PTR pNativeCodeStartAddress, ULONG32 cMap,
ULONG32 *pcMap, COR_DEBUG_IL_TO_NATIVE_MAP map[])
{
CONTRACTL
@@ -3037,7 +3058,7 @@ HRESULT Debugger::GetILToNativeMapping(MethodDesc *pMD, ULONG32 cMap,
_ASSERTE(CORProfilerPresent());
#endif // PROFILING_SUPPORTED
- DebuggerJitInfo *pDJI = GetLatestJitInfoFromMethodDesc(pMD);
+ DebuggerJitInfo *pDJI = GetJitInfoFromAddr(pNativeCodeStartAddress);
// Dunno what went wrong
if (pDJI == NULL)
@@ -4952,6 +4973,15 @@ HRESULT Debugger::MapAndBindFunctionPatches(DebuggerJitInfo *djiNew,
continue;
}
+ // If the patch only applies in certain generic instances, don't bind it
+ // elsewhere.
+ if(dcp->pMethodDescFilter != NULL && dcp->pMethodDescFilter != djiNew->m_fd)
+ {
+ LOG((LF_CORDB, LL_INFO10000, "Patch not in this generic instance\n"));
+ continue;
+ }
+
+
// Do not copy over slave breakpoint patches. Instead place a new slave
// based off the master.
if (dcp->IsILSlavePatch())
@@ -9685,7 +9715,7 @@ void Debugger::LoadModuleFinished(Module * pRuntimeModule, AppDomain * pAppDomai
// Found a relevant IL master patch. Now bind all corresponding slave patches
// that belong to this Module
DebuggerMethodInfo::DJIIterator it;
- dmi->IterateAllDJIs(pAppDomain, pRuntimeModule, &it);
+ dmi->IterateAllDJIs(pAppDomain, pRuntimeModule, pMasterPatchCur->pMethodDescFilter, &it);
for (; !it.IsAtEnd(); it.Next())
{
DebuggerJitInfo *dji = it.Current();
@@ -12565,7 +12595,7 @@ bool Debugger::IsThreadAtSafePlaceWorker(Thread *thread)
CONTEXT ctx;
ZeroMemory(&rd, sizeof(rd));
ZeroMemory(&ctx, sizeof(ctx));
-#if defined(_TARGET_X86_)
+#if defined(_TARGET_X86_) && !defined(WIN64EXCEPTIONS)
rd.ControlPC = ctx.Eip;
rd.PCTAddr = (TADDR)&(ctx.Eip);
#else
diff --git a/src/debug/ee/debugger.h b/src/debug/ee/debugger.h
index f99931e9dd..2ea7330ac0 100644
--- a/src/debug/ee/debugger.h
+++ b/src/debug/ee/debugger.h
@@ -955,6 +955,7 @@ public:
DebuggerJitInfo* m_pCurrent;
Module* m_pLoaderModuleFilter;
+ MethodDesc* m_pMethodDescFilter;
public:
DJIIterator();
@@ -964,8 +965,12 @@ public:
};
- // Ensure the DJI cache is completely up to date. (This is heavy weight).
- void CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pModuleFilter = NULL);
+ // Ensure the DJI cache is completely up to date. (This can be an expensive call, but
+ // much less so if pMethodDescFilter is used).
+ void CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pModuleFilter, MethodDesc * pMethodDescFilter);
+
+ // Ensure the DJI cache is up to date for a particular closed method desc
+ void CreateDJIsForMethodDesc(MethodDesc * pMethodDesc);
// Get an iterator for all native blobs (accounts for Generics, Enc, + Prejiiting).
// Must be stopped when we do this. This could be heavy weight.
@@ -973,7 +978,9 @@ public:
// You may optionally pass pLoaderModuleFilter to restrict the DJIs iterated to
// exist only on MethodDescs whose loader module matches the filter (pass NULL not
// to filter by loader module).
- void IterateAllDJIs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, DJIIterator * pEnum);
+ // You may optionally pass pMethodDescFilter to restrict the DJIs iterated to only
+ // a single generic instantiation.
+ void IterateAllDJIs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc * pMethodDescFilter, DJIIterator * pEnum);
private:
// The linked list of JIT's of this version of the method. This will ALWAYS
@@ -1003,7 +1010,7 @@ public:
// Creating the Jit-infos.
DebuggerJitInfo *FindOrCreateInitAndAddJitInfo(MethodDesc* fd);
- DebuggerJitInfo *CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr);
+ DebuggerJitInfo *CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr, BOOL* jitInfoWasCreated);
void DeleteJitInfo(DebuggerJitInfo *dji);
@@ -2018,7 +2025,7 @@ public:
DebuggerJitInfo *GetLatestJitInfoFromMethodDesc(MethodDesc * pMethodDesc);
- HRESULT GetILToNativeMapping(MethodDesc *pMD, ULONG32 cMap, ULONG32 *pcMap,
+ HRESULT GetILToNativeMapping(UINT_PTR pNativeCodeStartAddress, ULONG32 cMap, ULONG32 *pcMap,
COR_DEBUG_IL_TO_NATIVE_MAP map[]);
HRESULT GetILToNativeMappingIntoArrays(
diff --git a/src/debug/ee/functioninfo.cpp b/src/debug/ee/functioninfo.cpp
index aa75b30407..db0cfc86f9 100644
--- a/src/debug/ee/functioninfo.cpp
+++ b/src/debug/ee/functioninfo.cpp
@@ -1580,14 +1580,15 @@ DebuggerJitInfo *DebuggerMethodInfo::FindOrCreateInitAndAddJitInfo(MethodDesc* f
// CreateInitAndAddJitInfo takes a lock and checks the list again, which
// makes this thread-safe.
- return CreateInitAndAddJitInfo(fd, addr);
+ BOOL unused;
+ return CreateInitAndAddJitInfo(fd, addr, &unused);
}
// Create a DJI around a method-desc. The EE already has all the information we need for a DJI,
// the DJI just serves as a cache of the information for the debugger.
// Caller makes no guarantees about whether the DJI is already in the table. (Caller should avoid this if
// it knows it's in the table, but b/c we can't expect caller to synchronize w/ the other threads).
-DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr)
+DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr, BOOL* jitInfoWasCreated)
{
CONTRACTL
{
@@ -1603,6 +1604,7 @@ DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TAD
// May or may-not be jitted, that's why we passed in the start addr & size explicitly.
_ASSERTE(startAddr != NULL);
+ *jitInfoWasCreated = FALSE;
// No support for light-weight codegen methods.
if (fd->IsDynamicMethod())
@@ -1642,6 +1644,10 @@ DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TAD
DeleteInteropSafe(dji);
return pResult;
}
+ else
+ {
+ *jitInfoWasCreated = TRUE;
+ }
}
// We know it's not in the table. Go add it!
@@ -1814,6 +1820,10 @@ void DebuggerMethodInfo::DJIIterator::Next(BOOL fFirst /*=FALSE*/)
if ((m_pLoaderModuleFilter != NULL) && (m_pLoaderModuleFilter != pLoaderModule))
continue;
+ //Obey the methodDesc filter if it is provided
+ if ((m_pMethodDescFilter != NULL) && (m_pMethodDescFilter != m_pCurrent->m_fd))
+ continue;
+
// Skip modules that are unloaded, but still hanging around. Note that we can't use DebuggerModule for this check
// because of it is deleted pretty early during unloading, and we do not want to recreate it.
if (pLoaderModule->GetLoaderAllocator()->IsUnloaded())
@@ -1923,7 +1933,7 @@ void DebuggerMethodInfo::SetJMCStatus(bool fStatus)
// Get an iterator that will go through ALL native code-blobs (DJI) in the specified
// AppDomain, optionally filtered by loader module (if pLoaderModuleFilter != NULL).
// This is EnC/ Generics / Prejit aware.
-void DebuggerMethodInfo::IterateAllDJIs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, DebuggerMethodInfo::DJIIterator * pEnum)
+void DebuggerMethodInfo::IterateAllDJIs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc * pMethodDescFilter, DebuggerMethodInfo::DJIIterator * pEnum)
{
CONTRACTL
{
@@ -1934,13 +1944,14 @@ void DebuggerMethodInfo::IterateAllDJIs(AppDomain * pAppDomain, Module * pLoader
CONTRACTL_END;
_ASSERTE(pEnum != NULL);
- _ASSERTE(pAppDomain != NULL);
+ _ASSERTE(pAppDomain != NULL || pMethodDescFilter != NULL);
// Esnure we have DJIs for everything.
- CreateDJIsForNativeBlobs(pAppDomain, pLoaderModuleFilter);
+ CreateDJIsForNativeBlobs(pAppDomain, pLoaderModuleFilter, pMethodDescFilter);
pEnum->m_pCurrent = m_latestJitInfo;
pEnum->m_pLoaderModuleFilter = pLoaderModuleFilter;
+ pEnum->m_pMethodDescFilter = pMethodDescFilter;
// Advance to the first DJI that passes the filter
pEnum->Next(TRUE);
@@ -1956,9 +1967,10 @@ void DebuggerMethodInfo::IterateAllDJIs(AppDomain * pAppDomain, Module * pLoader
// loader module matches this one. (This can be different from m_module in the
// case of generics defined in one module and instantiated in another). If
// non-NULL, create DJIs for all modules in pAppDomain.
+// * pMethodDescFilter - If non-NULL, create DJIs only for this single MethodDesc.
//
-void DebuggerMethodInfo::CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pLoaderModuleFilter /* = NULL */)
+void DebuggerMethodInfo::CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module * pLoaderModuleFilter, MethodDesc* pMethodDescFilter)
{
CONTRACTL
{
@@ -1970,46 +1982,104 @@ void DebuggerMethodInfo::CreateDJIsForNativeBlobs(AppDomain * pAppDomain, Module
// If we're not stopped and the module we're iterating over allows types to load,
// then it's possible new native blobs are being created underneath us.
- _ASSERTE(g_pDebugger->IsStopped() || ((pLoaderModuleFilter != NULL) && !pLoaderModuleFilter->IsReadyForTypeLoad()));
-
- // @todo - we really only need to do this if the stop-counter goes up (else we know nothing new is added).
- // B/c of generics, it's possible that new instantiations of a method may have been jitted.
- // So just loop through all known instantiations and ensure that we have all the DJIs.
- // Note that this iterator won't show previous EnC versions, but we're already guaranteed to
- // have DJIs for every verision of a method that was EnCed.
- // This also handles the possibility of getting the same methoddesc back from the iterator.
- // It also lets EnC + generics play nice together (including if an generic method was EnC-ed)
- LoadedMethodDescIterator it(pAppDomain, m_module, m_token);
- CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
- while (it.Next(pDomainAssembly.This()))
- {
- MethodDesc * pDesc = it.Current();
- if (!pDesc->HasNativeCode())
+ _ASSERTE(g_pDebugger->IsStopped() ||
+ ((pLoaderModuleFilter != NULL) && !pLoaderModuleFilter->IsReadyForTypeLoad()) ||
+ pMethodDescFilter != NULL);
+
+ if (pMethodDescFilter != NULL)
+ {
+ CreateDJIsForMethodDesc(pMethodDescFilter);
+ }
+ else
+ {
+ // @todo - we really only need to do this if the stop-counter goes up (else we know nothing new is added).
+ // B/c of generics, it's possible that new instantiations of a method may have been jitted.
+ // So just loop through all known instantiations and ensure that we have all the DJIs.
+ // Note that this iterator won't show previous EnC versions, but we're already guaranteed to
+ // have DJIs for every verision of a method that was EnCed.
+ // This also handles the possibility of getting the same methoddesc back from the iterator.
+ // It also lets EnC + generics play nice together (including if an generic method was EnC-ed)
+ LoadedMethodDescIterator it(pAppDomain, m_module, m_token);
+ CollectibleAssemblyHolder<DomainAssembly *> pDomainAssembly;
+ while (it.Next(pDomainAssembly.This()))
{
- continue;
+ MethodDesc * pDesc = it.Current();
+ if (!pDesc->HasNativeCode())
+ {
+ continue;
+ }
+
+ Module * pLoaderModule = pDesc->GetLoaderModule();
+
+ // Obey the module filter if it's provided
+ if ((pLoaderModuleFilter != NULL) && (pLoaderModuleFilter != pLoaderModule))
+ continue;
+
+ // Skip modules that are unloaded, but still hanging around. Note that we can't use DebuggerModule for this check
+ // because of it is deleted pretty early during unloading, and we do not want to recreate it.
+ if (pLoaderModule->GetLoaderAllocator()->IsUnloaded())
+ continue;
+
+ CreateDJIsForMethodDesc(pDesc);
}
+ }
+}
- Module * pLoaderModule = pDesc->GetLoaderModule();
- // Obey the module filter if it's provided
- if ((pLoaderModuleFilter != NULL) && (pLoaderModuleFilter != pLoaderModule))
- continue;
+//---------------------------------------------------------------------------------------
+//
+// Bring the DJI cache up to date for jitted code instances of a particular MethodDesc.
+//
+//
+void DebuggerMethodInfo::CreateDJIsForMethodDesc(MethodDesc * pMethodDesc)
+{
+ CONTRACTL
+ {
+ SO_NOT_MAINLINE;
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
- // Skip modules that are unloaded, but still hanging around. Note that we can't use DebuggerModule for this check
- // because of it is deleted pretty early during unloading, and we do not want to recreate it.
- if (pLoaderModule->GetLoaderAllocator()->IsUnloaded())
- continue;
- // We just ask for the DJI to ensure that it's lazily created.
- // This should only fail in an oom scenario.
- DebuggerJitInfo * djiTest = g_pDebugger->GetLatestJitInfoFromMethodDesc(pDesc);
- if (djiTest == NULL)
+ // The debugger doesn't track Lightweight-codegen methods b/c they have no metadata.
+ if (pMethodDesc->IsDynamicMethod())
+ {
+ return;
+ }
+
+#ifdef FEATURE_CODE_VERSIONING
+ CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
+ // grab the code version lock to iterate available versions of the code
+ {
+ CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
+ NativeCodeVersionCollection nativeCodeVersions = pCodeVersionManager->GetNativeCodeVersions(pMethodDesc);
+
+ for (NativeCodeVersionIterator itr = nativeCodeVersions.Begin(), end = nativeCodeVersions.End(); itr != end; itr++)
{
- // We're oom. Give up.
- ThrowOutOfMemory();
- return;
+ // Some versions may not be compiled yet - skip those for now
+ // if they compile later the JitCompiled callback will add a DJI to our cache at that time
+ PCODE codeAddr = itr->GetNativeCode();
+ if (codeAddr)
+ {
+ // The DJI may already be populated in the cache, if so CreateInitAndAdd is
+ // a no-op and that is fine.
+ BOOL unusedDjiWasCreated;
+ CreateInitAndAddJitInfo(pMethodDesc, codeAddr, &unusedDjiWasCreated);
+ }
}
}
+#else
+ // We just ask for the DJI to ensure that it's lazily created.
+ // This should only fail in an oom scenario.
+ DebuggerJitInfo * djiTest = g_pDebugger->GetLatestJitInfoFromMethodDesc(pDesc);
+ if (djiTest == NULL)
+ {
+ // We're oom. Give up.
+ ThrowOutOfMemory();
+ return;
+ }
+#endif
}
/*
diff --git a/src/debug/ee/rcthread.cpp b/src/debug/ee/rcthread.cpp
index d4e707dd06..58547411c1 100644
--- a/src/debug/ee/rcthread.cpp
+++ b/src/debug/ee/rcthread.cpp
@@ -763,7 +763,6 @@ HRESULT DebuggerRCThread::SetupRuntimeOffsets(DebuggerIPCControlBlock * pDebugge
g_pEEInterface->GetRuntimeOffsets(&pDebuggerRuntimeOffsets->m_TLSIndex,
&pDebuggerRuntimeOffsets->m_TLSIsSpecialIndex,
&pDebuggerRuntimeOffsets->m_TLSCantStopIndex,
- &pDebuggerRuntimeOffsets->m_TLSIndexOfPredefs,
&pDebuggerRuntimeOffsets->m_EEThreadStateOffset,
&pDebuggerRuntimeOffsets->m_EEThreadStateNCOffset,
&pDebuggerRuntimeOffsets->m_EEThreadPGCDisabledOffset,
@@ -778,10 +777,6 @@ HRESULT DebuggerRCThread::SetupRuntimeOffsets(DebuggerIPCControlBlock * pDebugge
&pDebuggerRuntimeOffsets->m_EEFrameNextOffset,
&pDebuggerRuntimeOffsets->m_EEIsManagedExceptionStateMask);
-#ifndef FEATURE_IMPLICIT_TLS
- _ASSERTE((pDebuggerRuntimeOffsets->m_TLSIndexOfPredefs != 0) || !"CExecutionEngine::TlsIndex is not initialized yet");
-#endif
-
// Remember the struct in the control block.
pDebuggerIPCControlBlock->m_pRuntimeOffsets = pDebuggerRuntimeOffsets;
diff --git a/src/debug/inc/dbgipcevents.h b/src/debug/inc/dbgipcevents.h
index dc900660c3..8a6786a378 100644
--- a/src/debug/inc/dbgipcevents.h
+++ b/src/debug/inc/dbgipcevents.h
@@ -133,7 +133,6 @@ struct MSLAYOUT DebuggerIPCRuntimeOffsets
SIZE_T m_TLSIndex; // The TLS index the CLR is using to hold Thread objects
SIZE_T m_TLSIsSpecialIndex; // The index into the Predef block of the the "IsSpecial" status for a thread.
SIZE_T m_TLSCantStopIndex; // The index into the Predef block of the the Can't-Stop count.
- SIZE_T m_TLSIndexOfPredefs; // The TLS index of the Predef block.
SIZE_T m_EEThreadStateOffset; // Offset of m_state in a Thread
SIZE_T m_EEThreadStateNCOffset; // Offset of m_stateNC in a Thread
SIZE_T m_EEThreadPGCDisabledOffset; // Offset of the bit for whether PGC is disabled or not in a Thread
diff --git a/src/debug/shim/debugshim.cpp b/src/debug/shim/debugshim.cpp
index 03b9c5f550..08f1ec58a1 100644
--- a/src/debug/shim/debugshim.cpp
+++ b/src/debug/shim/debugshim.cpp
@@ -38,7 +38,7 @@
// CLRDebuggingImpl implementation (ICLRDebugging)
//*****************************************************************************
-typedef HRESULT (__stdcall *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId,
+typedef HRESULT (STDAPICALLTYPE *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId,
IUnknown * pDataTarget,
HMODULE hDacDll,
CLR_DEBUGGING_VERSION * pMaxDebuggerSupportedVersion,
@@ -46,7 +46,7 @@ typedef HRESULT (__stdcall *OpenVirtualProcessImplFnPtr)(ULONG64 clrInstanceId,
IUnknown ** ppInstance,
CLR_DEBUGGING_PROCESS_FLAGS * pdwFlags);
-typedef HRESULT (__stdcall *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId,
+typedef HRESULT (STDAPICALLTYPE *OpenVirtualProcess2FnPtr)(ULONG64 clrInstanceId,
IUnknown * pDataTarget,
HMODULE hDacDll,
REFIID riid,
diff --git a/src/dlls/mscordbi/mscordbi.cpp b/src/dlls/mscordbi/mscordbi.cpp
index 4ef92c7ee8..0197d13d06 100644
--- a/src/dlls/mscordbi/mscordbi.cpp
+++ b/src/dlls/mscordbi/mscordbi.cpp
@@ -11,7 +11,7 @@
//*****************************************************************************
#include "stdafx.h"
-extern BOOL STDMETHODCALLTYPE DbgDllMain(HINSTANCE hInstance, DWORD dwReason,
+extern BOOL WINAPI DbgDllMain(HINSTANCE hInstance, DWORD dwReason,
LPVOID lpReserved);
//*****************************************************************************
diff --git a/src/dlls/mscoree/mscoree.cpp b/src/dlls/mscoree/mscoree.cpp
index f3e22da46b..36b22f2a57 100644
--- a/src/dlls/mscoree/mscoree.cpp
+++ b/src/dlls/mscoree/mscoree.cpp
@@ -518,60 +518,6 @@ STDAPI LoadStringRCEx(
#endif // CROSSGEN_COMPILE
-
-
-// Note that there are currently two callers of this function: code:CCompRC.LoadLibrary
-// and code:CorLaunchApplication.
-STDAPI GetRequestedRuntimeInfoInternal(LPCWSTR pExe,
- LPCWSTR pwszVersion,
- LPCWSTR pConfigurationFile,
- DWORD startupFlags,
- DWORD runtimeInfoFlags,
- __out_ecount_opt(dwDirectory) LPWSTR pDirectory,
- DWORD dwDirectory,
- __out_opt DWORD *pdwDirectoryLength,
- __out_ecount_opt(cchBuffer) LPWSTR pVersion,
- DWORD cchBuffer,
- __out_opt DWORD* pdwLength)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- ENTRY_POINT;
- PRECONDITION( pVersion != NULL && cchBuffer > 0);
- } CONTRACTL_END;
-
- // for simplicity we will cheat and return the entire system directory in pDirectory
- pVersion[0] = 0;
- if (pdwLength != NULL)
- *pdwLength = 0;
- HRESULT hr;
-
- BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(SetLastError(COR_E_STACKOVERFLOW); return COR_E_STACKOVERFLOW;)
- EX_TRY
- {
-
- PathString pDirectoryPath;
-
- hr = GetCORSystemDirectoryInternaL(pDirectoryPath);
- *pdwLength = pDirectoryPath.GetCount() + 1;
- if (dwDirectory >= *pdwLength)
- {
- wcscpy_s(pDirectory, pDirectoryPath.GetCount() + 1, pDirectoryPath);
- }
- else
- {
- hr = E_FAIL;
- }
-
- }
- EX_CATCH_HRESULT(hr);
- END_SO_INTOLERANT_CODE
-
- return hr;
-}
-
// Replacement for legacy shim API GetCORRequiredVersion(...) used in linked libraries.
// Used in code:TiggerStorage::GetDefaultVersion#CallTo_CLRRuntimeHostInternal_GetImageVersionString.
HRESULT
diff --git a/src/dlls/mscorrc/mscorrc.rc b/src/dlls/mscorrc/mscorrc.rc
index 8be5abc2c1..bbf5a296c0 100644
--- a/src/dlls/mscorrc/mscorrc.rc
+++ b/src/dlls/mscorrc/mscorrc.rc
@@ -1156,10 +1156,6 @@ BEGIN
IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD "The interop method '%1' cannot access the stub method '%2' specified in ManagedToNativeComInteropStubAttribute. Please make sure they have compatible access modifiers and security accessibility."
#endif // FEATURE_COMINTEROP
-#ifdef FEATURE_WINDOWSPHONE
- IDS_EE_INTEROP_DLL_IMPORT_ON_USER_METHOD "DllImport cannot be used by application code. Use the Windows Runtime to call native code."
-#endif
-
#ifdef FEATURE_COMINTEROP
IDS_EE_STRUCTLAYOUT_WINRT "Windows Runtime value types must have sequential layout."
IDS_EE_PRESERVESIG_WINRT "The PreserveSigAttribute may not be used on Windows Runtime methods."
@@ -1177,8 +1173,6 @@ BEGIN
IDS_EE_CANNOTCAST_NOMARSHAL "The Windows Runtime Object can only be used in the threading context where it was created, because it implements INoMarshal or has MarshalingBehaviorAttribute(MarshalingType.None) set."
IDS_EE_WINRT_WEAKREF_BAD_TYPE "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'"
#endif // FEATURE_COMINTEROP
-
- IDS_EE_INTEROP_CODE_SIZE_COMMENT "Code size"
IDS_EE_ADUNLOAD_IN_FINALIZER "AppDomain cannot be unloaded during object finalization."
IDS_EE_ADUNLOAD_DEFAULT "The default domain cannot be unloaded."
@@ -1277,14 +1271,10 @@ BEGIN
IDS_CLASSLOAD_EQUIVALENTSTRUCTFIELDS "Could not load the structure '%1' from assembly '%2'. The structure is marked as eligible for type equivalence, but it has a static or non-public field."
IDS_CLASSLOAD_EQUIVALENTBADTYPE "Could not load type '%1' from assembly '%2'. The type is marked as eligible for type equivalence, but either it has generic parameters, or it is not a structure, COM imported interface, enumeration, or delegate."
IDS_CLASSLOAD_EQUIVALENTNOTTRUSTED "Could not load type '%1' from assembly '%2'. The type is marked as eligible for type equivalence, but the containing assembly is not loaded as fully trusted."
- IDS_CLASSLOAD_EQUIVALENTTRANSPARENCY "Could not load type '%1' from assembly '%2'. The type is marked as eligible for type equivalence, but either it is not marked as safe-critical or transparent, or it has a field or method that is not marked as safe-critical or transparent."
IDS_CLASSLOAD_EQUIVALENTNOTPUBLIC "Could not load type '%1' from assembly '%2'. The type is marked as eligible for type equivalence, but it is not marked as public."
IDS_EE_CODEEXECUTION_CONTAINSGENERICVAR "Could not execute the method because either the method itself or the containing type is not fully instantiated."
IDS_CLASSLOAD_WRONGCPU "Could not load file or assembly '%1'. This assembly was compiled for a different processor."
-
- IDS_SECURITY_DEMAND_DENIED "Request for permission of type '%1' failed."
-
IDS_CANNOT_MARSHAL "Type '%1' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed."
IDS_PINVOKE_STRINGBUILDEROVERFLOW "Warning: A StringBuilder buffer has been overflowed by unmanaged code. The process may become unstable. Insufficient capacity allocated to the StringBuilder before marshaling it."
@@ -1538,44 +1528,15 @@ BEGIN
IDS_UNMARSHALABLE_DEMAND_OBJECT "The security object (Permission or PermissionSet) used for performing a Demand caused an error relating to serialization/deserialization."
IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED "Invalid managed/unmanaged type combination (Marshaling to and from COM VARIANTs isn't supported)."
IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED "Invalid managed/unmanaged type combination (Marshaling to and from COM interface pointers isn't supported)."
- IDS_TYPE_INHERITANCE_RULES_VIOLATED "Inheritance security rules violated by type: '%1'. Derived types must either match the security accessibility of the base type or be less accessible. If the base class has a non-transparent default constructor, the derived class must also have a default constructor, and the method inheritance rules apply across those two methods."
- IDS_METHOD_INHERITANCE_RULES_VIOLATED "Inheritance security rules violated while overriding member: '%1'. Security accessibility of the overriding method must match the security accessibility of the method being overriden."
- IDS_CRITICAL_METHOD_ACCESS_DENIED "Attempt to access method %1 in violation of security transparency rules failed."
- IDS_CRITICAL_TYPE_ACCESS_DENIED "Attempt to access type %1 in violation of security transparency rules failed."
- IDS_APPLICATION_ASSEMBLY_EXEC_DENIED "Application assemblies cannot be directly executed: %1"
- IDS_REFLECTION_METHOD_ACCESS_DENIED "Application code cannot access %1 using Reflection."
-
- IDS_E_LOAD_CRITICAL_IN_PARTIAL_TRUST "Assembly '%1' is partially trusted, however it is not entirely security transparent. If this assembly is meant to be used in partial trust, you will need to apply the SecurityTransparentAttribute to it."
- IDS_E_TRANSPARENT_CALL_LINKDEMAND "Attempt by security transparent method '%1' to access LinkDemand protected method '%2' failed. Methods must be security critical or security safe-critical to satisfy a LinkDemand."
- IDS_E_TRANSPARENT_CALL_NATIVE "Attempt by security transparent method '%1' to call native code through method '%2' failed. Methods must be security critical or security safe-critical to call native code."
- IDS_E_TRANSPARENT_REFLECTION "Security transparent method %1 cannot access %2 using reflection."
- IDS_E_TRANSPARENT_METHOD_CRITICAL_TYPE "Method '%1' is security transparent, but is a member of a security critical type."
- IDS_E_UNKNOWN_SECURITY_RULESET "Assembly '%1' specified an unknown security rule set."
- IDS_E_UNTRUSTED_APPDOMAIN_MANAGER "Partial trust applications may not specify an AppDomainManager for the default domain."
IDS_E_FIELDACCESS "Attempt by method '%1' to access field '%2' failed.%3"
IDS_E_METHODACCESS "Attempt by method '%1' to access method '%2' failed.%3"
IDS_E_TYPEACCESS "Attempt by method '%1' to access type '%2' failed.%3"
- IDS_E_CRITICAL_FIELD_ACCESS_DENIED "Attempt by security transparent method '%1' to access security critical field '%2' failed.%3"
- IDS_E_CRITICAL_METHOD_ACCESS_DENIED "Attempt by security transparent method '%1' to access security critical method '%2' failed.%3"
- IDS_E_CRITICAL_TYPE_ACCESS_DENIED "Attempt by security transparent method '%1' to access security critical type '%2' failed.%3"
- IDS_E_DELEGATE_BINDING_TRANSPARENCY "A delegate of type '%1' cannot be bound to the method '%2' due to security transparency rules. Ensure the delegate type and the method being bound have compatible security transparency."
- IDS_E_DELEGATE_FULLTRUST_ARPIC_1 "Delegate '%1' must be bound to a method in a fully-trusted assembly and the method must have the AllowReversePinvokeCallsAttribute."
- IDS_E_DELEGATE_FULLTRUST_ARPIC_2 "Cannot create a Delegate for marshalling out unless it is bound to a method in a fully-trusted assembly and the method has the AllowReversePinvokeCallsAttribute."
- IDS_E_ACCESSING_PRIVATE_FRAMEWORK_CODE "Reflection invocation to internal or private types or members in the framework is not allowed."
IDS_EE_TORNSTATE "Unexpected change made to file '%1'."
END
-// These strings are attached to various access exceptions to provide additional context as to what may have
-// caused them, and how they might be fixed.
-STRINGTABLE DISCARDABLE
-BEGIN
- IDS_ACCESS_EXCEPTION_CONTEXT_LEVEL2_APTCA "Assembly '%1' is marked with the AllowPartiallyTrustedCallersAttribute, and uses the level 2 security transparency model. Level 2 transparency causes all methods in AllowPartiallyTrustedCallers assemblies to become security transparent by default, which may be the cause of this exception."
- IDS_ACCESS_EXCEPTION_CONTEXT_PT_TRANSPARENT "Assembly '%1' is partially trusted, which causes the CLR to make it entirely security transparent regardless of any transparency annotations in the assembly itself. In order to access security critical code, this assembly must be fully trusted."
-END
-
// These strings are generated from within the EE for streams
STRINGTABLE DISCARDABLE
BEGIN
diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h
index 54b40efa9c..053b1b4e17 100644
--- a/src/dlls/mscorrc/resource.h
+++ b/src/dlls/mscorrc/resource.h
@@ -217,7 +217,6 @@
#define IDS_STREAMS_FILE_NAME 0x176d
#define IDS_STREAMS_SEEK_MODIFIER 0x176e
-#define IDS_SECURITY_DEMAND_DENIED 0x176f
#define IDS_CANNOT_MARSHAL 0x1770
#define IDS_PINVOKE_STRINGBUILDEROVERFLOW 0x1771
@@ -598,7 +597,6 @@
#define IDS_CLASSLOAD_COLLECTIBLEFIXEDVTATTR 0x1ab6
#define IDS_CLASSLOAD_EQUIVALENTBADTYPE 0x1ab7
#define IDS_CLASSLOAD_EQUIVALENTNOTTRUSTED 0x1ab8
-#define IDS_CLASSLOAD_EQUIVALENTTRANSPARENCY 0x1ab9
#define IDS_CLASSLOAD_EQUIVALENTNOTPUBLIC 0x1aba
#define IDS_EE_CODEEXECUTION_CONTAINSGENERICVAR 0x1abb
#define IDS_CLASSLOAD_WRONGCPU 0x1abc
@@ -771,14 +769,6 @@
#define IDS_EE_OBJECT_TO_VARIANT_NOT_SUPPORTED 0x2090
#define IDS_EE_OBJECT_TO_ITF_NOT_SUPPORTED 0x2091
-#define IDS_INHERITIANCE_RULES_VIOLATED 0x2092
-#define IDS_CRITICAL_METHOD_ACCESS_DENIED 0x2093
-#define IDS_CRITICAL_TYPE_ACCESS_DENIED 0x2094
-#define IDS_APPLICATION_ASSEMBLY_EXEC_DENIED 0x2095
-#define IDS_REFLECTION_METHOD_ACCESS_DENIED 0x2096
-#define IDS_METHOD_INHERITANCE_RULES_VIOLATED 0x2097
-#define IDS_TYPE_INHERITANCE_RULES_VIOLATED 0x2098
-
#define IDS_EE_BADMARSHALFIELD_DECIMAL 0x2099
#define IDS_EE_CANNOTCASTSAME 0x209a
@@ -787,13 +777,6 @@
#define IDS_CLASSLOAD_COLLECTIBLE_CONTEXT_BOUND_OBJECT 0x209d
-#define IDS_E_LOAD_CRITICAL_IN_PARTIAL_TRUST 0x2100
-#define IDS_E_TRANSPARENT_CALL_LINKDEMAND 0x2101
-#define IDS_E_TRANSPARENT_METHOD_CRITICAL_TYPE 0x2102
-#define IDS_E_UNKNOWN_SECURITY_RULESET 0x2103
-#define IDS_E_UNTRUSTED_APPDOMAIN_MANAGER 0x2104
-#define IDS_E_LOADFROM_REMOTE_SOURCE 0x2106
-
// For ForwardInteropStubAttribute
#ifdef FEATURE_COMINTEROP
#define IDS_EE_INTEROP_STUB_CA_MUST_BE_WITHIN_SAME_ASSEMBLY 0x2107
@@ -803,33 +786,11 @@
#define IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD 0x2111
#endif
-#define IDS_EE_INTEROP_CODE_SIZE_COMMENT 0x2112
-
#define BFA_REFERENCE_ASSEMBLY 0x2113
#define IDS_E_FIELDACCESS 0x2114
#define IDS_E_METHODACCESS 0x2115
#define IDS_E_TYPEACCESS 0x2116
-#define IDS_E_CRITICAL_FIELD_ACCESS_DENIED 0x2117
-#define IDS_E_CRITICAL_METHOD_ACCESS_DENIED 0x2118
-#define IDS_E_CRITICAL_TYPE_ACCESS_DENIED 0x2119
-
-#define IDS_E_TRANSPARENT_CALL_NATIVE 0x2120
-#define IDS_E_TRANSPARENT_REFLECTION 0x2121
-
-#define IDS_E_DELEGATE_BINDING_TRANSPARENCY 0x2122
-
-#define IDS_E_ACCESSING_PRIVATE_FRAMEWORK_CODE 0x2123
-
-#define IDS_E_DELEGATE_FULLTRUST_ARPIC_1 0x2124
-#define IDS_E_DELEGATE_FULLTRUST_ARPIC_2 0x2125
-
-#define IDS_ACCESS_EXCEPTION_CONTEXT_LEVEL2_APTCA 0x2200
-#define IDS_ACCESS_EXCEPTION_CONTEXT_APTCA_KILLBIT 0x2201
-#define IDS_ACCESS_EXCEPTION_CONTEXT_CONDITIONAL_APTCA 0x2202
-#define IDS_ACCESS_EXCEPTION_CONTEXT_PT_TRANSPARENT 0x2203
-
-#define IDS_E_LOADFROM_REMOTE_SOURCE_MOTW 0x2204
// Profiler error messages for event log
#define IDS_E_PROF_NO_CLSID 0x2500
@@ -910,10 +871,6 @@
#define IDS_EE_TORNSTATE 0x2613
-#ifdef FEATURE_WINDOWSPHONE
-#define IDS_EE_INTEROP_DLL_IMPORT_ON_USER_METHOD 0x262b
-#endif
-
#ifdef FEATURE_COMINTEROP
#define IDS_EE_WINRT_WEAKREF_BAD_TYPE 0x262e
diff --git a/src/gc/CMakeLists.txt b/src/gc/CMakeLists.txt
index 21eb66070a..3240074b9b 100644
--- a/src/gc/CMakeLists.txt
+++ b/src/gc/CMakeLists.txt
@@ -1,5 +1,22 @@
set(CMAKE_INCLUDE_CURRENT_DIR ON)
+# Local GC meta-issue: https://github.com/dotnet/coreclr/issues/11518
+
+# https://github.com/dotnet/coreclr/issues/11514
+remove_definitions(-DFEATURE_EVENT_TRACE=1)
+
+# https://github.com/dotnet/coreclr/issues/11517
+remove_definitions(-DFEATURE_APPDOMAIN_RESOURCE_MONITORING)
+
+# https://github.com/dotnet/coreclr/issues/11516
+remove_definitions(-DSTRESS_HEAP)
+
+# https://github.com/dotnet/coreclr/issues/11519
+remove_definitions(-DWRITE_BARRIER_CHECK)
+
+# https://github.com/dotnet/coreclr/issues/14701
+add_definitions(-DFEATURE_REDHAWK)
+
set( GC_SOURCES
gcconfig.cpp
gccommon.cpp
@@ -14,6 +31,7 @@ set( GC_SOURCES
gchandletable.cpp
gceesvr.cpp
gceewks.cpp
+ gcload.cpp
handletablecache.cpp)
if(CLR_CMAKE_PLATFORM_UNIX)
@@ -40,13 +58,13 @@ endif(WIN32)
convert_to_absolute_path(GC_SOURCES ${GC_SOURCES})
-add_library_clr(gc SHARED ${GC_SOURCES})
-target_link_libraries(gc ${GC_LINK_LIBRARIES})
-install_clr(gc)
+add_library_clr(clrgc SHARED ${GC_SOURCES})
+target_link_libraries(clrgc ${GC_LINK_LIBRARIES})
+install_clr(clrgc)
if(CLR_CMAKE_PLATFORM_UNIX)
add_compile_options(-fPIC)
- # dprintf causes many warnings
+ # dprintf causes many warnings (https://github.com/dotnet/coreclr/issues/13367)
add_compile_options(-Wno-format)
endif(CLR_CMAKE_PLATFORM_UNIX)
diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h
index fb2f9da488..734b46fd3d 100644
--- a/src/gc/env/gcenv.base.h
+++ b/src/gc/env/gcenv.base.h
@@ -11,8 +11,6 @@
#include <intrin.h>
#endif // _MSC_VER
-#define FEATURE_REDHAWK 1
-
#define REDHAWK_PALIMPORT extern "C"
#define REDHAWK_PALAPI __stdcall
@@ -208,6 +206,16 @@ typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter);
#endif // defined(__i386__) || defined(__x86_64__)
+#ifdef __aarch64__
+ #define YieldProcessor() asm volatile ("yield")
+ #define MemoryBarrier __sync_synchronize
+#endif // __aarch64__
+
+#ifdef __arm__
+ #define YieldProcessor()
+ #define MemoryBarrier __sync_synchronize
+#endif // __arm__
+
#endif // _MSC_VER
#ifdef _MSC_VER
@@ -420,12 +428,6 @@ typedef PTR_PTR_Object PTR_UNCHECKED_OBJECTREF;
class Thread;
-inline bool IsGCSpecialThread()
-{
- // [LOCALGC TODO] this is not correct
- return false;
-}
-
inline bool dbgOnly_IsSpecialEEThread()
{
return false;
@@ -454,12 +456,6 @@ namespace ETW
} GC_ROOT_KIND;
};
-inline bool IsGCThread()
-{
- // [LOCALGC TODO] this is not correct
- return false;
-}
-
inline bool FitsInU1(uint64_t val)
{
return val == (uint64_t)(uint8_t)val;
diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h
index e7103b15a5..3d2f659a75 100644
--- a/src/gc/env/gcenv.ee.h
+++ b/src/gc/env/gcenv.ee.h
@@ -80,6 +80,8 @@ public:
static bool GetIntConfigValue(const char* key, int64_t* value);
static bool GetStringConfigValue(const char* key, const char** value);
static void FreeStringConfigValue(const char* key);
+ static bool IsGCThread();
+ static bool IsGCSpecialThread();
};
#endif // __GCENV_EE_H__
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index cb5e7d098e..042f2f4929 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -1740,7 +1740,7 @@ static BOOL try_enter_spin_lock(GCSpinLock *pSpinLock)
inline
static void leave_spin_lock(GCSpinLock *pSpinLock)
{
- BOOL gc_thread_p = IsGCSpecialThread();
+ bool gc_thread_p = GCToEEInterface::IsGCSpecialThread();
// _ASSERTE((pSpinLock->holding_thread == GCToEEInterface::GetThread()) || gc_thread_p || pSpinLock->released_by_gc_p);
pSpinLock->released_by_gc_p = gc_thread_p;
pSpinLock->holding_thread = (Thread*) -1;
@@ -2327,7 +2327,7 @@ void stomp_write_barrier_ephemeral(uint8_t* ephemeral_low, uint8_t* ephemeral_hi
GCToEEInterface::StompWriteBarrier(&args);
}
-void stomp_write_barrier_initialize()
+void stomp_write_barrier_initialize(uint8_t* ephemeral_low, uint8_t* ephemeral_high)
{
WriteBarrierParameters args = {};
args.operation = WriteBarrierOp::Initialize;
@@ -2341,8 +2341,8 @@ void stomp_write_barrier_initialize()
args.lowest_address = g_gc_lowest_address;
args.highest_address = g_gc_highest_address;
- args.ephemeral_low = reinterpret_cast<uint8_t*>(1);
- args.ephemeral_high = reinterpret_cast<uint8_t*>(~0);
+ args.ephemeral_low = ephemeral_low;
+ args.ephemeral_high = ephemeral_high;
GCToEEInterface::StompWriteBarrier(&args);
}
@@ -5401,9 +5401,11 @@ void gc_heap::gc_thread_function ()
proceed_with_gc_p = FALSE;
}
else
+ {
settings.init_mechanisms();
+ gc_start_event.Set();
+ }
dprintf (3, ("%d gc thread waiting...", heap_number));
- gc_start_event.Set();
}
else
{
@@ -5411,6 +5413,8 @@ void gc_heap::gc_thread_function ()
dprintf (3, ("%d gc thread waiting... Done", heap_number));
}
+ assert ((heap_number == 0) || proceed_with_gc_p);
+
if (proceed_with_gc_p)
garbage_collect (GCHeap::GcCondemnedGeneration);
@@ -5447,7 +5451,18 @@ void gc_heap::gc_thread_function ()
gc_heap::internal_gc_done = true;
- set_gc_done();
+ if (proceed_with_gc_p)
+ set_gc_done();
+ else
+ {
+ // If we didn't actually do a GC, it means we didn't wait up the other threads,
+ // we still need to set the gc_done_event for those threads.
+ for (int i = 0; i < gc_heap::n_heaps; i++)
+ {
+ gc_heap* hp = gc_heap::g_heaps[i];
+ hp->set_gc_done();
+ }
+ }
}
else
{
@@ -7450,7 +7465,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
// Either this thread was the thread that did the suspension which means we are suspended; or this is called
// from a GC thread which means we are in a blocking GC and also suspended.
- BOOL is_runtime_suspended = IsGCThread();
+ bool is_runtime_suspended = GCToEEInterface::IsGCThread();
if (!is_runtime_suspended)
{
// Note on points where the runtime is suspended anywhere in this function. Upon an attempt to suspend the
@@ -7513,7 +7528,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start,
// to be changed, so we are doing this after all global state has
// been updated. See the comment above suspend_EE() above for more
// info.
- stomp_write_barrier_resize(!!IsGCThread(), la != saved_g_lowest_address);
+ stomp_write_barrier_resize(GCToEEInterface::IsGCThread(), la != saved_g_lowest_address);
}
@@ -10602,7 +10617,18 @@ gc_heap::init_gc_heap (int h_number)
make_background_mark_stack (b_arr);
#endif //BACKGROUND_GC
- adjust_ephemeral_limits();
+ ephemeral_low = generation_allocation_start(generation_of(max_generation - 1));
+ ephemeral_high = heap_segment_reserved(ephemeral_heap_segment);
+ if (heap_number == 0)
+ {
+ stomp_write_barrier_initialize(
+#ifdef MULTIPLE_HEAPS
+ reinterpret_cast<uint8_t*>(1), reinterpret_cast<uint8_t*>(~0)
+#else
+ ephemeral_low, ephemeral_high
+#endif //!MULTIPLE_HEAPS
+ );
+ }
#ifdef MARK_ARRAY
// why would we clear the mark array for this page? it should be cleared..
@@ -13226,7 +13252,7 @@ int gc_heap::try_allocate_more_space (alloc_context* acontext, size_t size,
// Unfortunately some of the ETW macros do not check whether the ETW feature is enabled.
// The ones that do are much less efficient.
#if defined(FEATURE_EVENT_TRACE)
- if (EventEnabledGCAllocationTick_V2())
+ if (EventEnabledGCAllocationTick_V3())
{
fire_etw_allocation_event (etw_allocation_running_amount[etw_allocation_index], gen_number, acontext->alloc_ptr);
}
@@ -15508,8 +15534,8 @@ void gc_heap::gc1()
#endif //BACKGROUND_GC
{
#ifndef FEATURE_REDHAWK
- // IsGCThread() always returns false on CoreRT, but this assert is useful in CoreCLR.
- assert(!!IsGCThread());
+ // GCToEEInterface::IsGCThread() always returns false on CoreRT, but this assert is useful in CoreCLR.
+ assert(GCToEEInterface::IsGCThread());
#endif // FEATURE_REDHAWK
adjust_ephemeral_limits();
}
@@ -33575,8 +33601,6 @@ HRESULT GCHeap::Initialize ()
return E_FAIL;
}
- stomp_write_barrier_initialize();
-
#ifndef FEATURE_REDHAWK // Redhawk forces relocation a different way
#if defined (STRESS_HEAP) && !defined (MULTIPLE_HEAPS)
if (GCStress<cfg_any>::IsEnabled()) {
@@ -34004,7 +34028,7 @@ bool GCHeap::StressHeap(gc_alloc_context * context)
#ifdef BACKGROUND_GC
// don't trigger a GC from the GC threads but still trigger GCs from user threads.
- if (IsGCSpecialThread())
+ if (GCToEEInterface::IsGCSpecialThread())
{
return FALSE;
}
diff --git a/src/gc/gccommon.cpp b/src/gc/gccommon.cpp
index 92c0e7b7b5..54873ffa4a 100644
--- a/src/gc/gccommon.cpp
+++ b/src/gc/gccommon.cpp
@@ -114,107 +114,4 @@ void record_changed_seg (uint8_t* start, uint8_t* end,
}
}
-namespace WKS
-{
- extern void PopulateDacVars(GcDacVars* dacVars);
-}
-
-namespace SVR
-{
- extern void PopulateDacVars(GcDacVars* dacVars);
-}
-
-extern void PopulateHandleTableDacVars(GcDacVars* dacVars);
-
-//------------------------------------------------------------------
-// Externally-facing GC symbols, used to initialize the GC
-// -----------------------------------------------------------------
-
-#ifdef _MSC_VER
-#define DLLEXPORT __declspec(dllexport)
-#else
-#define DLLEXPORT __attribute__ ((visibility ("default")))
-#endif // _MSC_VER
-
-#ifdef BUILD_AS_STANDALONE
-#define GC_API extern "C" DLLEXPORT
-#else
-#define GC_API extern "C"
-#endif // BUILD_AS_STANDALONE
-
-GC_API
-bool
-InitializeGarbageCollector(
- /* In */ IGCToCLR* clrToGC,
- /* Out */ IGCHeap** gcHeap,
- /* Out */ IGCHandleManager** gcHandleManager,
- /* Out */ GcDacVars* gcDacVars
- )
-{
- LIMITED_METHOD_CONTRACT;
-
- IGCHeapInternal* heap;
-
- assert(gcDacVars != nullptr);
- assert(gcHeap != nullptr);
- assert(gcHandleManager != nullptr);
-
-#ifdef BUILD_AS_STANDALONE
- assert(clrToGC != nullptr);
- g_theGCToCLR = clrToGC;
-#else
- UNREFERENCED_PARAMETER(clrToGC);
- assert(clrToGC == nullptr);
-#endif
-
- // Initialize GCConfig before anything else - initialization of our
- // various components may want to query the current configuration.
- GCConfig::Initialize();
- if (!GCToOSInterface::Initialize())
- {
- return false;
- }
-
- IGCHandleManager* handleManager = CreateGCHandleManager();
- if (handleManager == nullptr)
- {
- return false;
- }
-
-#ifdef FEATURE_SVR_GC
- if (GCConfig::GetServerGC())
- {
-#ifdef WRITE_BARRIER_CHECK
- g_GCShadow = 0;
- g_GCShadowEnd = 0;
-#endif // WRITE_BARRIER_CHECK
-
- g_gc_heap_type = GC_HEAP_SVR;
- heap = SVR::CreateGCHeap();
- SVR::PopulateDacVars(gcDacVars);
- }
- else
- {
- g_gc_heap_type = GC_HEAP_WKS;
- heap = WKS::CreateGCHeap();
- WKS::PopulateDacVars(gcDacVars);
- }
-#else
- g_gc_heap_type = GC_HEAP_WKS;
- heap = WKS::CreateGCHeap();
- WKS::PopulateDacVars(gcDacVars);
-#endif
-
- PopulateHandleTableDacVars(gcDacVars);
- if (heap == nullptr)
- {
- return false;
- }
-
- g_theGCHeap = heap;
- *gcHandleManager = handleManager;
- *gcHeap = heap;
- return true;
-}
-
#endif // !DACCESS_COMPILE
diff --git a/src/gc/gcenv.ee.standalone.inl b/src/gc/gcenv.ee.standalone.inl
index 0dcf05da4d..0b6a1cfb11 100644
--- a/src/gc/gcenv.ee.standalone.inl
+++ b/src/gc/gcenv.ee.standalone.inl
@@ -246,4 +246,16 @@ inline void GCToEEInterface::FreeStringConfigValue(const char* value)
g_theGCToCLR->FreeStringConfigValue(value);
}
+inline bool GCToEEInterface::IsGCThread()
+{
+ assert(g_theGCToCLR != nullptr);
+ return g_theGCToCLR->IsGCThread();
+}
+
+inline bool GCToEEInterface::IsGCSpecialThread()
+{
+ assert(g_theGCToCLR != nullptr);
+ return g_theGCToCLR->IsGCSpecialThread();
+}
+
#endif // __GCTOENV_EE_STANDALONE_INL__
diff --git a/src/gc/gcinterface.ee.h b/src/gc/gcinterface.ee.h
index 1e08043b02..d65da60678 100644
--- a/src/gc/gcinterface.ee.h
+++ b/src/gc/gcinterface.ee.h
@@ -191,6 +191,17 @@ public:
virtual
void FreeStringConfigValue(const char* value) = 0;
+
+ // Asks the EE about whether or not the current thread is a GC thread:
+ // a server GC thread, background GC thread, or the thread that suspended
+ // the EE at the start of a GC.
+ virtual
+ bool IsGCThread() = 0;
+
+ // Asks the EE about whether or not the current thread is a GC "special"
+ // thread: a server GC thread or a background GC thread.
+ virtual
+ bool IsGCSpecialThread() = 0;
};
#endif // _GCINTERFACE_EE_H_
diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h
index 5bec7212e8..b1d6b8090c 100644
--- a/src/gc/gcinterface.h
+++ b/src/gc/gcinterface.h
@@ -5,6 +5,15 @@
#ifndef _GC_INTERFACE_H_
#define _GC_INTERFACE_H_
+// The major version of the GC/EE interface. Breaking changes to this interface
+// require bumps in the major version number.
+#define GC_INTERFACE_MAJOR_VERSION 1
+
+// The minor version of the GC/EE interface. Non-breaking changes are required
+// to bump the minor version number. GCs and EEs with minor version number
+// mismatches can still interopate correctly, with some care.
+#define GC_INTERFACE_MINOR_VERSION 1
+
struct ScanContext;
struct gc_alloc_context;
class CrawlFrame;
@@ -174,20 +183,6 @@ class Object;
class IGCHeap;
class IGCHandleManager;
-// The function that initialzes the garbage collector.
-// Should only be called once: here, during EE startup.
-// Returns true if the initialization was successful, false otherwise.
-typedef bool (*InitializeGarbageCollectorFunction)(
- /* In */ IGCToCLR*,
- /* Out */ IGCHeap**,
- /* Out */ IGCHandleManager**,
- /* Out */ GcDacVars*
-);
-
-// The name of the function that initializes the garbage collector,
-// to be used as an argument to GetProcAddress.
-#define INITIALIZE_GC_FUNCTION_NAME "InitializeGarbageCollector"
-
#ifdef WRITE_BARRIER_CHECK
//always defined, but should be 0 in Server GC
extern uint8_t* g_GCShadow;
@@ -842,15 +837,19 @@ struct ScanContext
bool concurrent; //TRUE: concurrent scanning
#if CHECK_APP_DOMAIN_LEAKS || defined (FEATURE_APPDOMAIN_RESOURCE_MONITORING) || defined (DACCESS_COMPILE)
AppDomain *pCurrentDomain;
+#else
+ void* _unused1;
#endif //CHECK_APP_DOMAIN_LEAKS || FEATURE_APPDOMAIN_RESOURCE_MONITORING || DACCESS_COMPILE
-#ifndef FEATURE_REDHAWK
#if defined(GC_PROFILING) || defined (DACCESS_COMPILE)
MethodDesc *pMD;
+#else
+ void* _unused2;
#endif //GC_PROFILING || DACCESS_COMPILE
-#endif // FEATURE_REDHAWK
#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
EtwGCRootKind dwEtwRootKind;
+#else
+ int _unused3;
#endif // GC_PROFILING || FEATURE_EVENT_TRACE
ScanContext()
@@ -871,4 +870,24 @@ struct ScanContext
}
};
+// These types are used as part of the loader protocol between the EE
+// and the GC.
+struct VersionInfo {
+ uint32_t MajorVersion;
+ uint32_t MinorVersion;
+ uint32_t BuildVersion;
+ const char* Name;
+};
+
+typedef void (*GC_VersionInfoFunction)(
+ /* Out */ VersionInfo*
+);
+
+typedef HRESULT (*GC_InitializeFunction)(
+ /* In */ IGCToCLR*,
+ /* Out */ IGCHeap**,
+ /* Out */ IGCHandleManager**,
+ /* Out */ GcDacVars*
+);
+
#endif // _GC_INTERFACE_H_
diff --git a/src/gc/gcload.cpp b/src/gc/gcload.cpp
new file mode 100644
index 0000000000..21eedb250f
--- /dev/null
+++ b/src/gc/gcload.cpp
@@ -0,0 +1,120 @@
+// 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.
+
+/*
+ * gcload.cpp
+ *
+ * Code for loading and initializing the GC. The code in this file
+ * is used in the startup path of both a standalone and non-standalone GC.
+ */
+
+#include "common.h"
+#include "gcenv.h"
+#include "gc.h"
+
+#ifdef _MSC_VER
+#define DLLEXPORT __declspec(dllexport)
+#else
+#define DLLEXPORT __attribute__ ((visibility ("default")))
+#endif // _MSC_VER
+
+#define GC_EXPORT extern "C" DLLEXPORT
+
+// These symbols are defined in gc.cpp and populate the GcDacVars
+// structure with the addresses of DAC variables within the GC.
+namespace WKS
+{
+ extern void PopulateDacVars(GcDacVars* dacVars);
+}
+
+namespace SVR
+{
+ extern void PopulateDacVars(GcDacVars* dacVars);
+}
+
+// This symbol populates GcDacVars with handle table dacvars.
+extern void PopulateHandleTableDacVars(GcDacVars* dacVars);
+
+GC_EXPORT
+void
+GC_VersionInfo(/* Out */ VersionInfo* info)
+{
+ info->MajorVersion = GC_INTERFACE_MAJOR_VERSION;
+ info->MinorVersion = GC_INTERFACE_MINOR_VERSION;
+ info->BuildVersion = 0;
+ info->Name = "CoreCLR GC";
+}
+
+GC_EXPORT
+HRESULT
+GC_Initialize(
+ /* In */ IGCToCLR* clrToGC,
+ /* Out */ IGCHeap** gcHeap,
+ /* Out */ IGCHandleManager** gcHandleManager,
+ /* Out */ GcDacVars* gcDacVars
+)
+{
+ IGCHeapInternal* heap;
+
+ assert(gcDacVars != nullptr);
+ assert(gcHeap != nullptr);
+ assert(gcHandleManager != nullptr);
+
+#ifdef BUILD_AS_STANDALONE
+ assert(clrToGC != nullptr);
+ g_theGCToCLR = clrToGC;
+#else
+ UNREFERENCED_PARAMETER(clrToGC);
+ assert(clrToGC == nullptr);
+#endif
+
+ // Initialize GCConfig before anything else - initialization of our
+ // various components may want to query the current configuration.
+ GCConfig::Initialize();
+ if (!GCToOSInterface::Initialize())
+ {
+ return E_FAIL;
+ }
+
+ IGCHandleManager* handleManager = CreateGCHandleManager();
+ if (handleManager == nullptr)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+#ifdef FEATURE_SVR_GC
+ if (GCConfig::GetServerGC())
+ {
+#ifdef WRITE_BARRIER_CHECK
+ g_GCShadow = 0;
+ g_GCShadowEnd = 0;
+#endif // WRITE_BARRIER_CHECK
+
+ g_gc_heap_type = GC_HEAP_SVR;
+ heap = SVR::CreateGCHeap();
+ SVR::PopulateDacVars(gcDacVars);
+ }
+ else
+ {
+ g_gc_heap_type = GC_HEAP_WKS;
+ heap = WKS::CreateGCHeap();
+ WKS::PopulateDacVars(gcDacVars);
+ }
+#else
+ g_gc_heap_type = GC_HEAP_WKS;
+ heap = WKS::CreateGCHeap();
+ WKS::PopulateDacVars(gcDacVars);
+#endif
+
+ PopulateHandleTableDacVars(gcDacVars);
+ if (heap == nullptr)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ g_theGCHeap = heap;
+ *gcHandleManager = handleManager;
+ *gcHeap = heap;
+ return S_OK;
+}
diff --git a/src/gc/sample/CMakeLists.txt b/src/gc/sample/CMakeLists.txt
index 42f097a6e3..6f8aa615d7 100644
--- a/src/gc/sample/CMakeLists.txt
+++ b/src/gc/sample/CMakeLists.txt
@@ -5,6 +5,8 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(..)
include_directories(../env)
+add_definitions(-DFEATURE_REDHAWK)
+
set(SOURCES
GCSample.cpp
gcenv.ee.cpp
@@ -14,6 +16,7 @@ set(SOURCES
../gchandletable.cpp
../gcscan.cpp
../gcwks.cpp
+ ../gcload.cpp
../handletable.cpp
../handletablecache.cpp
../handletablecore.cpp
diff --git a/src/gc/sample/GCSample.cpp b/src/gc/sample/GCSample.cpp
index 62eec6698f..4248d92256 100644
--- a/src/gc/sample/GCSample.cpp
+++ b/src/gc/sample/GCSample.cpp
@@ -107,7 +107,7 @@ void WriteBarrier(Object ** dst, Object * ref)
ErectWriteBarrier(dst, ref);
}
-extern "C" bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleManager** gcHandleManager, GcDacVars* gcDacVars);
+extern "C" HRESULT GC_Initialize(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleManager** gcHandleManager, GcDacVars* gcDacVars);
int __cdecl main(int argc, char* argv[])
{
@@ -133,7 +133,7 @@ int __cdecl main(int argc, char* argv[])
GcDacVars dacVars;
IGCHeap *pGCHeap;
IGCHandleManager *pGCHandleManager;
- if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGCHandleManager, &dacVars))
+ if (GC_Initialize(nullptr, &pGCHeap, &pGCHandleManager, &dacVars) != S_OK)
{
return -1;
}
diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp
index de1a2ad5ee..8fd4487192 100644
--- a/src/gc/sample/gcenv.ee.cpp
+++ b/src/gc/sample/gcenv.ee.cpp
@@ -316,6 +316,16 @@ void GCToEEInterface::FreeStringConfigValue(const char *value)
}
+bool GCToEEInterface::IsGCThread()
+{
+ return false;
+}
+
+bool GCToEEInterface::IsGCSpecialThread()
+{
+ return false;
+}
+
MethodTable* GCToEEInterface::GetFreeObjectMethodTable()
{
return g_pFreeObjectMethodTable;
diff --git a/src/ildasm/dasm.cpp b/src/ildasm/dasm.cpp
index 3d172f009e..ca64522d59 100644
--- a/src/ildasm/dasm.cpp
+++ b/src/ildasm/dasm.cpp
@@ -149,7 +149,7 @@ extern ULONG g_LocalComTypeNum;
// MetaInfo integration:
#include "../tools/metainfo/mdinfo.h"
-#include "ivehandler.h"
+
BOOL g_fDumpMetaInfo = FALSE;
ULONG g_ulMetaInfoFilter = MDInfo::dumpDefault;
// Validator module type.
@@ -6849,29 +6849,6 @@ void DumpMI(__in __nullterminated const char *str)
}
}
-HRESULT VEHandlerReporter( // Return status.
- LPCWSTR szMsg, // Error message.
- VEContext Context, // Error context (offset,token)
- HRESULT hrRpt) // HRESULT for the message
-{
- WCHAR* wzMsg;
- if(szMsg)
- {
- size_t L = wcslen(szMsg)+256;
- if((wzMsg = new (nothrow) WCHAR[L]) != NULL)
- {
- wcscpy_s(wzMsg,L,szMsg);
- // include token and offset from Context
- if(Context.Token) swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), W(" [token:0x%08X]"),Context.Token);
- if(Context.uOffset) swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), W(" [at:0x%X]"),Context.uOffset);
- swprintf_s(&wzMsg[wcslen(wzMsg)], L-wcslen(wzMsg), W(" [hr:0x%08X]\n"),hrRpt);
- DumpMI(UnicodeToUtf(wzMsg));
- delete[] wzMsg;
- }
- }
- return S_OK;
-}
-
void DumpMetaInfo(__in __nullterminated const WCHAR* pwzFileName, __in_opt __nullterminated const char* pszObjFileName, void* GUICookie)
{
const WCHAR* pch = wcsrchr(pwzFileName,L'.');
@@ -6913,7 +6890,6 @@ void DumpMetaInfo(__in __nullterminated const WCHAR* pwzFileName, __in_opt __nul
printLine(GUICookie,RstrUTF(IDS_E_MISTART));
//MDInfo metaDataInfo(g_pPubImport, g_pAssemblyImport, (LPCWSTR)pwzFileName, DumpMI, g_ulMetaInfoFilter);
MDInfo metaDataInfo(g_pDisp,(LPCWSTR)pwzFileName, DumpMI, g_ulMetaInfoFilter);
- metaDataInfo.SetVEHandlerReporter((__int64) (size_t) VEHandlerReporter);
metaDataInfo.DisplayMD();
printLine(GUICookie,RstrUTF(IDS_E_MIEND));
}
diff --git a/src/inc/CMakeLists.txt b/src/inc/CMakeLists.txt
index 4c82f157bc..c109c2f3a7 100644
--- a/src/inc/CMakeLists.txt
+++ b/src/inc/CMakeLists.txt
@@ -6,11 +6,8 @@ set( CORGUIDS_IDL_SOURCES
xclrdata.idl
corprof.idl
corpub.idl
- ivalidator.idl
- ivehandler.idl
gchost.idl
mscorsvc.idl
- tlbimpexp.idl
clrprivappxhosting.idl
clrprivbinding.idl
clrprivhosting.idl
diff --git a/src/inc/CrstTypes.def b/src/inc/CrstTypes.def
index 5bf4ec63db..5afc1ed949 100644
--- a/src/inc/CrstTypes.def
+++ b/src/inc/CrstTypes.def
@@ -752,9 +752,6 @@ End
Crst PinnedByrefValidation
End
-Crst AssemblyUsageLog
-End
-
Crst VSDIndirectionCellLock
AcquiredBefore LoaderHeap
End
@@ -783,3 +780,6 @@ End
Crst EventPipe
AcquiredBefore ThreadIdDispenser ThreadStore DomainLocalBlock InstMethodHashTable
End
+
+Crst NotifyGdb
+End
diff --git a/src/inc/MSCOREE.IDL b/src/inc/MSCOREE.IDL
index a6b60b9278..15be516e17 100644
--- a/src/inc/MSCOREE.IDL
+++ b/src/inc/MSCOREE.IDL
@@ -22,7 +22,6 @@ import "unknwn.idl";
#if defined(FEATURE_WINDOWSPHONE)
import "gchost.idl";
#endif
-import "ivalidator.idl";
#include "product_version.h"
@@ -931,11 +930,6 @@ library mscoree
{
importlib("stdole32.tlb");
-#ifdef INCLUDE_SVC_IDL
-#define IN_MSCOREE
-#include "mscorsvc.idl"
-#endif
-
//*****************************************************************************
//
//*****************************************************************************
diff --git a/src/inc/assemblyusagelog.idl b/src/inc/assemblyusagelog.idl
deleted file mode 100644
index b942d59148..0000000000
--- a/src/inc/assemblyusagelog.idl
+++ /dev/null
@@ -1,51 +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.
-//+---------------------------------------------------------------------------
-//
-// File: assemblyusageloginterface.idl
-//
-// Contents: COM interface for assembly usage log.
-//
-// Classes:
-//
-// Functions:
-//
-//
-//----------------------------------------------------------------------------
-
-cpp_quote("")
-cpp_quote("#ifdef _MSC_VER")
-cpp_quote("#pragma comment(lib,\"uuid.lib\")")
-cpp_quote("#endif")
-cpp_quote("")
-cpp_quote("//---------------------------------------------------------------------------=")
-cpp_quote("// Assembly Usage Log Interfaces")
-cpp_quote("")
-
-import "objidl.idl";
-
-cpp_quote("#ifdef _MSC_VER")
-cpp_quote("#pragma once")
-cpp_quote("#endif")
-
-cpp_quote("// {ec2b5f70-d576-4d33-876f-6e3caeb0a7ba}")
-cpp_quote("EXTERN_GUID(IID_IAssemblyUsageLog, 0xec2b5f70, 0xd576, 0x4d33, 0x87, 0x6f, 0x6e, 0x3c, 0xae, 0xb0, 0xa7, 0xba);")
-
-typedef enum
-{
- ASSEMBLY_USAGE_LOG_FLAGS_NI = 1,
- ASSEMBLY_USAGE_LOG_FLAGS_IL = 2,
-} ASSEMBLY_USAGE_LOG_FLAGS;
-
-[
- local,
- object,
- uuid(ec2b5f70-d576-4d33-876f-6e3caeb0a7ba),
- pointer_default(unique)
-]
-interface IAssemblyUsageLog : IUnknown
-{
- HRESULT LogFile(LPCWSTR pwszILFile, LPCWSTR pwszNIFile, ASSEMBLY_USAGE_LOG_FLAGS flags);
-};
-
diff --git a/src/inc/assemblyusagelogmanager.h b/src/inc/assemblyusagelogmanager.h
deleted file mode 100644
index 5fae606f56..0000000000
--- a/src/inc/assemblyusagelogmanager.h
+++ /dev/null
@@ -1,53 +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.
-//
-
-#ifndef ASSEMBLY_USAGE_LOG_MANAGER_H
-#define ASSEMBLY_USAGE_LOG_MANAGER_H
-
-#include "assemblyusagelog.h"
-#include "daccess.h"
-
-class AssemblyUsageLogManager
-{
-public:
-
- class Config
- {
- public:
- LPCWSTR wszLogDir;
- unsigned int cLogBufferSize;
-#ifdef FEATURE_APPX
- unsigned int uiLogRefreshInterval;
-#endif
- };
-
- enum GENERATE_LOG_FLAGS
- {
- GENERATE_LOG_FLAGS_NONE = 0,
- };
-
- // we depend on static PODs being initialized to 0 which is why ASSEMBLY_USAGE_LOG_FLAGS_NONE is 0
- enum ASSEMBLY_USAGE_LOG_FLAGS : DWORD
- {
- ASSEMBLY_USAGE_LOG_FLAGS_NONE = 0,
- ASSEMBLY_USAGE_LOG_FLAGS_INITTED = 1,
- ASSEMBLY_USAGE_LOG_FLAGS_APPLOCALNGENDISABLED = 2,
- };
-
- static HRESULT Init(const Config *pConfig);
- static HRESULT GenerateLog(GENERATE_LOG_FLAGS flags);
- static HRESULT GetUsageLogForContext(LPCWSTR binder, LPCWSTR binderParameter, IAssemblyUsageLog **ppUsageLog);
- static HRESULT RegisterBinderWithUsageLog(UINT_PTR binderId, IAssemblyUsageLog *pUsageLog);
- static HRESULT UnRegisterBinderFromUsageLog(UINT_PTR binderId);
- static IAssemblyUsageLog *GetUsageLogForBinder(UINT_PTR binderId);
- static ASSEMBLY_USAGE_LOG_FLAGS GetUsageLogFlags();
- static HRESULT SetUsageLogFlag(ASSEMBLY_USAGE_LOG_FLAGS flag, BOOL);
-
-private:
- SVAL_DECL(ASSEMBLY_USAGE_LOG_FLAGS, s_UsageLogFlags);
-};
-
-#endif /* ASSEMBLY_USAGE_LOG_MANAGER_H */
-
diff --git a/src/inc/binderngen.idl b/src/inc/binderngen.idl
deleted file mode 100644
index f3d41cd6a6..0000000000
--- a/src/inc/binderngen.idl
+++ /dev/null
@@ -1,254 +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.
-
-//+---------------------------------------------------------------------------
-//
-// File: binderngen.idl
-//
-// Contents: Binder to Native Binder Interfaces
-//
-// Classes:
-//
-// Functions:
-//
-//
-//----------------------------------------------------------------------------
-
-cpp_quote("")
-cpp_quote("#ifdef _MSC_VER")
-cpp_quote("#pragma comment(lib,\"uuid.lib\")")
-cpp_quote("#endif")
-cpp_quote("")
-cpp_quote("//---------------------------------------------------------------------------=")
-cpp_quote("// Binder Interfaces")
-cpp_quote("interface INativeImageInstallInfo;")
-cpp_quote("interface IILFingerprint;")
-cpp_quote("interface IILFingerprintFactory;")
-
-import "objidl.idl";
-import "fusion.idl";
-import "fusionpriv.idl";
-
-cpp_quote("#ifdef _MSC_VER")
-cpp_quote("#pragma once")
-cpp_quote("#endif")
-
-// interface IAssemblyName defined in fusion.idl
-// interface IAssemblyEnum defined in fusion.idl
-// interface ICorSvcLogger defined in mscorsvc.idl
-
-interface IAssemblyLocation;
-interface IBindResult;
-interface IBindContext;
-interface INativeImageInstallInfo;
-interface IILFingerprint;
-
-typedef enum
-{
- PRE_BIND_NONE = 0x00,
- PRE_BIND_APPLY_POLICY = 0x80
-} PRE_BIND_FLAGS;
-
-
-typedef enum
-{
- ASSEMBLY_LOCATION_PATH = 0x01,
- ASSEMBLY_LOCATION_GAC = 0x02,
- ASSEMBLY_LOCATION_HAS = 0x04,
- ASSEMBLY_LOCATION_BYTE_ARRAY = 0x08
-} ASSEMBLY_LOCATION_FLAGS;
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// IAssemblyLocation
-//
-///////////////////////////////////////////////////////////////////////////////
-
-cpp_quote("// {6970aad6-d5fb-469b-9098-a03ddc65a4bd}")
-cpp_quote("EXTERN_GUID(IID_IAssemblyLocation, 0x6970aad6, 0xd5fb, 0x469b, 0x90, 0x98, 0xa0, 0x3d, 0xdc, 0x65, 0xa4, 0xbd);")
-
-[
- local,
- object,
- uuid(6970aad6-d5fb-469b-9098-a03ddc65a4bd),
- pointer_default(unique)
-]
-interface IAssemblyLocation : IUnknown
-{
- typedef [unique] IAssemblyLocation *LPASSEMBLYLOCATION;
-
- HRESULT GetLocationType([in] DWORD *pdwLocationType);
-
- HRESULT GetPath([in, annotation("__inout_ecount(*pdwccAssemblyPath)")] LPWSTR pwzAssemblyPath,
- [in, annotation("__inout")] LPDWORD pdwccAssemblyPath);
-
- HRESULT GetHostID(UINT64 *puiHostID);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// IBindResult
-//
-// IBindResult was added mid-Dev10 when the native binder was split off
-// from Fusion. It seeks to provide a unified view of filepath-based assemblies (IAssembly),
-// host assemblies (IHostAssembly), NI images (the now-defunct CNativeImageAssembly) and
-// other things such as byte array assemblies (currently not expressible in Fusion at all.)
-//
-// At this time, it has not yet been widely adopted outside the native binder.
-//
-// @todo: Is it necessary for IBindResult to be a separately allocated object?
-// Why not create a base interface for the existing IAssembly/IHostAssembly?
-//
-//
-// Changes from Dev10:
-// Removed a bunch of methods that were added as expediencies and would
-// be long term liabilities if IBindResult is adopted as a universal assembly interface.
-//
-// In particular, it is no longer permitted to create IBindResult's that wrap
-// nothing more than an assembly name.
-//
-///////////////////////////////////////////////////////////////////////////////
-cpp_quote("// {82cff42f-55c2-45d2-aa6b-ff96e4de889c}")
-cpp_quote("EXTERN_GUID(IID_IBindResult, 0x82cff42f, 0x55c2, 0x45d2, 0xaa, 0x6b, 0xff, 0x96, 0xe4, 0xde, 0x88, 0x9c);")
-
-[
- local,
- object,
- uuid(82cff42f-55c2-45d2-aa6b-ff96e4de889c),
- pointer_default(unique)
-]
-interface IBindResult : IUnknown
-{
- typedef [unique] IBindResult *LPBINDRESULT;
-
- //--------------------------------------------------------------------------------
- // These methods are good candidates for a "universal" Assembly interface.
- //--------------------------------------------------------------------------------
- HRESULT GetAssemblyNameDef([out] IAssemblyName **ppIAssemblyNameDef);
-
- HRESULT GetNextAssemblyModuleName([in] DWORD dwNIndex,
- [in, out, annotation("__inout_ecount(*pdwCCModuleName)")] LPWSTR pwzModuleName,
- [in, out, annotation("__inout")] LPDWORD pdwCCModuleName);
-
- HRESULT GetAssemblyLocation([out] IAssemblyLocation **ppIAssemblyLocation);
-
-
- //--------------------------------------------------------------------------------
- // Native image binding.
- //
- // @todo: Do these need to be on IBindResult? I'd say it's cleaner for
- // these to be exposed as methods on the load context as was done pre-split.
- //--------------------------------------------------------------------------------
- HRESULT GetNativeImage([out] IBindResult **ppINativeImage,
- [out] BOOL *pfNativeImageProbed);
-
- HRESULT SetNativeImage([in] IBindResult *pINativeImage,
- [out] IBindResult **ppINativeImageFinal);
-
-
- //--------------------------------------------------------------------------------
- // This is needed because IBindResults in Dev10 are not "interned" objects
- // so we can't do pointer comparison on them as is done with IAssembly.
- //--------------------------------------------------------------------------------
- HRESULT IsEqual([in] IUnknown *pIUnk);
-
-
- //--------------------------------------------------------------------------------
- // These are used by the closure code only. We may want to rework these further
- // post Dev10-MQ.
- //--------------------------------------------------------------------------------
- HRESULT GetNextAssemblyNameRef([in] DWORD dwNIndex,
- [out] IAssemblyName **ppIAssemblyNameRef);
-
- HRESULT GetNextDependentAssembly([in] DWORD dwNIndex,
- [out] IUnknown **ppIUnknownAssembly);
-
- // Ad-hoc method that gives the closure code the info it needs without native IBindResults
- // actually having to maintain a reference to its partnered IL IBindResult.
- HRESULT GetAssemblyLocationOfILImage([out] IAssemblyLocation **ppAssemblyLocation);
-
-
- //--------------------------------------------------------------------------------
- // For use on IL's only: Obtain information about IL timestamps/MVIDs/SNHashes, etc.
- // Note that the MVID/SNHashes may be speculative (as we avoid opening the IL
- // for workset reasons.) However, everyone in the process will see the same MVID/SNHashs
- // for a given IL file.
- //--------------------------------------------------------------------------------
- HRESULT GetILFingerprint([out] IILFingerprint **ppFingerprint);
- HRESULT GetSourceILTimestamp([out] FILETIME* pFileTime);
- HRESULT GetSourceILSize([out] DWORD* pSize);
-
- //--------------------------------------------------------------------------------
- // For use on NI's only: Obtain information about NI version and dependencies.
- //--------------------------------------------------------------------------------
- HRESULT GetNIInfo([out] INativeImageInstallInfo** pInfo);
-
- enum
- {
- IBindResultFlag_Default = 0x00,
- IBindResultFlag_AssemblyNameDefIncomplete = 0x01,
- };
-
- //--------------------------------------------------------------------------------
- // Returns the set of flags, defined in IBindResultFlags, that apply to this
- // IBindResult object.
- //--------------------------------------------------------------------------------
- HRESULT GetFlags(DWORD * pdwFlags);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-//
-// IBindContext
-//
-// IBindContext represents a Fusion load context. It is an interface
-// via which Fusion provides services to the native binder.
-//
-// Note: This should *not* be adopted as a general interface for Fusion
-// load contexts. The services exposed here are quite specific to the native
-// binder's needs and it would be a liability to make them widely available.
-//
-///////////////////////////////////////////////////////////////////////////////
-cpp_quote("// {88db0d1a-460e-4341-96d7-a7c9b68f4679}")
-cpp_quote("EXTERN_GUID(IID_IBindContext, 0x88db0d1a, 0x460e, 0x4341, 0x96, 0xd7, 0xa7, 0xc9, 0xb6, 0x8f, 0x46, 0x79);")
-
-[
- local,
- object,
- uuid(88db0d1a-460e-4341-96d7-a7c9b68f4679),
- pointer_default(unique)
-]
-interface IBindContext : IUnknown
-{
- typedef [unique] IBindContext *LPBINDCONTEXT;
-
- HRESULT PreBind([in] IAssemblyName *pIAssemblyName,
- [in] DWORD dwPreBindFlags,
- [out] IBindResult **ppIBindResult);
-
- HRESULT IsDefaultContext();
-}
-
-
-
-#pragma midl_echo("STDAPI GetBindResultFromPath(LPCWSTR pwzFilePath, DWORD dwMetaDataImportFlags, DWORD dwAssemblyLocation, IBindContext *pBindContext, IBindResult **ppIBindResult, HANDLE hFile = INVALID_HANDLE_VALUE); ")
-//
-// Interface fraction implemented by ngen binder folks.
-//
-
-typedef struct
-{
- WCHAR *pwzZapConfigString;
- DWORD dwZapConfigMask;
-} NativeConfigData;
-
-#pragma midl_echo("interface ICorSvcLogger;")
-#pragma midl_echo("STDAPI InitializeNativeBinder(); ")
-#pragma midl_echo("STDAPI GetZapDir(__deref_out LPCWSTR *pszZapDir); ")
-#pragma midl_echo("STDAPI InstallNativeAssembly(LPCWSTR pwzAssemblyPath, HANDLE hFile, LPCWSTR pwzZapSet, IBindContext* pBindCtx, IAssemblyName **ppAssemblyName, IAssemblyLocation **ppAssemblyLocation);")
-#pragma midl_echo("STDAPI UninstallNativeAssembly(IAssemblyName *pIAssemblyName, ICorSvcLogger *pLogSink); ")
-#pragma midl_echo("STDAPI QueryNativeAssemblyInfo(IAssemblyName *pIAssemblyName, __out_ecount(*pdwSize) LPWSTR pwzFilePath, __inout LPDWORD pdwSize); ")
-#pragma midl_echo("STDAPI GetAssemblyNameFromNIPath(LPCWSTR wszNIPath, IAssemblyName ** ppAssemblyName); ")
-#pragma midl_echo("STDAPI CreateNativeAssemblyEnum(IAssemblyEnum **ppIAssemblyEnum, IAssemblyName *pIAssemblyName);")
-#pragma midl_echo("STDAPI BindToNativeAssembly(IBindResult *pGivenILAsm, const NativeConfigData *pNativeConfigData, IBindContext *pBindContext, IFusionBindLog *pFusionBindLog); ")
-#pragma midl_echo("struct IMDInternalImport;")
diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h
index 7b096b438f..e5cbaaa4a2 100644
--- a/src/inc/clrconfigvalues.h
+++ b/src/inc/clrconfigvalues.h
@@ -110,8 +110,6 @@ CONFIG_DWORD_INFO(INTERNAL_ADLogMemory, W("ADLogMemory"), 0, "Superseded by test
CONFIG_DWORD_INFO(INTERNAL_ADTakeDHSnapShot, W("ADTakeDHSnapShot"), 0, "Superseded by test hooks")
CONFIG_DWORD_INFO(INTERNAL_ADTakeSnapShot, W("ADTakeSnapShot"), 0, "Superseded by test hooks")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_EnableFullDebug, W("EnableFullDebug"), "Heavy-weight checking for AD boundary violations (AD leaks)")
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_DisableMSIPeek, W("DisableMSIPeek"), 0, "Disable MSI check in Fusion")
-CONFIG_DWORD_INFO(INTERNAL_MsiPeekForbid, W("MsiPeekForbid"), 0, "Assert on MSI calls")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ADULazyMemoryRelease, W("ADULazyMemoryRelease"), 1, "On by default. Turned off in cases when people try to catch memory leaks, in which case AD unload should be immediately followed by GC)")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_ADURetryCount, W("ADURetryCount"), "Controls timeout of AD unload. Used for workarounds when machine is too slow, there are network issues etc.")
RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_LEGACY_APPDOMAIN_MANAGER_ASM, W("APPDOMAIN_MANAGER_ASM"), "Legacy method to specify the assembly containing the AppDomainManager to use for the default domain", CLRConfig::DontPrependCOMPlus_ | CLRConfig::IgnoreHKLM | CLRConfig::IgnoreHKCU)
@@ -151,21 +149,6 @@ RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DesignerNamespaceResolutionEnabled, W("desi
CONFIG_DWORD_INFO_EX(INTERNAL_GetAssemblyIfLoadedIgnoreRidMap, W("GetAssemblyIfLoadedIgnoreRidMap"), 0, "Used to force loader to ignore assemblies cached in the rid-map", CLRConfig::REGUTIL_default)
//
-// BCL
-//
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_BCLCorrectnessWarnings, W("BCLCorrectnessWarnings"), "Flag a few common correctness bugs in the library with additional runtime checks.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_BCLPerfWarnings, W("BCLPerfWarnings"), "Flag some performance-related problems via asserts when people mis-use the library.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_TimeSpan_LegacyFormatMode, W("TimeSpan_LegacyFormatMode"), 0, "Flag to enable System.TimeSpan legacy (.NET Framework 3.5 and earlier) ToString behavior.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_CompatSortNLSVersion, W("CompatSortNLSVersion"), 0, "Determines the version of desired sorting behavior for AppCompat.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_NetFx45_CultureAwareComparerGetHashCode_LongStrings, W("NetFx45_CultureAwareComparerGetHashCode_LongStrings"), 0, "Opt in to use the new (as of v4.5) constant space hash algorithm for strings")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Resources_DisableUserPreferredFallback, W("DisableUserPreferredFallback"), 0, "Resource lookups should be dependent only on the CurrentUICulture, not a user-defined list of preferred languages nor the OS preferred fallback language. Intended to avoid falling back to a right-to-left language, which is undisplayable in console apps.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_RelativeBindForResources , W("relativeBindForResources"), 0, "Enables probing for satellite assemblies only next to the parent assembly")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_NetFx45_LegacyManagedDeflateStream, W("NetFx45_LegacyManagedDeflateStream"), 0, "Flag to enable legacy managed implementation of the deflater used by System.IO.Compression.DeflateStream.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DateTime_NetFX35ParseMode, W("DateTime_NetFX35ParseMode"), 0, "Flag to enable the .NET 3.5 System.DateTime Token Replacement Policy")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_ThrowUnobservedTaskExceptions, W("ThrowUnobservedTaskExceptions"), 0, "Flag to propagate unobserved task exceptions on the finalizer thread.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_DateTime_NetFX40AmPmParseAdjustment, W("EnableAmPmParseAdjustment"), 0, "Flag to enable the .NET 4.0 DateTimeParse to correctly parse AM/PM cases")
-
-//
// Conditional breakpoints
//
RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_BreakOnBadExit, W("BreakOnBadExit"), 0, "", CLRConfig::REGUTIL_default)
@@ -277,6 +260,9 @@ CONFIG_DWORD_INFO(UNSUPPORTED_Debugging_RequiredVersion, W("UNSUPPORTED_Debuggin
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
RETAIL_CONFIG_DWORD_INFO(INTERNAL_MiniMdBufferCapacity, W("MiniMdBufferCapacity"), 64 * 1024, "The max size of the buffer to store mini metadata information for triage- and mini-dumps.")
#endif // FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
+
+CONFIG_DWORD_INFO_EX(INTERNAL_DbgNativeCodeBpBindsAcrossVersions, W("DbgNativeCodeBpBindsAcrossVersions"), 0, "If non-zero causes native breakpoints at offset 0 to bind in all tiered compilation versions of the given method", CLRConfig::REGUTIL_default)
+
//
// Diagnostics (internal general-purpose)
//
@@ -284,7 +270,6 @@ CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ConditionalContracts, W("ConditionalCon
CONFIG_DWORD_INFO(INTERNAL_ConsistencyCheck, W("ConsistencyCheck"), 0, "")
CONFIG_DWORD_INFO_EX(INTERNAL_ContinueOnAssert, W("ContinueOnAssert"), 0, "If set, doesn't break on asserts.", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_disableStackOverflowProbing, W("disableStackOverflowProbing"), 0, "", CLRConfig::FavorConfigFile)
-CONFIG_DWORD_INFO(INTERNAL_EnforceEEThreadNotRequiredContracts, W("EnforceEEThreadNotRequiredContracts"), 0, "Indicates whether to enforce EE_THREAD_NOT_REQUIRED contracts (not enforced by default for perf reasons). Only applicable in dbg/chk builds--EE_THREAD_NOT_REQUIRED contracts never enforced in ret builds.")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_InjectFatalError, W("InjectFatalError"), "")
CONFIG_DWORD_INFO_EX(INTERNAL_InjectFault, W("InjectFault"), 0, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SuppressChecks, W("SuppressChecks"), "")
@@ -350,8 +335,7 @@ RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCNumaAware, W("GCNumaAware"), 1, "Specifie
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCCpuGroup, W("GCCpuGroup"), 0, "Specifies if to enable GC to support CPU groups")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCHeapCount, W("GCHeapCount"), 0, "")
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_GCNoAffinitize, W("GCNoAffinitize"), 0, "")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_GCUseStandalone, W("GCUseStandalone"), 0, "")
-RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCStandaloneLocation, W("GCStandaloneLocation"), "")
+RETAIL_CONFIG_STRING_INFO(EXTERNAL_GCName, W("GCName"), "")
//
// IBC
@@ -635,7 +619,6 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToConsole, W("LogToConsole"),
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToDebugger, W("LogToDebugger"), "Writes the CLR log to debugger (OutputDebugStringA).")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogToFile, W("LogToFile"), "Writes the CLR log to a file.")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_LogWithPid, W("LogWithPid"), "Appends pid to filename for the CLR log.")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_FusionLogFileNamesIncludePid, W("FusionLogFileNamesIncludePid"), 0, "Fusion logging will append process id to log filenames.", CLRConfig::REGUTIL_default)
//
// MetaData
@@ -650,8 +633,6 @@ CONFIG_DWORD_INFO_EX(INTERNAL_MD_MiniMDBreak, W("MD_MiniMDBreak"), 0, "ASSERT wh
CONFIG_DWORD_INFO_EX(INTERNAL_MD_PreSaveBreak, W("MD_PreSaveBreak"), 0, "ASSERT when calling CMiniMdRw::PreSave", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaBreak, W("MD_RegMetaBreak"), 0, "ASSERT when creating RegMeta class", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_MD_RegMetaDump, W("MD_RegMetaDump"), 0, "? Dump MD in 4 functions?", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_MD_TlbImp_BreakOnErr, W("MD_TlbImp_BreakOnErr"), 0, "ASSERT when importing TLB into MD", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_MD_TlbImp_BreakOnTypeImport, W("MD_TlbImp_BreakOnTypeImport"), "ASSERT when importing a type from TLB", (CLRConfig::LookupOptions) (CLRConfig::REGUTIL_default | CLRConfig::DontPrependCOMPlus_))
// MetaData - Desktop-only
CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_Disable, W("MD_WinMD_Disable"), 0, "Never activate the WinMD import adapter", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_EX(INTERNAL_MD_WinMD_AssertOnIllegalUsage, W("MD_WinMD_AssertOnIllegalUsage"), 0, "ASSERT if a WinMD import adapter detects a tool incompatibility", CLRConfig::REGUTIL_default)
@@ -743,21 +724,8 @@ CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureCount, W("NgenForceFailureCount"),
CONFIG_DWORD_INFO_EX(INTERNAL_NgenForceFailureKind, W("NgenForceFailureKind"), 1, "If set to 1, We will throw a TypeLoad exception; If set to 2, We will cause an A/V", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_NGenEnableCreatePdb, W("NGenEnableCreatePdb"), 0, "If set to >0 ngen.exe displays help on, recognizes createpdb in the command line")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenSimulateDiskFull, W("NGenSimulateDiskFull"), 0, "If set to 1, ngen will throw a Disk full exception in ZapWriter.cpp:Save()")
-RETAIL_CONFIG_STRING_INFO(INTERNAL_NGenAssemblyUsageLog, W("NGenAssemblyUsageLog"), "Directory to store ngen usage logs in.")
-#ifdef FEATURE_APPX
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenAssemblyUsageLogRefreshInterval, W("NGenAssemblyUsageLogRefreshInterval"), 24 * 60 * 60, "Interval to update usage log timestamp (seconds)");
-#endif
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_AppLocalAutongenNGenDisabled, W("AppLocalAutongenNGenDisabled"), 0, "Autongen disable flag.")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_PartialNGen, W("PartialNGen"), -1, "Generate partial NGen images")
RETAIL_CONFIG_DWORD_INFO(INTERNAL_NgenAllowMscorlibSoftbind, W("NgenAllowMscorlibSoftbind"), 0, "Disable forced hard-binding to mscorlib")
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_RegistryRoot, W("RegistryRoot"), "Redirects all registry access under HKLM\Software to a specified alternative", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_AssemblyPath, W("AssemblyPath"), "Redirects v2 GAC access to a specified alternative path", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_AssemblyPath2, W("AssemblyPath2"), "Redirects v4 GAC access to a specified alternative path", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_STRING_INFO_EX(UNSUPPORTED_NicPath, W("NicPath"), "Redirects NIC access to a specified alternative", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_NGenTaskDelayStart, W("NGenTaskDelayStart"), 0, "Use NGen Task delay start trigger, instead of critical idle task")
-
-// Flag for cross-platform ngen: Removes all execution of managed or third-party code in the ngen compilation process.
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_Ningen, W("Ningen"), 1, "Enable no-impact ngen")
CONFIG_DWORD_INFO(INTERNAL_NoASLRForNgen, W("NoASLRForNgen"), 0, "Turn off IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE bit in generated ngen images. Makes nidump output repeatable from run to run.")
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NgenAllowOutput, W("NgenAllowOutput"), 0, "If set to 1, the NGEN worker will bind to the parent console, thus allowing stdout output to work", CLRConfig::REGUTIL_default)
@@ -766,41 +734,6 @@ RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NgenAllowOutput, W("NgenAllowOutput"), 0, "
RETAIL_CONFIG_DWORD_INFO(INTERNAL_CrossGenAssumeInputSigned, W("CrossGenAssumeInputSigned"), 1, "CrossGen should assume that its input assemblies will be signed before deployment")
#endif
-//
-// NGEN service
-//
-// UNSUPPORTED_NGenMaxLogSize from NGEN section also applies to NGEN service.
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NGENServiceAbortIdleWorkUnderDebugger, W("NGENServiceAbortIdleWorkUnderDebugger"), 1, "Determines whether the Ngen service will abort idle-time tasks while under a debugger. Off by default. Allows for single-machine debugging of the idle-time logic.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NGENServiceAggressiveHardDiskIdleTimeout, W("NGENServiceAggressiveHardDiskIdleTimeout"), 1*60*60*1000, "This flag was intended as a backstop for HDD idle time detection (i.e. even if the hard disk is not idle, proceed with the compilation of the high-priority assemblies after the specified timeout). The current implementation compiles high-priority assemblies regardless of the state of the machine.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NGENServiceAggressiveWorkWaitTimeout, W("NGENServiceAggressiveWorkWaitTimeout"), 0, "This flag was intended as a backstop for machine idle time detection (i.e. even if the machine is not idle, proceed with the compilation of the high-priority assemblies after the specified timeout). The current implementation compiles high-priority assemblies regardless of the state of the machine.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceBreakOnStart, W("NGENServiceBreakOnStart"), 0, "Determines whether the Ngen service will call DebugBreak in its start routing. Off by default. Marginally useful for debugging service startup (there are other techniques as well).", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceConservative, W("NGENServiceConservative"), 0, "Determines whether the Ngen service will avoid compiling low-priority assemblies if multiple sessions exist on the machine and it can't determine their state. Off by default.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGenServiceDebugLog, W("NGenServiceDebugLog"), 0, "Configures the level of debug logging.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceIdleBatteryThreshold, W("NGENServiceIdleBatteryThreshold"), 50, "When a battery-powered system is below the threshold, Ngen will not process low-priority assemblies.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceIdleDebugInfo, W("NGENServiceIdleDebugInfo"), 0, "Determines whether the Ngen service will print the idle-time detection criteria to the debug log. Off by default. Ignored if NGenServiceDebugLog is 0.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceIdleDiskLogic, W("NGENServiceIdleDiskLogic"), 1, "Determines if the Ngen service will use hard disk idle time for its machine idle time heuristics.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceIdleDiskThreshold, W("NGENServiceIdleDiskThreshold"), 80, "The amount of time after which a disk is declared idle.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceIdleNoInputPeriod, W("NGENServiceIdleNoInputPeriod"), 5*60*1000, "The amount of time after which the machine is declared idle if no input was received.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServicePassiveExceptInputTimeout, W("NGENServicePassiveExceptInputTimeout"), 15*60*60*1000, "The amount of time after which only input state is considered for idle time detection (input backstop mode, which ignores everything except input).", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServicePassiveHardDiskIdleTimeout, W("NGENServicePassiveHardDiskIdleTimeout"), 36*60*60*1000, "The amount of time after which the state of the hard disk is ignored for idle time detection.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServicePassiveWorkWaitTimeout, W("NGENServicePassiveWorkWaitTimeout"), 0, "The amount of time after which the machine is declared idle and low priority assemblies are compiled no matter what the actual state is (absolute backstop mode: declaring the machine as idle disregarding the actual state).", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_NGENServicePolicy, W("NGENServicePolicy"), "The policy that will be used for the machine (client or server). By default, it's determined from the OS SKU.")
-RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_NGENServiceRestrictWorkersPrivileges, W("NGENServiceRestrictWorkersPrivileges"), 1, "Determines if worker processes are launched with restricted tokens.")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceSynchronization, W("NGENServiceSynchronization"), 1, "Determines if multiple services coordinate themselves so that only one service is working at a time.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_NGENServiceTestHookDll, W("NGENServiceTestHookDll"), "The name of a module used for testing in-process")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_NGENServiceWaitAggressiveWork, W("NGENServiceWaitAggressiveWork"), "Specifies how often the service will check the machine state when trying to do high-priority work.")
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceWaitPassiveWork, W("NGENServiceWaitPassiveWork"), 1*60*1000, "Specifies how often the service will check the machine state when trying to do low-priority work.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_NGENServiceWaitWorking, W("NGENServiceWaitWorking"), 1000, "While working, the Ngen service polls the state of the machine for changes (another service trying to do higher priority work, the Ngen command line tool trying to do work, machine coming out of idle state). This variable controls the frequency of the polling.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_NGENServiceWorkerPriority, W("NGENServiceWorkerPriority"), "The process priority class for workers.")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_EnableMultiproc, W("EnableMultiproc"), 1, "Turns on multiproc ngen", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_SvcRetryNgenFailures, W("SvcRetryNgenFailures"), 1, "If set to 1, The Ngen service will retry once when ngen fails", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NGenTaskDelayStartAmount, W("NGenTaskDelayStartAmount"), 5 * 60, "Number of seconds to delay for ngen update /queue /delay", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NGenProtectedProcess_FeatureEnabled, W("NGenProtectedProcess_FeatureEnabled"), -1, "Run ngen as PPL (protected process) if needed. Set to 0 to disable the feature for compat with older Win8 builds.", CLRConfig::IgnoreConfigFiles)
-CONFIG_STRING_INFO_EX(INTERNAL_NGenProtectedProcess_RequiredList, W("NGenProtectedProcess_RequiredList"), "Semicolon-separated list of assembly names that are required to be ngen'd in PPL process. Each name in the list is matched as prefix or suffix of assembly name/assembly file name.", CLRConfig::IgnoreConfigFiles)
-CONFIG_STRING_INFO_EX(INTERNAL_NGenProtectedProcess_ForbiddenList, W("NGenProtectedProcess_ForbiddenList"), "Semicolon-separated list of assembly names that are forbidden to be ngen'd in PPL process. Each name in the list is matched as prefix or suffix of assembly name/assembly file name.", CLRConfig::IgnoreConfigFiles)
-RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_NGenCopyFromRepository_SetCachedSigningLevel, W("NGenCopyFromRepository_SetCachedSigningLevel"), 0, "Support for test tree ngen.exe flag /CopyFromRepository to also vouch for the output NIs.", CLRConfig::IgnoreConfigFiles)
-
-//
// Perf
//
RETAIL_CONFIG_STRING_INFO(EXTERNAL_PerformanceScenario, W("performanceScenario"), "Activates a set of workload-specific default values for performance settings")
@@ -865,49 +798,8 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_ApplicationMigrationRuntimeActiv
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_TestOnlyEnsureImmersive, W("TestOnlyEnsureImmersive"), "Test-only flag used to indicate that it is expected that a process should be running as immersive.")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_EnableCoreClrHost, W("EnableCoreClrHost"), "Enables hosting coreclr from desktop mscoreei.dll to run windows store apps")
-
-//
-// Security
-//
-CONFIG_STRING_INFO_EX(INTERNAL_Security_AptcaAssemblyBreak, W("AptcaAssemblyBreak"), "Sets a breakpoint when checking if an assembly is APTCA or not", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO(INTERNAL_Security_AptcaAssemblySharingBreak, W("AptcaAssemblySharingBreak"), "Sets a breakpoint when checking if we can code share an assembly")
-CONFIG_DWORD_INFO(INTERNAL_Security_AptcaAssemblySharingDomainBreak, W("AptcaAssemblySharingDomainBreak"), 0, "Sets a breakpoint only in the specified domain when checking if we can code share an assembly")
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_Security_DefaultSecurityRuleSet, W("DefaultSecurityRuleSet"), 0, "Overrides the security rule set that assemblies which don't explicitly select their own rule set should use")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Security_LegacyCasPolicy, W("legacyCasPolicy"), 0, "Enable CAS policy for the process - for test use only, official access to this switch is through NetFx40_LegacySecurityPolicy.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Security_LoadFromRemoteSources, W("loadFromRemoteSources"), 0, "Enable loading from zones that are not MyComputer when not in CAS mode.")
-CONFIG_DWORD_INFO(UNSUPPORTED_Security_LogTransparencyErrors, W("LogTransparencyErrors"), 0, "Add an entry to the CLR log file for all transparency errors, rather than throwing an exception")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Security_NetFx40LegacySecurityPolicy, W("NetFx40_LegacySecurityPolicy"), 0, "Enable CAS policy for the process.")
-CONFIG_DWORD_INFO(INTERNAL_Security_NGenForPartialTrust, W("NGenForPartialTrust"), 0, "Force NGEN to generate code for assemblies that could be used in partial trust.")
-CONFIG_STRING_INFO_EX(INTERNAL_Security_TransparencyFieldBreak, W("TransparencyFieldBreak"), "Sets a breakpoint when figuring out the transparency of a specific field", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_Security_TransparencyMethodBreak, W("TransparencyMethodBreak"), "Sets a breakpoint when figuring out the transparency of a specific method", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_Security_TransparencyTypeBreak, W("TransparencyTypeBreak"), "Sets a breakpoint when figuring out the transparency of a specific type", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO(INTERNAL_Security_AlwaysInsertCallout, W("AlwaysInsertCallout"), 0, "Always insert security access/transparency/APTCA callouts")
-RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_Security_DisableAnonymouslyHostedDynamicMethodCreatorSecurityCheck, W("DisableAnonymouslyHostedDynamicMethodCreatorSecurityCheck"), 0, "Disables security checks for anonymously hosted dynamic methods based on their creator's security.")
-//
-// Serialization
-//
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Serialization_UnsafeTypeForwarding, W("unsafeTypeForwarding"), 0, "Enable unsafe type forwarding between unrelated assemblies")
-
-//
-// Stack overflow
-//
-CONFIG_DWORD_INFO_EX(INTERNAL_SOBreakOnProbeDuringSO, W("SOBreakOnProbeDuringSO"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_SODumpViolationsDir, W("SODumpViolationsDir"), "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SODumpViolationsStackTraceLength, W("SODumpViolationsStackTraceLength"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOEnableBackoutStackValidation, W("SOEnableBackoutStackValidation"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOEnableDefaultRWValidation, W("SOEnableDefaultRWValidation"), "")
-CONFIG_DWORD_INFO_EX(INTERNAL_SOEnableStackProtectionInDebugger, W("SOEnableStackProtectionInDebugger"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_SOEnableStackProtectionInDebuggerForProbeAtLine, W("SOEnableStackProtectionInDebuggerForProbeAtLine"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOEntryPointProbe, W("SOEntryPointProbe"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOInteriorProbe, W("SOInteriorProbe"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOLogger, W("SOLogger"), "")
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SOProbeAssertOnOverrun, W("SOProbeAssertOnOverrun"), "")
-CONFIG_DWORD_INFO_EX(INTERNAL_SOUpdateProbeAtLine, W("SOUpdateProbeAtLine"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_SOUpdateProbeAtLineAmount, W("SOUpdateProbeAtLineAmount"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_SOUpdateProbeAtLineInFile, W("SOUpdateProbeAtLineInFile"), "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_StackWalkStressUsingOldImpl, W("StackWalkStressUsingOldImpl"), 0, "to be removed", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_EX(INTERNAL_StackWalkStressUsingOS, W("StackWalkStressUsingOS"), 0, "to be removed", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_STRING_INFO(EXTERNAL_StartupDelayMS, W("StartupDelayMS"), "")
//
@@ -953,6 +845,7 @@ RETAIL_CONFIG_DWORD_INFO(EXTERNAL_Thread_UseAllCpuGroups, W("Thread_UseAllCpuGro
CONFIG_DWORD_INFO(INTERNAL_ThreadpoolTickCountAdjustment, W("ThreadpoolTickCountAdjustment"), 0, "")
+RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_Disable, W("HillClimbing_Disable"), 0, "Disables hill climbing for thread adjustments in the thread pool");
RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_WavePeriod, W("HillClimbing_WavePeriod"), 4, "");
RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_TargetSignalToNoiseRatio, W("HillClimbing_TargetSignalToNoiseRatio"), 300, "");
RETAIL_CONFIG_DWORD_INFO(INTERNAL_HillClimbing_ErrorSmoothingFactor, W("HillClimbing_ErrorSmoothingFactor"), 1, "");
@@ -1092,10 +985,6 @@ CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_CPUFeatures, W("CPUFeatures"), "")
CONFIG_STRING_INFO_EX(INTERNAL_DeadCodeMax, W("DeadCodeMax"), "Sets internal jit constants for Dead Code elmination", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_DefaultVersion, W("DefaultVersion"), "Version of CLR to load.")
RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(EXTERNAL_developerInstallation, W("developerInstallation"), "Flag to enable DEVPATH binding feature") // TODO: check special handling
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_shadowCopyVerifyByTimestamp, W("shadowCopyVerifyByTimestamp"), 0, "Fusion flag to enable quick verification of files in the shadow copy directory by using timestamps.", CLRConfig::FavorConfigFile | CLRConfig::MayHavePerformanceDefault)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_disableFusionUpdatesFromADManager, W("disableFusionUpdatesFromADManager"), 0, "Fusion flag to prevent changes to the AppDomainSetup object made by implementations of AppDomainManager.InitializeNewDomain from propagating to Fusion", CLRConfig::FavorConfigFile)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_disableCachingBindingFailures, W("disableCachingBindingFailures"), 0, "Fusion flag to re-enable Everett bind caching behavior (Whidbey caches failures for sharing)", CLRConfig::FavorConfigFile)
-RETAIL_CONFIG_DWORD_INFO(INTERNAL_EnableVerboseInstallLogging, W("enableVerboseInstallLogging"), 0, "Fusion flag to enable detailed logging of GAC install operations")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_disableCommitThreadStack, W("disableCommitThreadStack"), "This should only be internal but I believe ASP.Net uses this")
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_DisableConfigCache, W("DisableConfigCache"), 0, "Used to disable the \"probabilistic\" config cache, which walks through the appropriate config registry keys on init and probabilistically keeps track of which exist.", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_DisableStackwalkCache, W("DisableStackwalkCache"), "")
@@ -1109,26 +998,18 @@ RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_FORCE_ASSEMREF_DUPCHECK, W("FORCE_ASSEMR
CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_ForcedRuntime, W("ForcedRuntime"), "Verify version of CLR loaded")
CONFIG_DWORD_INFO_EX(INTERNAL_ForceRelocs, W("ForceRelocs"), 0, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_GenerateLongJumpDispatchStubRatio, W("GenerateLongJumpDispatchStubRatio"), "Useful for testing VSD on AMD64")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_generatePublisherEvidence, W("generatePublisherEvidence"), "If set, when the CLR loads an assembly that has an Authenticode signature we will verify that signature to generate Publisher evidence, at the expense of network hits and perf.")
CONFIG_DWORD_INFO_EX(INTERNAL_HashStack, W("HashStack"), 0, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO(INTERNAL_HostManagerConfig, W("HostManagerConfig"), (DWORD)-1, "")
CONFIG_DWORD_INFO(INTERNAL_HostTestADUnload, W("HostTestADUnload"), 0, "Alows setting Rude unload as default")
CONFIG_DWORD_INFO(INTERNAL_HostTestThreadAbort, W("HostTestThreadAbort"), 0, "")
RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_IgnoreDllMainReturn, W("IgnoreDllMainReturn"), 0, "Don't check the return value of DllMain if this is set", CLRConfig::ConfigFile_ApplicationFirst)
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_IJWEntrypointCompatMode, W("IJWEntrypointCompatMode"), 1, "Makes us run managed EP from DllMain. Basically brings the buggy behavior back.", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_InstallRoot, W("InstallRoot"), "Directory with installed CLRs")
CONFIG_STRING_INFO(INTERNAL_InvokeHalt, W("InvokeHalt"), "Throws an assert when the given method is invoked through reflection.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_legacyHMACMode, W("legacyHMACMode"), "v2.0 of the CLR shipped with a bug causing HMAC-SHA-384 and HMAC-SHA-512 to be calculated incorrectly. Orcas fixes this bug, but the config flag is added so that code which must verify v2.0 RTM HMACs can still interop with them.")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_legacyImpersonationPolicy, W("legacyImpersonationPolicy"), FALSE, "Windows identities should never flow across async points")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_legacyLoadMscorsnOnStartup, W("legacyLoadMscorsnOnStartup"), "Force mscorsn.dll to load when the VM starts")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_legacyNullReferenceExceptionPolicy, W("legacyNullReferenceExceptionPolicy"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_legacyUnhandledExceptionPolicy, W("legacyUnhandledExceptionPolicy"), "")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_legacyVirtualMethodCallVerification, W("legacyVirtualMethodCallVerification"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_ManagedLogFacility, W("ManagedLogFacility"), "?Log facility for managed code using the log")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStackDepth, W("MaxStackDepth"), "")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxStubUnwindInfoSegmentSize, W("MaxStubUnwindInfoSegmentSize"), "")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_MaxThreadRecord, W("MaxThreadRecord"), "")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_MergeCriticalAttributes, W("MergeCriticalAttributes"), 1, "", CLRConfig::REGUTIL_default)
CONFIG_DWORD_INFO(INTERNAL_MessageDebugOut, W("MessageDebugOut"), 0, "")
CONFIG_DWORD_INFO_EX(INTERNAL_MscorsnLogging, W("MscorsnLogging"), 0, "Enables strong name logging", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_NativeImageRequire, W("NativeImageRequire"), 0, "", CLRConfig::REGUTIL_default)
@@ -1152,7 +1033,6 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_RepositoryFlags, W("RepositoryFl
RETAIL_CONFIG_STRING_INFO(EXTERNAL_RestrictedGCStressExe, W("RestrictedGCStressExe"), "")
CONFIG_DWORD_INFO_EX(INTERNAL_ReturnSourceTypeForTesting, W("ReturnSourceTypeForTesting"), 0, "allows returning the (internal only) source type of an IL to Native mapping for debugging purposes", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(UNSUPPORTED_RSStressLog, W("RSStressLog"), 0, "allows turning on logging for RS startup", CLRConfig::REGUTIL_default)
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SafeHandleStackTraces, W("SafeHandleStackTraces"), "Debug-only ability to get a stack trace attached to every SafeHandle instance at creation time, for tracking down handle corruption problems.")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfo, W("SaveThreadInfo"), "")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_SaveThreadInfoMask, W("SaveThreadInfoMask"), "")
CONFIG_DWORD_INFO(INTERNAL_SBDumpOnNewIndex, W("SBDumpOnNewIndex"), 0, "Used for Syncblock debugging. It's been a while since any of those have been used.")
@@ -1167,8 +1047,6 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_SymbolReadingPolicy, W("SymbolRe
RETAIL_CONFIG_DWORD_INFO(UNSUPPORTED_TestDataConsistency, W("TestDataConsistency"), FALSE, "allows ensuring the left side is not holding locks (and may thus be in an inconsistent state) when inspection occurs")
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_ThreadGuardPages, W("ThreadGuardPages"), 0, "", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_Timeline, W("Timeline"), 0, "", CLRConfig::REGUTIL_default)
-CONFIG_STRING_INFO_EX(INTERNAL_TlbImpShouldBreakOnConvFunction, W("TlbImpShouldBreakOnConvFunction"), "", CLRConfig::REGUTIL_default)
-CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_TlbImpSkipLoading, W("TlbImpSkipLoading"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(UNSUPPORTED_TotalStressLogSize, W("TotalStressLogSize"), "Total stress log size in bytes.")
#ifdef _DEBUG
@@ -1177,15 +1055,10 @@ RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_TraceWrap, W("TraceWrap"), "")
#endif
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_TURNOFFDEBUGINFO, W("TURNOFFDEBUGINFO"), "")
-RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseGenericTlsGetters, W("UseGenericTlsGetters"), 0, "")
-RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_useLegacyIdentityFormat, W("useLegacyIdentityFormat"), 0, "Fusion flag to switch between Whidbey and Everett textual identity parser (have semantic differences)", CLRConfig::FavorConfigFile)
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseMethodDataCache, W("UseMethodDataCache"), FALSE, "Used during feature development; may now be removed.")
-RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_UseNewCrossDomainRemoting, W("UseNewCrossDomainRemoting"), "Forces the managed remoting stack to be used even for cross-domain remoting if set to 0 (default is 1)")
RETAIL_CONFIG_DWORD_INFO(EXTERNAL_UseParentMethodData, W("UseParentMethodData"), TRUE, "Used during feature development; may now be removed.")
CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_VerifierOff, W("VerifierOff"), "")
RETAIL_CONFIG_DWORD_INFO_DIRECT_ACCESS(EXTERNAL_VerifyAllOnLoad, W("VerifyAllOnLoad"), "")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_Version, W("Version"), "Version of CLR to load.")
-RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_ShimHookLibrary, W("ShimHookLibrary"), "Path to a DLL that should be notified when shim loads the runtime DLL.")
// **
// PLEASE MOVE ANY CONFIG SWITCH YOU OWN OUT OF THIS SECTION INTO A CATEGORY ABOVE
//
diff --git a/src/inc/clrnt.h b/src/inc/clrnt.h
index ebea066663..487a370d02 100644
--- a/src/inc/clrnt.h
+++ b/src/inc/clrnt.h
@@ -862,7 +862,7 @@ RtlpGetFunctionEndAddress (
__in TADDR ImageBase
)
{
- PUNWIND_INFO pUnwindInfo = (PUNWIND_INFO)(ImageBase + FunctionEntry->UnwindData);
+ PTR_UNWIND_INFO pUnwindInfo = (PTR_UNWIND_INFO)(ImageBase + FunctionEntry->UnwindData);
return FunctionEntry->BeginAddress + pUnwindInfo->FunctionLength;
}
diff --git a/src/inc/compatibilityflags.h b/src/inc/compatibilityflags.h
deleted file mode 100644
index c52e6084f3..0000000000
--- a/src/inc/compatibilityflags.h
+++ /dev/null
@@ -1,17 +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.
-
-// Unmanaged enum with compatibility flags. See compatibilityflagsdef.h for more details.
-
-
-#ifndef __COMPATIBILITYFLAGS_H__
-#define __COMPATIBILITYFLAGS_H__
-
-enum CompatibilityFlag {
-#define COMPATFLAGDEF(name) compat##name,
-#include "compatibilityflagsdef.h"
- compatCount,
-};
-
-#endif // __COMPATIBILITYFLAGS_H__
diff --git a/src/inc/compatibilityflagsdef.h b/src/inc/compatibilityflagsdef.h
deleted file mode 100644
index 611a043f2c..0000000000
--- a/src/inc/compatibilityflagsdef.h
+++ /dev/null
@@ -1,48 +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.
-
-// This file contains list of the CLR compatibility flags. The compatibility flags
-// are used to mitigate breaking changes in the platform code. They are used to trigger the legacy
-// behavior.
-
-// The general usage pattern is:
-
-// if (GetCompatibilityFlag(CompatibilityFlag.Foo)) {
-// // the legacy behavior
-// }
-// else {
-// // the new behavior
-// }
-
-// Add your own compatibility flags to the end of the list. You should go through the breaking
-// change approval process before adding it.
-//
-// Do not remove definitions for deprecated compatibility flags. Once the value is
-// assigned to the compatibility flag, it has to be kept forever.
-
-// This file is compiled twice: once to generate managed enum in clr\src\bcl, and second time
-// to generate the unmanaged enum in clr\src\vm.
-
-
-#ifndef COMPATFLAGDEF
-#error You must define COMPATFLAGDEF macro before including compatibilityflagsdef.h
-#endif
-
-COMPATFLAGDEF(SwallowUnhandledExceptions) // Legacy exception handling policy - swallow unhandled exceptions
-
-COMPATFLAGDEF(NullReferenceExceptionOnAV) // Legacy null reference exception policy - throw NullReferenceExceptions for access violations
-
-COMPATFLAGDEF(EagerlyGenerateRandomAsymmKeys) // Legacy mode for DSACryptoServiceProvider/RSACryptoServiceProvider - create a random key in the constructor eagerly
-
-COMPATFLAGDEF(FullTrustListAssembliesInGac) // Legacy mode for not requiring FT list assemblies to be in the GAC - if set, the requirement to be in the GAC would not be enforced.
-
-COMPATFLAGDEF(DateTimeParseIgnorePunctuation) // Through to V1.1, DateTime parse would ignore any unrecognized punctuation.
- // This flag restores that behavior.
-
-COMPATFLAGDEF(OnlyGACDomainNeutral) // This allows late setting of app domain security and
- // assembly evidence, even when LoaderOptimization=MultiDomain
-
-COMPATFLAGDEF(DisableReplacementCustomCulture) // This allow disabling replacement custom cultures. will always get the shipped framework culture.
-
-#undef COMPATFLAGDEF
diff --git a/src/inc/corhost.h b/src/inc/corhost.h
index 6d1d5772af..299057615f 100644
--- a/src/inc/corhost.h
+++ b/src/inc/corhost.h
@@ -26,8 +26,6 @@
#include "clrinternal.h"
-#include "ivehandler.h"
-#include "ivalidator.h"
#include "holder.h"
#include "clrprivhosting.h"
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
index b03f0456ac..cd48999cd0 100644
--- a/src/inc/corinfo.h
+++ b/src/inc/corinfo.h
@@ -213,12 +213,11 @@ TODO: Talk about initializing strutures before use
#define SELECTANY extern __declspec(selectany)
#endif
-// {CFEC7B89-D5FF-4A67-823A-EF99FE0286F4}
-SELECTANY const GUID JITEEVersionIdentifier = {
- 0xcfec7b89,
- 0xd5ff,
- 0x4a67,
- { 0x82, 0x3a, 0xef, 0x99, 0xfe, 0x2, 0x86, 0xf4 }
+SELECTANY const GUID JITEEVersionIdentifier = { /* b6af83a1-ca48-46c6-b7b0-5d7d6a79a5c5 */
+ 0xb6af83a1,
+ 0xca48,
+ 0x46c6,
+ {0xb7, 0xb0, 0x5d, 0x7d, 0x6a, 0x79, 0xa5, 0xc5}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -643,6 +642,7 @@ enum CorInfoHelpFunc
CORINFO_HELP_THROW_ARGUMENTEXCEPTION, // throw ArgumentException
CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException
+ CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, // throw PlatformNotSupportedException
CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
@@ -1955,6 +1955,14 @@ typedef SIZE_T GSCookie;
const int MAX_EnC_HANDLER_NESTING_LEVEL = 6;
+// Results from type comparison queries
+enum class TypeCompareState
+{
+ MustNot = -1, // types are not equal
+ May = 0, // types may be equal (must test at runtime)
+ Must = 1, // type are equal
+};
+
//
// This interface is logically split into sections for each class of information
// (ICorMethodInfo, ICorModuleInfo, etc.). This split used to exist physically as well
@@ -2086,6 +2094,12 @@ public:
CORINFO_CONTEXT_HANDLE ownerType = NULL /* IN */
) = 0;
+ // Get the unboxed entry point for a method, if possible.
+ virtual CORINFO_METHOD_HANDLE getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg = NULL /* OUT */
+ ) = 0;
+
// Given T, return the type of the default EqualityComparer<T>.
// Returns null if the type can't be determined exactly.
virtual CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(
@@ -2492,6 +2506,20 @@ public:
CORINFO_CLASS_HANDLE cls2
) = 0;
+ // See if a cast from fromClass to toClass will succeed, fail, or needs
+ // to be resolved at runtime.
+ virtual TypeCompareState compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass
+ ) = 0;
+
+ // See if types represented by cls1 and cls2 compare equal, not
+ // equal, or the comparison needs to be resolved at runtime.
+ virtual TypeCompareState compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ ) = 0;
+
// returns is the intersection of cls1 and cls2.
virtual CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
diff --git a/src/inc/corjit.h b/src/inc/corjit.h
index 61498594a3..6f217f14d4 100644
--- a/src/inc/corjit.h
+++ b/src/inc/corjit.h
@@ -113,7 +113,6 @@ public:
CORJIT_FLAG_USE_AVX = 14,
CORJIT_FLAG_USE_AVX2 = 15,
CORJIT_FLAG_USE_AVX_512 = 16,
- CORJIT_FLAG_FEATURE_SIMD = 17,
#else // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
@@ -121,10 +120,15 @@ public:
CORJIT_FLAG_UNUSED7 = 14,
CORJIT_FLAG_UNUSED8 = 15,
CORJIT_FLAG_UNUSED9 = 16,
- CORJIT_FLAG_UNUSED10 = 17,
#endif // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
+ #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+ CORJIT_FLAG_FEATURE_SIMD = 17,
+ #else
+ CORJIT_FLAG_UNUSED10 = 17,
+ #endif // !(defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
+
CORJIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter.
CORJIT_FLAG_READYTORUN = 19, // Use version-resilient code generation
CORJIT_FLAG_PROF_ENTERLEAVE = 20, // Instrument prologues/epilogues
diff --git a/src/inc/corpriv.h b/src/inc/corpriv.h
index c422351402..edd55e9111 100644
--- a/src/inc/corpriv.h
+++ b/src/inc/corpriv.h
@@ -390,8 +390,6 @@ DECLARE_INTERFACE_(ICeeGenInternal, IUnknown)
#ifdef FEATURE_PREJIT
// ===========================================================================
-#define CLR_OPTIMIZATION_SERVICE_DLL_NAME W("mscorsvc.dll")
-#define CLR_OPT_SVC_ENTRY_POINT "CorGetSvc"
// Use the default JIT compiler
#define DEFAULT_NGEN_COMPILER_DLL_NAME W("clrjit.dll")
@@ -473,12 +471,6 @@ typedef GUID CORCOMPILE_NGEN_SIGNATURE;
//**********************************************************************
// Internal versions of shim functions for use by the CLR.
-STDAPI LoadLibraryShimInternal(
- LPCWSTR szDllName,
- LPCWSTR szVersion,
- LPVOID pvReserved,
- HMODULE *phModDll);
-
STDAPI GetCORSystemDirectoryInternaL(
SString& pBuffer
);
@@ -495,18 +487,6 @@ STDAPI GetCORVersionInternal(
DWORD cchBuffer,
__out DWORD *pdwLength);
-STDAPI GetRequestedRuntimeInfoInternal(LPCWSTR pExe,
- LPCWSTR pwszVersion,
- LPCWSTR pConfigurationFile,
- DWORD startupFlags,
- DWORD runtimeInfoFlags,
- __out_ecount_opt(dwDirectory) LPWSTR pDirectory,
- DWORD dwDirectory,
- __out_opt DWORD *pdwDirectoryLength,
- __out_ecount_opt(cchBuffer) LPWSTR pVersion,
- DWORD cchBuffer,
- __out_opt DWORD* pdwLength);
-
#ifdef FEATURE_PREJIT
diff --git a/src/inc/corprof.idl b/src/inc/corprof.idl
index db67b3c6bb..f5da6e25a0 100644
--- a/src/inc/corprof.idl
+++ b/src/inc/corprof.idl
@@ -623,6 +623,8 @@ typedef enum
COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS = 0x00000004,
+ COR_PRF_HIGH_DISABLE_TIERED_COMPILATION = 0x00000008,
+
COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0,
COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS,
@@ -630,7 +632,7 @@ typedef enum
// MONITOR_IMMUTABLE represents all flags that may only be set during initialization.
// Trying to change any of these flags elsewhere will result in a
// failed HRESULT.
- COR_PRF_HIGH_MONITOR_IMMUTABLE = 0,
+ COR_PRF_HIGH_MONITOR_IMMUTABLE = COR_PRF_HIGH_DISABLE_TIERED_COMPILATION,
} COR_PRF_HIGH_MONITOR;
@@ -3889,6 +3891,24 @@ interface ICorProfilerInfo8 : ICorProfilerInfo7
[out] WCHAR wszName[]);
};
+[
+ object,
+ uuid(008170DB-F8CC-4796-9A51-DC8AA0B47012),
+ pointer_default(unique),
+ local
+]
+interface ICorProfilerInfo9 : ICorProfilerInfo8
+{
+ //Given functionId + rejitId, enumerate the native code start address of all jitted versions of this code that currently exist
+ HRESULT GetNativeCodeStartAddresses(FunctionID functionID, ReJITID reJitId, ULONG32 cCodeStartAddresses, ULONG32 *pcCodeStartAddresses, UINT_PTR codeStartAddresses[]);
+
+ //Given the native code start address, return the native->IL mapping information for this jitted version of the code
+ HRESULT GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress, ULONG32 cMap, ULONG32 *pcMap, COR_DEBUG_IL_TO_NATIVE_MAP map[]);
+
+ //Given the native code start address, return the the blocks of virtual memory that store this code (method code is not necessarily stored in a single contiguous memory region)
+ HRESULT GetCodeInfo4(UINT_PTR pNativeCodeStartAddress, ULONG32 cCodeInfos, ULONG32* pcCodeInfos, COR_PRF_CODE_INFO codeInfos[]);
+}
+
/*
* This interface lets you iterate over methods in the runtime.
*/
diff --git a/src/inc/crsttypes.h b/src/inc/crsttypes.h
index 55dc5bd4ab..1d6b349608 100644
--- a/src/inc/crsttypes.h
+++ b/src/inc/crsttypes.h
@@ -1,6 +1,8 @@
+//
// 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.
+//
#ifndef __CRST_TYPES_INCLUDED
#define __CRST_TYPES_INCLUDED
@@ -121,70 +123,71 @@ enum CrstType
CrstNativeBinderInit = 104,
CrstNativeImageCache = 105,
CrstNls = 106,
- CrstObjectList = 107,
- CrstOnEventManager = 108,
- CrstPatchEntryPoint = 109,
- CrstPEFileSecurityManager = 110,
- CrstPEImage = 111,
- CrstPEImagePDBStream = 112,
- CrstPendingTypeLoadEntry = 113,
- CrstPinHandle = 114,
- CrstPinnedByrefValidation = 115,
- CrstProfilerGCRefDataFreeList = 116,
- CrstProfilingAPIStatus = 117,
- CrstPublisherCertificate = 118,
- CrstRCWCache = 119,
- CrstRCWCleanupList = 120,
- CrstRCWRefCache = 121,
- CrstReDacl = 122,
- CrstReflection = 123,
- CrstReJITDomainTable = 124,
- CrstReJITGlobalRequest = 125,
- CrstReJITSharedDomainTable = 126,
- CrstRemoting = 127,
- CrstRetThunkCache = 128,
- CrstRWLock = 129,
- CrstSavedExceptionInfo = 130,
- CrstSaveModuleProfileData = 131,
- CrstSecurityPolicyCache = 132,
- CrstSecurityPolicyInit = 133,
- CrstSecurityStackwalkCache = 134,
- CrstSharedAssemblyCreate = 135,
- CrstSharedBaseDomain = 136,
- CrstSigConvert = 137,
- CrstSingleUseLock = 138,
- CrstSpecialStatics = 139,
- CrstSqmManager = 140,
- CrstStackSampler = 141,
- CrstStressLog = 142,
- CrstStrongName = 143,
- CrstStubCache = 144,
- CrstStubDispatchCache = 145,
- CrstStubUnwindInfoHeapSegments = 146,
- CrstSyncBlockCache = 147,
- CrstSyncHashLock = 148,
- CrstSystemBaseDomain = 149,
- CrstSystemDomain = 150,
- CrstSystemDomainDelayedUnloadList = 151,
- CrstThreadIdDispenser = 152,
- CrstThreadpoolEventCache = 153,
- CrstThreadpoolTimerQueue = 154,
- CrstThreadpoolWaitThreads = 155,
- CrstThreadpoolWorker = 156,
- CrstThreadStaticDataHashTable = 157,
- CrstThreadStore = 158,
- CrstTPMethodTable = 159,
- CrstTypeEquivalenceMap = 160,
- CrstTypeIDMap = 161,
- CrstUMEntryThunkCache = 162,
- CrstUMThunkHash = 163,
- CrstUniqueStack = 164,
- CrstUnresolvedClassLock = 165,
- CrstUnwindInfoTableLock = 166,
- CrstVSDIndirectionCellLock = 167,
- CrstWinRTFactoryCache = 168,
- CrstWrapperTemplate = 169,
- kNumberOfCrstTypes = 170
+ CrstNotifyGdb = 107,
+ CrstObjectList = 108,
+ CrstOnEventManager = 109,
+ CrstPatchEntryPoint = 110,
+ CrstPEFileSecurityManager = 111,
+ CrstPEImage = 112,
+ CrstPEImagePDBStream = 113,
+ CrstPendingTypeLoadEntry = 114,
+ CrstPinHandle = 115,
+ CrstPinnedByrefValidation = 116,
+ CrstProfilerGCRefDataFreeList = 117,
+ CrstProfilingAPIStatus = 118,
+ CrstPublisherCertificate = 119,
+ CrstRCWCache = 120,
+ CrstRCWCleanupList = 121,
+ CrstRCWRefCache = 122,
+ CrstReDacl = 123,
+ CrstReflection = 124,
+ CrstReJITDomainTable = 125,
+ CrstReJITGlobalRequest = 126,
+ CrstReJITSharedDomainTable = 127,
+ CrstRemoting = 128,
+ CrstRetThunkCache = 129,
+ CrstRWLock = 130,
+ CrstSavedExceptionInfo = 131,
+ CrstSaveModuleProfileData = 132,
+ CrstSecurityPolicyCache = 133,
+ CrstSecurityPolicyInit = 134,
+ CrstSecurityStackwalkCache = 135,
+ CrstSharedAssemblyCreate = 136,
+ CrstSharedBaseDomain = 137,
+ CrstSigConvert = 138,
+ CrstSingleUseLock = 139,
+ CrstSpecialStatics = 140,
+ CrstSqmManager = 141,
+ CrstStackSampler = 142,
+ CrstStressLog = 143,
+ CrstStrongName = 144,
+ CrstStubCache = 145,
+ CrstStubDispatchCache = 146,
+ CrstStubUnwindInfoHeapSegments = 147,
+ CrstSyncBlockCache = 148,
+ CrstSyncHashLock = 149,
+ CrstSystemBaseDomain = 150,
+ CrstSystemDomain = 151,
+ CrstSystemDomainDelayedUnloadList = 152,
+ CrstThreadIdDispenser = 153,
+ CrstThreadpoolEventCache = 154,
+ CrstThreadpoolTimerQueue = 155,
+ CrstThreadpoolWaitThreads = 156,
+ CrstThreadpoolWorker = 157,
+ CrstThreadStaticDataHashTable = 158,
+ CrstThreadStore = 159,
+ CrstTPMethodTable = 160,
+ CrstTypeEquivalenceMap = 161,
+ CrstTypeIDMap = 162,
+ CrstUMEntryThunkCache = 163,
+ CrstUMThunkHash = 164,
+ CrstUniqueStack = 165,
+ CrstUnresolvedClassLock = 166,
+ CrstUnwindInfoTableLock = 167,
+ CrstVSDIndirectionCellLock = 168,
+ CrstWinRTFactoryCache = 169,
+ CrstWrapperTemplate = 170,
+ kNumberOfCrstTypes = 171
};
#endif // __CRST_TYPES_INCLUDED
@@ -302,6 +305,7 @@ int g_rgCrstLevelMap[] =
-1, // CrstNativeBinderInit
-1, // CrstNativeImageCache
0, // CrstNls
+ 0, // CrstNotifyGdb
2, // CrstObjectList
0, // CrstOnEventManager
0, // CrstPatchEntryPoint
@@ -477,6 +481,7 @@ LPCSTR g_rgCrstNameMap[] =
"CrstNativeBinderInit",
"CrstNativeImageCache",
"CrstNls",
+ "CrstNotifyGdb",
"CrstObjectList",
"CrstOnEventManager",
"CrstPatchEntryPoint",
diff --git a/src/inc/dacvars.h b/src/inc/dacvars.h
index c5eb2cf996..f0f156dc62 100644
--- a/src/inc/dacvars.h
+++ b/src/inc/dacvars.h
@@ -127,7 +127,7 @@ DEFINE_DACVAR(ULONG, BOOL, SystemDomain__s_fForceInstrument, SystemDomain::s_fFo
DEFINE_DACVAR(ULONG, PTR_SharedDomain, SharedDomain__m_pSharedDomain, SharedDomain::m_pSharedDomain)
-DEFINE_DACVAR(ULONG, DWORD, CExecutionEngine__TlsIndex, CExecutionEngine::TlsIndex)
+DEFINE_DACVAR(ULONG, DWORD, dac__g_TlsIndex, g_TlsIndex)
#if defined(FEATURE_WINDOWSPHONE)
DEFINE_DACVAR(ULONG, int, CCLRErrorReportingManager__g_ECustomDumpFlavor, CCLRErrorReportingManager::g_ECustomDumpFlavor)
@@ -150,11 +150,6 @@ DEFINE_DACVAR(ULONG, PTR_JITNotification, dac__g_pNotificationTable, ::g_pNotifi
DEFINE_DACVAR(ULONG, ULONG32, dac__g_dacNotificationFlags, ::g_dacNotificationFlags)
DEFINE_DACVAR(ULONG, PTR_GcNotification, dac__g_pGcNotificationTable, ::g_pGcNotificationTable)
-#ifndef FEATURE_IMPLICIT_TLS
-DEFINE_DACVAR(ULONG, DWORD, dac__gThreadTLSIndex, ::gThreadTLSIndex)
-DEFINE_DACVAR(ULONG, DWORD, dac__gAppDomainTLSIndex, ::gAppDomainTLSIndex)
-#endif
-
DEFINE_DACVAR(ULONG, PTR_EEConfig, dac__g_pConfig, ::g_pConfig)
DEFINE_DACVAR(ULONG, MscorlibBinder, dac__g_Mscorlib, ::g_Mscorlib)
diff --git a/src/inc/ex.h b/src/inc/ex.h
index 80b9aa0a07..d345a74c89 100644
--- a/src/inc/ex.h
+++ b/src/inc/ex.h
@@ -1202,31 +1202,6 @@ Exception *ExThrowWithInnerHelper(Exception *inner);
} \
EX_END_CATCH(SwallowAllExceptions)
-
-//===================================================================================
-// Variant of the above Macro for used by ngen and mscorsvc to add
-// a RetailAssert when a reg key is set if we get an unexpected HRESULT
-// from one of the RPC calls.
-//===================================================================================
-
-#define EX_CATCH_HRESULT_AND_NGEN_CLEAN(_hr) \
- EX_CATCH \
- { \
- (_hr) = GET_EXCEPTION()->GetHR(); \
- RetailAssertIfExpectedClean(); \
- /* Enable this assert after we fix EH so that GetHR() never */ \
- /* mistakenly returns S_OK */ \
- /***/ \
- /* _ASSERTE(FAILED(_hr)); */ \
- IErrorInfo *pErr = GET_EXCEPTION()->GetErrorInfo(); \
- if (pErr != NULL) \
- { \
- SetErrorInfo(0, pErr); \
- pErr->Release(); \
- } \
- } \
- EX_END_CATCH(SwallowAllExceptions)
-
#else // FEATURE_COMINTEROP
#define EX_CATCH_HRESULT(_hr) EX_CATCH_HRESULT_NO_ERRORINFO(_hr)
diff --git a/src/inc/ivalidator.idl b/src/inc/ivalidator.idl
deleted file mode 100644
index d028d9888e..0000000000
--- a/src/inc/ivalidator.idl
+++ /dev/null
@@ -1,116 +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.
-/* ------------------------------------------------------------------------- *
- * Common Language Runtime Verifier / Validator Interace
- *
- * Purpose: IValidator is used to staticly validate COR images.
- *
- * Protocol:
- *
- * Client CoCreates CorHost.Validator,
- * Calls Validate()
- * [in/optional] IVEHandler for error callbacks on error
- * [in/optional] Appdomain to use for validating assemblies
- *
- * On Error, Validator calls IVEHandler.VEHandler() method.
- * (IVEHandler supplied by the client).
- * VEHandler() could return CONTINUE / STOP ...
- *
- * VEHandler() can call Validator.FormatEventInfo() to get a detailed
- * error message on any error passed to IVEHandler.
- *
- * ------------------------------------------------------------------------- */
-
-/* ------------------------------------------------------------------------- *
- * Imported types
- * ------------------------------------------------------------------------- */
-
-#ifndef DO_NO_IMPORTS
-import "ivehandler.idl";
-#endif
-
-#pragma warning(push)
-#pragma warning(disable:28718) //Unable to annotate as this is not a local interface
-
-
-
-/* ------------------------------------------------------------------------- *
- * Forward declarations
- * ------------------------------------------------------------------------- */
-
-interface IValidator;
-interface ILoader;
-
-
-/* ------------------------------------------------------------------------- *
- * Flags
- * ------------------------------------------------------------------------- */
-enum ValidatorFlags
-{
- VALIDATOR_EXTRA_VERBOSE = 0x00000001,
- VALIDATOR_SHOW_SOURCE_LINES = 0x00000002, // RESERVED FOR FUTURE USE
- VALIDATOR_CHECK_ILONLY = 0x00000004,
- VALIDATOR_CHECK_PEFORMAT_ONLY = 0x00000008,
- VALIDATOR_NOCHECK_PEFORMAT = 0x00000010,
- VALIDATOR_TRANSPARENT_ONLY = 0x00000020,
-};
-
-/* ------------------------------------------------------------------------- *
- * IValidator interface
- * ------------------------------------------------------------------------- */
-[
- object,
- uuid(63DF8730-DC81-4062-84A2-1FF943F59FAC),
- pointer_default(unique)
-]
-interface IValidator : IUnknown
-{
- HRESULT Validate(
- [in] IVEHandler *veh,
- [in] IUnknown *pAppDomain,
- [in] unsigned long ulFlags,
- [in] unsigned long ulMaxError,
- [in] unsigned long token,
- [in] LPWSTR fileName,
- [in, size_is(ulSize)] BYTE *pe,
- [in] unsigned long ulSize);
-
- HRESULT FormatEventInfo(
- [in] HRESULT hVECode,
- [in] VEContext Context,
- [in, out] LPWSTR msg,
- [in] unsigned long ulMaxLength,
- [in] SAFEARRAY(VARIANT) psa);
-};
-
-
-/* ------------------------------------------------------------------------- *
- * ICLRValidator interface
- * ------------------------------------------------------------------------- */
-[
- object,
- uuid(63DF8730-DC81-4062-84A2-1FF943F59FDD),
- pointer_default(unique)
-]
-interface ICLRValidator : IUnknown
-{
- HRESULT Validate(
- [in] IVEHandler *veh,
- [in] unsigned long ulAppDomainId,
- [in] unsigned long ulFlags,
- [in] unsigned long ulMaxError,
- [in] unsigned long token,
- [in] LPWSTR fileName,
- [in, size_is(ulSize)] BYTE *pe,
- [in] unsigned long ulSize);
-
- HRESULT FormatEventInfo(
- [in] HRESULT hVECode,
- [in] VEContext Context,
- [in, out] LPWSTR msg,
- [in] unsigned long ulMaxLength,
- [in] SAFEARRAY(VARIANT) psa);
-};
-#pragma warning(pop)
-
diff --git a/src/inc/ivehandler.idl b/src/inc/ivehandler.idl
deleted file mode 100644
index 0c0ad2b9da..0000000000
--- a/src/inc/ivehandler.idl
+++ /dev/null
@@ -1,72 +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.
-/* ------------------------------------------------------------------------- *
- * Common Language Runtime Verification Event Handler Interface
- * ------------------------------------------------------------------------- */
-
-/* ------------------------------------------------------------------------- *
- * Imported types
- * ------------------------------------------------------------------------- */
-
-#ifndef DO_NO_IMPORTS
-
-import "unknwn.idl";
-
-#define _VER_RAW_STRUCT_FOR_IDL_
-#include "VerError.h"
-#undef _VER_RAW_STRUCT_FOR_IDL_
-
-#endif
-
-typedef _VerError VEContext;
-
-/* ------------------------------------------------------------------------- *
- * Forward declarations
- * ------------------------------------------------------------------------- */
-
-interface IVEHandler;
-
-
-/* ------------------------------------------------------------------------- *
- * Library defintion
- * ------------------------------------------------------------------------- */
-
-[
- uuid(856CA1B0-7DAB-11d3-ACEC-00C04F86C309),
- version(1.0),
- helpstring("Common Language Runtime Verification Event Handler 1.0 Type Library")
-]
-library VEHandlerLib
-{
- importlib("STDOLE2.TLB");
-
- [
- uuid(856CA1B1-7DAB-11d3-ACEC-00C04F86C309)
- ]
- coclass VEHandlerClass
- {
- [default] interface IVEHandler;
- };
-
-};
-
-/* ------------------------------------------------------------------------- *
- * IVEHandler interface
- * ------------------------------------------------------------------------- */
-[
- object,
- uuid(856CA1B2-7DAB-11d3-ACEC-00C04F86C309),
- pointer_default(unique)
-]
-interface IVEHandler : IUnknown
-{
- HRESULT VEHandler(
- [in] HRESULT VECode,
- [in] VEContext Context,
- [in] SAFEARRAY(VARIANT) psa);
- HRESULT SetReporterFtn(
- [in] __int64 lFnPtr);
-
-};
-
diff --git a/src/inc/jithelpers.h b/src/inc/jithelpers.h
index 43b75293ae..1419cda2de 100644
--- a/src/inc/jithelpers.h
+++ b/src/inc/jithelpers.h
@@ -344,8 +344,9 @@
JITHELPER(CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR, JIT_LoopCloneChoiceAddr, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, JIT_DebugLogLoopCloning, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_THROW_ARGUMENTEXCEPTION, JIT_ThrowArgumentException, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, JIT_ThrowArgumentOutOfRangeException, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_THROW_ARGUMENTEXCEPTION, JIT_ThrowArgumentException, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, JIT_ThrowArgumentOutOfRangeException, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JIT_ThrowPlatformNotSupportedException, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, NULL, CORINFO_HELP_SIG_UNDEF)
JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, NULL, CORINFO_HELP_SIG_UNDEF)
diff --git a/src/inc/metahost_mktlb.rc b/src/inc/metahost_mktlb.rc
deleted file mode 100644
index a8a60ee1b2..0000000000
--- a/src/inc/metahost_mktlb.rc
+++ /dev/null
@@ -1,11 +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.
-
-#define FX_VER_FILEDESCRIPTION_STR "Microsoft .NET Runtime Metahosting Interfaces\0"
-#define FX_VER_INTERNALNAME_STR METAHOST.IDL
-
-#include <fxver.h>
-#include <fxver.rc>
-
-1 typelib REAL_METAHOST_TLB_FILE
diff --git a/src/inc/metahostpriv.idl b/src/inc/metahostpriv.idl
deleted file mode 100644
index 6d833b3a68..0000000000
--- a/src/inc/metahostpriv.idl
+++ /dev/null
@@ -1,212 +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.
-
-/**************************************************************************************
- ** NOTE: This file should be removed before 4.0 RTM. Specifically, when we decide **
- ** that enough time has elapsed that there should be no binaries left depending on **
- ** this old interface version.
- **************************************************************************************/
-
-import "metahost.idl";
-
-// IID ICLRMetaHostCompat1 : uuid(D332DB9E-B9B3-4125-8207-A14884F53215)
-cpp_quote("EXTERN_GUID(IID_ICLRMetaHostCompat1, 0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x15);")
-
-// IID ICLRMetaHostPolicyCompat1 : uuid(E2190695-77B2-492e-8E14-C4B3A7FDD592)
-cpp_quote("EXTERN_GUID(IID_ICLRMetaHostPolicyCompat1, 0xE2190695, 0x77B2, 0x492e, 0x8E, 0x14, 0xC4, 0xB3, 0xA7, 0xFD, 0xD5, 0x92);")
-
-// IID ICLRRuntimeHost3 : uuid(F4A7AE38-3213-4057-85FC-3DA54AFD0CFC)
-cpp_quote("EXTERN_GUID(IID_ICLRRuntimeHost3, 0xF4A7AE38, 0x3213, 0x4057, 0x85, 0xFC, 0x3D, 0xA5, 0x4A, 0xFD, 0x0C, 0xFC);")
-
-[
- uuid(D332DB9E-B9B3-4125-8207-A14884F53215),
- version(1.0),
- helpstring("CLR meta hosting interface"),
- local
-]
-interface ICLRMetaHostCompat1 : IUnknown
-{
- /**********************************************************************************
- ** Returns installed runtime with the specific version. Fails if not found. **
- ** NULL or any other wildcard is not accepted as pwzVersion **
- ** Supersedes: CorBindToRuntimeEx with STARTUP_LOADER_SAFEMODE **
-
-
- **********************************************************************************/
- HRESULT GetRuntime(
- [in] LPCWSTR pwzVersion,
- [in] REFIID riid, // IID_ICLRRuntimeInfo
- [out, iid_is(riid), retval] LPVOID *ppRuntime);
-
- /**********************************************************************************
- ** Returns runtime version burned into a file's metadata. **
- ** Supersedes: GetFileVersion **
- **********************************************************************************/
- HRESULT GetVersionFromFile(
- [in] LPCWSTR pwzFilePath,
- [out, size_is(*pcchBuffer), annotation("__out_ecount_full(*pcchBuffer)")]
- LPWSTR pwzBuffer,
- [in, out] DWORD *pcchBuffer);
-
- /**********************************************************************************
- ** Returns an enumerator of runtimes installed on the machine. **
- ** Supersedes: (none) **
- **********************************************************************************/
- HRESULT EnumerateInstalledRuntimes(
- [out, retval] IEnumUnknown **ppEnumerator);
-
- /**********************************************************************************
- ** Provides an enumerator of runtimes loaded into the given process. **
- ** Supersedes: GetVersionFromProcess **
-
- **********************************************************************************/
- HRESULT EnumerateLoadedRuntimes(
- [in] HANDLE hndProcess,
- [out, retval] IEnumUnknown **ppEnumerator);
-
- /**********************************************************************************
- ** Provides a callback when a new runtime version has just been loaded, but not **
- ** started. **
- ** **
- ** The callback works in the following way: **
- ** - the callback is invoked only when a runtime is loaded for the first time **
- ** - the callback will not be invoked for reentrant loads of the same runtime **
- ** - the callback will be for reentrant loads of other runtimes **
- ** - it is guaranteed that no other thread may load the runtime until the **
- ** callback returns; any thread that does so blocks until this time. **
- ** - for non-reentrant multi-threaded runtime loads, callbacks are serialized **
- ** - if the host intends to load (or cause to be loaded) another runtime in a **
- ** reentrant fashion, or intends to perform any operations on the runtime **
- ** corresponding to the callback instance, the pfnCallbackThreadSet and **
- ** pfnCallbackThreadUnset arguments provided in the callback must be used **
- ** in the following way: **
- ** - pfnCallbackThreadSet must be called by the thread that might cause a **
- ** runtime load before such a load is attempted **
- ** - pfnCallbackThreadUnset must be called when the thread will no longer **
- ** cause such a runtime load (and before returning from the initial **
- ** callback) **
- ** - pfnCallbackThreadSet and pfnCallbackThreadUnset are non-reentrant. **
- ** **
- ** pCallbackFunction: This function is invoked when a new runtime has just **
- ** been loaded. A value of NULL results in a failure **
- ** return value of E_POINTER. **
- ** **
- ** Supersedes: LockClrVersion **
- **********************************************************************************/
- HRESULT RequestRuntimeLoadedNotification(
- [in] RuntimeLoadedCallbackFnPtr pCallbackFunction);
-
- /**********************************************************************************
- ** Provides a mechanism to set the process wide config file settings. **
- ** Supersedes: none **
- **********************************************************************************/
- HRESULT SetProcessConfig(
- [in] IStream * pstmConfig);
-} // interface ICLRMetaHost
-
-
-/**************************************************************************************
- ** ICLRMetaHostPolicyCompat1 **
- ** Activated using mscoree!CreateInterface. Implements a policy for determining **
- ** a runtime based on various inputs (metadata, config stream, ...). **
- **************************************************************************************/
-[
- uuid(E2190695-77B2-492e-8E14-C4B3A7FDD592),
- version(1.0),
- helpstring("CLR meta hosting policy"),
- local
-]
-interface ICLRMetaHostPolicyCompat1 : IUnknown
-{
- /**********************************************************************************
- ** Returns requested runtime version and runtime (not necessarily of that **
- ** version) based on a managed binary, version, and config file. **
- ** The return value is S_OK if a compatible runtime was found and S_FALSE if **
- ** not. *ppRuntime will be NULL in the latter case. **
- ** Supersedes: GetRequestedRuntimeInfo, GetRequestedRuntimeVersion, **
- ** CorBindToRuntimeHost, CorBindToRuntimeByCfg, **
- ** GetCORRequiredVersion **
- **********************************************************************************/
- HRESULT GetRequestedRuntime(
- [in] METAHOST_POLICY_FLAGS dwPolicyFlags,
- [in] LPCWSTR pwzBinary, // optional
- [in] IStream *pCfgStream, // optional
- [in, out, size_is(*pcchVersion), annotation("__inout_ecount_full(*pcchVersion)")]
- LPWSTR pwzVersion, // optional
- [in, out] DWORD *pcchVersion,
- [out, size_is(*pcchImageVersion), annotation("__out_ecount_full(*pcchImageVersion)")]
- LPWSTR pwzImageVersion, // image version to be used by compilers
- [in, out] DWORD *pcchImageVersion,
- [in] REFIID riid, // IID_ICLRRuntimeInfo
- [out, iid_is(riid), retval] LPVOID *ppRuntime);
-} // interface ICLRMetaHostPolicy
-
-/**************************************************************************************
- ** ICLRRuntimeHost3 **
- ** This is the functionality that moved from being flat APIs (loading the latest **
- ** runtime) to something that is runtime-specific and requires the runtime to be **
- ** loaded.
- **************************************************************************************/
-[
- uuid(F4A7AE38-3213-4057-85FC-3DA54AFD0CFC),
- version(1.0),
- helpstring("CLR hosting interface for V4.0"),
- local
-]
-interface ICLRRuntimeHost3 : ICLRRuntimeHost
-{
- /**********************************************************************************
- ** Creates an instance of the type specified by a fully qualified name. **
- ** Returns a CCW wrapping the managed object. This method is intended to be **
- ** used primarily by the COM host. TODO: Specify the AppDomain? **
- **
- ** Supersedes: ClrCreateManagedInstance **
- **********************************************************************************/
- HRESULT CreateManagedObject(
- [in] LPCWSTR pwzTypeName,
- [in] REFIID riid,
- [out, iid_is(riid), retval] LPVOID *ppObject);
-
- /**********************************************************************************
- ** Releases all cached RCWs. **
- ** Supersedes: CoEEShutDownCOM **
- **********************************************************************************/
- HRESULT ShutdownCOMInterop();
-
- /**********************************************************************************
- ** Shuts down the current process. **
- ** Supersedes: CorExitProcess **
- **********************************************************************************/
- HRESULT ExitProcess(
- [in] INT32 iExitCode);
-
- /**********************************************************************************
- ** Returns TRUE if the runtime has been started, i.e. Start() has been called. **
- ** If it has been started, its STARTUP_FLAGS are returned. **
- ** Supersedes: (none) **
- **********************************************************************************/
- HRESULT IsStarted(
- [out] BOOL *pbStarted,
- [out] DWORD *pdwStartupFlags);
-
- /**********************************************************************************
- ** Starts the runtime with the given STARTUP_FLAGS and host config file. **
- ** Supersedes: ICLRRuntimeHost::Start **
- **********************************************************************************/
- HRESULT StartWithFlags(
- [in] DWORD dwStartupFlags,
- [in] LPCWSTR pwzHostConfigFile);
-}; // interface ICLRRuntimeHost3
-
-[
- uuid(5288DA6A-A8D3-43a1-8365-37DB0E7D5944),
- version(1.0),
-]
-library CLRMetaHostCompat
-{
- interface ICLRMetaHostCompat1;
- interface ICLRMetaHostPolicyCompat1;
- interface ICLRRuntimeHost3;
-};
-
diff --git a/src/inc/mscorcfg.h b/src/inc/mscorcfg.h
deleted file mode 100644
index c90cfe8b0a..0000000000
--- a/src/inc/mscorcfg.h
+++ /dev/null
@@ -1,34 +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.
-
-/*****************************************************************************
- ** **
- ** Cor.h - general header for the Runtime. **
- ** **
- *****************************************************************************/
-
-
-#ifndef _MSCORCFG_H_
-#define _MSCORCFG_H_
-#include <ole2.h> // Definitions of OLE types.
-#include <xmlparser.h>
-#include <specstrings.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// -----------------------------------------------------------------------
-// Returns an XMLParsr object. This can be used to parse any XML file.
-STDAPI GetXMLElementAttribute(LPCWSTR pwszAttributeName, __out_ecount(cchBuffer) LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwLen);
-STDAPI GetXMLElement(LPCWSTR wszFileName, LPCWSTR pwszTag);
-
-STDAPI GetXMLObject(IXMLParser **ppv);
-STDAPI CreateConfigStream(LPCWSTR pszFileName, IStream** ppStream);
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-#endif
diff --git a/src/inc/mscoree_tlb.idl b/src/inc/mscoree_tlb.idl
deleted file mode 100644
index 838e2cc34e..0000000000
--- a/src/inc/mscoree_tlb.idl
+++ /dev/null
@@ -1,15 +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.
-
-
-/**************************************************************************************
- ** **
- ** Mscoree_tlb.idl - mscoree.idl + internal intefaces from mscorsvc.dll **
- ** Used for making mscoree.tlb **
- ** **
- **************************************************************************************/
-
-#define INCLUDE_SVC_IDL
-#include "mscoree.idl"
-
diff --git a/src/inc/profilepriv.inl b/src/inc/profilepriv.inl
index d334e1086b..1af2914336 100644
--- a/src/inc/profilepriv.inl
+++ b/src/inc/profilepriv.inl
@@ -751,6 +751,22 @@ inline BOOL CORProfilerIsMonitoringDynamicFunctionUnloads()
((&g_profControlBlock)->dwEventMaskHigh & COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS));
}
+inline BOOL CORProfilerDisableTieredCompilation()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ CANNOT_TAKE_LOCK;
+ SO_NOT_MAINLINE;
+ }
+ CONTRACTL_END;
+
+
+ return (CORProfilerPresent() &&
+ ((&g_profControlBlock)->dwEventMaskHigh & COR_PRF_HIGH_DISABLE_TIERED_COMPILATION));
+}
+
#if defined(PROFILING_SUPPORTED) && !defined(CROSSGEN_COMPILE)
#if defined(FEATURE_PROFAPI_ATTACH_DETACH)
diff --git a/src/inc/switches.h b/src/inc/switches.h
index fae746d853..a9accbb2c6 100644
--- a/src/inc/switches.h
+++ b/src/inc/switches.h
@@ -64,13 +64,6 @@
#define GC_STATS
#endif
-
-#if defined(_DEBUG) && !defined(DACCESS_COMPILE) && (defined(_TARGET_X86_) || defined(_TARGET_AMD64_))
-// On x86/x64 Windows debug builds, respect the COMPlus_EnforceEEThreadNotRequiredContracts
-// runtime switch. See code:InitThreadManager and code:GetThreadGenericFullCheck
-#define ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-#endif
-
#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
#define USE_UPPER_ADDRESS 0
diff --git a/src/inc/sxshelpers.h b/src/inc/sxshelpers.h
deleted file mode 100644
index 199c1d4f44..0000000000
--- a/src/inc/sxshelpers.h
+++ /dev/null
@@ -1,141 +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.
-//****************************************************************************
-//
-// SxSHelpers.h
-//
-// Some helping classes and methods for SxS in mscoree and mscorwks/mscorsvr
-//
-
-//****************************************************************************
-
-
-#ifndef SXSHELPERS_H_
-#define SXSHELPERS_H_
-
-#define V1_VERSION_NUM W("v1.0.3705")
-
-// This string is the magic string located in the registry which determines that a key is actually
-// a version.
-//
-// For example:
-//
-// HCR/clsid/xxxx-xx-xx-xx/InprocServer32/1.0.3705.0
-// /1.0.3705.125
-//
-// If this SBSVERSIONVALUE is set as a ValueName in these
-// version keys, then we're saying that there is an implementation of the object
-// for that version of the runtime.
-//
-// i.e., if 1.0.3705.0 has the value name of SBSVERSIONVALUE, then 1.0.3705.0 implements
-// this class id.
-#define SBSVERSIONVALUE W("ImplementedInThisVersion")
-
-// Find the runtime version from registry for rclsid
-// If succeeded, *ppwzRuntimeVersion will have the runtime version
-// corresponding to the highest version
-// If failed, *ppwzRuntimeVersion will be NULL
-//
-// Note: If succeeded, this function will allocate memory for
-// *ppwzRuntimeVersion. It if the caller's repsonsibility to
-// release that memory
-HRESULT FindRuntimeVersionFromRegistry(
- REFCLSID rclsid,
- __deref_out_z LPWSTR *ppwzRuntimeVersion,
- __deref_out_opt LPWSTR *ppwzSupportedVersions);
-
-// Find assembly info from registry for rclsid
-// If succeeded, *ppwzClassName, *ppwzAssemblyString, *ppwzCodeBase
-// will have their value corresponding to the highest version
-// If failed, they will be set to NULL
-// Note: If succeeded, this function will allocate memory for
-// *ppwzClassName, *ppwzAssemblyString and *ppwzCodeBase.
-// Caller is responsible to release them.
-//
-HRESULT FindShimInfoFromRegistry(
- REFCLSID rclsid,
- BOOL bLoadRecord,
- WORD wHighestRuntimeMajorVersion,
- WORD wHighestRuntimeMinorVersion,
- __deref_out_z LPWSTR *ppwzClassName,
- __deref_out_z LPWSTR *ppwzAssemblyString,
- __deref_out_z LPWSTR *ppwzCodeBase);
-
-// Find assembly info from Win32 activattion context for rclsid
-// If succeeded, *ppwzRuntimeVersion, *ppwzClassName, *ppwzAssemblyString,
-// will have their value corresponding to the highest version
-// If failed, they will be set to NULL
-// Note: If succeeded, this function will allocate memory for
-// *ppwzClassName, *ppwzAssemblyString and *ppwzCodeBase.
-// Caller is responsible to release them.
-// Also notice codebase is not supported in Win32 case.
-//
-HRESULT FindShimInfoFromWin32(
- REFCLSID rclsid,
- BOOL bLoadRecord,
- __deref_opt_out_opt LPWSTR *ppwzRuntimeVersion,
- __deref_opt_out_opt LPWSTR *ppwszSupportedRuntimeVersions,
- __deref_opt_out_opt LPWSTR *ppwzClassName,
- __deref_opt_out_opt LPWSTR *ppwzAssemblyString,
- BOOL *pfRegFreePIA);
-
-// Get information from the Win32 fusion about the config file and the application base.
-HRESULT GetConfigFileFromWin32Manifest(__out_ecount_part(dwBuffer, *pSize) WCHAR* buffer, SIZE_T dwBuffer, SIZE_T* pSize);
-HRESULT GetApplicationPathFromWin32Manifest(__out_ecount_part(dwBuffer, *pSize) WCHAR* buffer, SIZE_T dwBuffer, SIZE_T* pSize);
-
-
-//****************************************************************************
-// AssemblyVersion
-//
-// class to handle assembly version
-// Since only functions in this file will use it,
-// we declare it in the cpp file so other people won't use it.
-//
-//****************************************************************************
-class AssemblyVersion
-{
- public:
- // constructors
- inline AssemblyVersion();
-
- inline AssemblyVersion(AssemblyVersion& version);
-
- // Init
- HRESULT Init(__in_z LPCWSTR pwzVersion, BOOL bStartsWithV);
- inline HRESULT Init(WORD major, WORD minor, WORD build, WORD revision);
-
- // Mofifiers.
- inline void SetBuild(WORD build);
- inline void SetRevision(WORD revision);
-
- // assign operator
- inline AssemblyVersion& operator=(const AssemblyVersion& version);
-
- // Comparison operator
- friend BOOL operator==(const AssemblyVersion& version1,
- const AssemblyVersion& version2);
- friend BOOL operator>=(const AssemblyVersion& version1,
- const AssemblyVersion& version2);
-
- private:
-
- // pwzVersion must have format of "a.b.c.d",
- // where a,b,c,d are all numbers
- HRESULT ValidateVersion(LPCWSTR pwzVersion);
-
- private:
- WORD _major;
- WORD _minor;
- WORD _build;
- WORD _revision;
-};
-extern BOOL operator==(const AssemblyVersion& version1,
- const AssemblyVersion& version2);
-
-extern BOOL operator>=(const AssemblyVersion& version1,
- const AssemblyVersion& version2);
-inline BOOL operator<(const AssemblyVersion& version1,
- const AssemblyVersion& version2);
-#include <sxshelpers.inl>
-#endif // SXSHELPERS_H_
diff --git a/src/inc/sxshelpers.inl b/src/inc/sxshelpers.inl
deleted file mode 100644
index 3e42051aa9..0000000000
--- a/src/inc/sxshelpers.inl
+++ /dev/null
@@ -1,76 +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.
-
-#ifndef _SXSHELPERS_INL_
-#define _SXSHELPERS_INL_
-
-AssemblyVersion::AssemblyVersion()
-:_major(0)
-,_minor(0)
-,_build(0)
-,_revision(0)
-{
- LIMITED_METHOD_CONTRACT;
-
-}
-
-AssemblyVersion::AssemblyVersion(AssemblyVersion& version)
-{
- LIMITED_METHOD_CONTRACT;
-
- _major = version._major;
- _minor = version._minor;
- _build = version._build;
- _revision = version._revision;
-}
-
-HRESULT AssemblyVersion::Init(WORD major, WORD minor, WORD build, WORD revision)
-{
- LIMITED_METHOD_CONTRACT;
-
- _major = major;
- _minor = minor;
- _build = build;
- _revision = revision;
-
- return S_OK;
-}
-
-
-void AssemblyVersion::SetBuild(WORD build)
-{
- LIMITED_METHOD_CONTRACT;
-
- _build = build;
-}
-
-void AssemblyVersion::SetRevision(WORD revision)
-{
- LIMITED_METHOD_CONTRACT;
-
- _revision = revision;
-}
-
-AssemblyVersion& AssemblyVersion::operator=(const AssemblyVersion& version)
-{
- LIMITED_METHOD_CONTRACT;
-
- _major = version._major;
- _minor = version._minor;
- _build = version._build;
- _revision = version._revision;
-
- return *this;
-}
-
-BOOL operator<(const AssemblyVersion& version1,
- const AssemblyVersion& version2)
-{
- WRAPPER_NO_CONTRACT;
-
- return !operator>=(version1, version2);
-}
-
-
-#endif /* _SXSHELPERS_INL_ */
diff --git a/src/inc/tlbimpexp.idl b/src/inc/tlbimpexp.idl
deleted file mode 100644
index b7b117495b..0000000000
--- a/src/inc/tlbimpexp.idl
+++ /dev/null
@@ -1,72 +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.
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-// .Net Developer Platform TypeLib importer/exporter event notification
-// interface definitions.
-//
-// NOTE: This IDL must remain synchronized with the definitions in
-// BCL/System/Runtime/InteropServices/ITypeLibConverter.cs.
-//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-[
- uuid(20BC1825-06F0-11d2-8CF4-00A0C9B0A063),
- version(1.0)
-]
-library TlbImpLib
-{
- importlib("stdole32.tlb") ;
-
- typedef [uuid(F82895D2-1338-36A8-9A89-F9B0AFBE7801)]
- enum {
- NOTIF_TYPECONVERTED = 0,
- NOTIF_CONVERTWARNING = 1,
- ERROR_REFTOINVALIDTYPELIB = 2
- } ImporterEventKind;
-
- [
- odl,
- uuid(F1C3BF76-C3E4-11D3-88E7-00902754C43A),
- oleautomation
- ]
- interface ITypeLibImporterNotifySink : IUnknown {
- HRESULT _stdcall ReportEvent(
- [in] ImporterEventKind EventKind,
- [in] long EventCode,
- [in] BSTR EventMsg);
- HRESULT _stdcall ResolveRef(
- [in] IUnknown* Typelib,
- [out, retval] IUnknown** pRetVal);
- };
-
- [
- odl,
- uuid(F1C3BF77-C3E4-11D3-88E7-00902754C43A),
- oleautomation
- ]
- interface ITypeLibExporterNotifySink : IUnknown {
- HRESULT _stdcall ReportEvent(
- [in] ImporterEventKind EventKind,
- [in] long EventCode,
- [in] BSTR EventMsg);
- HRESULT _stdcall ResolveRef(
- [in] IUnknown* Asm,
- [out, retval] IUnknown** pRetVal);
- };
-
- [
- odl,
- uuid(FA1F3615-ACB9-486d-9EAC-1BEF87E36B09),
- oleautomation
- ]
- interface ITypeLibExporterNameProvider : IUnknown {
- HRESULT _stdcall GetNames (
- [out, retval] SAFEARRAY(BSTR) *Names);
- };
-
-
-
-};
-
-
-
diff --git a/src/inc/tls.h b/src/inc/tls.h
index 55f74892bb..3e8c9a770d 100644
--- a/src/inc/tls.h
+++ b/src/inc/tls.h
@@ -13,20 +13,8 @@
#ifndef __tls_h__
#define __tls_h__
-#ifdef FEATURE_IMPLICIT_TLS
-#ifdef _WIN64
-#ifndef _DEBUG
-#define OFFSETOF__TLS__tls_ThreadLocalInfo 0x10
-#else // _DEBUG
-#define OFFSETOF__TLS__tls_ThreadLocalInfo 0x08
-#endif // _DEBUG
-#else // _WIN64
-#define OFFSETOF__TLS__tls_ThreadLocalInfo 0x04
-#endif // _WIN64
-
-#define OFFSETOF__TLS__tls_CurrentThread (OFFSETOF__TLS__tls_ThreadLocalInfo+0x0)
-#define OFFSETOF__TLS__tls_EETlsData (OFFSETOF__TLS__tls_CurrentThread+2*sizeof(void*))
-
+#define OFFSETOF__TLS__tls_CurrentThread (0x0)
+#define OFFSETOF__TLS__tls_EETlsData (2*sizeof(void*))
#ifdef _TARGET_WIN64_
#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x58
@@ -34,45 +22,4 @@
#define WINNT_OFFSETOF__TEB__ThreadLocalStoragePointer 0x2c
#endif
-#endif // FEATURE_IMPLICIT_TLS
-
-// Pointer to a function that retrieves the TLS data for a specific index.
-typedef LPVOID (*POPTIMIZEDTLSGETTER)();
-
-//---------------------------------------------------------------------------
-// Creates a platform-optimized version of TlsGetValue compiled
-// for a particular index. Can return NULL - the caller should substitute
-// a non-optimized getter in this case.
-//---------------------------------------------------------------------------
-POPTIMIZEDTLSGETTER MakeOptimizedTlsGetter(DWORD tlsIndex, LPVOID pBuffer = NULL, SIZE_T cbBuffer = 0, POPTIMIZEDTLSGETTER pGenericImpl = NULL, BOOL fForceGeneric = FALSE);
-
-
-//---------------------------------------------------------------------------
-// Frees a function created by MakeOptimizedTlsGetter().
-//---------------------------------------------------------------------------
-VOID FreeOptimizedTlsGetter(POPTIMIZEDTLSGETTER pOptimizedTlsGetter);
-
-
-
-//---------------------------------------------------------------------------
-// For ASM stub generators that want to inline Thread access for efficiency,
-// the Thread manager uses these constants to define how to access the Thread.
-//---------------------------------------------------------------------------
-enum TLSACCESSMODE {
- TLSACCESS_GENERIC = 1, // Make no platform assumptions: use the API
- // TLS
- TLSACCESS_WNT = 2, // WinNT-style TLS
- TLSACCESS_WNT_HIGH = 3, // WinNT5-style TLS, slot > TLS_MINIMUM_AVAILABLE
-};
-
-
-//---------------------------------------------------------------------------
-// WinNT store the TLS in different places relative to the
-// fs:[0]. This api reveals which. Can also return TLSACCESS_GENERIC if
-// no info is available about the Thread location (you have to use the TlsGetValue
-// api.) This is intended for use by stub generators that want to inline TLS
-// access.
-//---------------------------------------------------------------------------
-TLSACCESSMODE GetTLSAccessMode(DWORD tlsIndex);
-
#endif // __tls_h__
diff --git a/src/inc/warningcontrol.h b/src/inc/warningcontrol.h
index c0e21b90a7..abc4831639 100644
--- a/src/inc/warningcontrol.h
+++ b/src/inc/warningcontrol.h
@@ -69,6 +69,7 @@
#pragma warning(error :4700) // Local used w/o being initialized
#pragma warning(disable :4706) // assignment within conditional expression
+#pragma warning(disable :4768) // __declspec attributes before linkage specification are ignored
#pragma warning(error :4806) // unsafe operation involving type 'bool'
#pragma warning(disable :4995) // '_OLD_IOSTREAMS_ARE_DEPRECATED': name was marked as #pragma deprecated
diff --git a/src/inc/winsqmevents.h b/src/inc/winsqmevents.h
deleted file mode 100644
index 2394c84a8a..0000000000
--- a/src/inc/winsqmevents.h
+++ /dev/null
@@ -1,84 +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.
-
-//**********************************************************************`
-//* This is an include file generated by Message Compiler. *`
-//* *`
-
-//**********************************************************************`
-#pragma once
-//+
-// Provider Microsoft-Windows-CEIP Event Count 7
-//+
-EXTERN_C __declspec(selectany) const GUID S_Microsoft_Windows_CEIP = {0xa402fe09, 0xda6e, 0x45f2, {0x82, 0xaf, 0x3c, 0xb3, 0x71, 0x70, 0xee, 0x0c}};
-
-//
-// Event Descriptors
-//
-#define WSQMCONS_CONSOLIDATION_SUCCESS 0x400003EDL
-#define WSQMCONS_CONSOLIDATION_ERROR 0xC00003EEL
-#define WSQMCONS_UPLOAD_SUCCESS 0x400003EFL
-#define WSQMCONS_UPLOAD_ERROR 0xC00003F0L
-#define WSQMCONS_NOTIFY_SUCCESS 0x400003F1L
-#define WSQMCONS_NOTIFY_ERROR 0xC00003F2L
-#define WSQMCONS_MANIFEST_DOWNLOAD 0xC00003F3L
-//+
-// Provider Microsoft-Windows-SQM-Events Event Count 26
-//+
-EXTERN_C __declspec(selectany) const GUID Microsoft_Windows_SQM_Provider = {0xa97524f6, 0x064c, 0x4c4e, {0xb7, 0x4b, 0x1a, 0xcc, 0x87, 0xc3, 0x70, 0x0d}};
-
-//
-// Event Descriptors
-//
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Microsoft_Windows_SQM_Provider_EVENT_0x3_0_0_4_0_0_8000000000000 = {0x3, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define Microsoft_Windows_SQM_Provider_EVENT_0x3_0_0_4_0_0_8000000000000_value 0x3
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Microsoft_Windows_SQM_Provider_EVENT_0x4_0_0_4_0_0_8000000000000 = {0x4, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define Microsoft_Windows_SQM_Provider_EVENT_0x4_0_0_4_0_0_8000000000000_value 0x4
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SET_DWORD_V0 = {0x5, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SET_DWORD_V0_value 0x5
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_INCREMENT_DWORD_V0 = {0x6, 0x0, 0x0, 0x4, 0x2, 0x0, 0x8000000000000};
-#define SQM_INCREMENT_DWORD_V0_value 0x6
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_ADDTOAVERAGE_DWORD_V0 = {0x7, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_ADDTOAVERAGE_DWORD_V0_value 0x7
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SETIFMAX_DWORD_V0 = {0x8, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SETIFMAX_DWORD_V0_value 0x8
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SETIFMIN_DWORD_V0 = {0x9, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SETIFMIN_DWORD_V0_value 0x9
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR Microsoft_Windows_SQM_Provider_EVENT_0xb_0_0_4_0_0_8000000000000 = {0xb, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define Microsoft_Windows_SQM_Provider_EVENT_0xb_0_0_4_0_0_8000000000000_value 0xb
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_INIT = {0x1, 0x0, 0x0, 0x4, 0x1, 0x0, 0x8000000000000};
-#define SQM_INIT_value 0x1
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_CLEANUP = {0x2, 0x0, 0x0, 0x4, 0x2, 0x0, 0x8000000000000};
-#define SQM_CLEANUP_value 0x2
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_START_SESSION = {0x3, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_START_SESSION_value 0x3
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_END_SESSION = {0x4, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_END_SESSION_value 0x4
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SET_DWORD = {0x5, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SET_DWORD_value 0x5
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_INCREMENT_DWORD = {0x6, 0x1, 0x0, 0x4, 0x2, 0x0, 0x8000000000000};
-#define SQM_INCREMENT_DWORD_value 0x6
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_ADDTOAVERAGE_DWORD = {0x7, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_ADDTOAVERAGE_DWORD_value 0x7
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SETIFMAX_DWORD = {0x8, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SETIFMAX_DWORD_value 0x8
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SETIFMIN_DWORD = {0x9, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SETIFMIN_DWORD_value 0x9
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SET_STRING = {0xa, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SET_STRING_value 0xa
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_ADD_LEGACYSTREAMROW = {0xb, 0x1, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_ADD_LEGACYSTREAMROW_value 0xb
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_LOGON_USER = {0xc, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_LOGON_USER_value 0xc
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_LOGOFF_USER = {0xd, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_LOGOFF_USER_value 0xd
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_OPTIN_NOTIFICATION_SHOWN = {0xe, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_OPTIN_NOTIFICATION_SHOWN_value 0xe
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_OPTIN_NOTIFICATION_RESPONSE = {0xf, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_OPTIN_NOTIFICATION_RESPONSE_value 0xf
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_SET_DWORD64 = {0x10, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_SET_DWORD64_value 0x10
-EXTERN_C __declspec(selectany) const EVENT_DESCRIPTOR SQM_ADD_STREAMROW = {0x11, 0x0, 0x0, 0x4, 0x0, 0x0, 0x8000000000000};
-#define SQM_ADD_STREAMROW_value 0x11
-#define MSG_event_CEIP_EVENT_SOURCE 0x90000001L
diff --git a/src/inc/xmlparser.h b/src/inc/xmlparser.h
deleted file mode 100644
index 70bf380e58..0000000000
--- a/src/inc/xmlparser.h
+++ /dev/null
@@ -1,1385 +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.
-
-
-#ifdef _MSC_VER
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-#endif
-
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */
-
-
- /* File created by MIDL compiler version 6.00.0328 */
-/* Compiler settings for xmlparser.idl:
- Oicf (OptLev=i2), W1, Zp8, env=Win32 (32b run)
- protocol : dce , ms_ext, c_ext
- error checks: allocation ref bounds_check enum stub_data
- VC __declspec() decoration level:
- __declspec(uuid()), __declspec(selectany), __declspec(novtable)
- DECLSPEC_UUID(), MIDL_INTERFACE()
-*/
-//@@MIDL_FILE_HEADING( )
-
-
-/* verify that the <rpcndr.h> version is high enough to compile this file*/
-#ifndef __REQUIRED_RPCNDR_H_VERSION__
-#define __REQUIRED_RPCNDR_H_VERSION__ 440
-#endif
-
-#include "rpc.h"
-#include "rpcndr.h"
-
-#ifndef __xmlparser_h__
-#define __xmlparser_h__
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-#pragma once
-#endif
-
-/* Forward Declarations */
-
-#ifndef __IXMLNodeSource_FWD_DEFINED__
-#define __IXMLNodeSource_FWD_DEFINED__
-typedef interface IXMLNodeSource IXMLNodeSource;
-#endif /* __IXMLNodeSource_FWD_DEFINED__ */
-
-
-#ifndef __IXMLParser_FWD_DEFINED__
-#define __IXMLParser_FWD_DEFINED__
-typedef interface IXMLParser IXMLParser;
-#endif /* __IXMLParser_FWD_DEFINED__ */
-
-
-#ifndef __IXMLNodeFactory_FWD_DEFINED__
-#define __IXMLNodeFactory_FWD_DEFINED__
-typedef interface IXMLNodeFactory IXMLNodeFactory;
-#endif /* __IXMLNodeFactory_FWD_DEFINED__ */
-
-
-#ifndef __XMLParser_FWD_DEFINED__
-#define __XMLParser_FWD_DEFINED__
-
-#ifdef __cplusplus
-typedef class XMLParser XMLParser;
-#else
-typedef struct XMLParser XMLParser;
-#endif /* __cplusplus */
-
-#endif /* __XMLParser_FWD_DEFINED__ */
-
-
-/* header files for imported files */
-#include "unknwn.h"
-#include "objidl.h"
-#include "oaidl.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
-void __RPC_USER MIDL_user_free( void __RPC_FAR * );
-
-/* interface __MIDL_itf_xmlparser_0000 */
-/* [local] */
-
-typedef /* [public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0001
- { XML_ELEMENT = 1,
- XML_ATTRIBUTE = XML_ELEMENT + 1,
- XML_PI = XML_ATTRIBUTE + 1,
- XML_XMLDECL = XML_PI + 1,
- XML_DOCTYPE = XML_XMLDECL + 1,
- XML_DTDATTRIBUTE = XML_DOCTYPE + 1,
- XML_ENTITYDECL = XML_DTDATTRIBUTE + 1,
- XML_ELEMENTDECL = XML_ENTITYDECL + 1,
- XML_ATTLISTDECL = XML_ELEMENTDECL + 1,
- XML_NOTATION = XML_ATTLISTDECL + 1,
- XML_GROUP = XML_NOTATION + 1,
- XML_INCLUDESECT = XML_GROUP + 1,
- XML_PCDATA = XML_INCLUDESECT + 1,
- XML_CDATA = XML_PCDATA + 1,
- XML_IGNORESECT = XML_CDATA + 1,
- XML_COMMENT = XML_IGNORESECT + 1,
- XML_ENTITYREF = XML_COMMENT + 1,
- XML_WHITESPACE = XML_ENTITYREF + 1,
- XML_NAME = XML_WHITESPACE + 1,
- XML_NMTOKEN = XML_NAME + 1,
- XML_STRING = XML_NMTOKEN + 1,
- XML_PEREF = XML_STRING + 1,
- XML_MODEL = XML_PEREF + 1,
- XML_ATTDEF = XML_MODEL + 1,
- XML_ATTTYPE = XML_ATTDEF + 1,
- XML_ATTPRESENCE = XML_ATTTYPE + 1,
- XML_DTDSUBSET = XML_ATTPRESENCE + 1,
- XML_LASTNODETYPE = XML_DTDSUBSET + 1
- } XML_NODE_TYPE;
-
-typedef /* [public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0002
- { XML_VERSION = XML_LASTNODETYPE,
- XML_ENCODING = XML_VERSION + 1,
- XML_STANDALONE = XML_ENCODING + 1,
- XML_NS = XML_STANDALONE + 1,
- XML_XMLSPACE = XML_NS + 1,
- XML_XMLLANG = XML_XMLSPACE + 1,
- XML_SYSTEM = XML_XMLLANG + 1,
- XML_PUBLIC = XML_SYSTEM + 1,
- XML_NDATA = XML_PUBLIC + 1,
- XML_AT_CDATA = XML_NDATA + 1,
- XML_AT_ID = XML_AT_CDATA + 1,
- XML_AT_IDREF = XML_AT_ID + 1,
- XML_AT_IDREFS = XML_AT_IDREF + 1,
- XML_AT_ENTITY = XML_AT_IDREFS + 1,
- XML_AT_ENTITIES = XML_AT_ENTITY + 1,
- XML_AT_NMTOKEN = XML_AT_ENTITIES + 1,
- XML_AT_NMTOKENS = XML_AT_NMTOKEN + 1,
- XML_AT_NOTATION = XML_AT_NMTOKENS + 1,
- XML_AT_REQUIRED = XML_AT_NOTATION + 1,
- XML_AT_IMPLIED = XML_AT_REQUIRED + 1,
- XML_AT_FIXED = XML_AT_IMPLIED + 1,
- XML_PENTITYDECL = XML_AT_FIXED + 1,
- XML_EMPTY = XML_PENTITYDECL + 1,
- XML_ANY = XML_EMPTY + 1,
- XML_MIXED = XML_ANY + 1,
- XML_SEQUENCE = XML_MIXED + 1,
- XML_CHOICE = XML_SEQUENCE + 1,
- XML_STAR = XML_CHOICE + 1,
- XML_PLUS = XML_STAR + 1,
- XML_QUESTIONMARK = XML_PLUS + 1,
- XML_LASTSUBNODETYPE = XML_QUESTIONMARK + 1
- } XML_NODE_SUBTYPE;
-
-typedef /* [public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0003
- { XML_E_PARSEERRORBASE = 0xc00ce500L,
- XML_E_ENDOFINPUT = XML_E_PARSEERRORBASE,
- XML_E_MISSINGEQUALS = XML_E_ENDOFINPUT + 1,
- XML_E_MISSINGQUOTE = XML_E_MISSINGEQUALS + 1,
- XML_E_COMMENTSYNTAX = XML_E_MISSINGQUOTE + 1,
- XML_E_BADSTARTNAMECHAR = XML_E_COMMENTSYNTAX + 1,
- XML_E_BADNAMECHAR = XML_E_BADSTARTNAMECHAR + 1,
- XML_E_BADCHARINSTRING = XML_E_BADNAMECHAR + 1,
- XML_E_XMLDECLSYNTAX = XML_E_BADCHARINSTRING + 1,
- XML_E_BADCHARDATA = XML_E_XMLDECLSYNTAX + 1,
- XML_E_MISSINGWHITESPACE = XML_E_BADCHARDATA + 1,
- XML_E_EXPECTINGTAGEND = XML_E_MISSINGWHITESPACE + 1,
- XML_E_BADCHARINDTD = XML_E_EXPECTINGTAGEND + 1,
- XML_E_BADCHARINDECL = XML_E_BADCHARINDTD + 1,
- XML_E_MISSINGSEMICOLON = XML_E_BADCHARINDECL + 1,
- XML_E_BADCHARINENTREF = XML_E_MISSINGSEMICOLON + 1,
- XML_E_UNBALANCEDPAREN = XML_E_BADCHARINENTREF + 1,
- XML_E_EXPECTINGOPENBRACKET = XML_E_UNBALANCEDPAREN + 1,
- XML_E_BADENDCONDSECT = XML_E_EXPECTINGOPENBRACKET + 1,
- XML_E_INTERNALERROR = XML_E_BADENDCONDSECT + 1,
- XML_E_UNEXPECTED_WHITESPACE = XML_E_INTERNALERROR + 1,
- XML_E_INCOMPLETE_ENCODING = XML_E_UNEXPECTED_WHITESPACE + 1,
- XML_E_BADCHARINMIXEDMODEL = XML_E_INCOMPLETE_ENCODING + 1,
- XML_E_MISSING_STAR = XML_E_BADCHARINMIXEDMODEL + 1,
- XML_E_BADCHARINMODEL = XML_E_MISSING_STAR + 1,
- XML_E_MISSING_PAREN = XML_E_BADCHARINMODEL + 1,
- XML_E_BADCHARINENUMERATION = XML_E_MISSING_PAREN + 1,
- XML_E_PIDECLSYNTAX = XML_E_BADCHARINENUMERATION + 1,
- XML_E_EXPECTINGCLOSEQUOTE = XML_E_PIDECLSYNTAX + 1,
- XML_E_MULTIPLE_COLONS = XML_E_EXPECTINGCLOSEQUOTE + 1,
- XML_E_INVALID_DECIMAL = XML_E_MULTIPLE_COLONS + 1,
- XML_E_INVALID_HEXIDECIMAL = XML_E_INVALID_DECIMAL + 1,
- XML_E_INVALID_UNICODE = XML_E_INVALID_HEXIDECIMAL + 1,
- XML_E_WHITESPACEORQUESTIONMARK = XML_E_INVALID_UNICODE + 1,
- XML_E_TOKEN_ERROR = XML_E_PARSEERRORBASE + 0x50,
- XML_E_SUSPENDED = XML_E_TOKEN_ERROR,
- XML_E_STOPPED = XML_E_SUSPENDED + 1,
- XML_E_UNEXPECTEDENDTAG = XML_E_STOPPED + 1,
- XML_E_UNCLOSEDTAG = XML_E_UNEXPECTEDENDTAG + 1,
- XML_E_DUPLICATEATTRIBUTE = XML_E_UNCLOSEDTAG + 1,
- XML_E_MULTIPLEROOTS = XML_E_DUPLICATEATTRIBUTE + 1,
- XML_E_INVALIDATROOTLEVEL = XML_E_MULTIPLEROOTS + 1,
- XML_E_BADXMLDECL = XML_E_INVALIDATROOTLEVEL + 1,
- XML_E_MISSINGROOT = XML_E_BADXMLDECL + 1,
- XML_E_UNEXPECTEDEOF = XML_E_MISSINGROOT + 1,
- XML_E_BADPEREFINSUBSET = XML_E_UNEXPECTEDEOF + 1,
- XML_E_PE_NESTING = XML_E_BADPEREFINSUBSET + 1,
- XML_E_INVALID_CDATACLOSINGTAG = XML_E_PE_NESTING + 1,
- XML_E_UNCLOSEDPI = XML_E_INVALID_CDATACLOSINGTAG + 1,
- XML_E_UNCLOSEDSTARTTAG = XML_E_UNCLOSEDPI + 1,
- XML_E_UNCLOSEDENDTAG = XML_E_UNCLOSEDSTARTTAG + 1,
- XML_E_UNCLOSEDSTRING = XML_E_UNCLOSEDENDTAG + 1,
- XML_E_UNCLOSEDCOMMENT = XML_E_UNCLOSEDSTRING + 1,
- XML_E_UNCLOSEDDECL = XML_E_UNCLOSEDCOMMENT + 1,
- XML_E_UNCLOSEDMARKUPDECL = XML_E_UNCLOSEDDECL + 1,
- XML_E_UNCLOSEDCDATA = XML_E_UNCLOSEDMARKUPDECL + 1,
- XML_E_BADDECLNAME = XML_E_UNCLOSEDCDATA + 1,
- XML_E_BADEXTERNALID = XML_E_BADDECLNAME + 1,
- XML_E_BADELEMENTINDTD = XML_E_BADEXTERNALID + 1,
- XML_E_RESERVEDNAMESPACE = XML_E_BADELEMENTINDTD + 1,
- XML_E_EXPECTING_VERSION = XML_E_RESERVEDNAMESPACE + 1,
- XML_E_EXPECTING_ENCODING = XML_E_EXPECTING_VERSION + 1,
- XML_E_EXPECTING_NAME = XML_E_EXPECTING_ENCODING + 1,
- XML_E_UNEXPECTED_ATTRIBUTE = XML_E_EXPECTING_NAME + 1,
- XML_E_ENDTAGMISMATCH = XML_E_UNEXPECTED_ATTRIBUTE + 1,
- XML_E_INVALIDENCODING = XML_E_ENDTAGMISMATCH + 1,
- XML_E_INVALIDSWITCH = XML_E_INVALIDENCODING + 1,
- XML_E_EXPECTING_NDATA = XML_E_INVALIDSWITCH + 1,
- XML_E_INVALID_MODEL = XML_E_EXPECTING_NDATA + 1,
- XML_E_INVALID_TYPE = XML_E_INVALID_MODEL + 1,
- XML_E_INVALIDXMLSPACE = XML_E_INVALID_TYPE + 1,
- XML_E_MULTI_ATTR_VALUE = XML_E_INVALIDXMLSPACE + 1,
- XML_E_INVALID_PRESENCE = XML_E_MULTI_ATTR_VALUE + 1,
- XML_E_BADXMLCASE = XML_E_INVALID_PRESENCE + 1,
- XML_E_CONDSECTINSUBSET = XML_E_BADXMLCASE + 1,
- XML_E_CDATAINVALID = XML_E_CONDSECTINSUBSET + 1,
- XML_E_INVALID_STANDALONE = XML_E_CDATAINVALID + 1,
- XML_E_UNEXPECTED_STANDALONE = XML_E_INVALID_STANDALONE + 1,
- XML_E_DOCTYPE_IN_DTD = XML_E_UNEXPECTED_STANDALONE + 1,
- XML_E_MISSING_ENTITY = XML_E_DOCTYPE_IN_DTD + 1,
- XML_E_ENTITYREF_INNAME = XML_E_MISSING_ENTITY + 1,
- XML_E_DOCTYPE_OUTSIDE_PROLOG = XML_E_ENTITYREF_INNAME + 1,
- XML_E_INVALID_VERSION = XML_E_DOCTYPE_OUTSIDE_PROLOG + 1,
- XML_E_DTDELEMENT_OUTSIDE_DTD = XML_E_INVALID_VERSION + 1,
- XML_E_DUPLICATEDOCTYPE = XML_E_DTDELEMENT_OUTSIDE_DTD + 1,
- XML_E_RESOURCE = XML_E_DUPLICATEDOCTYPE + 1,
- XML_E_LASTERROR = XML_E_RESOURCE + 1
- } XML_ERROR_CODE;
-
-typedef /* [public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0004
- { XMLPARSER_IDLE = 0,
- XMLPARSER_WAITING = XMLPARSER_IDLE + 1,
- XMLPARSER_BUSY = XMLPARSER_WAITING + 1,
- XMLPARSER_ERROR = XMLPARSER_BUSY + 1,
- XMLPARSER_STOPPED = XMLPARSER_ERROR + 1,
- XMLPARSER_SUSPENDED = XMLPARSER_STOPPED + 1
- } XML_PARSER_STATE;
-
-typedef /* [public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0005
- { XMLFLAG_FLOATINGAMP = 1,
- XMLFLAG_SHORTENDTAGS = 2,
- XMLFLAG_CASEINSENSITIVE = 4,
- XMLFLAG_NONAMESPACES = 8,
- XMLFLAG_NOWHITESPACE = 16,
- XMLFLAG_IE4QUIRKS = 32,
- XMLFLAG_NODTDNODES = 64,
- XMLFLAG_IE4COMPATIBILITY = 255
- } XML_PARSER_FLAGS;
-
-typedef /* [public][public] */
-enum __MIDL___MIDL_itf_xmlparser_0000_0006
- { XMLNF_STARTDOCUMENT = 0,
- XMLNF_STARTDTD = XMLNF_STARTDOCUMENT + 1,
- XMLNF_ENDDTD = XMLNF_STARTDTD + 1,
- XMLNF_STARTDTDSUBSET = XMLNF_ENDDTD + 1,
- XMLNF_ENDDTDSUBSET = XMLNF_STARTDTDSUBSET + 1,
- XMLNF_ENDPROLOG = XMLNF_ENDDTDSUBSET + 1,
- XMLNF_STARTENTITY = XMLNF_ENDPROLOG + 1,
- XMLNF_ENDENTITY = XMLNF_STARTENTITY + 1,
- XMLNF_ENDDOCUMENT = XMLNF_ENDENTITY + 1,
- XMLNF_DATAAVAILABLE = XMLNF_ENDDOCUMENT + 1,
- XMLNF_LASTEVENT = XMLNF_DATAAVAILABLE
- } XML_NODEFACTORY_EVENT;
-
-typedef struct _XML_NODE_INFO
- {
- DWORD dwSize;
- DWORD dwType;
- DWORD dwSubType;
- BOOL fTerminal;
- const WCHAR __RPC_FAR *pwcText;
- ULONG ulLen;
- ULONG ulNsPrefixLen;
- PVOID pNode;
- PVOID pReserved;
- } XML_NODE_INFO;
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_xmlparser_0000_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_xmlparser_0000_v0_0_s_ifspec;
-
-
-#ifndef __XMLPSR_LIBRARY_DEFINED__
-#define __XMLPSR_LIBRARY_DEFINED__
-
-/* library XMLPSR */
-/* [version][lcid][helpstring][uuid] */
-
-
-EXTERN_C const IID LIBID_XMLPSR;
-
-#ifndef __IXMLNodeSource_INTERFACE_DEFINED__
-#define __IXMLNodeSource_INTERFACE_DEFINED__
-
-/* interface IXMLNodeSource */
-/* [unique][helpstring][uuid][local][object] */
-
-
-EXTERN_C const IID IID_IXMLNodeSource;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("d242361d-51a0-11d2-9caf-0060b0ec3d39")
- IXMLNodeSource : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE SetFactory(
- /* [in] */ IXMLNodeFactory __RPC_FAR *pNodeFactory) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetFactory(
- /* [out] */ IXMLNodeFactory __RPC_FAR *__RPC_FAR *ppNodeFactory) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Abort(
- /* [in] */ BSTR bstrErrorInfo) = 0;
-
- virtual ULONG STDMETHODCALLTYPE GetLineNumber( void) = 0;
-
- virtual ULONG STDMETHODCALLTYPE GetLinePosition( void) = 0;
-
- virtual ULONG STDMETHODCALLTYPE GetAbsolutePosition( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetLineBuffer(
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf,
- /* [out] */ ULONG __RPC_FAR *pulLen,
- /* [out] */ ULONG __RPC_FAR *pulStartPos) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetLastError( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetErrorInfo(
- /* [out] */ BSTR __RPC_FAR *pbstrErrorInfo) = 0;
-
- virtual ULONG STDMETHODCALLTYPE GetFlags( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetURL(
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf) = 0;
-
- };
-
-#else /* C style interface */
-
- typedef struct IXMLNodeSourceVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
- IXMLNodeSource __RPC_FAR * This,
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
- IXMLNodeSource __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
- IXMLNodeSource __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetFactory )(
- IXMLNodeSource __RPC_FAR * This,
- /* [in] */ IXMLNodeFactory __RPC_FAR *pNodeFactory);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetFactory )(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ IXMLNodeFactory __RPC_FAR *__RPC_FAR *ppNodeFactory);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Abort )(
- IXMLNodeSource __RPC_FAR * This,
- /* [in] */ BSTR bstrErrorInfo);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetLineNumber )(
- IXMLNodeSource __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetLinePosition )(
- IXMLNodeSource __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetAbsolutePosition )(
- IXMLNodeSource __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetLineBuffer )(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf,
- /* [out] */ ULONG __RPC_FAR *pulLen,
- /* [out] */ ULONG __RPC_FAR *pulStartPos);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetLastError )(
- IXMLNodeSource __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetErrorInfo )(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ BSTR __RPC_FAR *pbstrErrorInfo);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetFlags )(
- IXMLNodeSource __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetURL )(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf);
-
- END_INTERFACE
- } IXMLNodeSourceVtbl;
-
- interface IXMLNodeSource
- {
- CONST_VTBL struct IXMLNodeSourceVtbl __RPC_FAR *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define IXMLNodeSource_QueryInterface(This,riid,ppvObject) \
- (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
-
-#define IXMLNodeSource_AddRef(This) \
- (This)->lpVtbl -> AddRef(This)
-
-#define IXMLNodeSource_Release(This) \
- (This)->lpVtbl -> Release(This)
-
-
-#define IXMLNodeSource_SetFactory(This,pNodeFactory) \
- (This)->lpVtbl -> SetFactory(This,pNodeFactory)
-
-#define IXMLNodeSource_GetFactory(This,ppNodeFactory) \
- (This)->lpVtbl -> GetFactory(This,ppNodeFactory)
-
-#define IXMLNodeSource_Abort(This,bstrErrorInfo) \
- (This)->lpVtbl -> Abort(This,bstrErrorInfo)
-
-#define IXMLNodeSource_GetLineNumber(This) \
- (This)->lpVtbl -> GetLineNumber(This)
-
-#define IXMLNodeSource_GetLinePosition(This) \
- (This)->lpVtbl -> GetLinePosition(This)
-
-#define IXMLNodeSource_GetAbsolutePosition(This) \
- (This)->lpVtbl -> GetAbsolutePosition(This)
-
-#define IXMLNodeSource_GetLineBuffer(This,ppwcBuf,pulLen,pulStartPos) \
- (This)->lpVtbl -> GetLineBuffer(This,ppwcBuf,pulLen,pulStartPos)
-
-#define IXMLNodeSource_GetLastError(This) \
- (This)->lpVtbl -> GetLastError(This)
-
-#define IXMLNodeSource_GetErrorInfo(This,pbstrErrorInfo) \
- (This)->lpVtbl -> GetErrorInfo(This,pbstrErrorInfo)
-
-#define IXMLNodeSource_GetFlags(This) \
- (This)->lpVtbl -> GetFlags(This)
-
-#define IXMLNodeSource_GetURL(This,ppwcBuf) \
- (This)->lpVtbl -> GetURL(This,ppwcBuf)
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_SetFactory_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [in] */ IXMLNodeFactory __RPC_FAR *pNodeFactory);
-
-
-void __RPC_STUB IXMLNodeSource_SetFactory_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_GetFactory_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ IXMLNodeFactory __RPC_FAR *__RPC_FAR *ppNodeFactory);
-
-
-void __RPC_STUB IXMLNodeSource_GetFactory_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_Abort_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [in] */ BSTR bstrErrorInfo);
-
-
-void __RPC_STUB IXMLNodeSource_Abort_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-ULONG STDMETHODCALLTYPE IXMLNodeSource_GetLineNumber_Proxy(
- IXMLNodeSource __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLNodeSource_GetLineNumber_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-ULONG STDMETHODCALLTYPE IXMLNodeSource_GetLinePosition_Proxy(
- IXMLNodeSource __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLNodeSource_GetLinePosition_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-ULONG STDMETHODCALLTYPE IXMLNodeSource_GetAbsolutePosition_Proxy(
- IXMLNodeSource __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLNodeSource_GetAbsolutePosition_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_GetLineBuffer_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf,
- /* [out] */ ULONG __RPC_FAR *pulLen,
- /* [out] */ ULONG __RPC_FAR *pulStartPos);
-
-
-void __RPC_STUB IXMLNodeSource_GetLineBuffer_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_GetLastError_Proxy(
- IXMLNodeSource __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLNodeSource_GetLastError_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_GetErrorInfo_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ BSTR __RPC_FAR *pbstrErrorInfo);
-
-
-void __RPC_STUB IXMLNodeSource_GetErrorInfo_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-ULONG STDMETHODCALLTYPE IXMLNodeSource_GetFlags_Proxy(
- IXMLNodeSource __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLNodeSource_GetFlags_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeSource_GetURL_Proxy(
- IXMLNodeSource __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf);
-
-
-void __RPC_STUB IXMLNodeSource_GetURL_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-
-#endif /* __IXMLNodeSource_INTERFACE_DEFINED__ */
-
-
-#ifndef __IXMLParser_INTERFACE_DEFINED__
-#define __IXMLParser_INTERFACE_DEFINED__
-
-/* interface IXMLParser */
-/* [unique][helpstring][uuid][local][object] */
-
-
-EXTERN_C const IID IID_IXMLParser;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("d242361e-51a0-11d2-9caf-0060b0ec3d39")
- IXMLParser : public IXMLNodeSource
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE SetURL(
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fAsync) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Load(
- /* [in] */ BOOL fFullyAvailable,
- /* [in] */ IMoniker __RPC_FAR *pimkName,
- /* [in] */ LPBC pibc,
- /* [in] */ DWORD grfMode) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE SetInput(
- /* [in] */ IUnknown __RPC_FAR *pStm) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE PushData(
- /* [in] */ const char __RPC_FAR *pData,
- /* [in] */ ULONG ulChars,
- /* [in] */ BOOL fLastBuffer) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE LoadDTD(
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE LoadEntity(
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fpe) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE ParseEntity(
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen,
- /* [in] */ BOOL fpe) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE ExpandEntity(
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE SetRoot(
- /* [in] */ PVOID pRoot) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetRoot(
- /* [in] */ PVOID __RPC_FAR *ppRoot) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Run(
- /* [in] */ long lChars) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetParserState( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Suspend( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE SetFlags(
- /* [in] */ ULONG iFlags) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE SetSecureBaseURL(
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE GetSecureBaseURL(
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf) = 0;
-
- };
-
-#else /* C style interface */
-
- typedef struct IXMLParserVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
- IXMLParser __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetFactory )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ IXMLNodeFactory __RPC_FAR *pNodeFactory);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetFactory )(
- IXMLParser __RPC_FAR * This,
- /* [out] */ IXMLNodeFactory __RPC_FAR *__RPC_FAR *ppNodeFactory);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Abort )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ BSTR bstrErrorInfo);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetLineNumber )(
- IXMLParser __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetLinePosition )(
- IXMLParser __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetAbsolutePosition )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetLineBuffer )(
- IXMLParser __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf,
- /* [out] */ ULONG __RPC_FAR *pulLen,
- /* [out] */ ULONG __RPC_FAR *pulStartPos);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetLastError )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetErrorInfo )(
- IXMLParser __RPC_FAR * This,
- /* [out] */ BSTR __RPC_FAR *pbstrErrorInfo);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *GetFlags )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetURL )(
- IXMLParser __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetURL )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fAsync);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Load )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ BOOL fFullyAvailable,
- /* [in] */ IMoniker __RPC_FAR *pimkName,
- /* [in] */ LPBC pibc,
- /* [in] */ DWORD grfMode);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetInput )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ IUnknown __RPC_FAR *pStm);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *PushData )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const char __RPC_FAR *pData,
- /* [in] */ ULONG ulChars,
- /* [in] */ BOOL fLastBuffer);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *LoadDTD )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *LoadEntity )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fpe);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *ParseEntity )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen,
- /* [in] */ BOOL fpe);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *ExpandEntity )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetRoot )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ PVOID pRoot);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetRoot )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ PVOID __RPC_FAR *ppRoot);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Run )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ long lChars);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetParserState )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Suspend )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Reset )(
- IXMLParser __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetFlags )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ ULONG iFlags);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *SetSecureBaseURL )(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *GetSecureBaseURL )(
- IXMLParser __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf);
-
- END_INTERFACE
- } IXMLParserVtbl;
-
- interface IXMLParser
- {
- CONST_VTBL struct IXMLParserVtbl __RPC_FAR *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define IXMLParser_QueryInterface(This,riid,ppvObject) \
- (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
-
-#define IXMLParser_AddRef(This) \
- (This)->lpVtbl -> AddRef(This)
-
-#define IXMLParser_Release(This) \
- (This)->lpVtbl -> Release(This)
-
-
-#define IXMLParser_SetFactory(This,pNodeFactory) \
- (This)->lpVtbl -> SetFactory(This,pNodeFactory)
-
-#define IXMLParser_GetFactory(This,ppNodeFactory) \
- (This)->lpVtbl -> GetFactory(This,ppNodeFactory)
-
-#define IXMLParser_Abort(This,bstrErrorInfo) \
- (This)->lpVtbl -> Abort(This,bstrErrorInfo)
-
-#define IXMLParser_GetLineNumber(This) \
- (This)->lpVtbl -> GetLineNumber(This)
-
-#define IXMLParser_GetLinePosition(This) \
- (This)->lpVtbl -> GetLinePosition(This)
-
-#define IXMLParser_GetAbsolutePosition(This) \
- (This)->lpVtbl -> GetAbsolutePosition(This)
-
-#define IXMLParser_GetLineBuffer(This,ppwcBuf,pulLen,pulStartPos) \
- (This)->lpVtbl -> GetLineBuffer(This,ppwcBuf,pulLen,pulStartPos)
-
-#define IXMLParser_GetLastError(This) \
- (This)->lpVtbl -> GetLastError(This)
-
-#define IXMLParser_GetErrorInfo(This,pbstrErrorInfo) \
- (This)->lpVtbl -> GetErrorInfo(This,pbstrErrorInfo)
-
-#define IXMLParser_GetFlags(This) \
- (This)->lpVtbl -> GetFlags(This)
-
-#define IXMLParser_GetURL(This,ppwcBuf) \
- (This)->lpVtbl -> GetURL(This,ppwcBuf)
-
-
-#define IXMLParser_SetURL(This,pszBaseUrl,pszRelativeUrl,fAsync) \
- (This)->lpVtbl -> SetURL(This,pszBaseUrl,pszRelativeUrl,fAsync)
-
-#define IXMLParser_Load(This,fFullyAvailable,pimkName,pibc,grfMode) \
- (This)->lpVtbl -> Load(This,fFullyAvailable,pimkName,pibc,grfMode)
-
-#define IXMLParser_SetInput(This,pStm) \
- (This)->lpVtbl -> SetInput(This,pStm)
-
-#define IXMLParser_PushData(This,pData,ulChars,fLastBuffer) \
- (This)->lpVtbl -> PushData(This,pData,ulChars,fLastBuffer)
-
-#define IXMLParser_LoadDTD(This,pszBaseUrl,pszRelativeUrl) \
- (This)->lpVtbl -> LoadDTD(This,pszBaseUrl,pszRelativeUrl)
-
-#define IXMLParser_LoadEntity(This,pszBaseUrl,pszRelativeUrl,fpe) \
- (This)->lpVtbl -> LoadEntity(This,pszBaseUrl,pszRelativeUrl,fpe)
-
-#define IXMLParser_ParseEntity(This,pwcText,ulLen,fpe) \
- (This)->lpVtbl -> ParseEntity(This,pwcText,ulLen,fpe)
-
-#define IXMLParser_ExpandEntity(This,pwcText,ulLen) \
- (This)->lpVtbl -> ExpandEntity(This,pwcText,ulLen)
-
-#define IXMLParser_SetRoot(This,pRoot) \
- (This)->lpVtbl -> SetRoot(This,pRoot)
-
-#define IXMLParser_GetRoot(This,ppRoot) \
- (This)->lpVtbl -> GetRoot(This,ppRoot)
-
-#define IXMLParser_Run(This,lChars) \
- (This)->lpVtbl -> Run(This,lChars)
-
-#define IXMLParser_GetParserState(This) \
- (This)->lpVtbl -> GetParserState(This)
-
-#define IXMLParser_Suspend(This) \
- (This)->lpVtbl -> Suspend(This)
-
-#define IXMLParser_Reset(This) \
- (This)->lpVtbl -> Reset(This)
-
-#define IXMLParser_SetFlags(This,iFlags) \
- (This)->lpVtbl -> SetFlags(This,iFlags)
-
-#define IXMLParser_SetSecureBaseURL(This,pszBaseUrl) \
- (This)->lpVtbl -> SetSecureBaseURL(This,pszBaseUrl)
-
-#define IXMLParser_GetSecureBaseURL(This,ppwcBuf) \
- (This)->lpVtbl -> GetSecureBaseURL(This,ppwcBuf)
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_SetURL_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fAsync);
-
-
-void __RPC_STUB IXMLParser_SetURL_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_Load_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ BOOL fFullyAvailable,
- /* [in] */ IMoniker __RPC_FAR *pimkName,
- /* [in] */ LPBC pibc,
- /* [in] */ DWORD grfMode);
-
-
-void __RPC_STUB IXMLParser_Load_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_SetInput_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ IUnknown __RPC_FAR *pStm);
-
-
-void __RPC_STUB IXMLParser_SetInput_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_PushData_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const char __RPC_FAR *pData,
- /* [in] */ ULONG ulChars,
- /* [in] */ BOOL fLastBuffer);
-
-
-void __RPC_STUB IXMLParser_PushData_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_LoadDTD_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl);
-
-
-void __RPC_STUB IXMLParser_LoadDTD_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_LoadEntity_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl,
- /* [in] */ const WCHAR __RPC_FAR *pszRelativeUrl,
- /* [in] */ BOOL fpe);
-
-
-void __RPC_STUB IXMLParser_LoadEntity_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_ParseEntity_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen,
- /* [in] */ BOOL fpe);
-
-
-void __RPC_STUB IXMLParser_ParseEntity_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_ExpandEntity_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pwcText,
- /* [in] */ ULONG ulLen);
-
-
-void __RPC_STUB IXMLParser_ExpandEntity_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_SetRoot_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ PVOID pRoot);
-
-
-void __RPC_STUB IXMLParser_SetRoot_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_GetRoot_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ PVOID __RPC_FAR *ppRoot);
-
-
-void __RPC_STUB IXMLParser_GetRoot_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_Run_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ long lChars);
-
-
-void __RPC_STUB IXMLParser_Run_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_GetParserState_Proxy(
- IXMLParser __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLParser_GetParserState_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_Suspend_Proxy(
- IXMLParser __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLParser_Suspend_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_Reset_Proxy(
- IXMLParser __RPC_FAR * This);
-
-
-void __RPC_STUB IXMLParser_Reset_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_SetFlags_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ ULONG iFlags);
-
-
-void __RPC_STUB IXMLParser_SetFlags_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_SetSecureBaseURL_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [in] */ const WCHAR __RPC_FAR *pszBaseUrl);
-
-
-void __RPC_STUB IXMLParser_SetSecureBaseURL_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLParser_GetSecureBaseURL_Proxy(
- IXMLParser __RPC_FAR * This,
- /* [out] */ const WCHAR __RPC_FAR *__RPC_FAR *ppwcBuf);
-
-
-void __RPC_STUB IXMLParser_GetSecureBaseURL_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-
-#endif /* __IXMLParser_INTERFACE_DEFINED__ */
-
-
-#ifndef __IXMLNodeFactory_INTERFACE_DEFINED__
-#define __IXMLNodeFactory_INTERFACE_DEFINED__
-
-/* interface IXMLNodeFactory */
-/* [unique][helpstring][uuid][local][object] */
-
-
-EXTERN_C const IID IID_IXMLNodeFactory;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("d242361f-51a0-11d2-9caf-0060b0ec3d39")
- IXMLNodeFactory : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmpty,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE Error(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo) = 0;
-
- };
-
-#else /* C style interface */
-
- typedef struct IXMLNodeFactoryVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
- IXMLNodeFactory __RPC_FAR * This);
-
- ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
- IXMLNodeFactory __RPC_FAR * This);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *NotifyEvent )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *BeginChildren )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *EndChildren )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmpty,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Error )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo);
-
- HRESULT ( STDMETHODCALLTYPE __RPC_FAR *CreateNode )(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo);
-
- END_INTERFACE
- } IXMLNodeFactoryVtbl;
-
- interface IXMLNodeFactory
- {
- CONST_VTBL struct IXMLNodeFactoryVtbl __RPC_FAR *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define IXMLNodeFactory_QueryInterface(This,riid,ppvObject) \
- (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)
-
-#define IXMLNodeFactory_AddRef(This) \
- (This)->lpVtbl -> AddRef(This)
-
-#define IXMLNodeFactory_Release(This) \
- (This)->lpVtbl -> Release(This)
-
-
-#define IXMLNodeFactory_NotifyEvent(This,pSource,iEvt) \
- (This)->lpVtbl -> NotifyEvent(This,pSource,iEvt)
-
-#define IXMLNodeFactory_BeginChildren(This,pSource,pNodeInfo) \
- (This)->lpVtbl -> BeginChildren(This,pSource,pNodeInfo)
-
-#define IXMLNodeFactory_EndChildren(This,pSource,fEmpty,pNodeInfo) \
- (This)->lpVtbl -> EndChildren(This,pSource,fEmpty,pNodeInfo)
-
-#define IXMLNodeFactory_Error(This,pSource,hrErrorCode,cNumRecs,apNodeInfo) \
- (This)->lpVtbl -> Error(This,pSource,hrErrorCode,cNumRecs,apNodeInfo)
-
-#define IXMLNodeFactory_CreateNode(This,pSource,pNodeParent,cNumRecs,apNodeInfo) \
- (This)->lpVtbl -> CreateNode(This,pSource,pNodeParent,cNumRecs,apNodeInfo)
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeFactory_NotifyEvent_Proxy(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt);
-
-
-void __RPC_STUB IXMLNodeFactory_NotifyEvent_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeFactory_BeginChildren_Proxy(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo);
-
-
-void __RPC_STUB IXMLNodeFactory_BeginChildren_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeFactory_EndChildren_Proxy(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmpty,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo);
-
-
-void __RPC_STUB IXMLNodeFactory_EndChildren_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeFactory_Error_Proxy(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo);
-
-
-void __RPC_STUB IXMLNodeFactory_Error_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-HRESULT STDMETHODCALLTYPE IXMLNodeFactory_CreateNode_Proxy(
- IXMLNodeFactory __RPC_FAR * This,
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO __RPC_FAR *__RPC_FAR *apNodeInfo);
-
-
-void __RPC_STUB IXMLNodeFactory_CreateNode_Stub(
- IRpcStubBuffer *This,
- IRpcChannelBuffer *_pRpcChannelBuffer,
- PRPC_MESSAGE _pRpcMessage,
- DWORD *_pdwStubPhase);
-
-
-
-#endif /* __IXMLNodeFactory_INTERFACE_DEFINED__ */
-
-
-EXTERN_C const CLSID CLSID_XMLParser;
-
-#ifdef __cplusplus
-
-class DECLSPEC_UUID("d2423620-51a0-11d2-9caf-0060b0ec3d39")
-XMLParser;
-#endif
-#endif /* __XMLPSR_LIBRARY_DEFINED__ */
-
-/* Additional Prototypes for ALL interfaces */
-
-/* end of Additional Prototypes */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
diff --git a/src/inc/xmlparser_i.cpp b/src/inc/xmlparser_i.cpp
deleted file mode 100644
index 33927f651f..0000000000
--- a/src/inc/xmlparser_i.cpp
+++ /dev/null
@@ -1,86 +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.
-
-/* This was a created file from a newer version of xmlparser.idl than
- what made xmlparser.h in ndp/clr/src/inc, and then with extra
- GUIDs expurgated. */
-
-/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
-
-/* link this file in with the server and any clients */
-
-
- /* File created by MIDL compiler version 8.00.0571 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#ifdef _MSC_VER
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-#endif
-
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#include <rpc.h>
-#include <rpcndr.h>
-
-#ifdef _MIDL_USE_GUIDDEF_
-
-#ifndef INITGUID
-#define INITGUID
-#include <guiddef.h>
-#undef INITGUID
-#else
-#include <guiddef.h>
-#endif
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
-
-#else // !_MIDL_USE_GUIDDEF_
-
-#ifndef __IID_DEFINED__
-#define __IID_DEFINED__
-
-typedef struct _IID
-{
- unsigned long x;
- unsigned short s1;
- unsigned short s2;
- unsigned char c[8];
-} IID;
-
-#endif // __IID_DEFINED__
-
-#ifndef CLSID_DEFINED
-#define CLSID_DEFINED
-typedef IID CLSID;
-#endif // CLSID_DEFINED
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-
-#endif // !_MIDL_USE_GUIDDEF_
-
-MIDL_DEFINE_GUID(IID, LIBID_XMLPSR,0xd242361c,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
-
-
-MIDL_DEFINE_GUID(IID, IID_IXMLNodeSource,0xd242361d,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
-
-
-MIDL_DEFINE_GUID(IID, IID_IXMLParser,0xd242361e,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
-
-
-MIDL_DEFINE_GUID(IID, IID_IXMLNodeFactory,0xd242361f,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
-
-#undef MIDL_DEFINE_GUID
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
diff --git a/src/jit/CMakeLists.txt b/src/jit/CMakeLists.txt
index a6efcd8e24..32c6065c52 100644
--- a/src/jit/CMakeLists.txt
+++ b/src/jit/CMakeLists.txt
@@ -6,7 +6,7 @@ include_directories("../inc")
if (CLR_CMAKE_TARGET_ARCH_AMD64 OR (CLR_CMAKE_TARGET_ARCH_I386 AND NOT CLR_CMAKE_PLATFORM_UNIX))
add_definitions(-DFEATURE_SIMD)
- add_definitions(-DFEATURE_AVX_SUPPORT)
+ add_definitions(-DFEATURE_HW_INTRINSICS)
endif ()
# JIT_BUILD disables certain PAL_TRY debugging features
@@ -101,6 +101,7 @@ set( JIT_AMD64_SOURCES
targetamd64.cpp
unwindamd64.cpp
hwintrinsicxarch.cpp
+ hwintrinsiccodegenxarch.cpp
)
set( JIT_ARM_SOURCES
@@ -129,6 +130,7 @@ set( JIT_I386_SOURCES
targetx86.cpp
unwindx86.cpp
hwintrinsicxarch.cpp
+ hwintrinsiccodegenxarch.cpp
)
set( JIT_ARM64_SOURCES
@@ -261,6 +263,11 @@ if (CLR_CMAKE_PLATFORM_ARCH_I386 OR CLR_CMAKE_PLATFORM_ARCH_AMD64)
add_subdirectory(protononjit)
endif ()
+if (CLR_CMAKE_PLATFORM_ARCH_I386)
+ # On x86, build RyuJIT/ARM32 cross-compiling altjit for ARM_SOFTFP (armel).
+ add_subdirectory(armelnonjit)
+endif ()
+
if ((CLR_CMAKE_PLATFORM_ARCH_I386 OR CLR_CMAKE_PLATFORM_ARCH_AMD64) AND WIN32)
# On Windows, build altjit that targets the Linux ABI:
# On x86, build Linux/x86 altjit. This enables UNIX_X86_ABI.
diff --git a/src/jit/DIRS.proj b/src/jit/DIRS.proj
index 539743cc6e..b09e433dc0 100644
--- a/src/jit/DIRS.proj
+++ b/src/jit/DIRS.proj
@@ -39,6 +39,7 @@
<ProjectFile Condition="'$(BuildArchitecture)' == 'amd64'" Include="arm64altjit\arm64altjit.nativeproj" />
<ProjectFile Condition="'$(BuildArchitecture)' == 'i386'" Include="protojit\protojit.nativeproj" />
<ProjectFile Condition="'$(BuildArchitecture)' == 'i386'" Include="protononjit\protononjit.nativeproj" />
+ <!-- <ProjectFile Condition="'$(BuildArchitecture)' == 'i386'" Include="armelnonjit\armelnonjit.nativeproj" /> -->
</ItemGroup>
<!--Import the targets-->
diff --git a/src/jit/ICorJitInfo_API_names.h b/src/jit/ICorJitInfo_API_names.h
index fe86ea2e06..620e0dcfb8 100644
--- a/src/jit/ICorJitInfo_API_names.h
+++ b/src/jit/ICorJitInfo_API_names.h
@@ -169,5 +169,6 @@ DEF_CLR_API(getExpectedTargetArchitecture)
DEF_CLR_API(resolveVirtualMethod)
DEF_CLR_API(expandRawHandleIntrinsic)
DEF_CLR_API(getDefaultEqualityComparerClass)
+DEF_CLR_API(getUnboxedEntry)
#undef DEF_CLR_API
diff --git a/src/jit/ICorJitInfo_API_wrapper.hpp b/src/jit/ICorJitInfo_API_wrapper.hpp
index 69311a5917..3ab72b9994 100644
--- a/src/jit/ICorJitInfo_API_wrapper.hpp
+++ b/src/jit/ICorJitInfo_API_wrapper.hpp
@@ -1620,6 +1620,17 @@ CORINFO_METHOD_HANDLE WrapICorJitInfo::resolveVirtualMethod(
return result;
}
+CORINFO_METHOD_HANDLE WrapICorJitInfo::getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn, /* IN */
+ bool* requiresInstMethodTableArg /* OUT */
+)
+{
+ API_ENTER(getUnboxedEntry);
+ CORINFO_METHOD_HANDLE result = wrapHnd->getUnboxedEntry(ftn, requiresInstMethodTableArg);
+ API_LEAVE(getUnboxedEntry);
+ return result;
+}
+
CORINFO_CLASS_HANDLE WrapICorJitInfo::getDefaultEqualityComparerClass(
CORINFO_CLASS_HANDLE elemType)
{
diff --git a/src/jit/armelnonjit/.gitmirror b/src/jit/armelnonjit/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/jit/armelnonjit/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/jit/armelnonjit/CMakeLists.txt b/src/jit/armelnonjit/CMakeLists.txt
new file mode 100644
index 0000000000..9ee4b8ffc0
--- /dev/null
+++ b/src/jit/armelnonjit/CMakeLists.txt
@@ -0,0 +1,90 @@
+project(armelnonjit)
+
+add_definitions(-DALT_JIT)
+add_definitions(-DFEATURE_NO_HOST)
+add_definitions(-DSELF_NO_HOST)
+remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
+
+remove_definitions(-DFEATURE_SIMD)
+remove_definitions(-DFEATURE_HW_INTRINSICS)
+
+if(FEATURE_READYTORUN)
+ add_definitions(-DFEATURE_READYTORUN_COMPILER)
+endif(FEATURE_READYTORUN)
+
+if (CLR_CMAKE_PLATFORM_ARCH_I386)
+ remove_definitions(-D_TARGET_X86_=1)
+ add_definitions(-D_TARGET_ARM_)
+ add_definitions(-DARM_SOFTFP=1)
+ set(JIT_ARCH_ALTJIT_SOURCES ${JIT_ARM_SOURCES})
+ set(JIT_ARCH_LINK_LIBRARIES gcinfo_arm)
+elseif(CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ remove_definitions(-D_TARGET_AMD64_=1)
+ add_definitions(-D_TARGET_ARM64_)
+ set(JIT_ARCH_ALTJIT_SOURCES ${JIT_ARM64_SOURCES})
+ set(JIT_ARCH_LINK_LIBRARIES gcinfo_arm64)
+else()
+ clr_unknown_arch()
+endif()
+
+if (NOT WIN32)
+ if (CLR_CMAKE_PLATFORM_ARCH_I386)
+ remove_definitions(-DUNIX_X86_ABI)
+ elseif(CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ remove_definitions(-DUNIX_AMD64_ABI)
+ remove_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING)
+ else()
+ clr_unknown_arch()
+ endif()
+endif(NOT WIN32)
+
+if(WIN32)
+ add_definitions(-DFX_VER_INTERNALNAME_STR=armelnonjit.dll)
+endif(WIN32)
+
+add_library_clr(armelnonjit
+ SHARED
+ ${SHARED_LIB_SOURCES}
+ ${JIT_ARCH_ALTJIT_SOURCES}
+)
+
+add_dependencies(armelnonjit jit_exports)
+
+set_property(TARGET armelnonjit APPEND_STRING PROPERTY LINK_FLAGS ${JIT_EXPORTS_LINKER_OPTION})
+set_property(TARGET armelnonjit APPEND_STRING PROPERTY LINK_DEPENDS ${JIT_EXPORTS_FILE})
+
+set(RYUJIT_LINK_LIBRARIES
+ utilcodestaticnohost
+ ${JIT_ARCH_LINK_LIBRARIES}
+)
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ list(APPEND RYUJIT_LINK_LIBRARIES
+ mscorrc_debug
+ coreclrpal
+ palrt
+ )
+else()
+ list(APPEND RYUJIT_LINK_LIBRARIES
+ ${STATIC_MT_CRT_LIB}
+ ${STATIC_MT_VCRT_LIB}
+ kernel32.lib
+ advapi32.lib
+ ole32.lib
+ oleaut32.lib
+ uuid.lib
+ user32.lib
+ version.lib
+ shlwapi.lib
+ bcrypt.lib
+ crypt32.lib
+ RuntimeObject.lib
+ )
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+target_link_libraries(armelnonjit
+ ${RYUJIT_LINK_LIBRARIES}
+)
+
+# add the install targets
+install_clr(armelnonjit)
diff --git a/src/jit/armelnonjit/SOURCES b/src/jit/armelnonjit/SOURCES
new file mode 100644
index 0000000000..d0c01e7506
--- /dev/null
+++ b/src/jit/armelnonjit/SOURCES
@@ -0,0 +1,10 @@
+
+#
+# DO NOT EDIT THIS FILE!!! Modify the project file in this directory
+# This file merely allows the MSBuild project file in this directory to be integrated with Build.Exe
+#
+TARGETTYPE=NOTARGET
+CLR_TARGETTYPE=DLL
+MSBuildProjectFile=armelnonjit.nativeproj
+SOURCES=
+ \ No newline at end of file
diff --git a/src/jit/armelnonjit/armelnonjit.def b/src/jit/armelnonjit/armelnonjit.def
new file mode 100644
index 0000000000..1603af74ca
--- /dev/null
+++ b/src/jit/armelnonjit/armelnonjit.def
@@ -0,0 +1,7 @@
+; 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.
+EXPORTS
+ getJit
+ jitStartup
+ sxsJitStartup
diff --git a/src/jit/armelnonjit/armelnonjit.nativeproj b/src/jit/armelnonjit/armelnonjit.nativeproj
new file mode 100644
index 0000000000..e5d598a8f1
--- /dev/null
+++ b/src/jit/armelnonjit/armelnonjit.nativeproj
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+
+ <!--
+ PROTO JIT: The purpose of this module is to provide an isolated environment to develop
+ the RyuJIT backend without interfering with the development of the frontend. The
+ idea is to fork codegen and registerfp, that way we leave the PUCLR backend intact so
+ it can be still consumed by the RyuJIT frontend separately maintaining the code stability
+ of the PUCLR codegen.cpp logic.
+
+ This module is meant to be used as a throwaway or fallback cross-JIT (x86 -> arm) that will just
+ attempt to generate arm code, throw it away and then re-jit using the default jit on x86.
+ -->
+
+ <!--
+ Note that we are defining TargetArch directly because of altjit is not a real fully functional cross
+ compiled binary. It is just a convenience workaround for JIT devs.
+ -->
+ <PropertyGroup>
+ <TargetArch>arm</TargetArch>
+ </PropertyGroup>
+
+ <!-- Import the CLR's settings -->
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+
+ <PropertyGroup>
+
+ <!-- Set the output -->
+
+ <OutputName>armelnonjit</OutputName>
+ <FeatureMergeJitAndEngine>false</FeatureMergeJitAndEngine>
+ <TargetType>DYNLINK</TargetType>
+ <BuildCoreBinaries>false</BuildCoreBinaries>
+ <BuildSysBinaries>false</BuildSysBinaries>
+
+ <!-- Motherhood & apple pie here -->
+
+ <DllEntryPoint>_DllMainCRTStartup</DllEntryPoint>
+ <LinkSubsystem>windows</LinkSubsystem>
+ <LibCLib Condition="'$(FeatureMergeJitAndEngine)'!='true'">$(ClrCrtLib)</LibCLib>
+
+ <!-- JIT specific baloney -->
+
+ <LinkModuleDefinitionFile>$(OutputName).def</LinkModuleDefinitionFile>
+
+ <ClDefines>$(ClDefines);_TARGET_ARM_=1</ClDefines>
+ <ClDefines>$(ClDefines);ALT_JIT</ClDefines>
+
+ <Win32DllLibs>$(SdkLibPath)\kernel32.lib;$(SdkLibPath)\user32.lib;$(SdkLibPath)\advapi32.lib;$(SdkLibPath)\oleaut32.lib;$(SdkLibPath)\uuid.lib</Win32DllLibs>
+ <Win32DllLibs>$(Win32DllLibs);$(ClrLibPath)\utilcode.lib</Win32DllLibs>
+
+ <!-- Profile-guided optimization -->
+
+ <PogoOptimize>false</PogoOptimize>
+ <PogoInstrument>false</PogoInstrument>
+ <PogoUpdate>false</PogoUpdate>
+
+ <!-- Do we want to build with msvcdis disassembly? This should be enabled for DEBUG, disabled otherwise.
+ However, it can be useful to enable it temporarily in non-DEBUG builds, by changing the EnableLateDisasm property.
+ -->
+ <EnableLateDisasm>false</EnableLateDisasm>
+ <ClDefines Condition="'$(EnableLateDisasm)' == 'true'">$(ClDefines);LATE_DISASM=1</ClDefines>
+ <LinkDelayLoad Condition="'$(EnableLateDisasm)' == 'true'">$(LinkDelayLoad);msvcdis$(VC_NONCRT_ProdVerX).dll</LinkDelayLoad>
+ <UseDelayimpLib Condition="'$(EnableLateDisasm)' == 'true' and '$(FeatureMergeJitAndEngine)'!='true'">true</UseDelayimpLib>
+
+ </PropertyGroup>
+
+ <!-- Leaf Project Items -->
+ <ItemGroup>
+ <ProjectReference Include="$(ClrSrcDirectory)utilcode\dyncrt\dyncrt.nativeproj" />
+ <TargetLib Include="$(SdkLibPath)\mscoree.lib" />
+ <TargetLib Include="$(ClrLibPath)\ArmGCInfo.lib">
+ <ProjectReference>$(ClrSrcDirectory)gcinfo\armlib\ArmGCInfo.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(UseDelayimpLib)' == 'true'" Include="$(ClrLibPath)\delayimp.lib">
+ <ProjectReference>$(ClrSrcDirectory)delayimp\delayimp.nativeproj</ProjectReference>
+ </TargetLib>
+ <TargetLib Condition="'$(DebugBuild)' == 'true'" Include="$(SdkLibPath)\ole32.lib" />
+ <TargetLib Condition="'$(EnableLateDisasm)' == 'true'" Include="$(VCToolsLibPath)\msvcdis.lib" />
+ <RCResourceFile Include="..\native.rc" />
+ </ItemGroup>
+
+ <Import Project="..\jit.settings.targets" />
+
+</Project>
diff --git a/src/jit/armelnonjit/makefile b/src/jit/armelnonjit/makefile
new file mode 100644
index 0000000000..bf27e8c84b
--- /dev/null
+++ b/src/jit/armelnonjit/makefile
@@ -0,0 +1,7 @@
+
+#
+# DO NOT EDIT THIS FILE!!! Modify the project file in this directory
+# This file merely allows the MSBuild project file in this directory to be integrated with Build.Exe
+#
+
+!INCLUDE $(NTMAKEENV)\devdiv.def
diff --git a/src/jit/assertionprop.cpp b/src/jit/assertionprop.cpp
index ed49e841ea..712d7c0473 100644
--- a/src/jit/assertionprop.cpp
+++ b/src/jit/assertionprop.cpp
@@ -26,7 +26,7 @@ Compiler::fgWalkResult Compiler::optAddCopiesCallback(GenTreePtr* pTree, fgWalkD
{
GenTreePtr tree = *pTree;
- if (tree->OperKind() & GTK_ASGOP)
+ if (tree->OperIsAssignment())
{
GenTreePtr op1 = tree->gtOp.gtOp1;
Compiler* comp = data->compiler;
@@ -455,7 +455,7 @@ void Compiler::optAddCopies()
GenTreePtr tree = optAddCopyAsgnNode;
GenTreePtr op1 = tree->gtOp.gtOp1;
- noway_assert(tree && op1 && (tree->OperKind() & GTK_ASGOP) && (op1->gtOper == GT_LCL_VAR) &&
+ noway_assert(tree && op1 && tree->OperIsAssignment() && (op1->gtOper == GT_LCL_VAR) &&
(op1->gtLclVarCommon.gtLclNum == lclNum));
/* TODO-Review: BB_UNITY_WEIGHT is not the correct block weight */
@@ -4782,7 +4782,9 @@ Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, Gen
case GT_RSH:
case GT_RSZ:
case GT_NEG:
+#ifdef LEGACY_BACKEND
case GT_CHS:
+#endif
case GT_CAST:
case GT_INTRINSIC:
break;
diff --git a/src/jit/codegen.h b/src/jit/codegen.h
index 6261e42a14..879ee7bfa6 100644
--- a/src/jit/codegen.h
+++ b/src/jit/codegen.h
@@ -141,6 +141,7 @@ private:
}
#endif // REG_OPT_RSVD
+#ifdef LEGACY_BACKEND
regNumber findStkLclInReg(unsigned lclNum)
{
#ifdef DEBUG
@@ -148,6 +149,7 @@ private:
#endif
return regTracker.rsLclIsInReg(lclNum);
}
+#endif
//-------------------------------------------------------------------------
@@ -817,7 +819,9 @@ protected:
public:
void instInit();
+#ifdef LEGACY_BACKEND
regNumber genGetZeroRegister();
+#endif
void instGen(instruction ins);
#ifdef _TARGET_XARCH_
diff --git a/src/jit/codegenarm.cpp b/src/jit/codegenarm.cpp
index bc91b5d8d2..69640b739d 100644
--- a/src/jit/codegenarm.cpp
+++ b/src/jit/codegenarm.cpp
@@ -142,8 +142,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
GenTreeIntConCommon* con = tree->AsIntConCommon();
ssize_t cnsVal = con->IconValue();
- bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
- if (needReloc)
+ if (con->ImmedValNeedsReloc(compiler))
{
instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
regTracker.rsTrackRegTrash(targetReg);
@@ -893,9 +892,18 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
for (unsigned i = 0; i < slots; ++i)
{
if (gcPtrs[i] == GCT_GCREF)
+ {
attr = EA_GCREF;
+ }
else if (gcPtrs[i] == GCT_BYREF)
+ {
attr = EA_BYREF;
+ }
+ else
+ {
+ attr = EA_PTRSIZE;
+ }
+
emit->emitIns_R_R_I(INS_ldr, attr, tmpReg, REG_WRITE_BARRIER_SRC_BYREF, TARGET_POINTER_SIZE,
INS_FLAGS_DONT_CARE, INS_OPTS_LDST_POST_INC);
emit->emitIns_R_R_I(INS_str, attr, tmpReg, REG_WRITE_BARRIER_DST_BYREF, TARGET_POINTER_SIZE,
@@ -1712,7 +1720,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
}
regTracker.rsTrashRegSet(RBM_CALLEE_TRASH);
- regTracker.rsTrashRegsForGCInterruptability();
}
//------------------------------------------------------------------------
diff --git a/src/jit/codegenarm64.cpp b/src/jit/codegenarm64.cpp
index 8d21ae3b56..d559c92c81 100644
--- a/src/jit/codegenarm64.cpp
+++ b/src/jit/codegenarm64.cpp
@@ -1447,8 +1447,7 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
GenTreeIntConCommon* con = tree->AsIntConCommon();
ssize_t cnsVal = con->IconValue();
- bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
- if (needReloc)
+ if (con->ImmedValNeedsReloc(compiler))
{
instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, targetReg, cnsVal);
regTracker.rsTrackRegTrash(targetReg);
@@ -2665,62 +2664,209 @@ void CodeGen::genJumpTable(GenTree* treeNode)
// GT_LOCKADD, GT_XCHG, GT_XADD
void CodeGen::genLockedInstructions(GenTreeOp* treeNode)
{
-#if 0
- GenTree* data = treeNode->gtOp.gtOp2;
- GenTree* addr = treeNode->gtOp.gtOp1;
+ GenTree* data = treeNode->gtOp.gtOp2;
+ GenTree* addr = treeNode->gtOp.gtOp1;
regNumber targetReg = treeNode->gtRegNum;
regNumber dataReg = data->gtRegNum;
regNumber addrReg = addr->gtRegNum;
- instruction ins;
- // all of these nodes implicitly do an indirection on op1
- // so create a temporary node to feed into the pattern matching
- GenTreeIndir i = indirForm(data->TypeGet(), addr);
- genConsumeReg(addr);
+ regNumber exResultReg = treeNode->ExtractTempReg(RBM_ALLINT);
+ regNumber storeDataReg = (treeNode->OperGet() == GT_XCHG) ? dataReg : treeNode->ExtractTempReg(RBM_ALLINT);
+ regNumber loadReg = (targetReg != REG_NA) ? targetReg : storeDataReg;
- // The register allocator should have extended the lifetime of the address
- // so that it is not used as the target.
+ // Check allocator assumptions
+ //
+ // The register allocator should have extended the lifetimes of all input and internal registers so that
+ // none interfere with the target.
noway_assert(addrReg != targetReg);
- // If data is a lclVar that's not a last use, we'd better have allocated a register
- // for the result (except in the case of GT_LOCKADD which does not produce a register result).
- assert(targetReg != REG_NA || treeNode->OperGet() == GT_LOCKADD || !genIsRegCandidateLocal(data) || (data->gtFlags & GTF_VAR_DEATH) != 0);
+ noway_assert(addrReg != loadReg);
+ noway_assert(dataReg != loadReg);
- genConsumeIfReg(data);
- if (targetReg != REG_NA && dataReg != REG_NA && dataReg != targetReg)
- {
- inst_RV_RV(ins_Copy(data->TypeGet()), targetReg, dataReg);
- data->gtRegNum = targetReg;
+ noway_assert(addrReg != storeDataReg);
+ noway_assert((treeNode->OperGet() == GT_XCHG) || (addrReg != dataReg));
+
+ assert(addr->isUsedFromReg());
+ noway_assert(exResultReg != REG_NA);
+ noway_assert(exResultReg != targetReg);
+ noway_assert((targetReg != REG_NA) || (treeNode->OperGet() != GT_XCHG));
+
+ // Store exclusive unpredictable cases must be avoided
+ noway_assert(exResultReg != storeDataReg);
+ noway_assert(exResultReg != addrReg);
+
+ genConsumeAddress(addr);
+ genConsumeRegs(data);
+
+ // NOTE: `genConsumeAddress` marks the consumed register as not a GC pointer, as it assumes that the input registers
+ // die at the first instruction generated by the node. This is not the case for these atomics as the input
+ // registers are multiply-used. As such, we need to mark the addr register as containing a GC pointer until
+ // we are finished generating the code for this node.
+
+ gcInfo.gcMarkRegPtrVal(addrReg, addr->TypeGet());
+
+ // TODO-ARM64-CQ Use ARMv8.1 atomics if available
+ // https://github.com/dotnet/coreclr/issues/11881
+
+ // Emit code like this:
+ // retry:
+ // ldxr loadReg, [addrReg]
+ // add storeDataReg, loadReg, dataReg # Only for GT_XADD & GT_LOCKADD
+ // # GT_XCHG storeDataReg === dataReg
+ // stxr exResult, storeDataReg, [addrReg]
+ // cbnz exResult, retry
+
+ BasicBlock* labelRetry = genCreateTempLabel();
+ genDefineTempLabel(labelRetry);
+
+ emitAttr dataSize = emitActualTypeSize(data);
+ // The following instruction includes a acquire half barrier
+ // TODO-ARM64-CQ Evaluate whether this is necessary
+ // https://github.com/dotnet/coreclr/issues/14346
+ getEmitter()->emitIns_R_R(INS_ldaxr, dataSize, loadReg, addrReg);
- // TODO-ARM64-Cleanup: Consider whether it is worth it, for debugging purposes, to restore the
- // original gtRegNum on data, after calling emitInsBinary below.
- }
switch (treeNode->OperGet())
{
- case GT_LOCKADD:
- instGen(INS_lock);
- ins = INS_add;
- break;
- case GT_XCHG:
- // lock is implied by xchg
- ins = INS_xchg;
- break;
- case GT_XADD:
- instGen(INS_lock);
- ins = INS_xadd;
- break;
- default:
- unreached();
+ case GT_XADD:
+ case GT_LOCKADD:
+ if (data->isContainedIntOrIImmed())
+ {
+ // Even though INS_add is specified here, the encoder will choose either
+ // an INS_add or an INS_sub and encode the immediate as a positive value
+ genInstrWithConstant(INS_add, dataSize, storeDataReg, loadReg, data->AsIntConCommon()->IconValue(),
+ REG_NA);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R_R(INS_add, dataSize, storeDataReg, loadReg, dataReg);
+ }
+ break;
+ case GT_XCHG:
+ assert(!data->isContained());
+ storeDataReg = dataReg;
+ break;
+ default:
+ unreached();
}
- getEmitter()->emitInsBinary(ins, emitActualTypeSize(data), &i, data);
+
+ // The following instruction includes a release half barrier
+ // TODO-ARM64-CQ Evaluate whether this is necessary
+ // https://github.com/dotnet/coreclr/issues/14346
+ getEmitter()->emitIns_R_R_R(INS_stlxr, dataSize, exResultReg, storeDataReg, addrReg);
+
+ getEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, labelRetry, exResultReg);
+
+ gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask());
if (treeNode->gtRegNum != REG_NA)
{
genProduceReg(treeNode);
}
-#else // !0
- NYI("genLockedInstructions");
-#endif // !0
+}
+
+//------------------------------------------------------------------------
+// genCodeForSwap: Produce code for a GT_CMPXCHG node.
+//
+// Arguments:
+// tree - the GT_CMPXCHG node
+//
+void CodeGen::genCodeForCmpXchg(GenTreeCmpXchg* treeNode)
+{
+ assert(treeNode->OperIs(GT_CMPXCHG));
+
+ GenTreePtr addr = treeNode->gtOpLocation; // arg1
+ GenTreePtr data = treeNode->gtOpValue; // arg2
+ GenTreePtr comparand = treeNode->gtOpComparand; // arg3
+
+ regNumber targetReg = treeNode->gtRegNum;
+ regNumber dataReg = data->gtRegNum;
+ regNumber addrReg = addr->gtRegNum;
+ regNumber comparandReg = comparand->gtRegNum;
+ regNumber exResultReg = treeNode->ExtractTempReg(RBM_ALLINT);
+
+ // Check allocator assumptions
+ //
+ // The register allocator should have extended the lifetimes of all input and internal registers so that
+ // none interfere with the target.
+ noway_assert(addrReg != targetReg);
+ noway_assert(dataReg != targetReg);
+ noway_assert(comparandReg != targetReg);
+ noway_assert(addrReg != dataReg);
+ noway_assert(targetReg != REG_NA);
+ noway_assert(exResultReg != REG_NA);
+ noway_assert(exResultReg != targetReg);
+
+ assert(addr->isUsedFromReg());
+ assert(data->isUsedFromReg());
+ assert(!comparand->isUsedFromMemory());
+
+ // Store exclusive unpredictable cases must be avoided
+ noway_assert(exResultReg != dataReg);
+ noway_assert(exResultReg != addrReg);
+
+ genConsumeAddress(addr);
+ genConsumeRegs(data);
+ genConsumeRegs(comparand);
+
+ // NOTE: `genConsumeAddress` marks the consumed register as not a GC pointer, as it assumes that the input registers
+ // die at the first instruction generated by the node. This is not the case for these atomics as the input
+ // registers are multiply-used. As such, we need to mark the addr register as containing a GC pointer until
+ // we are finished generating the code for this node.
+
+ gcInfo.gcMarkRegPtrVal(addrReg, addr->TypeGet());
+
+ // TODO-ARM64-CQ Use ARMv8.1 atomics if available
+ // https://github.com/dotnet/coreclr/issues/11881
+
+ // Emit code like this:
+ // retry:
+ // ldxr targetReg, [addrReg]
+ // cmp targetReg, comparandReg
+ // bne compareFail
+ // stxr exResult, dataReg, [addrReg]
+ // cbnz exResult, retry
+ // compareFail:
+
+ BasicBlock* labelRetry = genCreateTempLabel();
+ BasicBlock* labelCompareFail = genCreateTempLabel();
+ genDefineTempLabel(labelRetry);
+
+ // The following instruction includes a acquire half barrier
+ // TODO-ARM64-CQ Evaluate whether this is necessary
+ // https://github.com/dotnet/coreclr/issues/14346
+ getEmitter()->emitIns_R_R(INS_ldaxr, emitTypeSize(treeNode), targetReg, addrReg);
+
+ if (comparand->isContainedIntOrIImmed())
+ {
+ if (comparand->IsIntegralConst(0))
+ {
+ getEmitter()->emitIns_J_R(INS_cbnz, emitActualTypeSize(treeNode), labelCompareFail, targetReg);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_I(INS_cmp, emitActualTypeSize(treeNode), targetReg,
+ comparand->AsIntConCommon()->IconValue());
+ getEmitter()->emitIns_J(INS_bne, labelCompareFail);
+ }
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R(INS_cmp, emitActualTypeSize(treeNode), targetReg, comparandReg);
+ getEmitter()->emitIns_J(INS_bne, labelCompareFail);
+ }
+
+ // The following instruction includes a release half barrier
+ // TODO-ARM64-CQ Evaluate whether this is necessary
+ // https://github.com/dotnet/coreclr/issues/14346
+ getEmitter()->emitIns_R_R_R(INS_stlxr, emitTypeSize(treeNode), exResultReg, dataReg, addrReg);
+
+ getEmitter()->emitIns_J_R(INS_cbnz, EA_4BYTE, labelRetry, exResultReg);
+
+ genDefineTempLabel(labelCompareFail);
+
+ gcInfo.gcMarkRegSetNpt(addr->gtGetRegMask());
+
+ genProduceReg(treeNode);
}
instruction CodeGen::genGetInsForOper(genTreeOps oper, var_types type)
@@ -3298,40 +3444,6 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
assert(!op1->isUsedFromMemory());
assert(!op2->isUsedFromMemory());
- // Case of op1 == 0 or op1 != 0:
- // Optimize generation of 'test' instruction if op1 sets flags.
- //
- // This behavior is designed to match the unexpected behavior
- // of XARCH genCompareInt();
- //
- // TODO-Cleanup Review GTF_USE_FLAGS usage
- // https://github.com/dotnet/coreclr/issues/14093
- if ((tree->gtFlags & GTF_USE_FLAGS) != 0)
- {
- // op1 must set flags
- assert(op1->gtSetFlags());
-
- // Must be compare against zero.
- assert(!tree->OperIs(GT_TEST_EQ, GT_TEST_NE));
- assert(op2->IsIntegralConst(0));
- assert(op2->isContained());
-
- // Just consume the operands
- genConsumeOperands(tree);
-
- // No need to generate compare instruction since
- // op1 sets flags
-
- // Are we evaluating this into a register?
- if (targetReg != REG_NA)
- {
- genSetRegToCond(targetReg, tree);
- genProduceReg(tree);
- }
-
- return;
- }
-
genConsumeOperands(tree);
emitAttr cmpSize = EA_ATTR(genTypeSize(op1Type));
@@ -3577,9 +3689,990 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
regMaskTP killMask = compiler->compHelperCallKillSet((CorInfoHelpFunc)helper);
regTracker.rsTrashRegSet(killMask);
- regTracker.rsTrashRegsForGCInterruptability();
}
+#ifdef FEATURE_SIMD
+
+//------------------------------------------------------------------------
+// genSIMDIntrinsic: Generate code for a SIMD Intrinsic. This is the main
+// routine which in turn calls apropriate genSIMDIntrinsicXXX() routine.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+// Notes:
+// Currently, we only recognize SIMDVector<float> and SIMDVector<int>, and
+// a limited set of methods.
+//
+// TODO-CLEANUP Merge all versions of this function and move to new file simdcodegencommon.cpp.
+void CodeGen::genSIMDIntrinsic(GenTreeSIMD* simdNode)
+{
+ // NYI for unsupported base types
+ if (simdNode->gtSIMDBaseType != TYP_INT && simdNode->gtSIMDBaseType != TYP_LONG &&
+ simdNode->gtSIMDBaseType != TYP_FLOAT && simdNode->gtSIMDBaseType != TYP_DOUBLE &&
+ simdNode->gtSIMDBaseType != TYP_CHAR && simdNode->gtSIMDBaseType != TYP_UBYTE &&
+ simdNode->gtSIMDBaseType != TYP_SHORT && simdNode->gtSIMDBaseType != TYP_BYTE &&
+ simdNode->gtSIMDBaseType != TYP_UINT && simdNode->gtSIMDBaseType != TYP_ULONG)
+ {
+ noway_assert(!"SIMD intrinsic with unsupported base type.");
+ }
+
+ switch (simdNode->gtSIMDIntrinsicID)
+ {
+ case SIMDIntrinsicInit:
+ genSIMDIntrinsicInit(simdNode);
+ break;
+
+ case SIMDIntrinsicInitN:
+ genSIMDIntrinsicInitN(simdNode);
+ break;
+
+ case SIMDIntrinsicSqrt:
+ case SIMDIntrinsicAbs:
+ case SIMDIntrinsicCast:
+ case SIMDIntrinsicConvertToSingle:
+ case SIMDIntrinsicConvertToInt32:
+ case SIMDIntrinsicConvertToUInt32:
+ case SIMDIntrinsicConvertToDouble:
+ case SIMDIntrinsicConvertToInt64:
+ case SIMDIntrinsicConvertToUInt64:
+ genSIMDIntrinsicUnOp(simdNode);
+ break;
+
+ case SIMDIntrinsicWidenLo:
+ case SIMDIntrinsicWidenHi:
+ genSIMDIntrinsicWiden(simdNode);
+ break;
+
+ case SIMDIntrinsicNarrow:
+ genSIMDIntrinsicNarrow(simdNode);
+ break;
+
+ case SIMDIntrinsicAdd:
+ case SIMDIntrinsicSub:
+ case SIMDIntrinsicMul:
+ case SIMDIntrinsicDiv:
+ case SIMDIntrinsicBitwiseAnd:
+ case SIMDIntrinsicBitwiseAndNot:
+ case SIMDIntrinsicBitwiseOr:
+ case SIMDIntrinsicBitwiseXor:
+ case SIMDIntrinsicMin:
+ case SIMDIntrinsicMax:
+ case SIMDIntrinsicEqual:
+ case SIMDIntrinsicLessThan:
+ case SIMDIntrinsicGreaterThan:
+ case SIMDIntrinsicLessThanOrEqual:
+ case SIMDIntrinsicGreaterThanOrEqual:
+ genSIMDIntrinsicBinOp(simdNode);
+ break;
+
+ case SIMDIntrinsicOpEquality:
+ case SIMDIntrinsicOpInEquality:
+ genSIMDIntrinsicRelOp(simdNode);
+ break;
+
+ case SIMDIntrinsicDotProduct:
+ genSIMDIntrinsicDotProduct(simdNode);
+ break;
+
+ case SIMDIntrinsicGetItem:
+ genSIMDIntrinsicGetItem(simdNode);
+ break;
+
+ case SIMDIntrinsicSetX:
+ case SIMDIntrinsicSetY:
+ case SIMDIntrinsicSetZ:
+ case SIMDIntrinsicSetW:
+ genSIMDIntrinsicSetItem(simdNode);
+ break;
+
+ case SIMDIntrinsicUpperSave:
+ genSIMDIntrinsicUpperSave(simdNode);
+ break;
+
+ case SIMDIntrinsicUpperRestore:
+ genSIMDIntrinsicUpperRestore(simdNode);
+ break;
+
+ case SIMDIntrinsicSelect:
+ NYI("SIMDIntrinsicSelect lowered during import to (a & sel) | (b & ~sel)");
+ break;
+
+ default:
+ noway_assert(!"Unimplemented SIMD intrinsic.");
+ unreached();
+ }
+}
+
+insOpts CodeGen::genGetSimdInsOpt(bool is16B, var_types elementType)
+{
+ insOpts result = INS_OPTS_NONE;
+
+ switch (elementType)
+ {
+ case TYP_DOUBLE:
+ case TYP_ULONG:
+ case TYP_LONG:
+ result = is16B ? INS_OPTS_2D : INS_OPTS_1D;
+ break;
+ case TYP_FLOAT:
+ case TYP_UINT:
+ case TYP_INT:
+ result = is16B ? INS_OPTS_4S : INS_OPTS_2S;
+ break;
+ case TYP_CHAR:
+ case TYP_SHORT:
+ result = is16B ? INS_OPTS_8H : INS_OPTS_4H;
+ break;
+ case TYP_UBYTE:
+ case TYP_BYTE:
+ result = is16B ? INS_OPTS_16B : INS_OPTS_8B;
+ break;
+ default:
+ assert(!"Unsupported element type");
+ unreached();
+ }
+
+ return result;
+}
+
+// getOpForSIMDIntrinsic: return the opcode for the given SIMD Intrinsic
+//
+// Arguments:
+// intrinsicId - SIMD intrinsic Id
+// baseType - Base type of the SIMD vector
+// immed - Out param. Any immediate byte operand that needs to be passed to SSE2 opcode
+//
+//
+// Return Value:
+// Instruction (op) to be used, and immed is set if instruction requires an immediate operand.
+//
+instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival /*=nullptr*/)
+{
+ instruction result = INS_invalid;
+ if (varTypeIsFloating(baseType))
+ {
+ switch (intrinsicId)
+ {
+ case SIMDIntrinsicAbs:
+ result = INS_fabs;
+ break;
+ case SIMDIntrinsicAdd:
+ result = INS_fadd;
+ break;
+ case SIMDIntrinsicBitwiseAnd:
+ result = INS_and;
+ break;
+ case SIMDIntrinsicBitwiseAndNot:
+ result = INS_bic;
+ break;
+ case SIMDIntrinsicBitwiseOr:
+ result = INS_orr;
+ break;
+ case SIMDIntrinsicBitwiseXor:
+ result = INS_eor;
+ break;
+ case SIMDIntrinsicCast:
+ result = INS_mov;
+ break;
+ case SIMDIntrinsicConvertToInt32:
+ case SIMDIntrinsicConvertToInt64:
+ result = INS_fcvtns;
+ break;
+ case SIMDIntrinsicConvertToUInt32:
+ case SIMDIntrinsicConvertToUInt64:
+ result = INS_fcvtnu;
+ break;
+ case SIMDIntrinsicDiv:
+ result = INS_fdiv;
+ break;
+ case SIMDIntrinsicEqual:
+ result = INS_fcmeq;
+ break;
+ case SIMDIntrinsicGreaterThan:
+ result = INS_fcmgt;
+ break;
+ case SIMDIntrinsicGreaterThanOrEqual:
+ result = INS_fcmge;
+ break;
+ case SIMDIntrinsicLessThan:
+ result = INS_fcmlt;
+ break;
+ case SIMDIntrinsicLessThanOrEqual:
+ result = INS_fcmle;
+ break;
+ case SIMDIntrinsicMax:
+ result = INS_fmax;
+ break;
+ case SIMDIntrinsicMin:
+ result = INS_fmin;
+ break;
+ case SIMDIntrinsicMul:
+ result = INS_fmul;
+ break;
+ case SIMDIntrinsicNarrow:
+ // Use INS_fcvtn lower bytes of result followed by INS_fcvtn2 for upper bytes
+ // Return lower bytes instruction here
+ result = INS_fcvtn;
+ break;
+ case SIMDIntrinsicSelect:
+ result = INS_bsl;
+ break;
+ case SIMDIntrinsicSqrt:
+ result = INS_fsqrt;
+ break;
+ case SIMDIntrinsicSub:
+ result = INS_fsub;
+ break;
+ case SIMDIntrinsicWidenLo:
+ result = INS_fcvtl;
+ break;
+ case SIMDIntrinsicWidenHi:
+ result = INS_fcvtl2;
+ break;
+ default:
+ assert(!"Unsupported SIMD intrinsic");
+ unreached();
+ }
+ }
+ else
+ {
+ bool isUnsigned = varTypeIsUnsigned(baseType);
+
+ switch (intrinsicId)
+ {
+ case SIMDIntrinsicAbs:
+ assert(!isUnsigned);
+ result = INS_abs;
+ break;
+ case SIMDIntrinsicAdd:
+ result = INS_add;
+ break;
+ case SIMDIntrinsicBitwiseAnd:
+ result = INS_and;
+ break;
+ case SIMDIntrinsicBitwiseAndNot:
+ result = INS_bic;
+ break;
+ case SIMDIntrinsicBitwiseOr:
+ result = INS_orr;
+ break;
+ case SIMDIntrinsicBitwiseXor:
+ result = INS_eor;
+ break;
+ case SIMDIntrinsicCast:
+ result = INS_mov;
+ break;
+ case SIMDIntrinsicConvertToDouble:
+ case SIMDIntrinsicConvertToSingle:
+ result = isUnsigned ? INS_ucvtf : INS_scvtf;
+ break;
+ case SIMDIntrinsicEqual:
+ result = INS_cmeq;
+ break;
+ case SIMDIntrinsicGreaterThan:
+ result = isUnsigned ? INS_cmhi : INS_cmgt;
+ break;
+ case SIMDIntrinsicGreaterThanOrEqual:
+ result = isUnsigned ? INS_cmhs : INS_cmge;
+ break;
+ case SIMDIntrinsicLessThan:
+ assert(!isUnsigned);
+ result = INS_cmlt;
+ break;
+ case SIMDIntrinsicLessThanOrEqual:
+ assert(!isUnsigned);
+ result = INS_cmle;
+ break;
+ case SIMDIntrinsicMax:
+ result = isUnsigned ? INS_umax : INS_smax;
+ break;
+ case SIMDIntrinsicMin:
+ result = isUnsigned ? INS_umin : INS_smin;
+ break;
+ case SIMDIntrinsicMul:
+ result = INS_mul;
+ break;
+ case SIMDIntrinsicNarrow:
+ // Use INS_xtn lower bytes of result followed by INS_xtn2 for upper bytes
+ // Return lower bytes instruction here
+ result = INS_xtn;
+ break;
+ case SIMDIntrinsicSelect:
+ result = INS_bsl;
+ break;
+ case SIMDIntrinsicSub:
+ result = INS_sub;
+ break;
+ case SIMDIntrinsicWidenLo:
+ result = isUnsigned ? INS_uxtl : INS_sxtl;
+ break;
+ case SIMDIntrinsicWidenHi:
+ result = isUnsigned ? INS_uxtl2 : INS_sxtl2;
+ break;
+ default:
+ assert(!"Unsupported SIMD intrinsic");
+ unreached();
+ }
+ }
+
+ noway_assert(result != INS_invalid);
+ return result;
+}
+
+//------------------------------------------------------------------------
+// genSIMDIntrinsicInit: Generate code for SIMD Intrinsic Initialize.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInit);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = simdNode->TypeGet();
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+
+ // TODO-ARM64-CQ Add support contain int const zero
+ // TODO-ARM64-CQ Add LD1R to allow SIMDIntrinsicInit from contained memory
+ // TODO-ARM64-CQ Add MOVI to allow SIMDIntrinsicInit from contained immediate small constants
+
+ assert(!op1->isContained());
+ assert(!op1->isUsedFromMemory());
+
+ assert(genIsValidFloatReg(targetReg));
+ assert(genIsValidIntReg(op1Reg) || genIsValidFloatReg(op1Reg));
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ if (genIsValidIntReg(op1Reg))
+ {
+ getEmitter()->emitIns_R_R(INS_dup, attr, targetReg, op1Reg, opt);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R_I(INS_dup, attr, targetReg, op1Reg, 0, opt);
+ }
+
+ genProduceReg(simdNode);
+}
+
+//-------------------------------------------------------------------------------------------
+// genSIMDIntrinsicInitN: Generate code for SIMD Intrinsic Initialize for the form that takes
+// a number of arguments equal to the length of the Vector.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicInitN(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicInitN);
+
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+
+ var_types targetType = simdNode->TypeGet();
+
+ var_types baseType = simdNode->gtSIMDBaseType;
+
+ regNumber vectorReg = targetReg;
+
+ if (varTypeIsFloating(baseType))
+ {
+ // Note that we cannot use targetReg before consuming all float source operands.
+ // Therefore use an internal temp register
+ vectorReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
+ }
+
+ emitAttr baseTypeSize = emitTypeSize(baseType);
+
+ // We will first consume the list items in execution (left to right) order,
+ // and record the registers.
+ regNumber operandRegs[FP_REGSIZE_BYTES];
+ unsigned initCount = 0;
+ for (GenTree* list = simdNode->gtGetOp1(); list != nullptr; list = list->gtGetOp2())
+ {
+ assert(list->OperGet() == GT_LIST);
+ GenTree* listItem = list->gtGetOp1();
+ assert(listItem->TypeGet() == baseType);
+ assert(!listItem->isContained());
+ regNumber operandReg = genConsumeReg(listItem);
+ operandRegs[initCount] = operandReg;
+ initCount++;
+ }
+
+ assert((initCount * baseTypeSize) <= simdNode->gtSIMDSize);
+
+ if (initCount * baseTypeSize < EA_16BYTE)
+ {
+ getEmitter()->emitIns_R_I(INS_movi, EA_16BYTE, vectorReg, 0x00, INS_OPTS_16B);
+ }
+
+ if (varTypeIsIntegral(baseType))
+ {
+ for (unsigned i = 0; i < initCount; i++)
+ {
+ getEmitter()->emitIns_R_R_I(INS_ins, baseTypeSize, vectorReg, operandRegs[i], i);
+ }
+ }
+ else
+ {
+ for (unsigned i = 0; i < initCount; i++)
+ {
+ getEmitter()->emitIns_R_R_I_I(INS_ins, baseTypeSize, vectorReg, operandRegs[i], i, 0);
+ }
+ }
+
+ // Load the initialized value.
+ if (targetReg != vectorReg)
+ {
+ getEmitter()->emitIns_R_R(INS_mov, EA_16BYTE, targetReg, vectorReg);
+ }
+
+ genProduceReg(simdNode);
+}
+
+//----------------------------------------------------------------------------------
+// genSIMDIntrinsicUnOp: Generate code for SIMD Intrinsic unary operations like sqrt.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicUnOp(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSqrt || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicCast ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAbs ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToSingle ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt32 ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToUInt32 ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToDouble ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToInt64 ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicConvertToUInt64);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = simdNode->TypeGet();
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidFloatReg(targetReg));
+
+ instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = (ins == INS_mov) ? INS_OPTS_NONE : genGetSimdInsOpt(is16B, baseType);
+
+ getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
+
+ genProduceReg(simdNode);
+}
+
+//--------------------------------------------------------------------------------
+// genSIMDIntrinsicWiden: Generate code for SIMD Intrinsic Widen operations
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Notes:
+// The Widen intrinsics are broken into separate intrinsics for the two results.
+//
+void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode)
+{
+ assert((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenLo) ||
+ (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi));
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types simdType = simdNode->TypeGet();
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber srcReg = op1Reg;
+ emitAttr emitSize = emitActualTypeSize(simdType);
+
+ instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
+
+ bool is16B = (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicWidenHi);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
+
+ genProduceReg(simdNode);
+}
+
+//--------------------------------------------------------------------------------
+// genSIMDIntrinsicNarrow: Generate code for SIMD Intrinsic Narrow operations
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Notes:
+// This intrinsic takes two arguments. The first operand is narrowed to produce the
+// lower elements of the results, and the second operand produces the high elements.
+//
+void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicNarrow);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types simdType = simdNode->TypeGet();
+ emitAttr emitSize = emitTypeSize(simdType);
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidFloatReg(op2Reg));
+ assert(genIsValidFloatReg(targetReg));
+ assert(op2Reg != targetReg);
+
+ instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
+
+ assert((ins == INS_fcvtn) || (ins == INS_xtn));
+
+ instruction ins2 = ins == INS_fcvtn ? INS_fcvtn2 : INS_xtn2;
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ getEmitter()->emitIns_R_R(ins, attr, targetReg, op1Reg, opt);
+ getEmitter()->emitIns_R_R(ins2, attr, targetReg, op2Reg, opt);
+
+ genProduceReg(simdNode);
+}
+
+//--------------------------------------------------------------------------------
+// genSIMDIntrinsicBinOp: Generate code for SIMD Intrinsic binary operations
+// add, sub, mul, bit-wise And, AndNot and Or.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicAdd || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicSub ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDiv ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAnd ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseAndNot ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseOr ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicBitwiseXor || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMin ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMax || simdNode->gtSIMDIntrinsicID == SIMDIntrinsicEqual ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThan ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThan ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicLessThanOrEqual ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGreaterThanOrEqual);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = simdNode->TypeGet();
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidFloatReg(op2Reg));
+ assert(genIsValidFloatReg(targetReg));
+
+ // TODO-ARM64-CQ Contain integer constants where posible
+
+ instruction ins = getOpForSIMDIntrinsic(simdNode->gtSIMDIntrinsicID, baseType);
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ getEmitter()->emitIns_R_R_R(ins, attr, targetReg, op1Reg, op2Reg, opt);
+
+ genProduceReg(simdNode);
+}
+
+//--------------------------------------------------------------------------------
+// genSIMDIntrinsicRelOp: Generate code for a SIMD Intrinsic relational operater
+// == and !=
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality ||
+ simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ var_types targetType = simdNode->TypeGet();
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+ regNumber otherReg = op2Reg;
+
+ instruction ins = getOpForSIMDIntrinsic(SIMDIntrinsicEqual, baseType);
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ // TODO-ARM64-CQ Contain integer constants where posible
+
+ regNumber tmpFloatReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
+
+ getEmitter()->emitIns_R_R_R(ins, attr, tmpFloatReg, op1Reg, op2Reg, opt);
+
+ getEmitter()->emitIns_R_R(INS_uminv, attr, tmpFloatReg, tmpFloatReg,
+ (simdNode->gtSIMDSize > 8) ? INS_OPTS_16B : INS_OPTS_8B);
+
+ getEmitter()->emitIns_R_R_I(INS_mov, EA_1BYTE, targetReg, tmpFloatReg, 0);
+
+ if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality)
+ {
+ getEmitter()->emitIns_R_R_I(INS_eor, EA_4BYTE, targetReg, targetReg, 0x1);
+ }
+
+ getEmitter()->emitIns_R_R_I(INS_and, EA_4BYTE, targetReg, targetReg, 0x1);
+
+ genProduceReg(simdNode);
+}
+
+//--------------------------------------------------------------------------------
+// genSIMDIntrinsicDotProduct: Generate code for SIMD Intrinsic Dot Product.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicDotProduct);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ var_types simdType = op1->TypeGet();
+
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+
+ var_types targetType = simdNode->TypeGet();
+ assert(targetType == baseType);
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+ regNumber tmpReg = targetReg;
+
+ if (!varTypeIsFloating(baseType))
+ {
+ tmpReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
+ }
+
+ instruction ins = getOpForSIMDIntrinsic(SIMDIntrinsicMul, baseType);
+
+ bool is16B = (simdNode->gtSIMDSize > 8);
+ emitAttr attr = is16B ? EA_16BYTE : EA_8BYTE;
+ insOpts opt = genGetSimdInsOpt(is16B, baseType);
+
+ // Vector multiply
+ getEmitter()->emitIns_R_R_R(ins, attr, tmpReg, op1Reg, op2Reg, opt);
+
+ if ((simdNode->gtFlags & GTF_SIMD12_OP) != 0)
+ {
+ // For 12Byte vectors we must zero upper bits to get correct dot product
+ // We do not assume upper bits are zero.
+ getEmitter()->emitIns_R_R_I(INS_ins, EA_4BYTE, tmpReg, REG_ZR, 3);
+ }
+
+ // Vector add horizontal
+ if (varTypeIsFloating(baseType))
+ {
+ if (baseType == TYP_FLOAT)
+ {
+ if (opt == INS_OPTS_4S)
+ {
+ getEmitter()->emitIns_R_R_R(INS_faddp, attr, tmpReg, tmpReg, tmpReg, INS_OPTS_4S);
+ }
+ getEmitter()->emitIns_R_R(INS_faddp, EA_4BYTE, targetReg, tmpReg);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R(INS_faddp, EA_8BYTE, targetReg, tmpReg);
+ }
+ }
+ else
+ {
+ ins = varTypeIsUnsigned(baseType) ? INS_uaddlv : INS_saddlv;
+
+ getEmitter()->emitIns_R_R(ins, attr, tmpReg, tmpReg, opt);
+
+ // Mov to integer register
+ if (varTypeIsUnsigned(baseType) || (genTypeSize(baseType) < 4))
+ {
+ getEmitter()->emitIns_R_R_I(INS_mov, emitTypeSize(baseType), targetReg, tmpReg, 0);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R_I(INS_smov, emitActualTypeSize(baseType), targetReg, tmpReg, 0);
+ }
+ }
+
+ genProduceReg(simdNode);
+}
+
+//------------------------------------------------------------------------------------
+// genSIMDIntrinsicGetItem: Generate code for SIMD Intrinsic get element at index i.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicGetItem);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types simdType = op1->TypeGet();
+ assert(varTypeIsSIMD(simdType));
+
+ // op1 of TYP_SIMD12 should be considered as TYP_SIMD16
+ if (simdType == TYP_SIMD12)
+ {
+ simdType = TYP_SIMD16;
+ }
+
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = simdNode->TypeGet();
+ assert(targetType == genActualType(baseType));
+
+ // GetItem has 2 operands:
+ // - the source of SIMD type (op1)
+ // - the index of the value to be returned.
+ genConsumeOperands(simdNode);
+ regNumber srcReg = op1->gtRegNum;
+
+ // TODO-ARM64-CQ Optimize SIMDIntrinsicGetItem
+ // Optimize the case of op1 is in memory and trying to access ith element.
+ assert(op1->isUsedFromReg());
+
+ if (op2->IsCnsIntOrI())
+ {
+ assert(op2->isContained());
+
+ emitAttr attr = emitTypeSize(baseType);
+ unsigned int index = (unsigned int)op2->gtIntCon.gtIconVal;
+
+ getEmitter()->emitIns_R_R_I(INS_mov, attr, targetReg, srcReg, index);
+ }
+ else
+ {
+ NYI("getItem() with non const index");
+ assert(op2->IsCnsIntOrI());
+ }
+
+ genProduceReg(simdNode);
+}
+
+//------------------------------------------------------------------------------------
+// genSIMDIntrinsicSetItem: Generate code for SIMD Intrinsic set element at index i.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
+{
+ // Determine index based on intrinsic ID
+ int index = -1;
+ switch (simdNode->gtSIMDIntrinsicID)
+ {
+ case SIMDIntrinsicSetX:
+ index = 0;
+ break;
+ case SIMDIntrinsicSetY:
+ index = 1;
+ break;
+ case SIMDIntrinsicSetZ:
+ index = 2;
+ break;
+ case SIMDIntrinsicSetW:
+ index = 3;
+ break;
+
+ default:
+ unreached();
+ }
+ assert(index != -1);
+
+ // op1 is the SIMD vector
+ // op2 is the value to be set
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = simdNode->TypeGet();
+ assert(varTypeIsSIMD(targetType));
+
+ assert(op2->TypeGet() == baseType);
+ assert(simdNode->gtSIMDSize >= ((index + 1) * genTypeSize(baseType)));
+
+ genConsumeOperands(simdNode);
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+
+ assert(genIsValidFloatReg(targetReg));
+ assert(genIsValidFloatReg(op1Reg));
+ assert(genIsValidIntReg(op2Reg) || genIsValidFloatReg(op2Reg));
+
+ emitAttr attr = emitTypeSize(baseType);
+
+ // Insert mov if register assignment requires it
+ getEmitter()->emitIns_R_R(INS_mov, EA_16BYTE, targetReg, op1Reg);
+
+ if (genIsValidIntReg(op2Reg))
+ {
+ getEmitter()->emitIns_R_R_I(INS_ins, attr, targetReg, op2Reg, index);
+ }
+ else
+ {
+ getEmitter()->emitIns_R_R_I_I(INS_ins, attr, targetReg, op2Reg, index, 0);
+ }
+
+ genProduceReg(simdNode);
+}
+
+//-----------------------------------------------------------------------------
+// genSIMDIntrinsicUpperSave: save the upper half of a TYP_SIMD16 vector to
+// the given register, if any, or to memory.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+// Notes:
+// The upper half of all SIMD registers are volatile, even the callee-save registers.
+// When a 16-byte SIMD value is live across a call, the register allocator will use this intrinsic
+// to cause the upper half to be saved. It will first attempt to find another, unused, callee-save
+// register. If such a register cannot be found, it will save it to an available caller-save register.
+// In that case, this node will be marked GTF_SPILL, which will cause genProduceReg to save the 8 byte
+// value to the stack. (Note that if there are no caller-save registers available, the entire 16 byte
+// value will be spilled to the stack.)
+//
+void CodeGen::genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperSave);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ assert(op1->IsLocal() && op1->TypeGet() == TYP_SIMD16);
+ regNumber targetReg = simdNode->gtRegNum;
+ regNumber op1Reg = genConsumeReg(op1);
+ assert(op1Reg != REG_NA);
+ assert(targetReg != REG_NA);
+ getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, targetReg, op1Reg, 0, 1);
+
+ genProduceReg(simdNode);
+}
+
+//-----------------------------------------------------------------------------
+// genSIMDIntrinsicUpperRestore: Restore the upper half of a TYP_SIMD16 vector to
+// the given register, if any, or to memory.
+//
+// Arguments:
+// simdNode - The GT_SIMD node
+//
+// Return Value:
+// None.
+//
+// Notes:
+// For consistency with genSIMDIntrinsicUpperSave, and to ensure that lclVar nodes always
+// have their home register, this node has its targetReg on the lclVar child, and its source
+// on the simdNode.
+// Regarding spill, please see the note above on genSIMDIntrinsicUpperSave. If we have spilled
+// an upper-half to a caller save register, this node will be marked GTF_SPILLED. However, unlike
+// most spill scenarios, the saved tree will be different from the restored tree, but the spill
+// restore logic, which is triggered by the call to genConsumeReg, requires us to provide the
+// spilled tree (saveNode) in order to perform the reload. We can easily find that tree,
+// as it is in the spill descriptor for the register from which it was saved.
+//
+void CodeGen::genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicUpperRestore);
+
+ GenTree* op1 = simdNode->gtGetOp1();
+ assert(op1->IsLocal() && op1->TypeGet() == TYP_SIMD16);
+ regNumber srcReg = simdNode->gtRegNum;
+ regNumber lclVarReg = genConsumeReg(op1);
+ unsigned varNum = op1->AsLclVarCommon()->gtLclNum;
+ assert(lclVarReg != REG_NA);
+ assert(srcReg != REG_NA);
+ if (simdNode->gtFlags & GTF_SPILLED)
+ {
+ GenTree* saveNode = regSet.rsSpillDesc[srcReg]->spillTree;
+ noway_assert(saveNode != nullptr && (saveNode->gtRegNum == srcReg));
+ genConsumeReg(saveNode);
+ }
+ getEmitter()->emitIns_R_R_I_I(INS_mov, EA_8BYTE, lclVarReg, srcReg, 1, 0);
+}
+
+#endif // FEATURE_SIMD
+
/*****************************************************************************
* Unit testing of the ARM64 emitter: generate a bunch of instructions into the prolog
* (it's as good a place as any), then use COMPlus_JitLateDisasm=* to see if the late
@@ -3684,6 +4777,30 @@ void CodeGen::genArm64EmitterUnitTests()
theEmitter->emitIns_R_R(INS_stlrb, EA_4BYTE, REG_R5, REG_R14);
theEmitter->emitIns_R_R(INS_stlrh, EA_4BYTE, REG_R3, REG_R15);
+ // ldaxr Rt, [reg]
+ theEmitter->emitIns_R_R(INS_ldaxr, EA_8BYTE, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R(INS_ldaxr, EA_4BYTE, REG_R7, REG_R10);
+ theEmitter->emitIns_R_R(INS_ldaxrb, EA_4BYTE, REG_R5, REG_R11);
+ theEmitter->emitIns_R_R(INS_ldaxrh, EA_4BYTE, REG_R5, REG_R12);
+
+ // ldxr Rt, [reg]
+ theEmitter->emitIns_R_R(INS_ldxr, EA_8BYTE, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R(INS_ldxr, EA_4BYTE, REG_R7, REG_R10);
+ theEmitter->emitIns_R_R(INS_ldxrb, EA_4BYTE, REG_R5, REG_R11);
+ theEmitter->emitIns_R_R(INS_ldxrh, EA_4BYTE, REG_R5, REG_R12);
+
+ // stxr Ws, Rt, [reg]
+ theEmitter->emitIns_R_R_R(INS_stxr, EA_8BYTE, REG_R1, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R_R(INS_stxr, EA_4BYTE, REG_R3, REG_R7, REG_R13);
+ theEmitter->emitIns_R_R_R(INS_stxrb, EA_4BYTE, REG_R8, REG_R5, REG_R14);
+ theEmitter->emitIns_R_R_R(INS_stxrh, EA_4BYTE, REG_R12, REG_R3, REG_R15);
+
+ // stlxr Ws, Rt, [reg]
+ theEmitter->emitIns_R_R_R(INS_stlxr, EA_8BYTE, REG_R1, REG_R9, REG_R8);
+ theEmitter->emitIns_R_R_R(INS_stlxr, EA_4BYTE, REG_R3, REG_R7, REG_R13);
+ theEmitter->emitIns_R_R_R(INS_stlxrb, EA_4BYTE, REG_R8, REG_R5, REG_R14);
+ theEmitter->emitIns_R_R_R(INS_stlxrh, EA_4BYTE, REG_R12, REG_R3, REG_R15);
+
#endif // ALL_ARM64_EMITTER_UNIT_TESTS
#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
@@ -5391,6 +6508,77 @@ void CodeGen::genArm64EmitterUnitTests()
theEmitter->emitIns_R_R(INS_rev64, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
theEmitter->emitIns_R_R(INS_rev64, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+ // addv vector
+ theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_addv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_addv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // saddlv vector
+ theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_saddlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_saddlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // smaxlv vector
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_smaxlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // sminlv vector
+ theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_sminlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_sminlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // uaddlv vector
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_uaddlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // umaxlv vector
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_umaxlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // uminlv vector
+ theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V4, REG_V5, INS_OPTS_8B);
+ theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V6, REG_V7, INS_OPTS_16B);
+ theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V8, REG_V9, INS_OPTS_4H);
+ theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R(INS_uminlv, EA_8BYTE, REG_V12, REG_V13, INS_OPTS_2S);
+ theEmitter->emitIns_R_R(INS_uminlv, EA_16BYTE, REG_V14, REG_V15, INS_OPTS_4S);
+
+ // faddp scalar
+ theEmitter->emitIns_R_R(INS_faddp, EA_4BYTE, REG_V0, REG_V1);
+ theEmitter->emitIns_R_R(INS_faddp, EA_8BYTE, REG_V2, REG_V3);
+
+ // INS_fcvtl
+ theEmitter->emitIns_R_R(INS_fcvtl, EA_4BYTE, REG_V0, REG_V1);
+
+ // INS_fcvtl2
+ theEmitter->emitIns_R_R(INS_fcvtl2, EA_4BYTE, REG_V0, REG_V1);
+
+ // INS_fcvtn
+ theEmitter->emitIns_R_R(INS_fcvtn, EA_8BYTE, REG_V0, REG_V1);
+
+ // INS_fcvtn2
+ theEmitter->emitIns_R_R(INS_fcvtn2, EA_8BYTE, REG_V0, REG_V1);
#endif
#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
@@ -5882,7 +7070,120 @@ void CodeGen::genArm64EmitterUnitTests()
theEmitter->emitIns_R_R_R(INS_uabd, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
theEmitter->emitIns_R_R_R(INS_uabd, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
theEmitter->emitIns_R_R_R(INS_uabd, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+#endif // ALL_ARM64_EMITTER_UNIT_TESTS
+#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
+ // smax vector
+ theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_smax, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_smax, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+
+ // smin vector
+ theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_smin, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_smin, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+
+ // umax vector
+ theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_umax, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_umax, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+
+ // umin vector
+ theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_umin, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_umin, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+
+ // cmeq vector
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_cmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // cmge vector
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_cmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // cmgt vector
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_cmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // cmhi vector
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_cmhi, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // cmhs vector
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_cmhs, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // ctst vector
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V0, REG_V1, REG_V2, INS_OPTS_8B);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V3, REG_V4, REG_V5, INS_OPTS_16B);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V6, REG_V7, REG_V8, INS_OPTS_4H);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V9, REG_V10, REG_V11, INS_OPTS_8H);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_1D);
+ theEmitter->emitIns_R_R_R(INS_ctst, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // faddp vector
+ theEmitter->emitIns_R_R_R(INS_faddp, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_faddp, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_faddp, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // fcmeq vector
+ theEmitter->emitIns_R_R_R(INS_fcmeq, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_fcmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_fcmeq, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // fcmge vector
+ theEmitter->emitIns_R_R_R(INS_fcmge, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_fcmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_fcmge, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
+
+ // fcmgt vector
+ theEmitter->emitIns_R_R_R(INS_fcmgt, EA_8BYTE, REG_V12, REG_V13, REG_V14, INS_OPTS_2S);
+ theEmitter->emitIns_R_R_R(INS_fcmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_4S);
+ theEmitter->emitIns_R_R_R(INS_fcmgt, EA_16BYTE, REG_V15, REG_V16, REG_V17, INS_OPTS_2D);
#endif // ALL_ARM64_EMITTER_UNIT_TESTS
#ifdef ALL_ARM64_EMITTER_UNIT_TESTS
diff --git a/src/jit/codegenarmarch.cpp b/src/jit/codegenarmarch.cpp
index 22aed1056d..ba0e8723b1 100644
--- a/src/jit/codegenarmarch.cpp
+++ b/src/jit/codegenarmarch.cpp
@@ -69,12 +69,11 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
switch (treeNode->gtOper)
{
-#ifdef _TARGET_ARM64_
-
case GT_START_NONGC:
getEmitter()->emitDisableGC();
break;
+#ifdef _TARGET_ARM64_
case GT_PROF_HOOK:
// We should be seeing this only if profiler hook is needed
noway_assert(compiler->compIsProfilerHookNeeded());
@@ -343,7 +342,10 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
break;
case GT_CMPXCHG:
- NYI("GT_CMPXCHG");
+ NYI_ARM("GT_CMPXCHG");
+#ifdef _TARGET_ARM64_
+ genCodeForCmpXchg(treeNode->AsCmpXchg());
+#endif
break;
case GT_RELOAD:
@@ -538,8 +540,8 @@ void CodeGen::genIntrinsic(GenTreePtr treeNode)
void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
{
assert(treeNode->OperIs(GT_PUTARG_STK));
- var_types targetType = treeNode->TypeGet();
GenTreePtr source = treeNode->gtOp1;
+ var_types targetType = genActualType(source->TypeGet());
emitter* emit = getEmitter();
// This is the varNum for our store operations,
@@ -564,9 +566,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
// All other calls - stk arg is setup in out-going arg area.
if (treeNode->putInIncomingArgArea())
{
- NYI_ARM("genPutArgStk: fast tail call");
-
-#ifdef _TARGET_ARM64_
varNumOut = getFirstArgWithStackSlot();
argOffsetMax = compiler->compArgSize;
#if FEATURE_FASTTAILCALL
@@ -579,7 +578,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
LclVarDsc* varDsc = &(compiler->lvaTable[varNumOut]);
assert(varDsc != nullptr);
#endif // FEATURE_FASTTAILCALL
-#endif // _TARGET_ARM64_
}
else
{
@@ -611,7 +609,8 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
{
genConsumeReg(source);
emit->emitIns_S_R(storeIns, storeAttr, source->gtRegNum, varNumOut, argOffsetOut);
- if (compiler->opts.compUseSoftFP && targetType == TYP_LONG)
+#ifdef _TARGET_ARM_
+ if (targetType == TYP_LONG)
{
// This case currently only occurs for double types that are passed as TYP_LONG;
// actual long types would have been decomposed by now.
@@ -621,6 +620,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
argOffsetOut += EA_4BYTE;
emit->emitIns_S_R(storeIns, storeAttr, otherReg, varNumOut, argOffsetOut);
}
+#endif // _TARGET_ARM_
}
argOffsetOut += EA_SIZE_IN_BYTES(storeAttr);
assert(argOffsetOut <= argOffsetMax); // We can't write beyound the outgoing area area
@@ -1963,7 +1963,6 @@ void CodeGen::genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode)
// b) The size argument of the InitBlk is >= INITBLK_STOS_LIMIT bytes.
void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
{
- // Make sure we got the arguments of the initblk operation in the right registers
unsigned size = initBlkNode->Size();
GenTreePtr dstAddr = initBlkNode->Addr();
GenTreePtr initVal = initBlkNode->Data();
@@ -1974,14 +1973,6 @@ void CodeGen::genCodeForInitBlk(GenTreeBlk* initBlkNode)
assert(!dstAddr->isContained());
assert(!initVal->isContained());
- if (initBlkNode->gtOper == GT_STORE_DYN_BLK)
- {
- assert(initBlkNode->AsDynBlk()->gtDynamicSize->gtRegNum == REG_ARG_2);
- }
- else
- {
- assert(initBlkNode->gtRsvdRegs == RBM_ARG_2);
- }
#ifdef _TARGET_ARM64_
if (size != 0)
@@ -2209,16 +2200,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
inst_RV_RV(ins_Move_Extend(argNode->TypeGet(), true), argReg, argNode->gtRegNum);
}
}
-
- // In the case of a varargs call,
- // the ABI dictates that if we have floating point args,
- // we must pass the enregistered arguments in both the
- // integer and floating point registers so, let's do that.
- if (call->IsVarargs() && varTypeIsFloating(argNode))
- {
- NYI_ARM("CodeGen - IsVarargs");
- NYI_ARM64("CodeGen - IsVarargs");
- }
}
// Insert a null check on "this" pointer if asked.
@@ -2271,15 +2252,11 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
genConsumeReg(target);
- NYI_ARM("fast tail call");
-
-#ifdef _TARGET_ARM64_
- // Use IP0 as the call target register.
- if (target->gtRegNum != REG_IP0)
+ // Use IP0 on ARM64 and R12 on ARM32 as the call target register.
+ if (target->gtRegNum != REG_FASTTAILCALL_TARGET)
{
- inst_RV_RV(INS_mov, REG_IP0, target->gtRegNum);
+ inst_RV_RV(INS_mov, REG_FASTTAILCALL_TARGET, target->gtRegNum);
}
-#endif // _TARGET_ARM64_
return;
}
@@ -2288,7 +2265,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
// the GC pointer state before the callsite.
// We can't utilize the typical lazy killing of GC pointers
// at (or inside) the callsite.
- if (call->IsUnmanaged())
+ if (compiler->killGCRefs(call))
{
genDefineTempLabel(genCreateTempLabel());
}
@@ -3673,9 +3650,6 @@ void CodeGen::genStructReturn(GenTreePtr treeNode)
}
else // op1 must be multi-reg GT_CALL
{
-#ifdef _TARGET_ARM_
- NYI_ARM("struct return from multi-reg GT_CALL");
-#endif
assert(op1->IsMultiRegCall() || op1->IsCopyOrReloadOfMultiRegCall());
genConsumeRegs(op1);
diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
index 07a52415d0..ac8c667fba 100644
--- a/src/jit/codegencommon.cpp
+++ b/src/jit/codegencommon.cpp
@@ -1609,10 +1609,12 @@ void CodeGen::genDefineTempLabel(BasicBlock* label)
label->bbEmitCookie =
getEmitter()->emitAddLabel(gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur, gcInfo.gcRegByrefSetCur);
+#ifdef LEGACY_BACKEND
/* gcInfo.gcRegGCrefSetCur does not account for redundant load-suppression
of GC vars, and the emitter will not know about */
regTracker.rsTrackRegClrPtr();
+#endif
}
/*****************************************************************************
@@ -2845,7 +2847,11 @@ void CodeGen::genCheckOverflow(GenTreePtr tree)
if (jumpKind == EJ_lo)
{
- if ((tree->OperGet() != GT_SUB) && (tree->gtOper != GT_ASG_SUB))
+ if ((tree->OperGet() != GT_SUB)
+#ifdef LEGACY_BACKEND
+ && (tree->gtOper != GT_ASG_SUB)
+#endif
+ )
{
jumpKind = EJ_hs;
}
@@ -6148,7 +6154,9 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
}
#endif // !_TARGET_XARCH_
+#if CPU_LOAD_STORE_ARCH
instGen_Set_Reg_To_Zero(EA_PTRSIZE, initReg);
+#endif // CPU_LOAD_STORE_ARCH
//
// Can't have a label inside the ReJIT padding area
@@ -6209,40 +6217,53 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni
// The encoding differs based on the architecture and what register is
// used (namely, using RAX has a smaller encoding).
//
- // loop:
// For x86
- // test [esp + eax], eax 3
- // sub eax, 0x1000 5
- // cmp EAX, -frameSize 5
+ // lea eax, [esp - frameSize]
+ // loop:
+ // lea esp, [esp - pageSize] 7
+ // test [esp], eax 3
+ // cmp esp, eax 2
// jge loop 2
+ // lea rsp, [rbp + frameSize]
//
// For AMD64 using RAX
- // test [rsp + rax], rax 4
- // sub rax, 0x1000 6
- // cmp rax, -frameSize 6
+ // lea rax, [rsp - frameSize]
+ // loop:
+ // lea rsp, [rsp - pageSize] 8
+ // test [rsp], rax 4
+ // cmp rsp, rax 3
// jge loop 2
+ // lea rsp, [rax + frameSize]
//
// For AMD64 using RBP
- // test [rsp + rbp], rbp 4
- // sub rbp, 0x1000 7
- // cmp rbp, -frameSize 7
+ // lea rbp, [rsp - frameSize]
+ // loop:
+ // lea rsp, [rsp - pageSize] 8
+ // test [rsp], rbp 4
+ // cmp rsp, rbp 3
// jge loop 2
+ // lea rsp, [rbp + frameSize]
- getEmitter()->emitIns_R_ARR(INS_TEST, EA_PTRSIZE, initReg, REG_SPBASE, initReg, 0);
- inst_RV_IV(INS_sub, initReg, pageSize, EA_PTRSIZE);
- inst_RV_IV(INS_cmp, initReg, -((ssize_t)frameSize), EA_PTRSIZE);
+ int sPageSize = (int)pageSize;
+
+ getEmitter()->emitIns_R_AR(INS_lea, EA_PTRSIZE, initReg, REG_SPBASE, -((ssize_t)frameSize)); // get frame border
+
+ getEmitter()->emitIns_R_AR(INS_lea, EA_PTRSIZE, REG_SPBASE, REG_SPBASE, -sPageSize);
+ getEmitter()->emitIns_R_AR(INS_TEST, EA_PTRSIZE, initReg, REG_SPBASE, 0);
+ inst_RV_RV(INS_cmp, REG_SPBASE, initReg);
int bytesForBackwardJump;
#ifdef _TARGET_AMD64_
assert((initReg == REG_EAX) || (initReg == REG_EBP)); // We use RBP as initReg for EH funclets.
- bytesForBackwardJump = ((initReg == REG_EAX) ? -18 : -20);
+ bytesForBackwardJump = -17;
#else // !_TARGET_AMD64_
assert(initReg == REG_EAX);
- bytesForBackwardJump = -15;
+ bytesForBackwardJump = -14;
#endif // !_TARGET_AMD64_
inst_IV(INS_jge, bytesForBackwardJump); // Branch backwards to start of loop
+ getEmitter()->emitIns_R_AR(INS_lea, EA_PTRSIZE, REG_SPBASE, initReg, frameSize); // restore stack pointer
#endif // !CPU_LOAD_STORE_ARCH
*pInitRegZeroed = false; // The initReg does not contain zero
@@ -9387,14 +9408,14 @@ void CodeGen::genFnProlog()
* Please consult the "debugger team notification" comment in genFnProlog().
*/
-#if defined(_TARGET_ARM_)
+#if defined(_TARGET_ARMARCH_)
void CodeGen::genFnEpilog(BasicBlock* block)
{
#ifdef DEBUG
if (verbose)
printf("*************** In genFnEpilog()\n");
-#endif
+#endif // DEBUG
ScopedSetVariable<bool> _setGeneratingEpilog(&compiler->compGeneratingEpilog, true);
@@ -9418,10 +9439,11 @@ void CodeGen::genFnEpilog(BasicBlock* block)
getEmitter()->emitDispRegSet(gcInfo.gcRegByrefSetCur);
printf("\n");
}
-#endif
+#endif // DEBUG
bool jmpEpilog = ((block->bbFlags & BBF_HAS_JMP) != 0);
+#ifdef _TARGET_ARM_
// We delay starting the unwind codes until we have an instruction which we know
// needs an unwind code. In particular, for large stack frames in methods without
// localloc, the sequence might look something like this:
@@ -9477,148 +9499,28 @@ void CodeGen::genFnEpilog(BasicBlock* block)
compiler->unwindAllocStack(preSpillRegArgSize);
}
- if (jmpEpilog)
- {
- noway_assert(block->bbJumpKind == BBJ_RETURN);
- noway_assert(block->bbTreeList);
-
- // We better not have used a pop PC to return otherwise this will be unreachable code
- noway_assert(!genUsedPopToReturn);
-
- /* figure out what jump we have */
-
- GenTree* jmpNode = block->lastNode();
- noway_assert(jmpNode->gtOper == GT_JMP);
-
- CORINFO_METHOD_HANDLE methHnd = (CORINFO_METHOD_HANDLE)jmpNode->gtVal.gtVal1;
-
- CORINFO_CONST_LOOKUP addrInfo;
- void* addr;
- regNumber indCallReg;
- emitter::EmitCallType callType;
-
- compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo);
- switch (addrInfo.accessType)
- {
- case IAT_VALUE:
- if (arm_Valid_Imm_For_BL((ssize_t)addrInfo.addr))
- {
- // Simple direct call
- callType = emitter::EC_FUNC_TOKEN;
- addr = addrInfo.addr;
- indCallReg = REG_NA;
- break;
- }
-
- // otherwise the target address doesn't fit in an immediate
- // so we have to burn a register...
- __fallthrough;
-
- case IAT_PVALUE:
- // Load the address into a register, load indirect and call through a register
- // We have to use R12 since we assume the argument registers are in use
- callType = emitter::EC_INDIR_R;
- indCallReg = REG_R12;
- addr = NULL;
- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
- if (addrInfo.accessType == IAT_PVALUE)
- {
- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
- regTracker.rsTrackRegTrash(indCallReg);
- }
- break;
-
- case IAT_PPVALUE:
- default:
- NO_WAY("Unsupported JMP indirection");
- }
-
- /* Simply emit a jump to the methodHnd. This is similar to a call so we can use
- * the same descriptor with some minor adjustments.
- */
-
- // clang-format off
- getEmitter()->emitIns_Call(callType,
- methHnd,
- INDEBUG_LDISASM_COMMA(nullptr)
- addr,
- 0, // argSize
- EA_UNKNOWN, // retSize
- gcInfo.gcVarPtrSetCur,
- gcInfo.gcRegGCrefSetCur,
- gcInfo.gcRegByrefSetCur,
- BAD_IL_OFFSET, // IL offset
- indCallReg, // ireg
- REG_NA, // xreg
- 0, // xmul
- 0, // disp
- true); // isJump
- // clang-format on
- }
- else
- {
- if (!genUsedPopToReturn)
- {
- // If we did not use a pop to return, then we did a "pop {..., lr}" instead of "pop {..., pc}",
- // so we need a "bx lr" instruction to return from the function.
- inst_RV(INS_bx, REG_LR, TYP_I_IMPL);
- compiler->unwindBranch16();
- }
- }
-
- compiler->unwindEndEpilog();
-}
-
-#elif defined(_TARGET_ARM64_)
-
-void CodeGen::genFnEpilog(BasicBlock* block)
-{
-#ifdef DEBUG
- if (verbose)
- printf("*************** In genFnEpilog()\n");
-#endif
-
- ScopedSetVariable<bool> _setGeneratingEpilog(&compiler->compGeneratingEpilog, true);
-
- VarSetOps::Assign(compiler, gcInfo.gcVarPtrSetCur, getEmitter()->emitInitGCrefVars);
- gcInfo.gcRegGCrefSetCur = getEmitter()->emitInitGCrefRegs;
- gcInfo.gcRegByrefSetCur = getEmitter()->emitInitByrefRegs;
-
-#ifdef DEBUG
- if (compiler->opts.dspCode)
- printf("\n__epilog:\n");
-
- if (verbose)
- {
- printf("gcVarPtrSetCur=%s ", VarSetOps::ToString(compiler, gcInfo.gcVarPtrSetCur));
- dumpConvertedVarSet(compiler, gcInfo.gcVarPtrSetCur);
- printf(", gcRegGCrefSetCur=");
- printRegMaskInt(gcInfo.gcRegGCrefSetCur);
- getEmitter()->emitDispRegSet(gcInfo.gcRegGCrefSetCur);
- printf(", gcRegByrefSetCur=");
- printRegMaskInt(gcInfo.gcRegByrefSetCur);
- getEmitter()->emitDispRegSet(gcInfo.gcRegByrefSetCur);
- printf("\n");
- }
-#endif
-
- bool jmpEpilog = ((block->bbFlags & BBF_HAS_JMP) != 0);
-
+#else // _TARGET_ARM64_
compiler->unwindBegEpilog();
genPopCalleeSavedRegistersAndFreeLclFrame(jmpEpilog);
+#endif // _TARGET_ARM64_
if (jmpEpilog)
{
noway_assert(block->bbJumpKind == BBJ_RETURN);
noway_assert(block->bbTreeList != nullptr);
- // figure out what jump we have
+#ifdef _TARGET_ARM_
+ // We better not have used a pop PC to return otherwise this will be unreachable code
+ noway_assert(!genUsedPopToReturn);
+#endif // _TARGET_ARM_
+
+ /* figure out what jump we have */
GenTree* jmpNode = block->lastNode();
#if !FEATURE_FASTTAILCALL
noway_assert(jmpNode->gtOper == GT_JMP);
-#else
- // arm64
+#else // FEATURE_FASTTAILCALL
+ // armarch
// If jmpNode is GT_JMP then gtNext must be null.
// If jmpNode is a fast tail call, gtNext need not be null since it could have embedded stmts.
noway_assert((jmpNode->gtOper != GT_JMP) || (jmpNode->gtNext == nullptr));
@@ -9629,7 +9531,7 @@ void CodeGen::genFnEpilog(BasicBlock* block)
// The next block is associated with this "if" stmt
if (jmpNode->gtOper == GT_JMP)
-#endif
+#endif // FEATURE_FASTTAILCALL
{
// Simply emit a jump to the methodHnd. This is similar to a call so we can use
// the same descriptor with some minor adjustments.
@@ -9637,6 +9539,70 @@ void CodeGen::genFnEpilog(BasicBlock* block)
CORINFO_CONST_LOOKUP addrInfo;
compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo);
+
+#ifdef _TARGET_ARM_
+ emitter::EmitCallType callType;
+ void* addr;
+ regNumber indCallReg;
+ switch (addrInfo.accessType)
+ {
+ case IAT_VALUE:
+ if (arm_Valid_Imm_For_BL((ssize_t)addrInfo.addr))
+ {
+ // Simple direct call
+ callType = emitter::EC_FUNC_TOKEN;
+ addr = addrInfo.addr;
+ indCallReg = REG_NA;
+ break;
+ }
+
+ // otherwise the target address doesn't fit in an immediate
+ // so we have to burn a register...
+ __fallthrough;
+
+ case IAT_PVALUE:
+ // Load the address into a register, load indirect and call through a register
+ // We have to use R12 since we assume the argument registers are in use
+ callType = emitter::EC_INDIR_R;
+ indCallReg = REG_R12;
+ addr = NULL;
+ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
+ if (addrInfo.accessType == IAT_PVALUE)
+ {
+ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+ regTracker.rsTrackRegTrash(indCallReg);
+ }
+ break;
+
+ case IAT_PPVALUE:
+ default:
+ NO_WAY("Unsupported JMP indirection");
+ }
+
+ /* Simply emit a jump to the methodHnd. This is similar to a call so we can use
+ * the same descriptor with some minor adjustments.
+ */
+
+ // clang-format off
+ getEmitter()->emitIns_Call(callType,
+ methHnd,
+ INDEBUG_LDISASM_COMMA(nullptr)
+ addr,
+ 0, // argSize
+ EA_UNKNOWN, // retSize
+ gcInfo.gcVarPtrSetCur,
+ gcInfo.gcRegGCrefSetCur,
+ gcInfo.gcRegByrefSetCur,
+ BAD_IL_OFFSET, // IL offset
+ indCallReg, // ireg
+ REG_NA, // xreg
+ 0, // xmul
+ 0, // disp
+ true); // isJump
+ // clang-format on
+ CLANG_FORMAT_COMMENT_ANCHOR;
+
+#else // _TARGET_ARM64_
if (addrInfo.accessType != IAT_VALUE)
{
NYI_ARM64("Unsupported JMP indirection");
@@ -9661,22 +9627,35 @@ void CodeGen::genFnEpilog(BasicBlock* block)
BAD_IL_OFFSET, REG_NA, REG_NA, 0, 0, /* iloffset, ireg, xreg, xmul, disp */
true); /* isJump */
// clang-format on
+ CLANG_FORMAT_COMMENT_ANCHOR;
+
+#endif // _TARGET_ARM64_
}
#if FEATURE_FASTTAILCALL
else
{
// Fast tail call.
- // Call target = REG_IP0.
+ // Call target = REG_FASTTAILCALL_TARGET
// https://github.com/dotnet/coreclr/issues/4827
// Do we need a special encoding for stack walker like rex.w prefix for x64?
- getEmitter()->emitIns_R(INS_br, emitTypeSize(TYP_I_IMPL), REG_IP0);
+ getEmitter()->emitIns_R(INS_br, emitTypeSize(TYP_I_IMPL), REG_FASTTAILCALL_TARGET);
}
#endif // FEATURE_FASTTAILCALL
}
else
{
+#ifdef _TARGET_ARM_
+ if (!genUsedPopToReturn)
+ {
+ // If we did not use a pop to return, then we did a "pop {..., lr}" instead of "pop {..., pc}",
+ // so we need a "bx lr" instruction to return from the function.
+ inst_RV(INS_bx, REG_LR, TYP_I_IMPL);
+ compiler->unwindBranch16();
+ }
+#else // _TARGET_ARM64_
inst_RV(INS_ret, REG_LR, TYP_I_IMPL);
compiler->unwindReturn(REG_LR);
+#endif // _TARGET_ARM64_
}
compiler->unwindEndEpilog();
@@ -11154,7 +11133,6 @@ void CodeGen::genRestoreCalleeSavedFltRegs(unsigned lclFrameSize)
//
void CodeGen::genVzeroupperIfNeeded(bool check256bitOnly /* = true*/)
{
-#ifdef FEATURE_AVX_SUPPORT
bool emitVzeroUpper = false;
if (check256bitOnly)
{
@@ -11167,10 +11145,9 @@ void CodeGen::genVzeroupperIfNeeded(bool check256bitOnly /* = true*/)
if (emitVzeroUpper)
{
- assert(compiler->getSIMDInstructionSet() == InstructionSet_AVX);
+ assert(compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported);
instGen(INS_vzeroupper);
}
-#endif
}
#endif // defined(_TARGET_XARCH_) && !FEATURE_STACK_FP_X87
@@ -11356,7 +11333,7 @@ instruction CodeGen::genMapShiftInsToShiftByConstantIns(instruction ins, int shi
#endif // _TARGET_XARCH_
-#if !defined(LEGACY_BACKEND) && (defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_))
+#if !defined(LEGACY_BACKEND)
//------------------------------------------------------------------------------------------------ //
// getFirstArgWithStackSlot - returns the first argument with stack slot on the caller's frame.
@@ -11368,13 +11345,13 @@ instruction CodeGen::genMapShiftInsToShiftByConstantIns(instruction ins, int shi
// On x64 Windows the caller always creates slots (homing space) in its frame for the
// first 4 arguments of a callee (register passed args). So, the the variable number
// (lclNum) for the first argument with a stack slot is always 0.
-// For System V systems or arm64, there is no such calling convention requirement, and the code needs to find
+// For System V systems or armarch, there is no such calling convention requirement, and the code needs to find
// the first stack passed argument from the caller. This is done by iterating over
// all the lvParam variables and finding the first with lvArgReg equals to REG_STK.
//
unsigned CodeGen::getFirstArgWithStackSlot()
{
-#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARM64_)
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) || defined(_TARGET_ARMARCH_)
unsigned baseVarNum = 0;
#if defined(FEATURE_UNIX_AMR64_STRUCT_PASSING)
baseVarNum = compiler->lvaFirstStackIncomingArgNum;
@@ -11412,14 +11389,14 @@ unsigned CodeGen::getFirstArgWithStackSlot()
return baseVarNum;
#elif defined(_TARGET_AMD64_)
return 0;
-#else
+#else // _TARGET_X86
// Not implemented for x86.
NYI_X86("getFirstArgWithStackSlot not yet implemented for x86.");
return BAD_VAR_NUM;
-#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING || _TARGET_ARM64_
+#endif // _TARGET_X86_
}
-#endif // !LEGACY_BACKEND && (_TARGET_XARCH_ || _TARGET_ARM64_)
+#endif // !LEGACY_BACKEND
//------------------------------------------------------------------------
// genSinglePush: Report a change in stack level caused by a single word-sized push instruction
diff --git a/src/jit/codegeninterface.h b/src/jit/codegeninterface.h
index a993ddb629..c1c912ad6a 100644
--- a/src/jit/codegeninterface.h
+++ b/src/jit/codegeninterface.h
@@ -105,10 +105,12 @@ public:
RegTracker regTracker;
public:
+#ifdef LEGACY_BACKEND
void trashReg(regNumber reg)
{
regTracker.rsTrackRegTrash(reg);
}
+#endif
protected:
Compiler* compiler;
diff --git a/src/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp
index fa85df63a3..528ab6efdc 100644
--- a/src/jit/codegenlegacy.cpp
+++ b/src/jit/codegenlegacy.cpp
@@ -4872,11 +4872,11 @@ void CodeGen::genStressRegs(GenTreePtr tree)
void CodeGen::genCodeForTreeConst(GenTreePtr tree, regMaskTP destReg, regMaskTP bestReg)
{
noway_assert(tree->IsCnsIntOrI());
-
- ssize_t ival = tree->gtIntConCommon.IconValue();
- regMaskTP needReg = destReg;
- regNumber reg;
- bool needReloc = compiler->opts.compReloc && tree->IsIconHandle();
+ GenTreeIntConCommon* con = tree->AsIntConCommon();
+ ssize_t ival = con->IconValue();
+ bool needReloc = con->ImmedValNeedsReloc(compiler);
+ regMaskTP needReg = destReg;
+ regNumber reg;
#if REDUNDANT_LOAD
@@ -11603,8 +11603,10 @@ void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
case GT_CNS_INT:
+ GenTreeIntConCommon* con;
+ con = op2->AsIntConCommon();
ssize_t ival;
- ival = op2->gtIntCon.gtIconVal;
+ ival = con->IconValue();
emitAttr size;
size = emitTypeSize(tree->TypeGet());
@@ -11660,7 +11662,7 @@ void CodeGen::genCodeForTreeSmpOpAsg(GenTreePtr tree)
/* Move the value into the target */
noway_assert(op1->gtOper != GT_REG_VAR);
- if (compiler->opts.compReloc && op2->IsIconHandle())
+ if (con->ImmedValNeedsReloc(compiler))
{
/* The constant is actually a handle that may need relocation
applied to it. genComputeReg will do the right thing (see
@@ -16661,8 +16663,10 @@ size_t CodeGen::genPushArgList(GenTreeCall* call)
else
#endif
{
- bool needReloc = compiler->opts.compReloc && curr->IsIconHandle();
- emitAttr attr = needReloc ? EA_HANDLE_CNS_RELOC : emitTypeSize(type);
+ GenTreeIntConCommon* con = curr->AsIntConCommon();
+ bool needReloc = con->ImmedValNeedsReloc(compiler);
+ emitAttr attr = needReloc ? EA_HANDLE_CNS_RELOC : emitTypeSize(type);
+
instGen_Store_Imm_Into_Lcl(type, attr, curr->gtIntCon.gtIconVal,
compiler->lvaOutgoingArgSpaceVar, argOffset);
}
diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp
index 1ee288b505..830183ed5a 100644
--- a/src/jit/codegenlinear.cpp
+++ b/src/jit/codegenlinear.cpp
@@ -398,11 +398,8 @@ void CodeGen::genCodeForBBlist()
// performed at the end of each block.
// TODO: could these checks be performed more frequently? E.g., at each location where
// the register allocator says there are no live non-variable registers. Perhaps this could
- // be done by (a) keeping a running count of live non-variable registers by using
- // gtLsraInfo.srcCount and gtLsraInfo.dstCount to decrement and increment the count, respectively,
- // and running the checks when the count is zero. Or, (b) use the map maintained by LSRA
- // (operandToLocationInfoMap) to mark a node somehow when, after the execution of that node,
- // there will be no live non-variable registers.
+ // be done by using the map maintained by LSRA (operandToLocationInfoMap) to mark a node
+ // somehow when, after the execution of that node, there will be no live non-variable registers.
regSet.rsSpillChk();
@@ -1375,15 +1372,12 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode,
regNumber srcReg,
regNumber sizeReg)
{
- assert(varTypeIsStruct(putArgNode));
-
// The putArgNode children are always contained. We should not consume any registers.
assert(putArgNode->gtGetOp1()->isContained());
- GenTree* dstAddr = putArgNode;
-
// Get the source address.
GenTree* src = putArgNode->gtGetOp1();
+ assert(varTypeIsStruct(src));
assert((src->gtOper == GT_OBJ) || ((src->gtOper == GT_IND && varTypeIsSIMD(src))));
GenTree* srcAddr = src->gtGetOp1();
@@ -1406,6 +1400,7 @@ void CodeGen::genConsumePutStructArgStk(GenTreePutArgStk* putArgNode,
assert(dstReg != REG_SPBASE);
inst_RV_RV(INS_mov, dstReg, REG_SPBASE);
#else // !_TARGET_X86_
+ GenTree* dstAddr = putArgNode;
if (dstAddr->gtRegNum != dstReg)
{
// Generate LEA instruction to load the stack of the outgoing var + SlotNum offset (or the incoming arg area
diff --git a/src/jit/codegenlinear.h b/src/jit/codegenlinear.h
index 2cee11dcdb..ec3252fd17 100644
--- a/src/jit/codegenlinear.h
+++ b/src/jit/codegenlinear.h
@@ -53,9 +53,7 @@ void genPutArgSplit(GenTreePutArgSplit* treeNode);
unsigned getBaseVarForPutArgStk(GenTreePtr treeNode);
#endif // _TARGET_XARCH_
-#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
unsigned getFirstArgWithStackSlot();
-#endif // _TARGET_XARCH_ || _TARGET_ARM64_
void genCompareFloat(GenTreePtr treeNode);
void genCompareInt(GenTreePtr treeNode);
@@ -68,6 +66,9 @@ enum SIMDScalarMoveType
SMT_PreserveUpper // preserve target upper bits
};
+#ifdef _TARGET_ARM64_
+insOpts genGetSimdInsOpt(bool is16B, var_types elementType);
+#endif
instruction getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_types baseType, unsigned* ival = nullptr);
void genSIMDScalarMove(
var_types targetType, var_types type, regNumber target, regNumber src, SIMDScalarMoveType moveType);
@@ -113,6 +114,25 @@ void genPutArgStkSIMD12(GenTree* treeNode);
#endif // _TARGET_X86_
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+void genHWIntrinsic(GenTreeHWIntrinsic* node);
+void genSSEIntrinsic(GenTreeHWIntrinsic* node);
+void genSSE2Intrinsic(GenTreeHWIntrinsic* node);
+void genSSE3Intrinsic(GenTreeHWIntrinsic* node);
+void genSSSE3Intrinsic(GenTreeHWIntrinsic* node);
+void genSSE41Intrinsic(GenTreeHWIntrinsic* node);
+void genSSE42Intrinsic(GenTreeHWIntrinsic* node);
+void genAVXIntrinsic(GenTreeHWIntrinsic* node);
+void genAVX2Intrinsic(GenTreeHWIntrinsic* node);
+void genAESIntrinsic(GenTreeHWIntrinsic* node);
+void genBMI1Intrinsic(GenTreeHWIntrinsic* node);
+void genBMI2Intrinsic(GenTreeHWIntrinsic* node);
+void genFMAIntrinsic(GenTreeHWIntrinsic* node);
+void genLZCNTIntrinsic(GenTreeHWIntrinsic* node);
+void genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node);
+void genPOPCNTIntrinsic(GenTreeHWIntrinsic* node);
+#endif // FEATURE_HW_INTRINSICS
+
#if !defined(_TARGET_64BIT_)
// CodeGen for Long Ints
diff --git a/src/jit/codegenxarch.cpp b/src/jit/codegenxarch.cpp
index 58c6c10222..a256c2eb9f 100644
--- a/src/jit/codegenxarch.cpp
+++ b/src/jit/codegenxarch.cpp
@@ -466,12 +466,11 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre
{
double constValue = tree->gtDblCon.gtDconVal;
- // Make sure we use "xorpd reg, reg" only for +ve zero constant (0.0) and not for -ve zero (-0.0)
+ // Make sure we use "xorps reg, reg" only for +ve zero constant (0.0) and not for -ve zero (-0.0)
if (*(__int64*)&constValue == 0)
{
// A faster/smaller way to generate 0
- instruction ins = genGetInsForOper(GT_XOR, targetType);
- inst_RV_RV(ins, targetReg, targetReg, targetType);
+ inst_RV_RV(INS_xorps, targetReg, targetReg, targetType);
}
else
{
@@ -808,8 +807,7 @@ void CodeGen::genCodeForBinary(GenTree* treeNode)
assert(oper == GT_OR || oper == GT_XOR || oper == GT_AND || oper == GT_ADD || oper == GT_SUB);
#else // !defined(_TARGET_64BIT_)
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_LONG || oper == GT_DIV_HI || oper == GT_MOD_HI ||
- oper == GT_ADD || oper == GT_SUB);
+ oper == GT_SUB_LO || oper == GT_SUB_HI || oper == GT_ADD || oper == GT_SUB);
#endif // !defined(_TARGET_64BIT_)
GenTreePtr op1 = treeNode->gtGetOp1();
@@ -1871,6 +1869,12 @@ void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
break;
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+ genHWIntrinsic(treeNode->AsHWIntrinsic());
+ break;
+#endif // FEATURE_HW_INTRINSICS
+
case GT_CKFINITE:
genCkfinite(treeNode);
break;
@@ -3206,13 +3210,10 @@ unsigned CodeGen::genMove1IfNeeded(unsigned size, regNumber intTmpReg, GenTree*
//
void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode)
{
+ GenTreePtr src = putArgNode->gtOp.gtOp1;
// We will never call this method for SIMD types, which are stored directly
// in genPutStructArgStk().
- noway_assert(putArgNode->TypeGet() == TYP_STRUCT);
-
- // Make sure we got the arguments of the cpblk operation in the right registers
- GenTreePtr dstAddr = putArgNode;
- GenTreePtr src = putArgNode->gtOp.gtOp1;
+ noway_assert(src->TypeGet() == TYP_STRUCT);
unsigned size = putArgNode->getArgSize();
assert(size <= CPBLK_UNROLL_LIMIT);
@@ -3330,14 +3331,12 @@ void CodeGen::genStructPutArgUnroll(GenTreePutArgStk* putArgNode)
//
void CodeGen::genStructPutArgRepMovs(GenTreePutArgStk* putArgNode)
{
- assert(putArgNode->TypeGet() == TYP_STRUCT);
- assert(putArgNode->getArgSize() > CPBLK_UNROLL_LIMIT);
-
- // Make sure we got the arguments of the cpblk operation in the right registers
- GenTreePtr dstAddr = putArgNode;
GenTreePtr srcAddr = putArgNode->gtGetOp1();
+ assert(srcAddr->TypeGet() == TYP_STRUCT);
+ assert(putArgNode->getArgSize() > CPBLK_UNROLL_LIMIT);
- // Validate state.
+ // Make sure we got the arguments of the cpblk operation in the right registers, and that
+ // 'srcAddr' is contained as expected.
assert(putArgNode->gtRsvdRegs == (RBM_RDI | RBM_RCX | RBM_RSI));
assert(srcAddr->isContained());
@@ -3423,7 +3422,7 @@ void CodeGen::genCodeForCpObj(GenTreeObj* cpObjNode)
sourceIsLocal = true;
}
- bool dstOnStack = dstAddr->OperIsLocalAddr();
+ bool dstOnStack = dstAddr->gtSkipReloadOrCopy()->OperIsLocalAddr();
#ifdef DEBUG
@@ -5215,34 +5214,24 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
GenTreePtr arg = args->gtOp.gtOp1;
if (arg->OperGet() != GT_ARGPLACE && !(arg->gtFlags & GTF_LATE_ARG))
{
-#if defined(_TARGET_X86_)
- if ((arg->OperGet() == GT_PUTARG_STK) && (arg->gtGetOp1()->OperGet() == GT_FIELD_LIST))
+ if (arg->OperGet() == GT_PUTARG_STK)
{
+ GenTree* source = arg->gtOp.gtOp1;
+ unsigned size = arg->AsPutArgStk()->getArgSize();
+ stackArgBytes += size;
+#ifdef DEBUG
fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
assert(curArgTabEntry);
- stackArgBytes += curArgTabEntry->numSlots * TARGET_POINTER_SIZE;
- }
- else
-#endif // defined(_TARGET_X86_)
-
+ assert(size == (curArgTabEntry->numSlots * TARGET_POINTER_SIZE));
#ifdef FEATURE_PUT_STRUCT_ARG_STK
- if (genActualType(arg->TypeGet()) == TYP_STRUCT)
- {
- assert(arg->OperGet() == GT_PUTARG_STK);
-
- GenTreeObj* obj = arg->gtGetOp1()->AsObj();
- unsigned argBytes = (unsigned)roundUp(obj->gtBlkSize, TARGET_POINTER_SIZE);
-#ifdef DEBUG
- fgArgTabEntryPtr curArgTabEntry = compiler->gtArgEntryByNode(call, arg);
- assert((curArgTabEntry->numSlots * TARGET_POINTER_SIZE) == argBytes);
-#endif // DEBUG
- stackArgBytes += argBytes;
- }
- else
+ if (source->TypeGet() == TYP_STRUCT)
+ {
+ GenTreeObj* obj = source->AsObj();
+ unsigned argBytes = (unsigned)roundUp(obj->gtBlkSize, TARGET_POINTER_SIZE);
+ assert((curArgTabEntry->numSlots * TARGET_POINTER_SIZE) == argBytes);
+ }
#endif // FEATURE_PUT_STRUCT_ARG_STK
-
- {
- stackArgBytes += genTypeSize(genActualType(arg->TypeGet()));
+#endif // DEBUG
}
}
args = args->gtOp.gtOp2;
@@ -5300,7 +5289,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
// the GC pointer state before the callsite.
// We can't utilize the typical lazy killing of GC pointers
// at (or inside) the callsite.
- if (call->IsUnmanaged())
+ if (compiler->killGCRefs(call))
{
genDefineTempLabel(genCreateTempLabel());
}
@@ -5369,7 +5358,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
}
#endif // defined(_TARGET_X86_)
-#ifdef FEATURE_AVX_SUPPORT
// When it's a PInvoke call and the call type is USER function, we issue VZEROUPPER here
// if the function contains 256bit AVX instructions, this is to avoid AVX-256 to Legacy SSE
// transition penalty, assuming the user function contains legacy SSE instruction.
@@ -5378,10 +5366,9 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
// when there's preceding 256-bit AVX to legacy SSE transition penalty.
if (call->IsPInvoke() && (call->gtCallType == CT_USER_FUNC) && getEmitter()->Contains256bitAVX())
{
- assert(compiler->getSIMDInstructionSet() == InstructionSet_AVX);
+ assert(compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported);
instGen(INS_vzeroupper);
}
-#endif
if (target != nullptr)
{
@@ -6243,66 +6230,6 @@ void CodeGen::genCompareInt(GenTreePtr treeNode)
var_types op2Type = op2->TypeGet();
regNumber targetReg = tree->gtRegNum;
- // Case of op1 == 0 or op1 != 0:
- // Optimize generation of 'test' instruction if op1 sets flags.
- //
- // TODO-Cleanup Review GTF_USE_FLAGS usage
- // https://github.com/dotnet/coreclr/issues/14093
- //
- // Note that if LSRA has inserted any GT_RELOAD/GT_COPY before
- // op1, it will not modify the flags set by codegen of op1.
- // Similarly op1 could also be reg-optional at its use and
- // it was spilled after producing its result in a register.
- // Spill code too will not modify the flags set by op1.
- GenTree* realOp1 = op1->gtSkipReloadOrCopy();
- if ((tree->gtFlags & GTF_USE_FLAGS) != 0)
- {
- // op1 must set ZF and SF flags
- assert(realOp1->gtSetZSFlags());
- assert(realOp1->gtSetFlags());
-
- // Must be (in)equality against zero.
- assert(tree->OperIs(GT_EQ, GT_NE));
- assert(op2->IsIntegralConst(0));
- assert(op2->isContained());
-
- // Just consume the operands
- genConsumeOperands(tree);
-
- // No need to generate test instruction since
- // op1 sets flags
-
- // Are we evaluating this into a register?
- if (targetReg != REG_NA)
- {
- genSetRegToCond(targetReg, tree);
- genProduceReg(tree);
- }
-
- return;
- }
-
-#ifdef FEATURE_SIMD
- // If we have GT_JTRUE(GT_EQ/NE(GT_SIMD((in)Equality, v1, v2), true/false)),
- // then we don't need to generate code for GT_EQ/GT_NE, since SIMD (in)Equality intrinsic
- // would set or clear Zero flag.
- if ((targetReg == REG_NA) && tree->OperIs(GT_EQ, GT_NE))
- {
- // Is it a SIMD (in)Equality that doesn't need to materialize result into a register?
- if ((op1->gtRegNum == REG_NA) && op1->IsSIMDEqualityOrInequality())
- {
- // Must be comparing against true or false.
- assert(op2->IsIntegralConst(0) || op2->IsIntegralConst(1));
- assert(op2->isContainedIntOrIImmed());
-
- // In this case SIMD (in)Equality will set or clear
- // Zero flag, based on which GT_JTRUE would generate
- // the right conditional jump.
- return;
- }
- }
-#endif // FEATURE_SIMD
-
genConsumeOperands(tree);
assert(!op1->isContainedIntOrIImmed());
@@ -7364,7 +7291,7 @@ void CodeGen::genSSE2BitwiseOp(GenTreePtr treeNode)
// Neg(x) = flip the sign bit.
// Neg(f) = f ^ 0x80000000
// Neg(d) = d ^ 0x8000000000000000
- ins = genGetInsForOper(GT_XOR, targetType);
+ ins = INS_xorps;
if (targetType == TYP_FLOAT)
{
bitMask = &negBitmaskFlt;
@@ -7390,7 +7317,7 @@ void CodeGen::genSSE2BitwiseOp(GenTreePtr treeNode)
// Abs(x) = set sign-bit to zero
// Abs(f) = f & 0x7fffffff
// Abs(d) = d & 0x7fffffffffffffff
- ins = genGetInsForOper(GT_AND, targetType);
+ ins = INS_andps;
if (targetType == TYP_FLOAT)
{
bitMask = &absBitmaskFlt;
@@ -7655,10 +7582,12 @@ void CodeGen::genRemoveAlignmentAfterCall(GenTreeCall* call, unsigned bias)
//
bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk)
{
+ const unsigned argSize = putArgStk->getArgSize();
+ GenTree* source = putArgStk->gtGetOp1();
+
#ifdef FEATURE_SIMD
- if (varTypeIsSIMD(putArgStk))
+ if (!source->OperIs(GT_FIELD_LIST) && varTypeIsSIMD(source))
{
- const unsigned argSize = genTypeSize(putArgStk);
inst_RV_IV(INS_sub, REG_SPBASE, argSize, EA_PTRSIZE);
AddStackLevel(argSize);
m_pushStkArg = false;
@@ -7666,8 +7595,6 @@ bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk)
}
#endif // FEATURE_SIMD
- const unsigned argSize = putArgStk->getArgSize();
-
// If the gtPutArgStkKind is one of the push types, we do not pre-adjust the stack.
// This is set in Lowering, and is true if and only if:
// - This argument contains any GC pointers OR
@@ -7680,13 +7607,11 @@ bool CodeGen::genAdjustStackForPutArgStk(GenTreePutArgStk* putArgStk)
{
case GenTreePutArgStk::Kind::RepInstr:
case GenTreePutArgStk::Kind::Unroll:
- assert((putArgStk->gtNumberReferenceSlots == 0) && (putArgStk->gtGetOp1()->OperGet() != GT_FIELD_LIST) &&
- (argSize >= 16));
+ assert((putArgStk->gtNumberReferenceSlots == 0) && (source->OperGet() != GT_FIELD_LIST) && (argSize >= 16));
break;
case GenTreePutArgStk::Kind::Push:
case GenTreePutArgStk::Kind::PushAllSlots:
- assert((putArgStk->gtNumberReferenceSlots != 0) || (putArgStk->gtGetOp1()->OperGet() == GT_FIELD_LIST) ||
- (argSize < 16));
+ assert((putArgStk->gtNumberReferenceSlots != 0) || (source->OperGet() == GT_FIELD_LIST) || (argSize < 16));
break;
case GenTreePutArgStk::Kind::Invalid:
default:
@@ -7930,26 +7855,21 @@ void CodeGen::genPutArgStkFieldList(GenTreePutArgStk* putArgStk)
//
void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk)
{
- var_types targetType = putArgStk->TypeGet();
+ GenTreePtr data = putArgStk->gtOp1;
+ var_types targetType = genActualType(data->TypeGet());
#ifdef _TARGET_X86_
genAlignStackBeforeCall(putArgStk);
- if (varTypeIsStruct(targetType))
+ if ((data->OperGet() != GT_FIELD_LIST) && varTypeIsStruct(targetType))
{
(void)genAdjustStackForPutArgStk(putArgStk);
genPutStructArgStk(putArgStk);
return;
}
- // The following logic is applicable for x86 arch.
- assert(!varTypeIsFloating(targetType) || (targetType == putArgStk->gtOp1->TypeGet()));
-
- GenTreePtr data = putArgStk->gtOp1;
-
- // On a 32-bit target, all of the long arguments are handled with GT_FIELD_LIST,
- // and the type of the putArgStk is TYP_VOID.
+ // On a 32-bit target, all of the long arguments are handled with GT_FIELD_LISTs of TYP_INT.
assert(targetType != TYP_LONG);
const unsigned argSize = putArgStk->getArgSize();
@@ -7995,7 +7915,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk)
#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
noway_assert(targetType != TYP_STRUCT);
- assert(!varTypeIsFloating(targetType) || (targetType == putArgStk->gtOp1->TypeGet()));
// Get argument offset on stack.
// Here we cross check that argument offset hasn't changed from lowering to codegen since
@@ -8008,8 +7927,6 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* putArgStk)
assert(argOffset == (int)curArgTabEntry->slotNum * TARGET_POINTER_SIZE);
#endif
- GenTreePtr data = putArgStk->gtOp1;
-
if (data->isContainedIntOrIImmed())
{
getEmitter()->emitIns_S_I(ins_Store(targetType), emitTypeSize(targetType), baseVarNum, argOffset,
@@ -8193,10 +8110,11 @@ void CodeGen::genStoreRegToStackArg(var_types type, regNumber srcReg, int offset
// For non tail calls this is the outgoingArgSpace.
void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
{
- var_types targetType = putArgStk->TypeGet();
+ GenTree* source = putArgStk->gtGetOp1();
+ var_types targetType = source->TypeGet();
#if defined(_TARGET_X86_) && defined(FEATURE_SIMD)
- if (targetType == TYP_SIMD12)
+ if (putArgStk->isSIMD12())
{
genPutArgStkSIMD12(putArgStk);
return;
@@ -8205,7 +8123,7 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
if (varTypeIsSIMD(targetType))
{
- regNumber srcReg = genConsumeReg(putArgStk->gtGetOp1());
+ regNumber srcReg = genConsumeReg(source);
assert((srcReg != REG_NA) && (genIsValidFloatReg(srcReg)));
genStoreRegToStackArg(targetType, srcReg, 0);
return;
@@ -8244,7 +8162,7 @@ void CodeGen::genPutStructArgStk(GenTreePutArgStk* putArgStk)
// future.
assert(m_pushStkArg);
- GenTree* srcAddr = putArgStk->gtGetOp1()->gtGetOp1();
+ GenTree* srcAddr = source->gtGetOp1();
BYTE* gcPtrs = putArgStk->gtGcPtrs;
const unsigned numSlots = putArgStk->gtNumSlots;
@@ -8694,7 +8612,6 @@ void CodeGen::genEmitHelperCall(unsigned helper, int argSize, emitAttr retSize,
// clang-format on
regTracker.rsTrashRegSet(killMask);
- regTracker.rsTrashRegsForGCInterruptability();
}
#if !defined(_TARGET_64BIT_)
@@ -8791,7 +8708,6 @@ void CodeGen::genAmd64EmitterUnitTests()
CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef ALL_XARCH_EMITTER_UNIT_TESTS
-#ifdef FEATURE_AVX_SUPPORT
genDefineTempLabel(genCreateTempLabel());
// vhaddpd ymm0,ymm1,ymm2
@@ -8861,7 +8777,6 @@ void CodeGen::genAmd64EmitterUnitTests()
getEmitter()->emitIns_R_R_R(INS_cvtss2sd, EA_4BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
// vdivsd xmm0,xmm1,xmm2
getEmitter()->emitIns_R_R_R(INS_cvtsd2ss, EA_8BYTE, REG_XMM0, REG_XMM1, REG_XMM2);
-#endif // FEATURE_AVX_SUPPORT
#endif // ALL_XARCH_EMITTER_UNIT_TESTS
printf("*************** End of genAmd64EmitterUnitTests()\n");
}
diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp
index 6e1323ff2e..efad4cfd0f 100644
--- a/src/jit/compiler.cpp
+++ b/src/jit/compiler.cpp
@@ -1997,6 +1997,7 @@ void Compiler::compInit(ArenaAllocator* pAlloc, InlineInfo* inlineInfo)
compLongUsed = false;
compTailCallUsed = false;
compLocallocUsed = false;
+ compLocallocOptimized = false;
compQmarkRationalized = false;
compQmarkUsed = false;
compFloatingPointUsed = false;
@@ -2443,6 +2444,52 @@ const char* Compiler::compLocalVarName(unsigned varNum, unsigned offs)
#endif // DEBUG
/*****************************************************************************/
+#ifdef _TARGET_XARCH_
+static bool configEnableISA(InstructionSet isa)
+{
+#ifdef DEBUG
+ switch (isa)
+ {
+ case InstructionSet_SSE:
+ return JitConfig.EnableSSE() != 0;
+ case InstructionSet_SSE2:
+ return JitConfig.EnableSSE2() != 0;
+ case InstructionSet_SSE3:
+ return JitConfig.EnableSSE3() != 0;
+ case InstructionSet_SSSE3:
+ return JitConfig.EnableSSSE3() != 0;
+ case InstructionSet_SSE41:
+ return JitConfig.EnableSSE41() != 0;
+ case InstructionSet_SSE42:
+ return JitConfig.EnableSSE42() != 0;
+ case InstructionSet_AVX:
+ return JitConfig.EnableAVX() != 0;
+ case InstructionSet_AVX2:
+ return JitConfig.EnableAVX2() != 0;
+
+ case InstructionSet_AES:
+ return JitConfig.EnableAES() != 0;
+ case InstructionSet_BMI1:
+ return JitConfig.EnableBMI1() != 0;
+ case InstructionSet_BMI2:
+ return JitConfig.EnableBMI2() != 0;
+ case InstructionSet_FMA:
+ return JitConfig.EnableFMA() != 0;
+ case InstructionSet_LZCNT:
+ return JitConfig.EnableLZCNT() != 0;
+ case InstructionSet_PCLMULQDQ:
+ return JitConfig.EnablePCLMULQDQ() != 0;
+ case InstructionSet_POPCNT:
+ return JitConfig.EnablePOPCNT() != 0;
+ default:
+ return false;
+ }
+#else
+ return true;
+#endif
+}
+#endif // _TARGET_XARCH_
+
void Compiler::compSetProcessor()
{
const JitFlags& jitFlags = *opts.jitFlags;
@@ -2450,7 +2497,7 @@ void Compiler::compSetProcessor()
#if defined(_TARGET_ARM_)
info.genCPU = CPU_ARM;
#elif defined(_TARGET_AMD64_)
- info.genCPU = CPU_X64;
+ info.genCPU = CPU_X64;
#elif defined(_TARGET_X86_)
if (jitFlags.IsSet(JitFlags::JIT_FLAG_TARGET_P4))
info.genCPU = CPU_X86_PENTIUM_4;
@@ -2464,16 +2511,16 @@ void Compiler::compSetProcessor()
CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef _TARGET_XARCH_
- opts.compCanUseSSE3_4 = false;
- if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3_4))
+ opts.compCanUseSSE4 = false;
+ if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE41) &&
+ jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE42))
{
if (JitConfig.EnableSSE3_4() != 0)
{
- opts.compCanUseSSE3_4 = true;
+ opts.compCanUseSSE4 = true;
}
}
-#ifdef FEATURE_AVX_SUPPORT
// COMPlus_EnableAVX can be used to disable using AVX if available on a target machine.
opts.compCanUseAVX = false;
if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
@@ -2483,11 +2530,9 @@ void Compiler::compSetProcessor()
opts.compCanUseAVX = true;
}
}
-#endif // FEATURE_AVX_SUPPORT
if (!compIsForInlining())
{
-#ifdef FEATURE_AVX_SUPPORT
if (opts.compCanUseAVX)
{
codeGen->getEmitter()->SetUseAVX(true);
@@ -2495,11 +2540,9 @@ void Compiler::compSetProcessor()
codeGen->getEmitter()->SetContainsAVX(false);
codeGen->getEmitter()->SetContains256bitAVX(false);
}
- else
-#endif // FEATURE_AVX_SUPPORT
- if (opts.compCanUseSSE3_4)
+ else if (opts.compCanUseSSE4)
{
- codeGen->getEmitter()->SetUseSSE3_4(true);
+ codeGen->getEmitter()->SetUseSSE4(true);
}
}
#endif // _TARGET_XARCH_
@@ -2509,22 +2552,16 @@ void Compiler::compSetProcessor()
opts.compUseCMOV = true;
opts.compCanUseSSE2 = true;
#elif defined(_TARGET_X86_)
- opts.compUseFCOMI = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FCOMI);
- opts.compUseCMOV = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_CMOV);
- opts.compCanUseSSE2 = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE2);
+ opts.compUseFCOMI = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FCOMI);
+ opts.compUseCMOV = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_CMOV);
-#if !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
+#ifdef LEGACY_BACKEND
+ opts.compCanUseSSE2 = jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE2);
+#else
// RyuJIT/x86 requires SSE2 to be available: there is no support for generating floating-point
- // code with x87 instructions. On .NET Core, the VM always tells us that SSE2 is available.
- // However, on desktop, under ngen, (and presumably in the unlikely case you're actually
- // running on a machine without SSE2), the VM does not set the SSE2 flag. We ignore this and
- // go ahead and generate SSE2 code anyway.
- if (!opts.compCanUseSSE2)
- {
- JITDUMP("VM didn't set CORJIT_FLG_USE_SSE2! Ignoring, and generating SSE2 code anyway.\n");
- opts.compCanUseSSE2 = true;
- }
-#endif // !defined(LEGACY_BACKEND) && !defined(FEATURE_CORECLR)
+ // code with x87 instructions.
+ opts.compCanUseSSE2 = true;
+#endif
#ifdef DEBUG
if (opts.compUseFCOMI)
@@ -2569,59 +2606,104 @@ void Compiler::compSetProcessor()
{
if (opts.compCanUseSSE2)
{
- opts.setSupportedISA(InstructionSet_SSE);
- opts.setSupportedISA(InstructionSet_SSE2);
+ if (configEnableISA(InstructionSet_SSE))
+ {
+ opts.setSupportedISA(InstructionSet_SSE);
+ }
+ if (configEnableISA(InstructionSet_SSE2))
+ {
+ opts.setSupportedISA(InstructionSet_SSE2);
+ }
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AES))
{
- opts.setSupportedISA(InstructionSet_AES);
+ if (configEnableISA(InstructionSet_AES))
+ {
+ opts.setSupportedISA(InstructionSet_AES);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX))
{
- opts.setSupportedISA(InstructionSet_AVX);
+ if (configEnableISA(InstructionSet_AVX))
+ {
+ opts.setSupportedISA(InstructionSet_AVX);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
{
- opts.setSupportedISA(InstructionSet_AVX2);
+ if (configEnableISA(InstructionSet_AVX2))
+ {
+ opts.setSupportedISA(InstructionSet_AVX2);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI1))
{
- opts.setSupportedISA(InstructionSet_BMI1);
+ if (configEnableISA(InstructionSet_BMI1))
+ {
+ opts.setSupportedISA(InstructionSet_BMI1);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_BMI2))
{
- opts.setSupportedISA(InstructionSet_BMI2);
+ if (configEnableISA(InstructionSet_BMI2))
+ {
+ opts.setSupportedISA(InstructionSet_BMI2);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_FMA))
{
- opts.setSupportedISA(InstructionSet_FMA);
+ if (configEnableISA(InstructionSet_FMA))
+ {
+ opts.setSupportedISA(InstructionSet_FMA);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_LZCNT))
{
- opts.setSupportedISA(InstructionSet_LZCNT);
+ if (configEnableISA(InstructionSet_LZCNT))
+ {
+ opts.setSupportedISA(InstructionSet_LZCNT);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_PCLMULQDQ))
{
- opts.setSupportedISA(InstructionSet_PCLMULQDQ);
+ if (configEnableISA(InstructionSet_PCLMULQDQ))
+ {
+ opts.setSupportedISA(InstructionSet_PCLMULQDQ);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_POPCNT))
{
- opts.setSupportedISA(InstructionSet_POPCNT);
+ if (configEnableISA(InstructionSet_POPCNT))
+ {
+ opts.setSupportedISA(InstructionSet_POPCNT);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE3))
{
- opts.setSupportedISA(InstructionSet_SSE3);
+ if (configEnableISA(InstructionSet_SSE3))
+ {
+ opts.setSupportedISA(InstructionSet_SSE3);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE41))
{
- opts.setSupportedISA(InstructionSet_SSE41);
+ if (configEnableISA(InstructionSet_SSE41))
+ {
+ opts.setSupportedISA(InstructionSet_SSE41);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSE42))
{
- opts.setSupportedISA(InstructionSet_SSE42);
+ if (configEnableISA(InstructionSet_SSE42))
+ {
+ opts.setSupportedISA(InstructionSet_SSE42);
+ }
}
if (jitFlags.IsSet(JitFlags::JIT_FLAG_USE_SSSE3))
{
- opts.setSupportedISA(InstructionSet_SSSE3);
+ if (configEnableISA(InstructionSet_SSSE3))
+ {
+ opts.setSupportedISA(InstructionSet_SSSE3);
+ }
}
}
}
@@ -9229,10 +9311,12 @@ int cTreeKindsIR(Compiler* comp, GenTree* tree)
{
chars += printf("[LOGOP]");
}
+#ifdef LEGACY_BACKEND
if (kind & GTK_ASGOP)
{
chars += printf("[ASGOP]");
}
+#endif
if (kind & GTK_COMMUTE)
{
chars += printf("[COMMUTE]");
@@ -9805,8 +9889,10 @@ int cTreeFlagsIR(Compiler* comp, GenTree* tree)
case GT_CAST:
case GT_ADD:
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
case GT_ASG_SUB:
+#endif
if (tree->gtFlags & GTF_OVERFLOW)
{
chars += printf("[OVERFLOW]");
@@ -9847,11 +9933,11 @@ int cTreeFlagsIR(Compiler* comp, GenTree* tree)
{
chars += printf("[SPILLED_OP2]");
}
-#endif
if (tree->gtFlags & GTF_ZSF_SET)
{
chars += printf("[ZSF_SET]");
}
+#endif
#if FEATURE_SET_FLAGS
if (tree->gtFlags & GTF_SET_FLAGS)
{
@@ -11307,3 +11393,33 @@ HelperCallProperties Compiler::s_helperCallProperties;
/*****************************************************************************/
/*****************************************************************************/
+
+//------------------------------------------------------------------------
+// killGCRefs:
+// Given some tree node return does it need all GC refs to be spilled from
+// callee save registers.
+//
+// Arguments:
+// tree - the tree for which we ask about gc refs.
+//
+// Return Value:
+// true - tree kills GC refs on callee save registers
+// false - tree doesn't affect GC refs on callee save registers
+bool Compiler::killGCRefs(GenTreePtr tree)
+{
+ if (tree->IsCall())
+ {
+ GenTreeCall* call = tree->AsCall();
+ if (call->IsUnmanaged())
+ {
+ return true;
+ }
+
+ if (call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_JIT_PINVOKE_BEGIN))
+ {
+ assert(opts.ShouldUsePInvokeHelpers());
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/jit/compiler.h b/src/jit/compiler.h
index 4bdb7ac07e..ffaa8cec9d 100644
--- a/src/jit/compiler.h
+++ b/src/jit/compiler.h
@@ -137,12 +137,12 @@ unsigned ReinterpretHexAsDecimal(unsigned);
/*****************************************************************************/
-#ifdef FEATURE_SIMD
-#ifdef FEATURE_AVX_SUPPORT
+#if defined(FEATURE_SIMD)
+#if defined(_TARGET_XARCH_)
const unsigned TEMP_MAX_SIZE = YMM_REGSIZE_BYTES;
-#else // !FEATURE_AVX_SUPPORT
-const unsigned TEMP_MAX_SIZE = XMM_REGSIZE_BYTES;
-#endif // !FEATURE_AVX_SUPPORT
+#elif defined(_TARGET_ARM64_)
+const unsigned TEMP_MAX_SIZE = FP_REGSIZE_BYTES;
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
#else // !FEATURE_SIMD
const unsigned TEMP_MAX_SIZE = sizeof(double);
#endif // !FEATURE_SIMD
@@ -1170,9 +1170,14 @@ struct FuncInfoDsc
BYTE unwindCodes[offsetof(UNWIND_INFO, UnwindCode) + (0xFF * sizeof(UNWIND_CODE))];
unsigned unwindCodeSlot;
-#ifdef UNIX_AMD64_ABI
- jitstd::vector<CFI_CODE>* cfiCodes;
-#endif // UNIX_AMD64_ABI
+#elif defined(_TARGET_X86_)
+
+#if defined(_TARGET_UNIX_)
+ emitLocation* startLoc;
+ emitLocation* endLoc;
+ emitLocation* coldStartLoc; // locations for the cold section, if there is one.
+ emitLocation* coldEndLoc;
+#endif // _TARGET_UNIX_
#elif defined(_TARGET_ARMARCH_)
@@ -1184,8 +1189,19 @@ struct FuncInfoDsc
// Note 2: we currently don't support hot/cold splitting in functions
// with EH, so uwiCold will be NULL for all funclets.
+#if defined(_TARGET_UNIX_)
+ emitLocation* startLoc;
+ emitLocation* endLoc;
+ emitLocation* coldStartLoc; // locations for the cold section, if there is one.
+ emitLocation* coldEndLoc;
+#endif // _TARGET_UNIX_
+
#endif // _TARGET_ARMARCH_
+#if defined(_TARGET_UNIX_)
+ jitstd::vector<CFI_CODE>* cfiCodes;
+#endif // _TARGET_UNIX_
+
// Eventually we may want to move rsModifiedRegsMask, lvaOutgoingArgSize, and anything else
// that isn't shared between the main function body and funclets.
};
@@ -1992,22 +2008,19 @@ public:
GenTree* gtNewPhysRegNode(regNumber reg, var_types type);
GenTreePtr gtNewJmpTableNode();
- GenTreePtr gtNewIconHandleNode(
- size_t value, unsigned flags, FieldSeqNode* fields = nullptr, unsigned handle1 = 0, void* handle2 = nullptr);
+
+ GenTreePtr gtNewIndOfIconHandleNode(var_types indType, size_t value, unsigned iconFlags, bool isInvariant);
+
+ GenTreePtr gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields = nullptr);
unsigned gtTokenToIconFlags(unsigned token);
- GenTreePtr gtNewIconEmbHndNode(void* value,
- void* pValue,
- unsigned flags,
- unsigned handle1 = 0,
- void* handle2 = nullptr,
- void* compileTimeHandle = nullptr);
+ GenTreePtr gtNewIconEmbHndNode(void* value, void* pValue, unsigned flags, void* compileTimeHandle);
- GenTreePtr gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
- GenTreePtr gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
- GenTreePtr gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
- GenTreePtr gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd, unsigned hnd1 = 0, void* hnd2 = nullptr);
+ GenTreePtr gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd);
+ GenTreePtr gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd);
+ GenTreePtr gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd);
+ GenTreePtr gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd);
GenTreePtr gtNewStringLiteralNode(InfoAccessType iat, void* pValue);
@@ -2075,6 +2088,19 @@ public:
void SetOpLclRelatedToSIMDIntrinsic(GenTreePtr op);
#endif
+#if FEATURE_HW_INTRINSICS
+ GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
+ var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
+ GenTreeHWIntrinsic* gtNewSimdHWIntrinsicNode(
+ var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size);
+ GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID);
+ GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode(var_types type,
+ GenTree* op1,
+ GenTree* op2,
+ NamedIntrinsic hwIntrinsicID);
+ GenTree* gtNewMustThrowException(unsigned helper, var_types type);
+#endif // FEATURE_HW_INTRINSICS
+
GenTreePtr gtNewLclLNode(unsigned lnum, var_types type, IL_OFFSETX ILoffs = BAD_IL_OFFSET);
GenTreeLclFld* gtNewLclFldNode(unsigned lnum, var_types type, unsigned offset);
GenTreePtr gtNewInlineCandidateReturnExpr(GenTreePtr inlineCandidate, var_types type);
@@ -2123,6 +2149,8 @@ public:
GenTreePtr gtNewAllocObjNode(unsigned int helper, CORINFO_CLASS_HANDLE clsHnd, var_types type, GenTreePtr op1);
+ GenTree* gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* lookupTree);
+
//------------------------------------------------------------------------
// Other GenTree functions
@@ -2230,8 +2258,8 @@ public:
//-------------------------------------------------------------------------
- GenTreePtr gtFoldExpr(GenTreePtr tree);
- GenTreePtr
+ GenTree* gtFoldExpr(GenTree* tree);
+ GenTree*
#ifdef __clang__
// TODO-Amd64-Unix: Remove this when the clang optimizer is fixed and/or the method implementation is
// refactored in a simpler code. This is a workaround for a bug in the clang-3.5 optimizer. The issue is that in
@@ -2242,9 +2270,12 @@ public:
// optimizations for now.
__attribute__((optnone))
#endif // __clang__
- gtFoldExprConst(GenTreePtr tree);
- GenTreePtr gtFoldExprSpecial(GenTreePtr tree);
- GenTreePtr gtFoldExprCompare(GenTreePtr tree);
+ gtFoldExprConst(GenTree* tree);
+ GenTree* gtFoldExprSpecial(GenTree* tree);
+ GenTree* gtFoldExprCompare(GenTree* tree);
+ GenTree* gtFoldExprCall(GenTreeCall* call);
+ GenTree* gtFoldTypeCompare(GenTree* tree);
+ GenTree* gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2);
// Options to control behavior of gtTryRemoveBoxUpstreamEffects
enum BoxRemovalOptions
@@ -2252,7 +2283,8 @@ public:
BR_REMOVE_AND_NARROW, // remove effects, minimize remaining work, return possibly narrowed source tree
BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE, // remove effects and minimize remaining work, return type handle tree
BR_REMOVE_BUT_NOT_NARROW, // remove effects, return original source tree
- BR_DONT_REMOVE // just check if removal is possible
+ BR_DONT_REMOVE, // just check if removal is possible
+ BR_MAKE_LOCAL_COPY // revise box to copy to temp local and return local's address
};
GenTree* gtTryRemoveBoxUpstreamEffects(GenTree* tree, BoxRemovalOptions options = BR_REMOVE_AND_NARROW);
@@ -3000,16 +3032,18 @@ protected:
void impImportLeave(BasicBlock* block);
void impResetLeaveBlock(BasicBlock* block, unsigned jmpAddr);
- GenTreePtr impIntrinsic(GenTreePtr newobjThis,
- CORINFO_CLASS_HANDLE clsHnd,
- CORINFO_METHOD_HANDLE method,
- CORINFO_SIG_INFO* sig,
- int memberRef,
- bool readonlyCall,
- bool tailCall,
- bool isJitIntrinsic,
- CorInfoIntrinsics* pIntrinsicID,
- bool* isSpecialIntrinsic = nullptr);
+ GenTree* impIntrinsic(GenTree* newobjThis,
+ CORINFO_CLASS_HANDLE clsHnd,
+ CORINFO_METHOD_HANDLE method,
+ CORINFO_SIG_INFO* sig,
+ unsigned methodFlags,
+ int memberRef,
+ bool readonlyCall,
+ bool tailCall,
+ CORINFO_RESOLVED_TOKEN* pContstrainedResolvedToken,
+ CORINFO_THIS_TRANSFORM constraintCallThisTransform,
+ CorInfoIntrinsics* pIntrinsicID,
+ bool* isSpecialIntrinsic = nullptr);
GenTree* impMathIntrinsic(CORINFO_METHOD_HANDLE method,
CORINFO_SIG_INFO* sig,
var_types callType,
@@ -3017,7 +3051,7 @@ protected:
bool tailCall);
NamedIntrinsic lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method);
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
InstructionSet lookupHWIntrinsicISA(const char* className);
NamedIntrinsic lookupHWIntrinsic(const char* methodName, InstructionSet isa);
InstructionSet isaOfHWIntrinsic(NamedIntrinsic intrinsic);
@@ -3037,7 +3071,7 @@ protected:
GenTree* impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
GenTree* impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
GenTree* impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig);
-#endif
+#endif // FEATURE_HW_INTRINSICS
GenTreePtr impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd,
CORINFO_SIG_INFO* sig,
int memberRef,
@@ -3056,13 +3090,13 @@ protected:
GenTreePtr impTreeList; // Trees for the BB being imported
GenTreePtr impTreeLast; // The last tree for the current BB
+public:
enum
{
CHECK_SPILL_ALL = -1,
CHECK_SPILL_NONE = -2
};
-public:
void impBeginTreeList();
void impEndTreeList(BasicBlock* block, GenTreePtr firstStmt, GenTreePtr lastStmt);
void impEndTreeList(BasicBlock* block);
@@ -3153,6 +3187,8 @@ public:
CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool isCastClass);
+ GenTree* impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass);
+
bool VarTypeIsMultiByteAndCanEnreg(var_types type,
CORINFO_CLASS_HANDLE typeClass,
unsigned* typeSize,
@@ -3663,7 +3699,7 @@ public:
// The following are boolean flags that keep track of the state of internal data structures
- bool fgStmtListThreaded;
+ bool fgStmtListThreaded; // true if the node list is now threaded
bool fgCanRelocateEHRegions; // true if we are allowed to relocate the EH regions
bool fgEdgeWeightsComputed; // true after we have called fgComputeEdgeWeights
bool fgHaveValidEdgeWeights; // true if we were successful in computing all of the edge weights
@@ -3752,7 +3788,11 @@ public:
bool fgFoldConditional(BasicBlock* block);
+#ifdef LEGACY_BACKEND
void fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loadw);
+#else
+ void fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw);
+#endif
void fgMorphBlocks();
bool fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(const char* msg));
@@ -3791,7 +3831,9 @@ public:
// lowering that is distributed between fgMorph and the lowering phase of LSRA.
void fgSimpleLowering();
+#ifdef LEGACY_BACKEND
bool fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse);
+#endif
GenTreePtr fgInitThisClass();
@@ -4536,7 +4578,10 @@ public:
void fgDebugCheckBBlist(bool checkBBNum = false, bool checkBBRefs = true);
void fgDebugCheckBlockLinks();
void fgDebugCheckLinks(bool morphTrees = false);
+ void fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees);
void fgDebugCheckNodeLinks(BasicBlock* block, GenTreePtr stmt);
+ void fgDebugCheckNodesUniqueness();
+
void fgDebugCheckFlags(GenTreePtr tree);
void fgDebugCheckFlagsHelper(GenTreePtr tree, unsigned treeFlags, unsigned chkFlags);
void fgDebugCheckTryFinallyExits();
@@ -4997,7 +5042,17 @@ private:
void fgLclFldAssign(unsigned lclNum);
static fgWalkPreFn gtHasLocalsWithAddrOpCB;
- bool gtCanOptimizeTypeEquality(GenTreePtr tree);
+
+ enum TypeProducerKind
+ {
+ TPK_Unknown = 0, // May not be a RuntimeType
+ TPK_Handle = 1, // RuntimeType via handle
+ TPK_GetType = 2, // RuntimeType via Object.get_Type()
+ TPK_Null = 3, // Tree value is null
+ TPK_Other = 4 // RuntimeType via other means
+ };
+
+ TypeProducerKind gtGetTypeProducerKind(GenTree* tree);
bool gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call);
bool gtIsActiveCSE_Candidate(GenTreePtr tree);
@@ -5784,11 +5839,7 @@ public:
optMethodFlags &= ~OMF_HAS_FATPOINTER;
}
- void addFatPointerCandidate(GenTreeCall* call)
- {
- setMethodHasFatPointer();
- call->SetFatPointerCandidate();
- }
+ void addFatPointerCandidate(GenTreeCall* call);
unsigned optMethodFlags;
@@ -5809,7 +5860,7 @@ public:
GenTreePtr getObjectHandleNodeFromAllocation(GenTreePtr tree);
GenTreePtr optPropGetValueRec(unsigned lclNum, unsigned ssaNum, optPropKind valueKind, int walkDepth);
GenTreePtr optPropGetValue(unsigned lclNum, unsigned ssaNum, optPropKind valueKind);
- bool optEarlyPropRewriteTree(GenTreePtr tree);
+ GenTreePtr optEarlyPropRewriteTree(GenTreePtr tree);
bool optDoEarlyPropForBlock(BasicBlock* block);
bool optDoEarlyPropForFunc();
void optEarlyProp();
@@ -6812,7 +6863,7 @@ public:
inline bool generateCFIUnwindCodes()
{
-#ifdef UNIX_AMD64_ABI
+#if defined(_TARGET_UNIX_)
return IsTargetAbi(CORINFO_CORERT_ABI);
#else
return false;
@@ -7261,10 +7312,10 @@ private:
#endif // _TARGET_AMD64_ || (_TARGET_X86_ && FEATURE_EH_FUNCLETS)
-#if defined(_TARGET_AMD64_)
-
UNATIVE_OFFSET unwindGetCurrentOffset(FuncInfoDsc* func);
+#if defined(_TARGET_AMD64_)
+
void unwindBegPrologWindows();
void unwindPushWindows(regNumber reg);
void unwindAllocStackWindows(unsigned size);
@@ -7272,13 +7323,7 @@ private:
void unwindSaveRegWindows(regNumber reg, unsigned offset);
#ifdef UNIX_AMD64_ABI
- void unwindBegPrologCFI();
- void unwindPushCFI(regNumber reg);
- void unwindAllocStackCFI(unsigned size);
- void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
void unwindSaveRegCFI(regNumber reg, unsigned offset);
- int mapRegNumToDwarfReg(regNumber reg);
- void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
#endif // UNIX_AMD64_ABI
#elif defined(_TARGET_ARM_)
@@ -7288,6 +7333,25 @@ private:
#endif // _TARGET_ARM_
+#if defined(_TARGET_UNIX_)
+ int mapRegNumToDwarfReg(regNumber reg);
+ void createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR opcode, USHORT dwarfReg, INT offset = 0);
+ void unwindPushCFI(regNumber reg);
+ void unwindBegPrologCFI();
+ void unwindPushMaskCFI(regMaskTP regMask, bool isFloat);
+ void unwindAllocStackCFI(unsigned size);
+ void unwindSetFrameRegCFI(regNumber reg, unsigned offset);
+ void unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode);
+#ifdef DEBUG
+ void DumpCfiInfo(bool isHotCode,
+ UNATIVE_OFFSET startOffset,
+ UNATIVE_OFFSET endOffset,
+ DWORD cfiCodeBytes,
+ const CFI_CODE* const pCfiCode);
+#endif
+
+#endif // _TARGET_UNIX_
+
#if !defined(__GNUC__)
#pragma endregion // Note: region is NOT under !defined(__GNUC__)
#endif
@@ -7305,39 +7369,39 @@ private:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/
- // Get highest available instruction set for floating point codegen
- InstructionSet getFloatingPointInstructionSet()
+ // Get highest available level for floating point codegen
+ SIMDLevel getFloatingPointCodegenLevel()
{
#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
if (canUseAVX())
{
- return InstructionSet_AVX;
+ return SIMD_AVX2_Supported;
}
- if (CanUseSSE3_4())
+ if (CanUseSSE4())
{
- return InstructionSet_SSE3_4;
+ return SIMD_SSE4_Supported;
}
// min bar is SSE2
assert(canUseSSE2());
- return InstructionSet_SSE2;
+ return SIMD_SSE2_Supported;
#else
assert(!"getFPInstructionSet() is not implemented for target arch");
unreached();
- return InstructionSet_NONE;
+ return SIMD_Not_Supported;
#endif
}
- // Get highest available instruction set for SIMD codegen
- InstructionSet getSIMDInstructionSet()
+ // Get highest available level for SIMD codegen
+ SIMDLevel getSIMDSupportLevel()
{
#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
- return getFloatingPointInstructionSet();
+ return getFloatingPointCodegenLevel();
#else
assert(!"Available instruction set(s) for SIMD codegen is not defined for target arch");
unreached();
- return InstructionSet_NONE;
+ return SIMD_Not_Supported;
#endif
}
@@ -7626,6 +7690,8 @@ private:
assert(canUseSSE2());
return TYP_SIMD16;
}
+#elif defined(_TARGET_ARM64_)
+ return TYP_SIMD16;
#else
assert(!"getSIMDVectorType() unimplemented on target arch");
unreached();
@@ -7662,6 +7728,8 @@ private:
assert(canUseSSE2());
return XMM_REGSIZE_BYTES;
}
+#elif defined(_TARGET_ARM64_)
+ return FP_REGSIZE_BYTES;
#else
assert(!"getSIMDVectorRegisterByteLength() unimplemented on target arch");
unreached();
@@ -7678,13 +7746,6 @@ private:
return emitTypeSize(TYP_SIMD8);
}
-#ifdef FEATURE_AVX_SUPPORT
- // (maxPossibleSIMDStructBytes is for use in a context that requires a compile-time constant.)
- static const unsigned maxPossibleSIMDStructBytes = 32;
-#else // !FEATURE_AVX_SUPPORT
- static const unsigned maxPossibleSIMDStructBytes = 16;
-#endif // !FEATURE_AVX_SUPPORT
-
// Returns the codegen type for a given SIMD size.
var_types getSIMDTypeForSize(unsigned size)
{
@@ -7701,12 +7762,10 @@ private:
{
simdType = TYP_SIMD16;
}
-#ifdef FEATURE_AVX_SUPPORT
else if (size == 32)
{
simdType = TYP_SIMD32;
}
-#endif // FEATURE_AVX_SUPPORT
else
{
noway_assert(!"Unexpected size for SIMD type");
@@ -7806,10 +7865,10 @@ private:
}
// Whether SSE3, SSE3, SSE4.1 and SSE4.2 is available
- bool CanUseSSE3_4() const
+ bool CanUseSSE4() const
{
#ifdef _TARGET_XARCH_
- return opts.compCanUseSSE3_4;
+ return opts.compCanUseSSE4;
#else
return false;
#endif
@@ -7817,7 +7876,7 @@ private:
bool canUseAVX() const
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifdef _TARGET_XARCH_
return opts.compCanUseAVX;
#else
return false;
@@ -7827,7 +7886,7 @@ private:
bool compSupports(InstructionSet isa)
{
#ifdef _TARGET_XARCH_
- return (opts.compSupportsISA & (1 << isa)) != 0;
+ return (opts.compSupportsISA & (1ULL << isa)) != 0;
#else
return false;
#endif
@@ -7858,6 +7917,7 @@ public:
bool compFloatingPointUsed; // Does the method use TYP_FLOAT or TYP_DOUBLE
bool compTailCallUsed; // Does the method do a tailcall
bool compLocallocUsed; // Does the method use localloc.
+ bool compLocallocOptimized; // Does the method have an optimized localloc
bool compQmarkUsed; // Does the method use GT_QMARK/GT_COLON
bool compQmarkRationalized; // Is it allowed to use a GT_QMARK/GT_COLON node.
bool compUnsafeCastUsed; // Does the method use LDIND/STIND to cast between scalar/refernce types
@@ -7938,19 +7998,16 @@ public:
bool compUseFCOMI;
bool compUseCMOV;
#ifdef _TARGET_XARCH_
- bool compCanUseSSE2; // Allow CodeGen to use "movq XMM" instructions
- bool compCanUseSSE3_4; // Allow CodeGen to use SSE3, SSSE3, SSE4.1 and SSE4.2 instructions
-
-#ifdef FEATURE_AVX_SUPPORT
- bool compCanUseAVX; // Allow CodeGen to use AVX 256-bit vectors for SIMD operations
-#endif // FEATURE_AVX_SUPPORT
-#endif // _TARGET_XARCH_
+ bool compCanUseSSE2; // Allow CodeGen to use "movq XMM" instructions
+ bool compCanUseSSE4; // Allow CodeGen to use SSE3, SSSE3, SSE4.1 and SSE4.2 instructions
+ bool compCanUseAVX; // Allow CodeGen to use AVX 256-bit vectors for SIMD operations
+#endif // _TARGET_XARCH_
#ifdef _TARGET_XARCH_
uint64_t compSupportsISA;
void setSupportedISA(InstructionSet isa)
{
- compSupportsISA |= 1 << isa;
+ compSupportsISA |= 1ULL << isa;
}
#endif
@@ -8088,7 +8145,7 @@ public:
// which gets reported as a GC root to stackwalker.
// (See also ICodeManager::GetAddrOfSecurityObject.)
- bool compReloc;
+ bool compReloc; // Generate relocs for pointers in code, true for all ngen/prejit codegen
#ifdef DEBUG
#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
@@ -9239,6 +9296,8 @@ public:
#define DEFAULT_MAX_INLINE_DEPTH 20 // Methods at more than this level deep will not be inlined
+#define DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE 32 // fixed locallocs of this size or smaller will convert to local buffers
+
private:
#ifdef FEATURE_JIT_METHOD_PERF
JitTimer* pCompJitTimer; // Timer data structure (by phases) for current compilation.
@@ -9525,6 +9584,8 @@ public:
void fgMorphMultiregStructArgs(GenTreeCall* call);
GenTreePtr fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr fgEntryPtr);
+ bool killGCRefs(GenTreePtr tree);
+
}; // end of class Compiler
// Inline methods of CompAllocator.
@@ -9772,6 +9833,7 @@ public:
case GT_RETURN:
case GT_RETFILT:
case GT_PHI:
+ case GT_RUNTIMELOOKUP:
{
GenTreeUnOp* const unOp = node->AsUnOp();
if (unOp->gtOp1 != nullptr)
diff --git a/src/jit/compiler.hpp b/src/jit/compiler.hpp
index 4a90760ce2..acc7bb688e 100644
--- a/src/jit/compiler.hpp
+++ b/src/jit/compiler.hpp
@@ -175,12 +175,25 @@ inline BOOL genMaxOneBit(unsigned value)
* Given a value that has exactly one bit set, return the position of that
* bit, in other words return the logarithm in base 2 of the given value.
*/
-
inline unsigned genLog2(unsigned value)
{
return BitPosition(value);
}
+// Given an unsigned 64-bit value, returns the lower 32-bits in unsigned format
+//
+inline unsigned ulo32(unsigned __int64 value)
+{
+ return static_cast<unsigned>(value);
+}
+
+// Given an unsigned 64-bit value, returns the upper 32-bits in unsigned format
+//
+inline unsigned uhi32(unsigned __int64 value)
+{
+ return static_cast<unsigned>(value >> 32);
+}
+
/*****************************************************************************
*
* Given a value that has exactly one bit set, return the position of that
@@ -189,8 +202,8 @@ inline unsigned genLog2(unsigned value)
inline unsigned genLog2(unsigned __int64 value)
{
- unsigned lo32 = (unsigned)value;
- unsigned hi32 = (unsigned)(value >> 32);
+ unsigned lo32 = ulo32(value);
+ unsigned hi32 = uhi32(value);
if (lo32 != 0)
{
@@ -1038,8 +1051,7 @@ inline GenTreePtr Compiler::gtNewLargeOperNode(genTreeOps oper, var_types type,
* that may need to be fixed up).
*/
-inline GenTreePtr Compiler::gtNewIconHandleNode(
- size_t value, unsigned flags, FieldSeqNode* fields, unsigned handle1, void* handle2)
+inline GenTreePtr Compiler::gtNewIconHandleNode(size_t value, unsigned flags, FieldSeqNode* fields)
{
GenTreePtr node;
assert((flags & (GTF_ICON_HDL_MASK | GTF_ICON_FIELD_OFF)) != 0);
@@ -1052,9 +1064,6 @@ inline GenTreePtr Compiler::gtNewIconHandleNode(
#if defined(LATE_DISASM)
node = new (this, LargeOpOpcode()) GenTreeIntCon(TYP_I_IMPL, value, fields DEBUGARG(/*largeNode*/ true));
-
- node->gtIntCon.gtIconHdl.gtIconHdl1 = handle1;
- node->gtIntCon.gtIconHdl.gtIconHdl2 = handle2;
#else
node = new (this, GT_CNS_INT) GenTreeIntCon(TYP_I_IMPL, value, fields);
#endif
@@ -1069,7 +1078,7 @@ inline GenTreePtr Compiler::gtNewIconHandleNode(
* These are versions for each specific type of HANDLE
*/
-inline GenTreePtr Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd, unsigned hnd1, void* hnd2)
+inline GenTreePtr Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd)
{
void *embedScpHnd, *pEmbedScpHnd;
@@ -1077,12 +1086,12 @@ inline GenTreePtr Compiler::gtNewIconEmbScpHndNode(CORINFO_MODULE_HANDLE scpHnd,
assert((!embedScpHnd) != (!pEmbedScpHnd));
- return gtNewIconEmbHndNode(embedScpHnd, pEmbedScpHnd, GTF_ICON_SCOPE_HDL, hnd1, hnd2, scpHnd);
+ return gtNewIconEmbHndNode(embedScpHnd, pEmbedScpHnd, GTF_ICON_SCOPE_HDL, scpHnd);
}
//-----------------------------------------------------------------------------
-inline GenTreePtr Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd, unsigned hnd1, void* hnd2)
+inline GenTreePtr Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd)
{
void *embedClsHnd, *pEmbedClsHnd;
@@ -1090,12 +1099,12 @@ inline GenTreePtr Compiler::gtNewIconEmbClsHndNode(CORINFO_CLASS_HANDLE clsHnd,
assert((!embedClsHnd) != (!pEmbedClsHnd));
- return gtNewIconEmbHndNode(embedClsHnd, pEmbedClsHnd, GTF_ICON_CLASS_HDL, hnd1, hnd2, clsHnd);
+ return gtNewIconEmbHndNode(embedClsHnd, pEmbedClsHnd, GTF_ICON_CLASS_HDL, clsHnd);
}
//-----------------------------------------------------------------------------
-inline GenTreePtr Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd, unsigned hnd1, void* hnd2)
+inline GenTreePtr Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHnd)
{
void *embedMethHnd, *pEmbedMethHnd;
@@ -1103,12 +1112,12 @@ inline GenTreePtr Compiler::gtNewIconEmbMethHndNode(CORINFO_METHOD_HANDLE methHn
assert((!embedMethHnd) != (!pEmbedMethHnd));
- return gtNewIconEmbHndNode(embedMethHnd, pEmbedMethHnd, GTF_ICON_METHOD_HDL, hnd1, hnd2, methHnd);
+ return gtNewIconEmbHndNode(embedMethHnd, pEmbedMethHnd, GTF_ICON_METHOD_HDL, methHnd);
}
//-----------------------------------------------------------------------------
-inline GenTreePtr Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd, unsigned hnd1, void* hnd2)
+inline GenTreePtr Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd)
{
void *embedFldHnd, *pEmbedFldHnd;
@@ -1116,7 +1125,7 @@ inline GenTreePtr Compiler::gtNewIconEmbFldHndNode(CORINFO_FIELD_HANDLE fldHnd,
assert((!embedFldHnd) != (!pEmbedFldHnd));
- return gtNewIconEmbHndNode(embedFldHnd, pEmbedFldHnd, GTF_ICON_FIELD_HDL, hnd1, hnd2, fldHnd);
+ return gtNewIconEmbHndNode(embedFldHnd, pEmbedFldHnd, GTF_ICON_FIELD_HDL, fldHnd);
}
/*****************************************************************************/
@@ -1169,6 +1178,23 @@ inline GenTreePtr Compiler::gtNewAllocObjNode(unsigned int helper,
return node;
}
+//------------------------------------------------------------------------
+// gtNewRuntimeLookup: Helper to create a runtime lookup node
+//
+// Arguments:
+// hnd - generic handle being looked up
+// hndTyp - type of the generic handle
+// tree - tree for the lookup
+//
+// Return Value:
+// New GenTreeRuntimeLookup node.
+inline GenTree* Compiler::gtNewRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
+{
+ assert(tree != nullptr);
+ GenTree* node = new (this, GT_RUNTIMELOOKUP) GenTreeRuntimeLookup(hnd, hndTyp, tree);
+ return node;
+}
+
/*****************************************************************************/
inline GenTreePtr Compiler::gtNewCodeRef(BasicBlock* block)
@@ -1439,33 +1465,6 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
}
}
-inline void GenTree::CopyFrom(const GenTree* src, Compiler* comp)
-{
- /* The source may be big only if the target is also a big node */
-
- assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL);
- GenTreePtr prev = gtPrev;
- GenTreePtr next = gtNext;
-
- RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
-
- // The VTable pointer is copied intentionally here
- memcpy((void*)this, (void*)src, src->GetNodeSize());
- this->gtPrev = prev;
- this->gtNext = next;
-#ifdef DEBUG
- gtSeqNum = 0;
-#endif
- // Transfer any annotations.
- if (src->OperGet() == GT_IND && src->gtFlags & GTF_IND_ARR_INDEX)
- {
- ArrayInfo arrInfo;
- bool b = comp->GetArrayInfoMap()->Lookup(src, &arrInfo);
- assert(b);
- comp->GetArrayInfoMap()->Set(this, arrInfo);
- }
-}
-
inline GenTreePtr Compiler::gtNewCastNode(var_types typ, GenTreePtr op1, var_types castType)
{
GenTreePtr res = new (this, GT_CAST) GenTreeCast(typ, op1, castType);
@@ -1504,7 +1503,7 @@ inline void GenTree::SetOper(genTreeOps oper, ValueNumberUpdate vnUpdate)
}
}
-inline void GenTree::CopyFrom(GenTreePtr src)
+inline void GenTree::ReplaceWith(GenTreePtr src)
{
RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
*this = *src;
@@ -1621,16 +1620,9 @@ inline bool GenTree::IsVarAddr() const
inline bool GenTree::gtOverflow() const
{
-#if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
- 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 || gtOper == GT_ADD || gtOper == GT_SUB || gtOper == GT_ASG_ADD ||
- gtOper == GT_ASG_SUB);
-#endif
+ assert(OperMayOverflow());
- if (gtFlags & GTF_OVERFLOW)
+ if ((gtFlags & GTF_OVERFLOW) != 0)
{
assert(varTypeIsIntegral(TypeGet()));
@@ -1644,15 +1636,7 @@ inline bool GenTree::gtOverflow() const
inline bool GenTree::gtOverflowEx() const
{
- if (gtOper == GT_MUL || gtOper == GT_CAST || gtOper == GT_ADD || gtOper == GT_SUB ||
-#if !defined(_TARGET_64BIT_) && !defined(LEGACY_BACKEND)
- gtOper == GT_ADD_HI || gtOper == GT_SUB_HI ||
-#endif
- gtOper == GT_ASG_ADD || gtOper == GT_ASG_SUB)
- {
- return gtOverflow();
- }
- return false;
+ return OperMayOverflow() && gtOverflow();
}
/*
@@ -3777,7 +3761,7 @@ inline void Compiler::LoopDsc::VERIFY_lpIterTree()
assert(lpIterTree);
- assert(lpIterTree->OperKind() & GTK_ASGOP); // +=, -=, etc or = +, = -, etc
+ assert(lpIterTree->OperIsAssignment());
if (lpIterTree->OperGet() == GT_ASG)
{
diff --git a/src/jit/decomposelongs.cpp b/src/jit/decomposelongs.cpp
index 174bba2a56..6de7ef6c74 100644
--- a/src/jit/decomposelongs.cpp
+++ b/src/jit/decomposelongs.cpp
@@ -274,31 +274,7 @@ GenTree* DecomposeLongs::DecomposeNode(GenTree* tree)
// element into two elements: one for each half of the GT_LONG.
if ((use.Def()->OperGet() == GT_LONG) && !use.IsDummyUse() && (use.User()->OperGet() == GT_FIELD_LIST))
{
- GenTreeOp* value = use.Def()->AsOp();
- Range().Remove(value);
-
- // The node returned by `use.User()` is the head of the field list. We need to find the actual node that uses
- // the `GT_LONG` so that we can split it.
- GenTreeFieldList* listNode = use.User()->AsFieldList();
- for (; listNode != nullptr; listNode = listNode->Rest())
- {
- if (listNode->Current() == value)
- {
- break;
- }
- }
-
- assert(listNode != nullptr);
- GenTree* rest = listNode->gtOp2;
-
- GenTreeFieldList* loNode = listNode;
- loNode->gtOp1 = value->gtOp1;
- loNode->gtFieldType = TYP_INT;
-
- GenTreeFieldList* hiNode =
- new (m_compiler, GT_FIELD_LIST) GenTreeFieldList(value->gtOp2, loNode->gtFieldOffset + 4, TYP_INT, loNode);
-
- hiNode->gtOp2 = rest;
+ DecomposeFieldList(use.User()->AsFieldList(), use.Def()->AsOp());
}
#ifdef DEBUG
@@ -725,6 +701,49 @@ GenTree* DecomposeLongs::DecomposeCnsLng(LIR::Use& use)
}
//------------------------------------------------------------------------
+// DecomposeFieldList: Decompose GT_FIELD_LIST.
+//
+// Arguments:
+// listNode - the head of the FIELD_LIST that contains the given GT_LONG.
+// longNode - the node to decompose
+//
+// Return Value:
+// The next node to process.
+//
+// Notes:
+// Split a LONG field list element into two elements: one for each half of the GT_LONG.
+//
+GenTree* DecomposeLongs::DecomposeFieldList(GenTreeFieldList* listNode, GenTreeOp* longNode)
+{
+ assert(longNode->OperGet() == GT_LONG);
+ // We are given the head of the field list. We need to find the actual node that uses
+ // the `GT_LONG` so that we can split it.
+ for (; listNode != nullptr; listNode = listNode->Rest())
+ {
+ if (listNode->Current() == longNode)
+ {
+ break;
+ }
+ }
+ assert(listNode != nullptr);
+
+ Range().Remove(longNode);
+
+ GenTree* rest = listNode->gtOp2;
+
+ GenTreeFieldList* loNode = listNode;
+ loNode->gtType = TYP_INT;
+ loNode->gtOp1 = longNode->gtOp1;
+ loNode->gtFieldType = TYP_INT;
+
+ GenTreeFieldList* hiNode =
+ new (m_compiler, GT_FIELD_LIST) GenTreeFieldList(longNode->gtOp2, loNode->gtFieldOffset + 4, TYP_INT, loNode);
+ hiNode->gtOp2 = rest;
+
+ return listNode->gtNext;
+}
+
+//------------------------------------------------------------------------
// DecomposeCall: Decompose GT_CALL.
//
// Arguments:
@@ -995,7 +1014,7 @@ GenTree* DecomposeLongs::DecomposeArith(LIR::Use& use)
loResult->gtFlags |= GTF_SET_FLAGS;
hiResult->gtFlags |= GTF_USE_FLAGS;
- if (loResult->gtOverflow())
+ if ((loResult->gtFlags & GTF_OVERFLOW) != 0)
{
hiResult->gtFlags |= GTF_OVERFLOW | GTF_EXCEPT;
loResult->gtFlags &= ~(GTF_OVERFLOW | GTF_EXCEPT);
@@ -1980,12 +1999,6 @@ genTreeOps DecomposeLongs::GetHiOper(genTreeOps oper)
case GT_SUB:
return GT_SUB_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;
diff --git a/src/jit/decomposelongs.h b/src/jit/decomposelongs.h
index 7a0d6ff5ba..c008fa255c 100644
--- a/src/jit/decomposelongs.h
+++ b/src/jit/decomposelongs.h
@@ -45,6 +45,7 @@ private:
GenTree* DecomposeStoreLclFld(LIR::Use& use);
GenTree* DecomposeCast(LIR::Use& use);
GenTree* DecomposeCnsLng(LIR::Use& use);
+ GenTree* DecomposeFieldList(GenTreeFieldList* listNode, GenTreeOp* longNode);
GenTree* DecomposeCall(LIR::Use& use);
GenTree* DecomposeInd(LIR::Use& use);
GenTree* DecomposeStoreInd(LIR::Use& use);
diff --git a/src/jit/dll/jit.nativeproj b/src/jit/dll/jit.nativeproj
index 7505f5e8ef..4d796f3b78 100644
--- a/src/jit/dll/jit.nativeproj
+++ b/src/jit/dll/jit.nativeproj
@@ -30,7 +30,7 @@
<LinkModuleDefinitionFile>$(OutputName).def</LinkModuleDefinitionFile>
- <ClDefines Condition="'$(BuildArchitecture)' == 'amd64'">$(ClDefines);FEATURE_SIMD;FEATURE_AVX_SUPPORT</ClDefines>
+ <ClDefines Condition="'$(BuildArchitecture)' == 'amd64'">$(ClDefines);FEATURE_SIMD</ClDefines>
<Win32DllLibs>$(SdkLibPath)\kernel32.lib;$(SdkLibPath)\user32.lib;$(SdkLibPath)\advapi32.lib;$(SdkLibPath)\oleaut32.lib;$(SdkLibPath)\uuid.lib</Win32DllLibs>
<Win32DllLibs>$(Win32DllLibs);$(ClrLibPath)\utilcode.lib</Win32DllLibs>
diff --git a/src/jit/earlyprop.cpp b/src/jit/earlyprop.cpp
index 8cb51a3fbd..b0cb26b973 100644
--- a/src/jit/earlyprop.cpp
+++ b/src/jit/earlyprop.cpp
@@ -194,10 +194,12 @@ void Compiler::optEarlyProp()
bool isRewritten = false;
for (GenTreePtr tree = stmt->gtStmt.gtStmtList; tree != nullptr; tree = tree->gtNext)
{
- if (optEarlyPropRewriteTree(tree))
+ GenTreePtr rewrittenTree = optEarlyPropRewriteTree(tree);
+ if (rewrittenTree != nullptr)
{
- gtUpdateSideEffects(stmt, tree);
+ gtUpdateSideEffects(stmt, rewrittenTree);
isRewritten = true;
+ tree = rewrittenTree;
}
}
@@ -228,9 +230,10 @@ void Compiler::optEarlyProp()
// tree - The input tree node to be rewritten.
//
// Return Value:
-// Return true iff "tree" is successfully rewritten.
-
-bool Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
+// Return a new tree if the original tree was successfully rewritten.
+// The containing tree links are updated.
+//
+GenTreePtr Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
{
GenTreePtr objectRefPtr = nullptr;
optPropKind propKind = optPropKind::OPK_INVALID;
@@ -254,7 +257,7 @@ bool Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
// \--* lclVar ref V02 loc0
if (compCurStmt->gtStmt.gtStmtExpr == tree)
{
- return false;
+ return nullptr;
}
objectRefPtr = tree->AsIndir()->Addr();
@@ -262,39 +265,42 @@ bool Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
}
else
{
- return false;
+ return nullptr;
}
}
else
{
- return false;
+ return nullptr;
}
if (!objectRefPtr->OperIsScalarLocal() || fgExcludeFromSsa(objectRefPtr->AsLclVarCommon()->GetLclNum()))
{
- return false;
+ return nullptr;
}
- bool isRewritten = false;
- GenTreePtr root = compCurStmt;
- unsigned lclNum = objectRefPtr->AsLclVarCommon()->GetLclNum();
- unsigned ssaNum = objectRefPtr->AsLclVarCommon()->GetSsaNum();
-
+ unsigned lclNum = objectRefPtr->AsLclVarCommon()->GetLclNum();
+ unsigned ssaNum = objectRefPtr->AsLclVarCommon()->GetSsaNum();
GenTreePtr actualVal = optPropGetValue(lclNum, ssaNum, propKind);
if (actualVal != nullptr)
{
+ assert((propKind == optPropKind::OPK_ARRAYLEN) || (propKind == optPropKind::OPK_OBJ_GETTYPE));
+ assert(actualVal->IsCnsIntOrI());
+#if SMALL_TREE_NODES
+ assert(actualVal->GetNodeSize() == TREE_NODE_SZ_SMALL);
+#endif
+
+ ssize_t actualConstVal = actualVal->AsIntCon()->IconValue();
+
if (propKind == optPropKind::OPK_ARRAYLEN)
{
- assert(actualVal->IsCnsIntOrI());
-
- if ((actualVal->AsIntCon()->IconValue() < 0) || (actualVal->AsIntCon()->IconValue() > INT32_MAX))
+ if ((actualConstVal < 0) || (actualConstVal > INT32_MAX))
{
// Don't propagate array lengths that are beyond the maximum value of a GT_ARR_LENGTH or negative.
// node. CORINFO_HELP_NEWARR_1_OBJ helper call allows to take a long integer as the
// array length argument, but the type of GT_ARR_LENGTH is always INT32.
- return false;
+ return nullptr;
}
// When replacing GT_ARR_LENGTH nodes with constants we can end up with GT_ARR_BOUNDS_CHECK
@@ -307,72 +313,58 @@ bool Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
{
GenTreeBoundsChk* check = tree->gtNext->AsBoundsChk();
- if ((check->gtArrLen == tree) && check->gtIndex->IsCnsIntOrI() &&
- (check->gtIndex->AsIntCon()->IconValue() >= 0) &&
- (check->gtIndex->AsIntCon()->IconValue() < actualVal->AsIntCon()->IconValue()))
+ if ((check->gtArrLen == tree) && check->gtIndex->IsCnsIntOrI())
{
- GenTree* comma = check->gtGetParent(nullptr);
-
- if ((comma != nullptr) && comma->OperIs(GT_COMMA) && (comma->gtGetOp1() == check))
+ ssize_t checkConstVal = check->gtIndex->AsIntCon()->IconValue();
+ if ((checkConstVal >= 0) && (checkConstVal < actualConstVal))
{
- GenTree* next = check->gtNext;
- optRemoveRangeCheck(comma, root);
- // Both `tree` and `check` have been removed from the statement. Ensure that optEarlyProp
- // can process the rest of the statment by changing tree->gtNext appropriately.
- tree->gtNext = next;
- return true;
+ GenTree* comma = check->gtGetParent(nullptr);
+ if ((comma != nullptr) && comma->OperIs(GT_COMMA) && (comma->gtGetOp1() == check))
+ {
+ GenTree* next = check->gtNext;
+ optRemoveRangeCheck(comma, compCurStmt);
+ // Both `tree` and `check` have been removed from the statement.
+ // 'tree' was replaced with 'nop' or side effect list under 'comma'.
+ return comma->gtGetOp1();
+ }
}
}
}
}
- else if (propKind == optPropKind::OPK_OBJ_GETTYPE)
- {
- assert(actualVal->IsCnsIntOrI());
- }
#ifdef DEBUG
if (verbose)
{
printf("optEarlyProp Rewriting BB%02u\n", compCurBB->bbNum);
- gtDispTree(root);
+ gtDispTree(compCurStmt);
printf("\n");
}
#endif
- // Rewrite the tree using a copy of "actualVal"
- GenTreePtr actualValCopy;
- var_types origType = tree->gtType;
+
+ GenTreePtr actualValClone = gtCloneExpr(actualVal);
+
+ if (actualValClone->gtType != tree->gtType)
+ {
+ assert(actualValClone->gtType == TYP_LONG);
+ assert(tree->gtType == TYP_INT);
+ assert((actualConstVal >= 0) && (actualConstVal <= INT32_MAX));
+ actualValClone->gtType = tree->gtType;
+ }
+
// Propagating a constant into an array index expression requires calling
// LabelIndex to update the FieldSeq annotations. EarlyProp may replace
// array length expressions with constants, so check if this is an array
// length operator that is part of an array index expression.
bool isIndexExpr = (tree->OperGet() == GT_ARR_LENGTH && ((tree->gtFlags & GTF_ARRLEN_ARR_IDX) != 0));
-
- if (actualVal->GetNodeSize() <= tree->GetNodeSize())
- {
- actualValCopy = tree;
- }
- else
- {
- actualValCopy = gtNewLargeOperNode(GT_ADD, TYP_INT);
- }
-
- DecLclVarRefCountsVisitor::WalkTree(this, tree);
-
- actualValCopy->CopyFrom(actualVal, this);
- actualValCopy->gtType = origType;
if (isIndexExpr)
{
- actualValCopy->LabelIndex(this);
- }
-
- IncLclVarRefCountsVisitor::WalkTree(this, actualValCopy);
-
- if (actualValCopy != tree)
- {
- gtReplaceTree(root, tree, actualValCopy);
+ actualValClone->LabelIndex(this);
}
- isRewritten = true;
+ DecLclVarRefCountsVisitor::WalkTree(this, tree);
+ // acutalValClone has small tree node size, it is safe to use CopyFrom here.
+ tree->ReplaceWith(actualValClone, this);
+ IncLclVarRefCountsVisitor::WalkTree(this, tree);
#ifdef DEBUG
if (verbose)
@@ -382,9 +374,10 @@ bool Compiler::optEarlyPropRewriteTree(GenTreePtr tree)
printf("\n");
}
#endif
+ return tree;
}
- return isRewritten;
+ return nullptr;
}
//-------------------------------------------------------------------------------------------
diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp
index b32d59fc51..4e65d24b30 100644
--- a/src/jit/ee_il_dll.cpp
+++ b/src/jit/ee_il_dll.cpp
@@ -205,9 +205,6 @@ ICorJitCompiler* __stdcall getJit()
// Information kept in thread-local storage. This is used in the noway_assert exceptional path.
// If you are using it more broadly in retail code, you would need to understand the
// performance implications of accessing TLS.
-//
-// If the JIT is being statically linked, these methods must be implemented by the consumer.
-#if !defined(FEATURE_MERGE_JIT_AND_ENGINE) || !defined(FEATURE_IMPLICIT_TLS)
__declspec(thread) void* gJitTls = nullptr;
@@ -221,15 +218,6 @@ void SetJitTls(void* value)
gJitTls = value;
}
-#else // !defined(FEATURE_MERGE_JIT_AND_ENGINE) || !defined(FEATURE_IMPLICIT_TLS)
-
-extern "C" {
-void* GetJitTls();
-void SetJitTls(void* value);
-}
-
-#endif // // defined(FEATURE_MERGE_JIT_AND_ENGINE) && defined(FEATURE_IMPLICIT_TLS)
-
#if defined(DEBUG)
JitTls::JitTls(ICorJitInfo* jitInfo) : m_compiler(nullptr), m_logEnv(jitInfo)
@@ -339,8 +327,6 @@ void CILJit::clearCache(void)
*/
BOOL CILJit::isCacheCleanupRequired(void)
{
- BOOL doCleanup;
-
if (g_realJitCompiler != nullptr)
{
if (g_realJitCompiler->isCacheCleanupRequired())
@@ -396,8 +382,7 @@ unsigned CILJit::getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags)
jitFlags.SetFromFlags(cpuCompileFlags);
#ifdef FEATURE_SIMD
-#ifdef _TARGET_XARCH_
-#ifdef FEATURE_AVX_SUPPORT
+#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
if (!jitFlags.IsSet(JitFlags::JIT_FLAG_PREJIT) && jitFlags.IsSet(JitFlags::JIT_FLAG_FEATURE_SIMD) &&
jitFlags.IsSet(JitFlags::JIT_FLAG_USE_AVX2))
{
@@ -410,13 +395,12 @@ unsigned CILJit::getMaxIntrinsicSIMDVectorLength(CORJIT_FLAGS cpuCompileFlags)
return 32;
}
}
-#endif // FEATURE_AVX_SUPPORT
+#endif // !(defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND))
if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
{
JITDUMP("getMaxIntrinsicSIMDVectorLength: returning 16\n");
}
return 16;
-#endif // _TARGET_XARCH_
#else // !FEATURE_SIMD
if (GetJitTls() != nullptr && JitTls::GetCompiler() != nullptr)
{
@@ -522,7 +506,7 @@ GenTreePtr Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO* szMetaSig)
cookie = info.compCompHnd->GetCookieForPInvokeCalliSig(szMetaSig, &pCookie);
assert((cookie == nullptr) != (pCookie == nullptr));
- return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL);
+ return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL, szMetaSig);
}
//------------------------------------------------------------------------
diff --git a/src/jit/eeinterface.cpp b/src/jit/eeinterface.cpp
index d8db947f02..5783037f22 100644
--- a/src/jit/eeinterface.cpp
+++ b/src/jit/eeinterface.cpp
@@ -103,8 +103,6 @@ const char* Compiler::eeGetMethodFullName(CORINFO_METHOD_HANDLE hnd)
/* figure out the signature */
- EXCEPTION_POINTERS exceptionPointers;
-
PAL_TRY(FilterSuperPMIExceptionsParam_eeinterface*, pParam, &param)
{
unsigned i;
diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp
index 4fc97bbd44..f9f3d855c9 100644
--- a/src/jit/emit.cpp
+++ b/src/jit/emit.cpp
@@ -1337,7 +1337,7 @@ void* emitter::emitAllocInstr(size_t sz, emitAttr opsz)
emitInsCount++;
-#if defined(DEBUG) || defined(LATE_DISASM)
+#if defined(DEBUG)
/* In debug mode we clear/set some additional fields */
instrDescDebugInfo* info = (instrDescDebugInfo*)emitGetMem(sizeof(*info));
@@ -1346,7 +1346,6 @@ void* emitter::emitAllocInstr(size_t sz, emitAttr opsz)
info->idSize = sz;
info->idVarRefOffs = 0;
info->idMemCookie = 0;
- info->idClsCookie = nullptr;
#ifdef TRANSLATE_PDB
info->idilStart = emitInstrDescILBase;
#endif
@@ -1356,7 +1355,7 @@ void* emitter::emitAllocInstr(size_t sz, emitAttr opsz)
id->idDebugOnlyInfo(info);
-#endif // defined(DEBUG) || defined(LATE_DISASM)
+#endif // defined(DEBUG)
/* Store the size and handle the two special values
that indicate GCref and ByRef */
@@ -1522,10 +1521,6 @@ void emitter::emitEndProlog()
{
assert(emitComp->compGeneratingProlog);
- size_t prolSz;
-
- insGroup* tempIG;
-
emitNoGCIG = false;
/* Save the prolog IG if non-empty or if only one block */
@@ -3649,7 +3644,7 @@ AGAIN:
ssz = JCC_SIZE_SMALL;
bool isTest = (jmp->idIns() == INS_tbz) || (jmp->idIns() == INS_tbnz);
- nsd = (isTest) ? TB_DIST_SMALL_MAX_NEG : JCC_DIST_SMALL_MAX_POS;
+ nsd = (isTest) ? TB_DIST_SMALL_MAX_NEG : JCC_DIST_SMALL_MAX_NEG;
psd = (isTest) ? TB_DIST_SMALL_MAX_POS : JCC_DIST_SMALL_MAX_POS;
}
else if (emitIsUncondJump(jmp))
@@ -7195,7 +7190,6 @@ const char* emitter::emitOffsetToLabel(unsigned offs)
char* retbuf;
insGroup* ig;
- UNATIVE_OFFSET of;
UNATIVE_OFFSET nextof = 0;
for (ig = emitIGlist; ig != nullptr; ig = ig->igNext)
diff --git a/src/jit/emit.h b/src/jit/emit.h
index 8c2b825fe7..163c4caa36 100644
--- a/src/jit/emit.h
+++ b/src/jit/emit.h
@@ -427,12 +427,9 @@ public:
#endif // DEBUG
#ifdef _TARGET_XARCH_
- SetUseSSE3_4(false);
-#endif // _TARGET_XARCH_
-
-#ifdef FEATURE_AVX_SUPPORT
+ SetUseSSE4(false);
SetUseAVX(false);
-#endif // FEATURE_AVX_SUPPORT
+#endif // _TARGET_XARCH_
}
#include "emitpub.h"
@@ -533,7 +530,7 @@ protected:
int amDisp : AM_DISP_BITS;
};
-#if defined(DEBUG) || defined(LATE_DISASM) // LATE_DISASM needs the idMemCookie on calls to display the call target name
+#ifdef DEBUG // This information is used in DEBUG builds to display the method name for call instructions
struct instrDesc;
@@ -542,8 +539,7 @@ protected:
unsigned idNum;
size_t idSize; // size of the instruction descriptor
unsigned idVarRefOffs; // IL offset for LclVar reference
- size_t idMemCookie; // for display of member names in addr modes
- void* idClsCookie; // for display of member names in addr modes
+ size_t idMemCookie; // for display of method name (also used by switch table)
#ifdef TRANSLATE_PDB
unsigned int idilStart; // instruction descriptor source information for PDB translation
#endif
@@ -552,7 +548,7 @@ protected:
CORINFO_SIG_INFO* idCallSig; // Used to report native call site signatures to the EE
};
-#endif // defined(DEBUG) || defined(LATE_DISASM)
+#endif // DEBUG
#ifdef _TARGET_ARM_
unsigned insEncodeSetFlags(insFlags sf);
@@ -582,13 +578,13 @@ protected:
struct instrDesc
{
private:
-#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+#if (defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)) && !defined(LEGACY_BACKEND)
// The assembly instruction
instruction _idIns : 9;
-#else // !defined(_TARGET_XARCH_) || defined(LEGACY_BACKEND)
+#else // !(defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)) || defined(LEGACY_BACKEND)
// The assembly instruction
instruction _idIns : 8;
-#endif // !defined(_TARGET_XARCH_) || defined(LEGACY_BACKEND)
+#endif // !(defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)) || defined(LEGACY_BACKEND)
// The format for the instruction
insFormat _idInsFmt : 8;
@@ -634,7 +630,7 @@ protected:
// x86: 16 bits
// amd64: 17 bits
// arm: 16 bits
- // arm64: 16 bits
+ // arm64: 17 bits
private:
#ifdef _TARGET_XARCH_
@@ -673,7 +669,7 @@ protected:
// x86: 30 bits
// amd64: 38 bits
// arm: 32 bits
- // arm64: 30 bits
+ // arm64: 31 bits
CLANG_FORMAT_COMMENT_ANCHOR;
#if HAS_TINY_DESC
@@ -723,8 +719,8 @@ protected:
#define ID_EXTRA_BITFIELD_BITS (16)
#elif defined(_TARGET_ARM64_)
-// For Arm64, we have used 16 bits from the second DWORD.
-#define ID_EXTRA_BITFIELD_BITS (16)
+// For Arm64, we have used 17 bits from the second DWORD.
+#define ID_EXTRA_BITFIELD_BITS (17)
#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
// For xarch !LEGACY_BACKEND, we have used 14 bits from the second DWORD.
#define ID_EXTRA_BITFIELD_BITS (14)
@@ -740,7 +736,7 @@ protected:
// x86: 38 bits // if HAS_TINY_DESC is not defined (which it is)
// amd64: 46 bits
// arm: 48 bits
- // arm64: 48 bits
+ // arm64: 49 bits
CLANG_FORMAT_COMMENT_ANCHOR;
unsigned _idCnsReloc : 1; // LargeCns is an RVA and needs reloc tag
@@ -753,7 +749,7 @@ protected:
// x86: 40 bits
// amd64: 48 bits
// arm: 50 bits
- // arm64: 50 bits
+ // arm64: 51 bits
CLANG_FORMAT_COMMENT_ANCHOR;
#define ID_EXTRA_BITS (ID_EXTRA_RELOC_BITS + ID_EXTRA_BITFIELD_BITS)
@@ -769,7 +765,7 @@ protected:
// x86: 24 bits
// amd64: 16 bits
// arm: 14 bits
- // arm64: 14 bits
+ // arm64: 13 bits
unsigned _idSmallCns : ID_BIT_SMALL_CNS;
@@ -780,7 +776,7 @@ protected:
#endif // !HAS_TINY_DESC
-#if defined(DEBUG) || defined(LATE_DISASM)
+#ifdef DEBUG
instrDescDebugInfo* _idDebugOnlyInfo;
@@ -795,7 +791,7 @@ protected:
}
private:
-#endif // defined(DEBUG) || defined(LATE_DISASM)
+#endif // DEBUG
//
// This is the end of the smallest instrDesc we can allocate for all
@@ -872,7 +868,7 @@ protected:
emitter::emitAllocInstr() to clear them.
*/
-#if defined(DEBUG) || defined(LATE_DISASM)
+#if DEBUG
#define TINY_IDSC_DEBUG_EXTRA (sizeof(void*))
#else
#define TINY_IDSC_DEBUG_EXTRA (0)
@@ -938,12 +934,12 @@ protected:
regNumber _idReg3 : REGNUM_BITS;
regNumber _idReg4 : REGNUM_BITS;
};
-#elif defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+#elif defined(_TARGET_XARCH_)
struct
{
regNumber _idReg3 : REGNUM_BITS;
};
-#endif // defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+#endif // defined(_TARGET_XARCH_)
} _idAddrUnion;
@@ -1109,7 +1105,7 @@ protected:
assert(reg == _idReg2);
}
-#if defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+#if defined(_TARGET_XARCH_)
regNumber idReg3() const
{
assert(!idIsTiny());
@@ -1123,7 +1119,7 @@ protected:
idAddr()->_idReg3 = reg;
assert(reg == idAddr()->_idReg3);
}
-#endif // defined(_TARGET_XARCH_) && !defined(LEGACY_BACKEND)
+#endif // defined(_TARGET_XARCH_)
#ifdef _TARGET_ARMARCH_
insOpts idInsOpt() const
{
diff --git a/src/jit/emitarm.cpp b/src/jit/emitarm.cpp
index c21f7aeb3e..ae98d31868 100644
--- a/src/jit/emitarm.cpp
+++ b/src/jit/emitarm.cpp
@@ -3808,19 +3808,12 @@ void emitter::emitIns_C_I(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE f
* The following adds instructions referencing address modes.
*/
-void emitter::emitIns_I_AR(
- instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie, void* clsCookie)
+void emitter::emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs)
{
NYI("emitIns_I_AR");
}
-void emitter::emitIns_R_AR(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie /* = 0 */,
- void* clsCookie /* = NULL */)
+void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
{
if (ins == INS_mov)
{
@@ -3890,13 +3883,7 @@ void emitter::emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize
NYI("emitIns_R_AI");
}
-void emitter::emitIns_AR_R(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie /* = 0 */,
- void* clsCookie /* = NULL */)
+void emitter::emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
{
if (ins == INS_mov)
{
@@ -4652,20 +4639,17 @@ void emitter::emitIns_Call(EmitCallType callType,
VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
}
}
-#endif
-#if defined(DEBUG) || defined(LATE_DISASM)
id->idDebugOnlyInfo()->idMemCookie = (size_t)methHnd; // method token
- id->idDebugOnlyInfo()->idClsCookie = 0;
id->idDebugOnlyInfo()->idCallSig = sigInfo;
-#endif
+#endif // DEBUG
-#if defined(LATE_DISASM)
+#ifdef LATE_DISASM
if (addr != nullptr)
{
codeGen->getDisAssembler().disSetMethod((size_t)addr, methHnd);
}
-#endif // defined(LATE_DISASM)
+#endif // LATE_DISASM
dispIns(id);
appendToCurIG(id);
@@ -7889,7 +7873,11 @@ regNumber emitter::emitInsTernary(instruction ins, emitAttr attr, GenTree* dst,
jumpKind = isUnsignedOverflow ? EJ_lo : EJ_vs;
if (jumpKind == EJ_lo)
{
- if ((dst->OperGet() != GT_SUB) && (dst->OperGet() != GT_ASG_SUB) && (dst->OperGet() != GT_SUB_HI))
+ if ((dst->OperGet() != GT_SUB) &&
+#ifdef LEGACY_BACKEND
+ (dst->OperGet() != GT_ASG_SUB) &&
+#endif
+ (dst->OperGet() != GT_SUB_HI))
{
jumpKind = EJ_hs;
}
diff --git a/src/jit/emitarm.h b/src/jit/emitarm.h
index 62d9af6569..5ba76fe226 100644
--- a/src/jit/emitarm.h
+++ b/src/jit/emitarm.h
@@ -325,16 +325,13 @@ void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg);
-void emitIns_I_AR(
- instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
-void emitIns_R_AR(
- instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
-void emitIns_AR_R(
- instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
diff --git a/src/jit/emitarm64.cpp b/src/jit/emitarm64.cpp
index d901f8a8cf..56df0424df 100644
--- a/src/jit/emitarm64.cpp
+++ b/src/jit/emitarm64.cpp
@@ -269,6 +269,15 @@ void emitter::emitInsSanityCheck(instrDesc* id)
assert(insOptsNone(id->idInsOpt()) || insOptsIndexed(id->idInsOpt()));
break;
+ case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
+ assert(isIntegerRegister(id->idReg1()));
+ assert(isIntegerRegister(id->idReg2()));
+ assert(isIntegerRegister(id->idReg3()));
+ assert(emitGetInsSC(id) == 0);
+ assert(!id->idIsLclVar());
+ assert(insOptsNone(id->idInsOpt()));
+ break;
+
case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
assert(isValidGeneralDatasize(id->idOpSize()));
assert(isGeneralRegister(id->idReg1()));
@@ -841,6 +850,7 @@ bool emitter::emitInsMayWriteToGCReg(instrDesc* id)
case IF_LS_3A: // LS_3A .X.......X.mmmmm xxxS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
case IF_LS_3B: // LS_3B X............... .aaaaannnnnttttt Rt Ra Rn
case IF_LS_3C: // LS_3C X.........iiiiii iaaaaannnnnttttt Rt Ra Rn imm(im7,sh)
+ case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
// For the Store instructions the "target" register is actually a "source" value
@@ -968,8 +978,12 @@ emitAttr emitter::emitInsTargetRegSize(instrDesc* id)
switch (ins)
{
+ case INS_ldxrb:
case INS_ldarb:
+ case INS_ldaxrb:
+ case INS_stxrb:
case INS_stlrb:
+ case INS_stlxrb:
case INS_ldrb:
case INS_strb:
case INS_ldurb:
@@ -977,8 +991,12 @@ emitAttr emitter::emitInsTargetRegSize(instrDesc* id)
result = EA_4BYTE;
break;
+ case INS_ldxrh:
case INS_ldarh:
+ case INS_ldaxrh:
+ case INS_stxrh:
case INS_stlrh:
+ case INS_stlxrh:
case INS_ldrh:
case INS_strh:
case INS_ldurh:
@@ -1009,8 +1027,12 @@ emitAttr emitter::emitInsTargetRegSize(instrDesc* id)
result = id->idOpSize();
break;
+ case INS_ldxr:
case INS_ldar:
+ case INS_ldaxr:
+ case INS_stxr:
case INS_stlr:
+ case INS_stlxr:
case INS_ldr:
case INS_str:
case INS_ldur:
@@ -1430,6 +1452,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
const static insFormat formatEncode4E[4] = {IF_DR_3A, IF_DR_3B, IF_DI_2C, IF_DV_3C};
const static insFormat formatEncode4F[4] = {IF_DR_3A, IF_DR_3B, IF_DV_3C, IF_DV_1B};
const static insFormat formatEncode4G[4] = {IF_DR_2E, IF_DR_2F, IF_DV_2M, IF_DV_2L};
+ const static insFormat formatEncode4H[4] = {IF_DV_3E, IF_DV_3A, IF_DV_2L, IF_DV_2M};
+ const static insFormat formatEncode4I[4] = {IF_DV_3D, IF_DV_3B, IF_DV_2G, IF_DV_2A};
const static insFormat formatEncode3A[3] = {IF_DR_3A, IF_DR_3B, IF_DI_2C};
const static insFormat formatEncode3B[3] = {IF_DR_2A, IF_DR_2B, IF_DI_1C};
const static insFormat formatEncode3C[3] = {IF_DR_3A, IF_DR_3B, IF_DV_3C};
@@ -1453,6 +1477,8 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
const static insFormat formatEncode2L[2] = {IF_DV_2G, IF_DV_2M};
const static insFormat formatEncode2M[2] = {IF_DV_3A, IF_DV_3AI};
const static insFormat formatEncode2N[2] = {IF_DV_2N, IF_DV_2O};
+ const static insFormat formatEncode2O[2] = {IF_DV_3E, IF_DV_3A};
+ const static insFormat formatEncode2P[2] = {IF_DV_2G, IF_DV_3B};
code_t code = BAD_CODE;
insFormat insFmt = emitInsFormat(ins);
@@ -1593,6 +1619,28 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
}
break;
+ case IF_EN4H:
+ for (index = 0; index < 4; index++)
+ {
+ if (fmt == formatEncode4H[index])
+ {
+ encoding_found = true;
+ break;
+ }
+ }
+ break;
+
+ case IF_EN4I:
+ for (index = 0; index < 4; index++)
+ {
+ if (fmt == formatEncode4I[index])
+ {
+ encoding_found = true;
+ break;
+ }
+ }
+ break;
+
case IF_EN3A:
for (index = 0; index < 3; index++)
{
@@ -1846,6 +1894,28 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
}
break;
+ case IF_EN2O:
+ for (index = 0; index < 2; index++)
+ {
+ if (fmt == formatEncode2O[index])
+ {
+ encoding_found = true;
+ break;
+ }
+ }
+ break;
+
+ case IF_EN2P:
+ for (index = 0; index < 2; index++)
+ {
+ if (fmt == formatEncode2P[index])
+ {
+ encoding_found = true;
+ break;
+ }
+ }
+ break;
+
case IF_BI_0A:
case IF_BI_0B:
case IF_BI_0C:
@@ -1860,6 +1930,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
case IF_LS_3A:
case IF_LS_3B:
case IF_LS_3C:
+ case IF_LS_3D:
case IF_DI_1A:
case IF_DI_1B:
case IF_DI_1C:
@@ -2974,7 +3045,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
result = INS_OPTS_1D;
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
}
@@ -2995,7 +3066,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
result = INS_OPTS_2D;
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
}
@@ -3194,7 +3265,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
result = (index < 1);
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
}
@@ -3215,7 +3286,7 @@ emitter::code_t emitter::emitInsCode(instruction ins, insFormat fmt)
result = (index < 2);
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
}
@@ -3265,7 +3336,7 @@ void emitter::emitIns_I(instruction ins, emitAttr attr, ssize_t imm)
}
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
assert(fmt != IF_NONE);
@@ -3555,7 +3626,7 @@ void emitter::emitIns_R_I(instruction ins, emitAttr attr, regNumber reg, ssize_t
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -3644,7 +3715,7 @@ void emitter::emitIns_R_F(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -3736,6 +3807,16 @@ void emitter::emitIns_R_R(
}
break;
+ case INS_dup:
+ // Vector operation
+ assert(insOptsAnyArrangement(opt));
+ assert(isVectorRegister(reg1));
+ assert(isGeneralRegisterOrZR(reg2));
+ assert(isValidVectorDatasize(size));
+ assert(isValidArrangement(size, opt));
+ fmt = IF_DV_2C;
+ break;
+
case INS_abs:
case INS_not:
assert(isVectorRegister(reg1));
@@ -3880,6 +3961,13 @@ void emitter::emitIns_R_R(
fmt = IF_DR_2G;
break;
+ case INS_addv:
+ case INS_saddlv:
+ case INS_smaxv:
+ case INS_sminv:
+ case INS_uaddlv:
+ case INS_umaxv:
+ case INS_uminv:
case INS_rev64:
assert(isVectorRegister(reg1));
assert(isVectorRegister(reg2));
@@ -3890,14 +3978,32 @@ void emitter::emitIns_R_R(
fmt = IF_DV_2M;
break;
+ case INS_xtn:
+ case INS_xtn2:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isValidVectorDatasize(size));
+ assert(isValidArrangement(size, opt));
+ elemsize = optGetElemsize(opt);
+ assert(size != EA_16BYTE); // Narrowing must start with wide format
+ assert(elemsize != EA_1BYTE); // Narrowing must start with more than one byte src
+ fmt = IF_DV_2M;
+ break;
+
case INS_ldar:
+ case INS_ldaxr:
+ case INS_ldxr:
case INS_stlr:
assert(isValidGeneralDatasize(size));
__fallthrough;
case INS_ldarb:
+ case INS_ldaxrb:
+ case INS_ldxrb:
case INS_ldarh:
+ case INS_ldaxrh:
+ case INS_ldxrh:
case INS_stlrb:
case INS_stlrh:
assert(isValidGeneralLSDatasize(size));
@@ -4024,6 +4130,28 @@ void emitter::emitIns_R_R(
}
break;
+ case INS_fcvtl:
+ case INS_fcvtl2:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isValidVectorDatasize(size));
+ assert(isValidArrangement(size, opt));
+ elemsize = optGetElemsize(opt);
+ assert(elemsize == EA_4BYTE); // Widening from Float to Double, opt should correspond to src layout
+ fmt = IF_DV_2G;
+ break;
+
+ case INS_fcvtn:
+ case INS_fcvtn2:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isValidVectorDatasize(size));
+ assert(isValidArrangement(size, opt));
+ elemsize = optGetElemsize(opt);
+ assert(elemsize == EA_8BYTE); // Narrowing from Double to Float, opt should correspond to src layout
+ fmt = IF_DV_2G;
+ break;
+
case INS_scvtf:
case INS_ucvtf:
if (insOptsAnyArrangement(opt))
@@ -4091,6 +4219,15 @@ void emitter::emitIns_R_R(
}
break;
+ case INS_faddp:
+ // Scalar operation
+ assert(insOptsNone(opt));
+ assert(isValidVectorElemsizeFloat(size));
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ fmt = IF_DV_2G;
+ break;
+
case INS_fcvt:
assert(insOptsConvertFloatToFloat(opt));
assert(isValidVectorFcvtsize(size));
@@ -4100,7 +4237,7 @@ void emitter::emitIns_R_R(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -4199,7 +4336,7 @@ void emitter::emitIns_R_I_I(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -4637,7 +4774,7 @@ void emitter::emitIns_R_R_I(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -4939,10 +5076,67 @@ void emitter::emitIns_R_R_R(
emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0, INS_OPTS_NONE);
return;
+ case INS_cmeq:
+ case INS_cmge:
+ case INS_cmgt:
+ case INS_cmhi:
+ case INS_cmhs:
+ case INS_ctst:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isVectorRegister(reg3));
+
+ if (isValidVectorDatasize(size))
+ {
+ // Vector operation
+ assert(insOptsAnyArrangement(opt));
+ assert(isValidArrangement(size, opt));
+ elemsize = optGetElemsize(opt);
+ fmt = IF_DV_3A;
+ }
+ else
+ {
+ NYI("Untested");
+ // Scalar operation
+ assert(size == EA_8BYTE); // Only Double supported
+ fmt = IF_DV_3E;
+ }
+ break;
+
+ case INS_fcmeq:
+ case INS_fcmge:
+ case INS_fcmgt:
+ assert(isVectorRegister(reg1));
+ assert(isVectorRegister(reg2));
+ assert(isVectorRegister(reg3));
+
+ if (isValidVectorDatasize(size))
+ {
+ // Vector operation
+ assert(insOptsAnyArrangement(opt));
+ assert(isValidArrangement(size, opt));
+ elemsize = optGetElemsize(opt);
+ assert((elemsize == EA_8BYTE) || (elemsize == EA_4BYTE)); // Only Double/Float supported
+ assert(opt != INS_OPTS_1D); // Reserved encoding
+ fmt = IF_DV_3B;
+ }
+ else
+ {
+ NYI("Untested");
+ // Scalar operation
+ assert((size == EA_8BYTE) || (size == EA_4BYTE)); // Only Double/Float supported
+ fmt = IF_DV_3D;
+ }
+ break;
+
case INS_saba:
case INS_sabd:
+ case INS_smax:
+ case INS_smin:
case INS_uaba:
case INS_uabd:
+ case INS_umax:
+ case INS_umin:
assert(isVectorRegister(reg1));
assert(isVectorRegister(reg2));
assert(isVectorRegister(reg3));
@@ -5055,6 +5249,7 @@ void emitter::emitIns_R_R_R(
fmt = IF_DV_3D;
break;
+ case INS_faddp:
case INS_fmla:
case INS_fmls:
assert(isVectorRegister(reg1));
@@ -5091,8 +5286,20 @@ void emitter::emitIns_R_R_R(
emitIns_R_R_R_I(ins, attr, reg1, reg2, reg3, 0);
return;
+ case INS_stxr:
+ case INS_stxrb:
+ case INS_stxrh:
+ case INS_stlxr:
+ case INS_stlxrb:
+ case INS_stlxrh:
+ assert(isGeneralRegisterOrZR(reg1));
+ assert(isGeneralRegisterOrZR(reg2));
+ assert(isGeneralRegisterOrSP(reg3));
+ fmt = IF_LS_3D;
+ break;
+
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5263,7 +5470,7 @@ void emitter::emitIns_R_R_R_I(instruction ins,
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5475,7 +5682,7 @@ void emitter::emitIns_R_R_R_Ext(instruction ins,
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5608,7 +5815,7 @@ void emitter::emitIns_R_R_I_I(instruction ins, emitAttr attr, regNumber reg1, re
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
assert(fmt != IF_NONE);
@@ -5671,7 +5878,7 @@ void emitter::emitIns_R_R_R_R(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
assert(fmt != IF_NONE);
@@ -5713,7 +5920,7 @@ void emitter::emitIns_R_COND(instruction ins, emitAttr attr, regNumber reg, insC
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5757,7 +5964,7 @@ void emitter::emitIns_R_R_COND(instruction ins, emitAttr attr, regNumber reg1, r
fmt = IF_DR_2D;
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5806,7 +6013,7 @@ void emitter::emitIns_R_R_R_COND(
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5854,7 +6061,7 @@ void emitter::emitIns_R_R_FLAGS_COND(
fmt = IF_DR_2I;
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5911,7 +6118,7 @@ void emitter::emitIns_R_I_FLAGS_COND(
}
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -5951,7 +6158,7 @@ void emitter::emitIns_BARR(instruction ins, insBarrier barrier)
imm = (ssize_t)barrier;
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
} // end switch (ins)
@@ -6024,8 +6231,8 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
case INS_str:
case INS_ldr:
- assert(isValidGeneralDatasize(size));
- scale = (size == EA_8BYTE) ? 3 : 2;
+ assert(isValidGeneralDatasize(size) || isValidVectorDatasize(size));
+ scale = genLog2(EA_SIZE_IN_BYTES(size));
break;
case INS_lea:
@@ -6046,7 +6253,7 @@ void emitter::emitIns_R_S(instruction ins, emitAttr attr, regNumber reg1, int va
base = emitComp->lvaFrameAddress(varx, &FPbased);
disp = base + offs;
- assert((scale >= 0) && (scale <= 3));
+ assert((scale >= 0) && (scale <= 4));
regNumber reg2 = FPbased ? REG_FPBASE : REG_SPBASE;
reg2 = encodingSPtoZR(reg2);
@@ -6586,13 +6793,7 @@ void emitter::emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE f
assert(!"emitIns_C_R not supported for RyuJIT backend");
}
-void emitter::emitIns_R_AR(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie /* = 0 */,
- void* clsCookie /* = NULL */)
+void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
{
NYI("emitIns_R_AR");
}
@@ -6651,13 +6852,7 @@ void emitter::emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize
}
}
-void emitter::emitIns_AR_R(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie /* = 0 */,
- void* clsCookie /* = NULL */)
+void emitter::emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs)
{
NYI("emitIns_AR_R");
}
@@ -7201,20 +7396,17 @@ void emitter::emitIns_Call(EmitCallType callType,
VarSetOps::ToString(emitComp, ((instrDescCGCA*)id)->idcGCvars));
}
}
-#endif
-#if defined(DEBUG) || defined(LATE_DISASM)
id->idDebugOnlyInfo()->idMemCookie = (size_t)methHnd; // method token
- id->idDebugOnlyInfo()->idClsCookie = 0;
id->idDebugOnlyInfo()->idCallSig = sigInfo;
-#endif
+#endif // DEBUG
-#if defined(LATE_DISASM)
+#ifdef LATE_DISASM
if (addr != nullptr)
{
codeGen->getDisAssembler().disSetMethod((size_t)addr, methHnd);
}
-#endif // defined(LATE_DISASM)
+#endif // LATE_DISASM
dispIns(id);
appendToCurIG(id);
@@ -7482,10 +7674,9 @@ void emitter::emitIns_Call(EmitCallType callType,
if ((code & 0x00800000) && !exclusive) // Is this a sign-extending opcode? (i.e. ldrsw, ldrsh, ldrsb)
{
- assert((size == EA_4BYTE) || (size == EA_8BYTE));
if ((code & 0x80000000) == 0) // Is it a ldrsh or ldrsb and not ldrsw ?
{
- if (size == EA_4BYTE) // Do we need to encode the 32-bit Rt size bit?
+ if (EA_SIZE(size) != EA_8BYTE) // Do we need to encode the 32-bit Rt size bit?
{
return 0x00400000; // set the bit at location 22
}
@@ -7493,8 +7684,7 @@ void emitter::emitIns_Call(EmitCallType callType,
}
else if (code & 0x80000000) // Is this a ldr/str/ldur/stur opcode?
{
- assert((size == EA_4BYTE) || (size == EA_8BYTE));
- if (size == EA_8BYTE) // Do we need to encode the 64-bit size bit?
+ if (EA_SIZE(size) == EA_8BYTE) // Do we need to encode the 64-bit size bit?
{
return 0x40000000; // set the bit at location 30
}
@@ -8963,6 +9153,18 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
dst += emitOutput_Instr(dst, code);
break;
+ case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
+ code = emitInsCode(ins, fmt);
+ // Arm64 store exclusive unpredictable cases
+ assert(id->idReg1() != id->idReg2());
+ assert(id->idReg1() != id->idReg3());
+ code |= insEncodeDatasizeLS(code, id->idOpSize()); // X
+ code |= insEncodeReg_Rm(id->idReg1()); // mmmmm
+ code |= insEncodeReg_Rt(id->idReg2()); // ttttt
+ code |= insEncodeReg_Rn(id->idReg3()); // nnnnn
+ dst += emitOutput_Instr(dst, code);
+ break;
+
case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
assert(insOptsNone(id->idInsOpt()) || insOptsLSL12(id->idInsOpt()));
imm = emitGetInsSC(id);
@@ -9372,7 +9574,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
cmode = 0xE; // 1110
break;
default:
- // TODO-Cleanup: add unreached() here
+ unreached();
break;
}
@@ -10640,6 +10842,13 @@ void emitter::emitDispIns(
emitDispAddrRI(id->idReg3(), id->idInsOpt(), imm);
break;
+ case IF_LS_3D: // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
+ assert(insOptsNone(id->idInsOpt()));
+ emitDispReg(id->idReg1(), EA_4BYTE, true);
+ emitDispReg(id->idReg2(), emitInsTargetRegSize(id), true);
+ emitDispAddrRI(id->idReg3(), id->idInsOpt(), 0);
+ break;
+
case IF_DI_1A: // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
emitDispReg(id->idReg1(), size, true);
emitDispImmOptsLSL12(emitGetInsSC(id), id->idInsOpt());
@@ -10824,6 +11033,15 @@ void emitter::emitDispIns(
emitDispReg(encodingZRtoSP(id->idReg1()), size, true);
emitDispReg(encodingZRtoSP(id->idReg2()), size, true);
}
+ else if ((ins == INS_smull) || (ins == INS_smulh))
+ {
+ // Rd is always 8 bytes
+ emitDispReg(id->idReg1(), EA_8BYTE, true);
+
+ // Rn, Rm effective size depends on instruction type
+ size = (ins == INS_smulh) ? EA_8BYTE : EA_4BYTE;
+ emitDispReg(id->idReg2(), size, true);
+ }
else
{
emitDispReg(id->idReg1(), size, true);
diff --git a/src/jit/emitarm64.h b/src/jit/emitarm64.h
index 87d99952cf..0838d6e336 100644
--- a/src/jit/emitarm64.h
+++ b/src/jit/emitarm64.h
@@ -783,16 +783,13 @@ void emitIns_J_R(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
void emitIns_J_R_I(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg, int imm);
-void emitIns_I_AR(
- instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
-void emitIns_R_AR(
- instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
-void emitIns_AR_R(
- instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs, int memCookie = 0, void* clsCookie = NULL);
+void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_R_ARR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, regNumber rg2, int disp);
diff --git a/src/jit/emitfmtsarm64.h b/src/jit/emitfmtsarm64.h
index c4be8ae45a..49b2dffd60 100644
--- a/src/jit/emitfmtsarm64.h
+++ b/src/jit/emitfmtsarm64.h
@@ -58,6 +58,8 @@ IF_DEF(EN4D, IS_NONE, NONE) // Instruction has 4 possible encoding types, type D
IF_DEF(EN4E, IS_NONE, NONE) // Instruction has 4 possible encoding types, type E
IF_DEF(EN4F, IS_NONE, NONE) // Instruction has 4 possible encoding types, type F
IF_DEF(EN4G, IS_NONE, NONE) // Instruction has 4 possible encoding types, type G
+IF_DEF(EN4H, IS_NONE, NONE) // Instruction has 4 possible encoding types, type H
+IF_DEF(EN4I, IS_NONE, NONE) // Instruction has 4 possible encoding types, type I
IF_DEF(EN3A, IS_NONE, NONE) // Instruction has 3 possible encoding types, type A
IF_DEF(EN3B, IS_NONE, NONE) // Instruction has 3 possible encoding types, type B
IF_DEF(EN3C, IS_NONE, NONE) // Instruction has 3 possible encoding types, type C
@@ -81,6 +83,8 @@ IF_DEF(EN2K, IS_NONE, NONE) // Instruction has 2 possible encoding types, type K
IF_DEF(EN2L, IS_NONE, NONE) // Instruction has 2 possible encoding types, type L
IF_DEF(EN2M, IS_NONE, NONE) // Instruction has 2 possible encoding types, type M
IF_DEF(EN2N, IS_NONE, NONE) // Instruction has 2 possible encoding types, type N
+IF_DEF(EN2O, IS_NONE, NONE) // Instruction has 2 possible encoding types, type O
+IF_DEF(EN2P, IS_NONE, NONE) // Instruction has 2 possible encoding types, type P
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
@@ -130,6 +134,7 @@ IF_DEF(LS_2C, IS_NONE, NONE) // LS_2C .X.......X.iiiii iiiiP.nnnnnttttt R
IF_DEF(LS_3A, IS_NONE, NONE) // LS_3A .X.......X.mmmmm xxxS..nnnnnttttt Rt Rn Rm ext(Rm) LSL {}
IF_DEF(LS_3B, IS_NONE, NONE) // LS_3B X............... .aaaaannnnnddddd Rd Ra Rn
IF_DEF(LS_3C, IS_NONE, NONE) // LS_3C X.........iiiiii iaaaaannnnnddddd Rd Ra Rn imm(im7,sh)
+IF_DEF(LS_3D, IS_NONE, NONE) // LS_3D .X.......X.mmmmm ......nnnnnttttt Wm Rt Rn
IF_DEF(DI_1A, IS_NONE, NONE) // DI_1A X.......shiiiiii iiiiiinnnnn..... Rn imm(i12,sh)
IF_DEF(DI_1B, IS_NONE, NONE) // DI_1B X........hwiiiii iiiiiiiiiiiddddd Rd imm(i16,hw)
diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp
index 1e82d6f3e9..fef5790d97 100644
--- a/src/jit/emitxarch.cpp
+++ b/src/jit/emitxarch.cpp
@@ -41,16 +41,16 @@ bool IsSSE4Instruction(instruction ins)
bool IsSSEOrAVXInstruction(instruction ins)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
return (ins >= INS_FIRST_SSE2_INSTRUCTION && ins <= INS_LAST_AVX_INSTRUCTION);
-#else // !FEATURE_AVX_SUPPORT
+#else // !LEGACY_BACKEND
return IsSSE2Instruction(ins);
-#endif // !FEATURE_AVX_SUPPORT
+#endif // LEGACY_BACKEND
}
bool IsAVXOnlyInstruction(instruction ins)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
return (ins >= INS_FIRST_AVX_INSTRUCTION && ins <= INS_LAST_AVX_INSTRUCTION);
#else
return false;
@@ -59,14 +59,14 @@ bool IsAVXOnlyInstruction(instruction ins)
bool emitter::IsAVXInstruction(instruction ins)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
return (UseAVX() && IsSSEOrAVXInstruction(ins));
#else
return false;
#endif
}
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
// Returns true if the AVX instruction is a binary operator that requires 3 operands.
// When we emit an instruction with only two operands, we will duplicate the destination
// as a source.
@@ -76,27 +76,26 @@ bool emitter::IsAVXInstruction(instruction ins)
bool emitter::IsDstDstSrcAVXInstruction(instruction ins)
{
return IsAVXInstruction(ins) &&
- (ins == INS_cvtsi2ss || ins == INS_cvtsi2sd || ins == INS_cvtss2sd || ins == INS_cvtsd2ss ||
- ins == INS_addss || ins == INS_addsd || ins == INS_subss || ins == INS_subsd || ins == INS_mulss ||
- ins == INS_mulsd || ins == INS_divss || ins == INS_divsd || ins == INS_addps || ins == INS_addpd ||
- ins == INS_subps || ins == INS_subpd || ins == INS_mulps || ins == INS_mulpd || ins == INS_cmpps ||
- ins == INS_cmppd || ins == INS_andps || ins == INS_andpd || ins == INS_orps || ins == INS_orpd ||
- ins == INS_xorps || ins == INS_xorpd || ins == INS_dpps || ins == INS_dppd || ins == INS_haddpd ||
- ins == INS_por || ins == INS_pand || ins == INS_pandn || ins == INS_pcmpeqd || ins == INS_pcmpgtd ||
- ins == INS_pcmpeqw || ins == INS_pcmpgtw || ins == INS_pcmpeqb || ins == INS_pcmpgtb ||
- ins == INS_pcmpeqq || ins == INS_pcmpgtq || ins == INS_pmulld || ins == INS_pmullw || ins == INS_shufps ||
- ins == INS_shufpd || ins == INS_minps || ins == INS_minss || ins == INS_minpd || ins == INS_minsd ||
- ins == INS_divps || ins == INS_divpd || ins == INS_maxps || ins == INS_maxpd || ins == INS_maxss ||
- ins == INS_maxsd || ins == INS_andnps || ins == INS_andnpd || ins == INS_paddb || ins == INS_paddw ||
- ins == INS_paddd || ins == INS_paddq || ins == INS_psubb || ins == INS_psubw || ins == INS_psubd ||
- ins == INS_psubq || ins == INS_pmuludq || ins == INS_pxor || ins == INS_insertps ||
- ins == INS_vinsertf128 || ins == INS_punpckldq || ins == INS_phaddd || ins == INS_pminub ||
- ins == INS_pminsw || ins == INS_pminsb || ins == INS_pminsd || ins == INS_pminuw || ins == INS_pminud ||
- ins == INS_pmaxub || ins == INS_pmaxsw || ins == INS_pmaxsb || ins == INS_pmaxsd || ins == INS_pmaxuw ||
- ins == INS_pmaxud || ins == INS_vinserti128 || ins == INS_punpckhbw || ins == INS_punpcklbw ||
- ins == INS_punpckhqdq || ins == INS_punpcklqdq || ins == INS_punpckhwd || ins == INS_punpcklwd ||
- ins == INS_punpckhdq || ins == INS_packssdw || ins == INS_packsswb || ins == INS_packuswb ||
- ins == INS_packusdw || ins == INS_vperm2i128);
+ (ins == INS_cvtsi2ss || ins == INS_cvtsi2sd || ins == INS_addss || ins == INS_addsd || ins == INS_subss ||
+ ins == INS_subsd || ins == INS_mulss || ins == INS_mulsd || ins == INS_divss || ins == INS_divsd ||
+ ins == INS_addps || ins == INS_addpd || ins == INS_subps || ins == INS_subpd || ins == INS_mulps ||
+ ins == INS_mulpd || ins == INS_cmpps || ins == INS_cmppd || ins == INS_andps || ins == INS_andpd ||
+ ins == INS_orps || ins == INS_orpd || ins == INS_xorps || ins == INS_xorpd || ins == INS_dpps ||
+ ins == INS_dppd || ins == INS_haddpd || ins == INS_por || ins == INS_pand || ins == INS_pandn ||
+ ins == INS_pcmpeqd || ins == INS_pcmpgtd || ins == INS_pcmpeqw || ins == INS_pcmpgtw ||
+ ins == INS_pcmpeqb || ins == INS_pcmpgtb || ins == INS_pcmpeqq || ins == INS_pcmpgtq || ins == INS_pmulld ||
+ ins == INS_pmullw || ins == INS_shufps || ins == INS_shufpd || ins == INS_minps || ins == INS_minss ||
+ ins == INS_minpd || ins == INS_minsd || ins == INS_divps || ins == INS_divpd || ins == INS_maxps ||
+ ins == INS_maxpd || ins == INS_maxss || ins == INS_maxsd || ins == INS_andnps || ins == INS_andnpd ||
+ ins == INS_paddb || ins == INS_paddw || ins == INS_paddd || ins == INS_paddq || ins == INS_psubb ||
+ ins == INS_psubw || ins == INS_psubd || ins == INS_psubq || ins == INS_pmuludq || ins == INS_pxor ||
+ ins == INS_insertps || ins == INS_vinsertf128 || ins == INS_punpckldq || ins == INS_phaddd ||
+ ins == INS_pminub || ins == INS_pminsw || ins == INS_pminsb || ins == INS_pminsd || ins == INS_pminuw ||
+ ins == INS_pminud || ins == INS_pmaxub || ins == INS_pmaxsw || ins == INS_pmaxsb || ins == INS_pmaxsd ||
+ ins == INS_pmaxuw || ins == INS_pmaxud || ins == INS_vinserti128 || ins == INS_punpckhbw ||
+ ins == INS_punpcklbw || ins == INS_punpckhqdq || ins == INS_punpcklqdq || ins == INS_punpckhwd ||
+ ins == INS_punpcklwd || ins == INS_punpckhdq || ins == INS_packssdw || ins == INS_packsswb ||
+ ins == INS_packuswb || ins == INS_packusdw || ins == INS_vperm2i128);
}
// Returns true if the AVX instruction requires 3 operands that duplicate the source
@@ -106,8 +105,9 @@ bool emitter::IsDstDstSrcAVXInstruction(instruction ins)
// to indicate whether a 3-operand instruction.
bool emitter::IsDstSrcSrcAVXInstruction(instruction ins)
{
- return IsAVXInstruction(ins) && (ins == INS_movlpd || ins == INS_movlps || ins == INS_movhpd || ins == INS_movhps ||
- ins == INS_movss || ins == INS_movlhps || ins == INS_sqrtss || ins == INS_sqrtsd);
+ return IsAVXInstruction(ins) &&
+ (ins == INS_movlpd || ins == INS_movlps || ins == INS_movhpd || ins == INS_movhps || ins == INS_movss ||
+ ins == INS_movlhps || ins == INS_sqrtss || ins == INS_sqrtsd || ins == INS_cvtss2sd || ins == INS_cvtsd2ss);
}
// ------------------------------------------------------------------------------
@@ -122,7 +122,7 @@ bool emitter::Is4ByteAVXInstruction(instruction ins)
{
return UseAVX() && (IsSSE4Instruction(ins) || IsAVXOnlyInstruction(ins)) && EncodedBySSE38orSSE3A(ins);
}
-#endif // FEATURE_AVX_SUPPORT
+#endif // !LEGACY_BACKEND
// -------------------------------------------------------------------
// Is4ByteSSE4Instruction: Returns true if the SSE4 instruction
@@ -136,14 +136,14 @@ bool emitter::Is4ByteAVXInstruction(instruction ins)
bool emitter::Is4ByteSSE4Instruction(instruction ins)
{
#ifdef LEGACY_BACKEND
- // On legacy backend SSE3_4 is not enabled.
+ // On legacy backend SSE4 is not enabled.
return false;
#else
- return UseSSE3_4() && IsSSE4Instruction(ins) && EncodedBySSE38orSSE3A(ins);
+ return UseSSE4() && IsSSE4Instruction(ins) && EncodedBySSE38orSSE3A(ins);
#endif
}
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
// Returns true if this instruction requires a VEX prefix
// All AVX instructions require a VEX prefix
bool emitter::TakesVexPrefix(instruction ins)
@@ -202,7 +202,7 @@ emitter::code_t emitter::AddVexPrefix(instruction ins, code_t code, emitAttr att
return code;
}
-#endif // FEATURE_AVX_SUPPORT
+#endif // !LEGACY_BACKEND
// Returns true if this instruction, for the given EA_SIZE(attr), will require a REX.W prefix
bool TakesRexWPrefix(instruction ins, emitAttr attr)
@@ -442,7 +442,7 @@ bool isPrefix(BYTE b)
// Outputs VEX prefix (in case of AVX instructions) and REX.R/X/W/B otherwise.
unsigned emitter::emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, code_t& code)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
if (hasVexPrefix(code))
{
// Only AVX instructions should have a VEX prefix
@@ -540,7 +540,7 @@ unsigned emitter::emitOutputRexOrVexPrefixIfNeeded(instruction ins, BYTE* dst, c
emitOutputByte(dst + 2, vexPrefix & 0xFF);
return 3;
}
-#endif // FEATURE_AVX_SUPPORT
+#endif // !LEGACY_BACKEND
#ifdef _TARGET_AMD64_
if (code > 0x00FFFFFFFFLL)
@@ -670,7 +670,7 @@ unsigned emitter::emitGetVexPrefixSize(instruction ins, emitAttr attr)
//=opcodeSize + vexPrefixAdjustedSize
unsigned emitter::emitGetVexPrefixAdjustedSize(instruction ins, emitAttr attr, code_t code)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
if (IsAVXInstruction(ins))
{
unsigned vexPrefixAdjustedSize = emitGetVexPrefixSize(ins, attr);
@@ -706,8 +706,7 @@ unsigned emitter::emitGetVexPrefixAdjustedSize(instruction ins, emitAttr attr, c
return vexPrefixAdjustedSize;
}
-#endif // FEATURE_AVX_SUPPORT
-
+#endif // !LEGACY_BACKEND
return 0;
}
@@ -1246,7 +1245,7 @@ inline unsigned emitter::insEncodeReg345(instruction ins, regNumber reg, emitAtt
*/
inline emitter::code_t emitter::insEncodeReg3456(instruction ins, regNumber reg, emitAttr size, code_t code)
{
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
assert(reg < REG_STK);
assert(IsAVXInstruction(ins));
assert(hasVexPrefix(code));
@@ -1495,8 +1494,12 @@ bool emitter::emitVerifyEncodable(instruction ins, emitAttr size, regNumber reg1
return true;
}
- if ((ins != INS_movsx) && // These two instructions support high register
- (ins != INS_movzx)) // encodings for reg1
+ if ((ins != INS_movsx) && // These three instructions support high register
+ (ins != INS_movzx) // encodings for reg1
+#if FEATURE_HW_INTRINSICS
+ && (ins != INS_crc32)
+#endif
+ )
{
// reg1 must be a byte-able register
if ((genRegMask(reg1) & RBM_BYTE_REGS) == 0)
@@ -3814,7 +3817,7 @@ void emitter::emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regN
// AVX: 3 byte VEX prefix + 1 byte opcode + 1 byte ModR/M + 1 byte immediate
// SSE4: 4 byte opcode + 1 byte ModR/M + 1 byte immediate
// SSE2: 3 byte opcode + 1 byte ModR/M + 1 byte immediate
- sz = (UseAVX() || UseSSE3_4()) ? 6 : 5;
+ sz = (UseAVX() || UseSSE4()) ? 6 : 5;
}
#ifdef _TARGET_AMD64_
@@ -3840,7 +3843,7 @@ void emitter::emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regN
dispIns(id);
emitCurIGsize += sz;
}
-#ifdef FEATURE_AVX_SUPPORT
+
/*****************************************************************************
*
* Add an instruction with three register operands.
@@ -3901,7 +3904,6 @@ void emitter::emitIns_R_R_R_I(
emitCurIGsize += sz;
}
-#endif
/*****************************************************************************
*
* Add an instruction with a register + static member operands.
@@ -4231,8 +4233,7 @@ void emitter::emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNu
* The following adds instructions referencing address modes.
*/
-void emitter::emitIns_I_AR(
- instruction ins, emitAttr attr, int val, regNumber reg, int disp, int memCookie, void* clsCookie)
+void emitter::emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int disp)
{
assert((CodeGen::instIsFP(ins) == false) && (EA_SIZE(attr) <= EA_8BYTE));
@@ -4276,13 +4277,6 @@ void emitter::emitIns_I_AR(
id->idIns(ins);
id->idInsFmt(fmt);
- assert((memCookie == NULL) == (clsCookie == nullptr));
-
-#ifdef DEBUG
- id->idDebugOnlyInfo()->idMemCookie = memCookie;
- id->idDebugOnlyInfo()->idClsCookie = clsCookie;
-#endif
-
id->idAddr()->iiaAddrMode.amBaseReg = reg;
id->idAddr()->iiaAddrMode.amIndxReg = REG_NA;
@@ -4351,8 +4345,7 @@ void emitter::emitIns_I_AI(instruction ins, emitAttr attr, int val, ssize_t disp
emitCurIGsize += sz;
}
-void emitter::emitIns_R_AR(
- instruction ins, emitAttr attr, regNumber ireg, regNumber base, int disp, int memCookie, void* clsCookie)
+void emitter::emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber base, int disp)
{
assert((CodeGen::instIsFP(ins) == false) && (EA_SIZE(attr) <= EA_32BYTE) && (ireg != REG_NA));
noway_assert(emitVerifyEncodable(ins, EA_SIZE(attr), ireg));
@@ -4376,13 +4369,6 @@ void emitter::emitIns_R_AR(
id->idInsFmt(fmt);
id->idReg1(ireg);
- assert((memCookie == NULL) == (clsCookie == nullptr));
-
-#ifdef DEBUG
- id->idDebugOnlyInfo()->idMemCookie = memCookie;
- id->idDebugOnlyInfo()->idClsCookie = clsCookie;
-#endif
-
id->idAddr()->iiaAddrMode.amBaseReg = base;
id->idAddr()->iiaAddrMode.amIndxReg = REG_NA;
@@ -4420,8 +4406,7 @@ void emitter::emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize
emitCurIGsize += sz;
}
-void emitter::emitIns_AR_R(
- instruction ins, emitAttr attr, regNumber ireg, regNumber base, int disp, int memCookie, void* clsCookie)
+void emitter::emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber base, int disp)
{
UNATIVE_OFFSET sz;
instrDesc* id = emitNewInstrAmd(attr, disp);
@@ -4448,13 +4433,6 @@ void emitter::emitIns_AR_R(
id->idIns(ins);
id->idInsFmt(fmt);
- assert((memCookie == NULL) == (clsCookie == nullptr));
-
-#ifdef DEBUG
- id->idDebugOnlyInfo()->idMemCookie = memCookie;
- id->idDebugOnlyInfo()->idClsCookie = clsCookie;
-#endif
-
id->idAddr()->iiaAddrMode.amBaseReg = base;
id->idAddr()->iiaAddrMode.amIndxReg = REG_NA;
@@ -5664,20 +5642,17 @@ void emitter::emitIns_Call(EmitCallType callType,
}
}
}
-#endif
-#if defined(DEBUG) || defined(LATE_DISASM)
id->idDebugOnlyInfo()->idMemCookie = (size_t)methHnd; // method token
- id->idDebugOnlyInfo()->idClsCookie = nullptr;
id->idDebugOnlyInfo()->idCallSig = sigInfo;
-#endif
+#endif // DEBUG
-#if defined(LATE_DISASM)
+#ifdef LATE_DISASM
if (addr != nullptr)
{
codeGen->getDisAssembler().disSetMethod((size_t)addr, methHnd);
}
-#endif // defined(LATE_DISASM)
+#endif // LATE_DISASM
id->idCodeSize(sz);
@@ -6436,19 +6411,8 @@ void emitter::emitDispAddrMode(instrDesc* id, bool noDetail)
printf("]");
- if (id->idDebugOnlyInfo()->idClsCookie)
- {
- if (id->idIns() == INS_call)
- {
- printf("%s", emitFncName((CORINFO_METHOD_HANDLE)id->idDebugOnlyInfo()->idMemCookie));
- }
- else
- {
- printf("%s", emitFldName((CORINFO_FIELD_HANDLE)id->idDebugOnlyInfo()->idMemCookie));
- }
- }
// pretty print string if it looks like one
- else if (id->idGCref() == GCT_GCREF && id->idIns() == INS_mov && id->idAddr()->iiaAddrMode.amBaseReg == REG_NA)
+ if ((id->idGCref() == GCT_GCREF) && (id->idIns() == INS_mov) && (id->idAddr()->iiaAddrMode.amBaseReg == REG_NA))
{
const wchar_t* str = emitComp->eeGetCPString(disp);
if (str != nullptr)
@@ -6718,13 +6682,12 @@ void emitter::emitDispIns(
/* Display the instruction name */
sstr = codeGen->genInsName(ins);
-#ifdef FEATURE_AVX_SUPPORT
+
if (IsAVXInstruction(ins))
{
printf(" v%-8s", sstr);
}
else
-#endif // FEATURE_AVX_SUPPORT
{
printf(" %-9s", sstr);
}
@@ -7079,6 +7042,12 @@ void emitter::emitDispIns(
// INS_bt operands are reversed. Display them in the normal order.
printf("%s, %s", emitRegName(id->idReg2(), attr), emitRegName(id->idReg1(), attr));
}
+#if FEATURE_HW_INTRINSICS
+ else if (ins == INS_crc32 && attr != EA_8BYTE)
+ {
+ printf("%s, %s", emitRegName(id->idReg1(), EA_4BYTE), emitRegName(id->idReg2(), attr));
+ }
+#endif // FEATURE_HW_INTRINSICS
else
{
printf("%s, %s", emitRegName(id->idReg1(), attr), emitRegName(id->idReg2(), attr));
@@ -7091,7 +7060,6 @@ void emitter::emitDispIns(
printf(" %s", emitRegName(id->idReg2(), attr));
break;
-#ifdef FEATURE_AVX_SUPPORT
case IF_RWR_RRD_RRD:
assert(IsAVXInstruction(ins));
assert(IsThreeOperandAVXInstruction(ins));
@@ -7108,7 +7076,6 @@ void emitter::emitDispIns(
val = emitGetInsSC(id);
goto PRINT_CONSTANT;
break;
-#endif
case IF_RRW_RRW_CNS:
printf("%s,", emitRegName(id->idReg1(), attr));
printf(" %s", emitRegName(id->idReg2(), attr));
@@ -9190,6 +9157,26 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id)
#endif // _TARGET_AMD64_
}
+#if FEATURE_HW_INTRINSICS
+ else if ((ins == INS_crc32) || (ins == INS_lzcnt) || (ins == INS_popcnt))
+ {
+ code = insEncodeRMreg(ins, code);
+ if ((ins == INS_crc32) && (size > EA_1BYTE))
+ {
+ code |= 0x0100;
+ }
+
+ if (size == EA_2BYTE)
+ {
+ assert(ins == INS_crc32);
+ dst += emitOutputByte(dst, 0x66);
+ }
+ else if (size == EA_8BYTE)
+ {
+ code = AddRexWPrefix(ins, code);
+ }
+ }
+#endif // FEATURE_HW_INTRINSICS
else
{
code = insEncodeMRreg(ins, insCodeMR(ins));
@@ -9487,7 +9474,6 @@ BYTE* emitter::emitOutputRR(BYTE* dst, instrDesc* id)
return dst;
}
-#ifdef FEATURE_AVX_SUPPORT
BYTE* emitter::emitOutputRRR(BYTE* dst, instrDesc* id)
{
code_t code;
@@ -9563,7 +9549,6 @@ BYTE* emitter::emitOutputRRR(BYTE* dst, instrDesc* id)
return dst;
}
-#endif
/*****************************************************************************
*
@@ -10756,7 +10741,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
sz = emitSizeOfInsDsc(id);
break;
-#ifdef FEATURE_AVX_SUPPORT
case IF_RWR_RRD_RRD:
dst = emitOutputRRR(dst, id);
sz = emitSizeOfInsDsc(id);
@@ -10766,7 +10750,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
sz = emitSizeOfInsDsc(id);
dst += emitOutputByte(dst, emitGetInsSC(id));
break;
-#endif
case IF_RRW_RRW_CNS:
assert(id->idGCref() == GCT_NONE);
@@ -10796,7 +10779,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
}
assert(code & 0x00FF0000);
-#ifdef FEATURE_AVX_SUPPORT
if (TakesRexWPrefix(ins, size))
{
code = AddRexWPrefix(ins, code);
@@ -10821,7 +10803,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
code = insEncodeReg3456(ins, id->idReg2(), size, code);
}
}
-#endif // FEATURE_AVX_SUPPORT
regcode = (insEncodeReg345(ins, rReg, size, &code) | insEncodeReg012(ins, mReg, size, &code)) << 8;
@@ -11174,7 +11155,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
case IF_MWR_RRD:
case IF_MRW_RRD:
code = insCodeMR(ins);
-#ifdef FEATURE_AVX_SUPPORT
code = AddVexPrefixIfNeeded(ins, code, size);
// In case of AVX instructions that take 3 operands, encode reg1 as first source.
@@ -11188,7 +11168,6 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp)
// encode source operand reg in 'vvvv' bits in 1's compliement form
code = insEncodeReg3456(ins, id->idReg1(), size, code);
}
-#endif // FEATURE_AVX_SUPPORT
regcode = (insEncodeReg345(ins, id->idReg1(), size, &code) << 8);
dst = emitOutputCV(dst, id, code | regcode | 0x0500);
diff --git a/src/jit/emitxarch.h b/src/jit/emitxarch.h
index 2bafe85133..f7e1e6bb7f 100644
--- a/src/jit/emitxarch.h
+++ b/src/jit/emitxarch.h
@@ -62,9 +62,7 @@ BYTE* emitOutputRI(BYTE* dst, instrDesc* id);
BYTE* emitOutputRR(BYTE* dst, instrDesc* id);
BYTE* emitOutputIV(BYTE* dst, instrDesc* id);
-#ifdef FEATURE_AVX_SUPPORT
BYTE* emitOutputRRR(BYTE* dst, instrDesc* id);
-#endif
BYTE* emitOutputLJ(BYTE* dst, instrDesc* id);
@@ -96,14 +94,14 @@ code_t AddRexXPrefix(instruction ins, code_t code);
code_t AddRexBPrefix(instruction ins, code_t code);
code_t AddRexPrefix(instruction ins, code_t code);
-bool useSSE3_4Encodings;
-bool UseSSE3_4()
+bool useSSE4Encodings;
+bool UseSSE4()
{
- return useSSE3_4Encodings;
+ return useSSE4Encodings;
}
-void SetUseSSE3_4(bool value)
+void SetUseSSE4(bool value)
{
- useSSE3_4Encodings = value;
+ useSSE4Encodings = value;
}
bool EncodedBySSE38orSSE3A(instruction ins);
bool Is4ByteSSE4Instruction(instruction ins);
@@ -118,7 +116,7 @@ bool hasRexPrefix(code_t code)
#endif // !_TARGET_AMD64_
}
-#ifdef FEATURE_AVX_SUPPORT
+#ifndef LEGACY_BACKEND
// 3-byte VEX prefix starts with byte 0xC4
#define VEX_PREFIX_MASK_3BYTE 0xFF000000000000ULL
@@ -186,19 +184,28 @@ bool IsThreeOperandAVXInstruction(instruction ins)
return (IsDstDstSrcAVXInstruction(ins) || IsDstSrcSrcAVXInstruction(ins));
}
bool Is4ByteAVXInstruction(instruction ins);
-#else // !FEATURE_AVX_SUPPORT
+#else // LEGACY_BACKEND
bool UseAVX()
{
return false;
}
+void SetUseAVX(bool value)
+{
+}
bool ContainsAVX()
{
return false;
}
+void SetContainsAVX(bool value)
+{
+}
bool Contains256bitAVX()
{
return false;
}
+void SetContains256bitAVX(bool value)
+{
+}
bool hasVexPrefix(code_t code)
{
return false;
@@ -231,7 +238,7 @@ code_t AddVexPrefixIfNeededAndNotPresent(instruction ins, code_t code, emitAttr
{
return code;
}
-#endif // !FEATURE_AVX_SUPPORT
+#endif // LEGACY_BACKEND
/************************************************************************/
/* Debug-only routines to display instructions */
@@ -358,11 +365,9 @@ void emitIns_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2)
void emitIns_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, int ival);
-#ifdef FEATURE_AVX_SUPPORT
void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3);
void emitIns_R_R_R_I(instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber reg3, int ival);
-#endif
void emitIns_S(instruction ins, emitAttr attr, int varx, int offs);
@@ -386,28 +391,15 @@ void emitIns_R_L(instruction ins, emitAttr attr, BasicBlock* dst, regNumber reg)
void emitIns_R_D(instruction ins, emitAttr attr, unsigned offs, regNumber reg);
-void emitIns_I_AR(
- instruction ins, emitAttr attr, int val, regNumber reg, int offs, int memCookie = 0, void* clsCookie = nullptr);
+void emitIns_I_AR(instruction ins, emitAttr attr, int val, regNumber reg, int offs);
void emitIns_I_AI(instruction ins, emitAttr attr, int val, ssize_t disp);
-void emitIns_R_AR(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie = 0,
- void* clsCookie = nullptr);
+void emitIns_R_AR(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_R_AI(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
-void emitIns_AR_R(instruction ins,
- emitAttr attr,
- regNumber ireg,
- regNumber reg,
- int offs,
- int memCookie = 0,
- void* clsCookie = nullptr);
+void emitIns_AR_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, int offs);
void emitIns_AI_R(instruction ins, emitAttr attr, regNumber ireg, ssize_t disp);
diff --git a/src/jit/flowgraph.cpp b/src/jit/flowgraph.cpp
index 06e0d3f712..946f77d7ae 100644
--- a/src/jit/flowgraph.cpp
+++ b/src/jit/flowgraph.cpp
@@ -309,21 +309,22 @@ void Compiler::fgInstrumentMethod()
continue;
}
+ // Assign the current block's IL offset into the profile data
bbProfileBuffer->ILOffset = block->bbCodeOffs;
- GenTreePtr addr;
- GenTreePtr value;
+ size_t addrOfBlockCount = (size_t)&bbProfileBuffer->ExecutionCount;
- value = gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode((void*)&bbProfileBuffer->ExecutionCount, nullptr,
- GTF_ICON_BBC_PTR));
- value = gtNewOperNode(GT_ADD, TYP_INT, value, gtNewIconNode(1));
+ // Read Basic-Block count value
+ GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfBlockCount, GTF_ICON_BBC_PTR, false);
- addr = gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode((void*)&bbProfileBuffer->ExecutionCount, nullptr,
- GTF_ICON_BBC_PTR));
+ // Increment value by 1
+ GenTree* rhsNode = gtNewOperNode(GT_ADD, TYP_INT, valueNode, gtNewIconNode(1));
- addr = gtNewAssignNode(addr, value);
+ // Write new Basic-Block count value
+ GenTree* lhsNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfBlockCount, GTF_ICON_BBC_PTR, false);
+ GenTree* asgNode = gtNewAssignNode(lhsNode, rhsNode);
- fgInsertStmtAtBeg(block, addr);
+ fgInsertStmtAtBeg(block, asgNode);
countOfBlocks--;
bbProfileBuffer++;
@@ -358,10 +359,13 @@ void Compiler::fgInstrumentMethod()
GenTreeArgList* args = gtNewArgList(arg);
GenTreePtr call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args);
- GenTreePtr handle =
- gtNewIconEmbHndNode((void*)&bbProfileBufferStart->ExecutionCount, nullptr, GTF_ICON_BBC_PTR);
- GenTreePtr value = gtNewOperNode(GT_IND, TYP_INT, handle);
- GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, value, gtNewIconNode(0, TYP_INT));
+ size_t addrOfBlockCount = (size_t)&bbProfileBuffer->ExecutionCount;
+
+ // Read Basic-Block count value
+ GenTreePtr valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfBlockCount, GTF_ICON_BBC_PTR, false);
+
+ // Compare Basic-Block count value against zero
+ GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT));
relop->gtFlags |= GTF_RELOP_QMARK; // TODO-Cleanup: [Simple] Move this to gtNewQmarkNode
GenTreePtr colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call);
GenTreePtr cond = gtNewQmarkNode(TYP_VOID, relop, colon);
@@ -3984,23 +3988,30 @@ bool Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block)
noway_assert(pAddrOfCaptureThreadGlobal == nullptr);
#endif
- GenTreePtr trap;
+ GenTreePtr value; // The value of g_TrapReturningThreads
if (pAddrOfCaptureThreadGlobal != nullptr)
{
- trap = gtNewOperNode(GT_IND, TYP_I_IMPL,
- gtNewIconHandleNode((size_t)pAddrOfCaptureThreadGlobal, GTF_ICON_PTR_HDL));
+ // Use a double indirection
+ GenTreePtr addr =
+ gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pAddrOfCaptureThreadGlobal, GTF_ICON_PTR_HDL, true);
+
+ value = gtNewOperNode(GT_IND, TYP_INT, addr);
+ // This indirection won't cause an exception.
+ value->gtFlags |= GTF_IND_NONFAULTING;
}
else
{
- trap = gtNewIconHandleNode((size_t)addrTrap, GTF_ICON_PTR_HDL);
+ // Use a single indirection
+ value = gtNewIndOfIconHandleNode(TYP_INT, (size_t)addrTrap, GTF_ICON_PTR_HDL, false);
}
- GenTreePtr trapRelop = gtNewOperNode(GT_EQ, TYP_INT,
- // lhs [g_TrapReturningThreads]
- gtNewOperNode(GT_IND, TYP_INT, trap),
- // rhs 0
- gtNewIconNode(0, TYP_INT));
- trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE; // Treat reading g_TrapReturningThreads as volatile.
+ // Treat the reading of g_TrapReturningThreads as volatile.
+ value->gtFlags |= GTF_IND_VOLATILE;
+
+ // Compare for equal to zero
+ GenTreePtr trapRelop = gtNewOperNode(GT_EQ, TYP_INT, value, gtNewIconNode(0, TYP_INT));
+
+ trapRelop->gtFlags |= GTF_RELOP_JMP_USED | GTF_DONT_CSE;
GenTreePtr trapCheck = gtNewOperNode(GT_JTRUE, TYP_VOID, trapRelop);
fgInsertStmtAtEnd(top, trapCheck);
top->bbJumpDest = bottom;
@@ -4322,6 +4333,18 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
compInlineResult->NoteBool(InlineObservation::CALLEE_IS_FORCE_INLINE, isForceInline);
compInlineResult->NoteInt(InlineObservation::CALLEE_IL_CODE_SIZE, codeSize);
+ // Determine if call site is within a try.
+ if (isInlining && impInlineInfo->iciBlock->hasTryIndex())
+ {
+ compInlineResult->Note(InlineObservation::CALLSITE_IN_TRY_REGION);
+ }
+
+ // Determine if the call site is in a loop.
+ if (isInlining && ((impInlineInfo->iciBlock->bbFlags & BBF_BACKWARD_JUMP) != 0))
+ {
+ compInlineResult->Note(InlineObservation::CALLSITE_IN_LOOP);
+ }
+
#ifdef DEBUG
// If inlining, this method should still be a candidate.
@@ -4796,8 +4819,6 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
// the list of other opcodes (for all platforms).
__fallthrough;
-
- case CEE_LOCALLOC:
case CEE_MKREFANY:
case CEE_RETHROW:
if (makeInlineObservations)
@@ -4815,6 +4836,19 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
}
break;
+ case CEE_LOCALLOC:
+
+ // We now allow localloc callees to become candidates in some cases.
+ if (makeInlineObservations)
+ {
+ compInlineResult->Note(InlineObservation::CALLEE_HAS_LOCALLOC);
+ if (isInlining && compInlineResult->IsFailure())
+ {
+ return;
+ }
+ }
+ break;
+
case CEE_LDARG_0:
case CEE_LDARG_1:
case CEE_LDARG_2:
@@ -4904,12 +4938,6 @@ void Compiler::fgFindJumpTargets(const BYTE* codeAddr, IL_OFFSET codeSize, BYTE*
}
}
- // Determine if call site is within a try.
- if (isInlining && impInlineInfo->iciBlock->hasTryIndex())
- {
- compInlineResult->Note(InlineObservation::CALLSITE_IN_TRY_REGION);
- }
-
// If the inline is viable and discretionary, do the
// profitability screening.
if (compInlineResult->IsDiscretionaryCandidate())
@@ -6827,7 +6855,8 @@ bool Compiler::fgIsThrow(GenTreePtr tree)
(tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWDIVZERO)) ||
(tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROWNULLREF)) ||
(tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW)) ||
- (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)))
+ (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_RETHROW)) ||
+ (tree->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED)))
{
noway_assert(tree->gtFlags & GTF_CALL);
noway_assert(tree->gtFlags & GTF_EXCEPT);
@@ -7023,9 +7052,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
if (pmoduleID)
{
- opModuleIDArg = gtNewIconHandleNode((size_t)pmoduleID, GTF_ICON_CIDMID_HDL);
- opModuleIDArg = gtNewOperNode(GT_IND, TYP_I_IMPL, opModuleIDArg);
- opModuleIDArg->gtFlags |= GTF_IND_INVARIANT;
+ opModuleIDArg = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pmoduleID, GTF_ICON_CIDMID_HDL, true);
}
else
{
@@ -7036,9 +7063,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo
{
if (pclsID)
{
- opClassIDArg = gtNewIconHandleNode((size_t)pclsID, GTF_ICON_CIDMID_HDL);
- opClassIDArg = gtNewOperNode(GT_IND, TYP_INT, opClassIDArg);
- opClassIDArg->gtFlags |= GTF_IND_INVARIANT;
+ opClassIDArg = gtNewIndOfIconHandleNode(TYP_INT, (size_t)pclsID, GTF_ICON_CIDMID_HDL, true);
}
else
{
@@ -7101,6 +7126,7 @@ GenTreeCall* Compiler::fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls)
bool Compiler::fgAddrCouldBeNull(GenTreePtr addr)
{
+ addr = addr->gtEffectiveVal();
if ((addr->gtOper == GT_CNS_INT) && addr->IsIconHandle())
{
return false;
@@ -7651,7 +7677,7 @@ GenTreePtr Compiler::fgGetCritSectOfStaticMethod()
critSect = info.compCompHnd->getMethodSync(info.compMethodHnd, (void**)&pCrit);
noway_assert((!critSect) != (!pCrit));
- tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL);
+ tree = gtNewIconEmbHndNode(critSect, pCrit, GTF_ICON_METHOD_HDL, info.compMethodHnd);
}
else
{
@@ -8491,7 +8517,10 @@ private:
assert(mergingReturns);
BasicBlock* mergedReturnBlock = nullptr;
- if ((returnBlock != nullptr) && (maxReturns > 1))
+
+ // Do not look for mergable constant returns in debug codegen as
+ // we may lose track of sequence points.
+ if ((returnBlock != nullptr) && (maxReturns > 1) && !comp->opts.compDbgCode)
{
// Check to see if this is a constant return so that we can search
// for and/or create a constant return block for it.
@@ -8886,9 +8915,9 @@ void Compiler::fgAddInternal()
if (dbgHandle || pDbgHandle)
{
- GenTreePtr guardCheckVal =
- gtNewOperNode(GT_IND, TYP_INT, gtNewIconEmbHndNode(dbgHandle, pDbgHandle, GTF_ICON_TOKEN_HDL));
- GenTreePtr guardCheckCond = gtNewOperNode(GT_EQ, TYP_INT, guardCheckVal, gtNewZeroConNode(TYP_INT));
+ GenTree* embNode = gtNewIconEmbHndNode(dbgHandle, pDbgHandle, GTF_ICON_TOKEN_HDL, info.compMethodHnd);
+ GenTree* guardCheckVal = gtNewOperNode(GT_IND, TYP_INT, embNode);
+ GenTree* guardCheckCond = gtNewOperNode(GT_EQ, TYP_INT, guardCheckVal, gtNewZeroConNode(TYP_INT));
guardCheckCond->gtFlags |= GTF_RELOP_QMARK;
// Create the callback which will yield the final answer
@@ -14465,6 +14494,10 @@ bool Compiler::fgOptimizeBranchToNext(BasicBlock* block, BasicBlock* bNext, Basi
LIR::Range& blockRange = LIR::AsRange(block);
GenTree* jmp = blockRange.LastNode();
assert(jmp->OperIsConditionalJump());
+ if (jmp->OperGet() == GT_JTRUE)
+ {
+ jmp->gtOp.gtOp1->gtFlags &= ~GTF_SET_FLAGS;
+ }
bool isClosed;
unsigned sideEffects;
@@ -21075,10 +21108,15 @@ void Compiler::fgDebugCheckFlags(GenTreePtr tree)
{
noway_assert(tree->gtOper != GT_STMT);
- genTreeOps oper = tree->OperGet();
- unsigned kind = tree->OperKind();
- unsigned treeFlags = tree->gtFlags & GTF_ALL_EFFECT;
- unsigned chkFlags = 0;
+ const genTreeOps oper = tree->OperGet();
+ const unsigned kind = tree->OperKind();
+ unsigned treeFlags = tree->gtFlags & GTF_ALL_EFFECT;
+ unsigned chkFlags = 0;
+
+ if (tree->OperMayThrow(this))
+ {
+ chkFlags |= GTF_EXCEPT;
+ }
/* Is this a leaf node? */
@@ -21215,7 +21253,7 @@ void Compiler::fgDebugCheckFlags(GenTreePtr tree)
/* For a GT_ASG(GT_IND(x), y) we are interested in the side effects of x */
GenTreePtr op1p;
- if ((kind & GTK_ASGOP) && (op1->gtOper == GT_IND))
+ if (GenTree::OperIsAssignment(oper) && (op1->gtOper == GT_IND))
{
op1p = op1->gtOp.gtOp1;
}
@@ -21241,11 +21279,6 @@ void Compiler::fgDebugCheckFlags(GenTreePtr tree)
chkFlags |= GTF_ASG;
}
- if (tree->OperMayThrow(this))
- {
- chkFlags |= GTF_EXCEPT;
- }
-
if (oper == GT_ADDR && (op1->OperIsLocal() || op1->gtOper == GT_CLS_VAR ||
(op1->gtOper == GT_IND && op1->gtOp.gtOp1->gtOper == GT_CLS_VAR_ADDR)))
{
@@ -21259,11 +21292,6 @@ void Compiler::fgDebugCheckFlags(GenTreePtr tree)
else
{
- if (tree->OperMayThrow(this))
- {
- chkFlags |= GTF_EXCEPT;
- }
-
switch (tree->OperGet())
{
case GT_CALL:
@@ -21537,7 +21565,6 @@ void Compiler::fgDebugCheckNodeLinks(BasicBlock* block, GenTree* node)
if (tree->OperIsUnary() && tree->gtOp.gtOp1)
{
- GenTreePtr lclVarTree;
expectedPrevTree = tree->gtOp.gtOp1;
}
else if (tree->OperIsBinary() && tree->gtOp.gtOp1)
@@ -21600,72 +21627,93 @@ void Compiler::fgDebugCheckLinks(bool morphTrees)
fgDebugCheckBlockLinks();
/* For each basic block check the bbTreeList links */
- for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
+ for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
{
- PROCESS_BLOCK_AGAIN:;
if (block->IsLIR())
{
LIR::AsRange(block).CheckLIR(this);
}
else
{
- for (GenTreeStmt* stmt = block->firstStmt(); stmt; stmt = stmt->gtNextStmt)
- {
- /* Verify that bbTreeList is threaded correctly */
- /* Note that for the GT_STMT list, the gtPrev list is circular. The gtNext list is not: gtNext of the
- * last GT_STMT in a block is nullptr. */
+ fgDebugCheckStmtsList(block, morphTrees);
+ }
+ }
- noway_assert(stmt->gtPrev);
+ fgDebugCheckNodesUniqueness();
+}
- if (stmt == block->bbTreeList)
- {
- noway_assert(stmt->gtPrev->gtNext == nullptr);
- }
- else
- {
- noway_assert(stmt->gtPrev->gtNext == stmt);
- }
+//------------------------------------------------------------------------------
+// fgDebugCheckStmtsList : Perfoms the set of checks:
+// - all statements in the block are linked correctly
+// - check statements flags
+// - check nodes gtNext and gtPrev values, if the node list is threaded
+//
+// Arguments:
+// block - the block to check statements in
+// morphTrees - try to morph trees in the checker
+//
+// Note:
+// Checking that all bits that are set in treeFlags are also set in chkFlags is currently disabled.
- if (stmt->gtNext)
- {
- noway_assert(stmt->gtNext->gtPrev == stmt);
- }
- else
- {
- noway_assert(block->lastStmt() == stmt);
- }
+void Compiler::fgDebugCheckStmtsList(BasicBlock* block, bool morphTrees)
+{
+ for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
+ {
+ /* Verify that bbTreeList is threaded correctly */
+ /* Note that for the GT_STMT list, the gtPrev list is circular. The gtNext list is not: gtNext of the
+ * last GT_STMT in a block is nullptr. */
- /* For each statement check that the exception flags are properly set */
+ noway_assert(stmt->gtPrev);
+
+ if (stmt == block->bbTreeList)
+ {
+ noway_assert(stmt->gtPrev->gtNext == nullptr);
+ }
+ else
+ {
+ noway_assert(stmt->gtPrev->gtNext == stmt);
+ }
- noway_assert(stmt->gtStmtExpr);
+ if (stmt->gtNext)
+ {
+ noway_assert(stmt->gtNext->gtPrev == stmt);
+ }
+ else
+ {
+ noway_assert(block->lastStmt() == stmt);
+ }
- if (verbose && 0)
- {
- gtDispTree(stmt->gtStmtExpr);
- }
+ /* For each statement check that the exception flags are properly set */
- fgDebugCheckFlags(stmt->gtStmtExpr);
+ noway_assert(stmt->gtStmtExpr);
- // Not only will this stress fgMorphBlockStmt(), but we also get all the checks
- // done by fgMorphTree()
+ if (verbose && 0)
+ {
+ gtDispTree(stmt->gtStmtExpr);
+ }
- if (morphTrees)
- {
- // If 'stmt' is removed from the block, restart
- if (fgMorphBlockStmt(block, stmt DEBUGARG("test morphing")))
- {
- goto PROCESS_BLOCK_AGAIN;
- }
- }
+ fgDebugCheckFlags(stmt->gtStmtExpr);
- /* For each GT_STMT node check that the nodes are threaded correcly - gtStmtList */
+ // Not only will this stress fgMorphBlockStmt(), but we also get all the checks
+ // done by fgMorphTree()
- if (fgStmtListThreaded)
- {
- fgDebugCheckNodeLinks(block, stmt);
- }
+ if (morphTrees)
+ {
+ // If 'stmt' is removed from the block, start a new check for the current block,
+ // break the current check.
+ if (fgMorphBlockStmt(block, stmt DEBUGARG("test morphing")))
+ {
+ fgDebugCheckStmtsList(block, morphTrees);
+ break;
}
}
+
+ /* For each GT_STMT node check that the nodes are threaded correcly - gtStmtList */
+
+ if (fgStmtListThreaded)
+ {
+ fgDebugCheckNodeLinks(block, stmt);
+ }
}
}
@@ -21674,7 +21722,7 @@ void Compiler::fgDebugCheckBlockLinks()
{
assert(fgFirstBB->bbPrev == nullptr);
- for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
+ for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
{
if (block->bbNext)
{
@@ -21726,6 +21774,76 @@ void Compiler::fgDebugCheckBlockLinks()
}
}
+// UniquenessCheckWalker keeps data that is neccesary to check
+// that each tree has it is own unique id and they do not repeat.
+class UniquenessCheckWalker
+{
+public:
+ UniquenessCheckWalker(Compiler* comp)
+ : comp(comp), nodesVecTraits(comp->compGenTreeID, comp), uniqueNodes(BitVecOps::MakeEmpty(&nodesVecTraits))
+ {
+ }
+
+ //------------------------------------------------------------------------
+ // fgMarkTreeId: Visit all subtrees in the tree and check gtTreeIDs.
+ //
+ // Arguments:
+ // pTree - Pointer to the tree to walk
+ // fgWalkPre - the UniquenessCheckWalker instance
+ //
+ static Compiler::fgWalkResult MarkTreeId(GenTree** pTree, Compiler::fgWalkData* fgWalkPre)
+ {
+ UniquenessCheckWalker* walker = static_cast<UniquenessCheckWalker*>(fgWalkPre->pCallbackData);
+ unsigned gtTreeID = (*pTree)->gtTreeID;
+ walker->CheckTreeId(gtTreeID);
+ return Compiler::WALK_CONTINUE;
+ }
+
+ //------------------------------------------------------------------------
+ // CheckTreeId: Check that this tree was not visit before and memorize it as visited.
+ //
+ // Arguments:
+ // gtTreeID - identificator of GenTree.
+ //
+ void CheckTreeId(unsigned gtTreeID)
+ {
+ assert(!BitVecOps::IsMember(&nodesVecTraits, uniqueNodes, gtTreeID));
+ BitVecOps::AddElemD(&nodesVecTraits, uniqueNodes, gtTreeID);
+ }
+
+private:
+ Compiler* comp;
+ BitVecTraits nodesVecTraits;
+ BitVec uniqueNodes;
+};
+
+//------------------------------------------------------------------------------
+// fgDebugCheckNodesUniqueness: Check that each tree in the method has its own unique gtTreeId.
+//
+void Compiler::fgDebugCheckNodesUniqueness()
+{
+ UniquenessCheckWalker walker(this);
+
+ for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext)
+ {
+ if (block->IsLIR())
+ {
+ for (GenTreePtr i : LIR::AsRange(block))
+ {
+ walker.CheckTreeId(i->gtTreeID);
+ }
+ }
+ else
+ {
+ for (GenTreeStmt* stmt = block->firstStmt(); stmt != nullptr; stmt = stmt->gtNextStmt)
+ {
+ GenTreePtr root = stmt->gtStmtExpr;
+ fgWalkTreePre(&root, UniquenessCheckWalker::MarkTreeId, &walker);
+ }
+ }
+ }
+}
+
/*****************************************************************************/
#endif // DEBUG
/*****************************************************************************/
@@ -21744,7 +21862,7 @@ void Compiler::fgDebugCheckBlockLinks()
//
// Likewise the depth limit is a policy consideration, and serves mostly
// as a safeguard to prevent runaway inlining of small methods.
-
+//
unsigned Compiler::fgCheckInlineDepthAndRecursion(InlineInfo* inlineInfo)
{
BYTE* candidateCode = inlineInfo->inlineCandidateInfo->methInfo.ILCode;
@@ -22124,7 +22242,7 @@ void Compiler::fgAttachStructInlineeToAsg(GenTreePtr tree, GenTreePtr child, COR
? fgAssignStructInlineeToVar(child, retClsHnd) // Assign to a variable if it is a call.
: child); // Just get the address, if not a call.
- tree->CopyFrom(gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false), this);
+ tree->ReplaceWith(gtNewCpObjNode(dstAddr, srcAddr, retClsHnd, false), this);
}
#endif // FEATURE_MULTIREG_RET
@@ -22198,12 +22316,12 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr
printf(" with ");
printTreeID(inlineCandidate);
printf("\n");
- // Dump out the old return expression placeholder it will be overwritten by the CopyFrom below
+ // Dump out the old return expression placeholder it will be overwritten by the ReplaceWith below
comp->gtDispTree(tree);
}
#endif // DEBUG
- tree->CopyFrom(inlineCandidate, comp);
+ tree->ReplaceWith(inlineCandidate, comp);
#ifdef DEBUG
if (comp->verbose)
@@ -22274,7 +22392,7 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr
else
{
// Just assign the inlinee to a variable to keep it simple.
- tree->CopyFrom(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
+ tree->ReplaceWith(comp->fgAssignStructInlineeToVar(tree, retClsHnd), comp);
}
}
}
@@ -22858,6 +22976,7 @@ _Done:
compLongUsed |= InlineeCompiler->compLongUsed;
compFloatingPointUsed |= InlineeCompiler->compFloatingPointUsed;
compLocallocUsed |= InlineeCompiler->compLocallocUsed;
+ compLocallocOptimized |= InlineeCompiler->compLocallocOptimized;
compQmarkUsed |= InlineeCompiler->compQmarkUsed;
compUnsafeCastUsed |= InlineeCompiler->compUnsafeCastUsed;
compNeedsGSSecurityCookie |= InlineeCompiler->compNeedsGSSecurityCookie;
@@ -22904,7 +23023,7 @@ _Done:
}
#endif // DEBUG
// Replace the call with the return expression
- iciCall->CopyFrom(pInlineInfo->retExpr, this);
+ iciCall->ReplaceWith(pInlineInfo->retExpr, this);
}
//
@@ -23024,7 +23143,7 @@ GenTreePtr Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo)
// Change the temp in-place to the actual argument.
// We currently do not support this for struct arguments, so it must not be a GT_OBJ.
assert(argNode->gtOper != GT_OBJ);
- argSingleUseNode->CopyFrom(argNode, this);
+ argSingleUseNode->ReplaceWith(argNode, this);
continue;
}
else
@@ -23463,8 +23582,10 @@ Compiler::fgWalkResult Compiler::fgChkThrowCB(GenTreePtr* pTree, fgWalkData* dat
case GT_MUL:
case GT_ADD:
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
case GT_ASG_SUB:
+#endif
case GT_CAST:
if (tree->gtOverflow())
{
diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
index 7b17eb0f24..6c6761e0e4 100644
--- a/src/jit/gentree.cpp
+++ b/src/jit/gentree.cpp
@@ -25,6 +25,7 @@ const unsigned short GenTree::gtOperKindTable[] = {
#include "gtlist.h"
};
+#ifdef LEGACY_BACKEND
/*****************************************************************************/
// static
genTreeOps GenTree::OpAsgToOper(genTreeOps op)
@@ -69,6 +70,7 @@ genTreeOps GenTree::OpAsgToOper(genTreeOps op)
unreached(); // Precondition implies we don't get here.
}
}
+#endif // LEGACY_BACKEND
/*****************************************************************************
*
@@ -429,6 +431,48 @@ bool GenTree::IsNodeProperlySized() const
}
#endif
+#if SMALL_TREE_NODES
+//------------------------------------------------------------------------
+// ReplaceWith: replace this with the src node. The source must be an isolated node
+// and cannot be used after the replacement.
+//
+// Arguments:
+// src - source tree, that replaces this.
+// comp - the compiler instance to transfer annotations for arrays.
+//
+void GenTree::ReplaceWith(GenTree* src, Compiler* comp)
+{
+ // The source may be big only if the target is also a big node
+ assert((gtDebugFlags & GTF_DEBUG_NODE_LARGE) || GenTree::s_gtNodeSizes[src->gtOper] == TREE_NODE_SZ_SMALL);
+
+ // The check is effective only if nodes have been already threaded.
+ assert((src->gtPrev == nullptr) && (src->gtNext == nullptr));
+
+ RecordOperBashing(OperGet(), src->OperGet()); // nop unless NODEBASH_STATS is enabled
+
+ GenTreePtr prev = gtPrev;
+ GenTreePtr next = gtNext;
+ // The VTable pointer is copied intentionally here
+ memcpy((void*)this, (void*)src, src->GetNodeSize());
+ this->gtPrev = prev;
+ this->gtNext = next;
+
+#ifdef DEBUG
+ gtSeqNum = 0;
+#endif
+ // Transfer any annotations.
+ if (src->OperGet() == GT_IND && src->gtFlags & GTF_IND_ARR_INDEX)
+ {
+ ArrayInfo arrInfo;
+ bool b = comp->GetArrayInfoMap()->Lookup(src, &arrInfo);
+ assert(b);
+ comp->GetArrayInfoMap()->Set(this, arrInfo);
+ }
+ DEBUG_DESTROY_NODE(src);
+}
+
+#endif
+
/*****************************************************************************
*
* When 'NODEBASH_STATS' is enabled in "jit.h" we record all instances of
@@ -1089,6 +1133,13 @@ bool GenTreeCall::AreArgsComplete() const
return false;
}
+#if !defined(FEATURE_PUT_STRUCT_ARG_STK) && !defined(LEGACY_BACKEND)
+unsigned GenTreePutArgStk::getArgSize()
+{
+ return genTypeSize(genActualType(gtOp1->gtType));
+}
+#endif // !defined(FEATURE_PUT_STRUCT_ARG_STK) && !defined(LEGACY_BACKEND)
+
/*****************************************************************************
*
* Returns non-zero if the two trees are identical.
@@ -1319,6 +1370,17 @@ AGAIN:
break;
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+ if ((op1->AsHWIntrinsic()->gtHWIntrinsicId != op2->AsHWIntrinsic()->gtHWIntrinsicId) ||
+ (op1->AsHWIntrinsic()->gtSIMDBaseType != op2->AsHWIntrinsic()->gtSIMDBaseType) ||
+ (op1->AsHWIntrinsic()->gtSIMDSize != op2->AsHWIntrinsic()->gtSIMDSize))
+ {
+ return false;
+ }
+ break;
+#endif
+
// For the ones below no extra argument matters for comparison.
case GT_QMARK:
break;
@@ -1562,7 +1624,7 @@ AGAIN:
return false;
}
- if (kind & GTK_ASGOP)
+ if (GenTree::OperIsAssignment(oper))
{
// 'tree' is the gtOp1 of an assignment node. So we can handle
// the case where defOnly is either true or false.
@@ -1834,6 +1896,7 @@ AGAIN:
switch (oper)
{
+ UINT64 bits;
case GT_LCL_VAR:
add = tree->gtLclVar.gtLclNum;
break;
@@ -1843,16 +1906,26 @@ AGAIN:
break;
case GT_CNS_INT:
- add = (int)tree->gtIntCon.gtIconVal;
+ add = tree->gtIntCon.gtIconVal;
break;
case GT_CNS_LNG:
- add = (int)tree->gtLngCon.gtLconVal;
+ bits = (UINT64)tree->gtLngCon.gtLconVal;
+#ifdef _TARGET_64BIT_
+ add = bits;
+#else // 32-bit target
+ add = genTreeHashAdd(uhi32(bits), ulo32(bits));
+#endif
break;
case GT_CNS_DBL:
- add = (int)tree->gtDblCon.gtDconVal;
+ bits = *(UINT64*)(&tree->gtDblCon.gtDconVal);
+#ifdef _TARGET_64BIT_
+ add = bits;
+#else // 32-bit target
+ add = genTreeHashAdd(uhi32(bits), ulo32(bits));
+#endif
break;
case GT_CNS_STR:
- add = (int)tree->gtStrCon.gtSconCPX;
+ add = tree->gtStrCon.gtSconCPX;
break;
case GT_JMP:
@@ -1864,8 +1937,17 @@ AGAIN:
break;
}
- // narrowing cast, but for hashing.
- hash = genTreeHashAdd(hash, (unsigned)add);
+ // clang-format off
+ // narrow 'add' into a 32-bit 'val'
+ unsigned val;
+#ifdef _TARGET_64BIT_
+ val = genTreeHashAdd(uhi32(add), ulo32(add));
+#else // 32-bit target
+ val = add;
+#endif
+ // clang-format on
+
+ hash = genTreeHashAdd(hash, val);
goto DONE;
}
@@ -1901,6 +1983,12 @@ AGAIN:
reinterpret_cast<uintptr_t>(tree->gtAllocObj.gtAllocObjClsHnd)));
hash = genTreeHashAdd(hash, tree->gtAllocObj.gtNewHelper);
break;
+ case GT_RUNTIMELOOKUP:
+ hash =
+ genTreeHashAdd(hash,
+ static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtRuntimeLookup.gtHnd)));
+ break;
+
case GT_OBJ:
hash =
genTreeHashAdd(hash, static_cast<unsigned>(reinterpret_cast<uintptr_t>(tree->gtObj.gtClass)));
@@ -1967,6 +2055,13 @@ AGAIN:
break;
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+ hash += tree->gtHWIntrinsic.gtHWIntrinsicId;
+ hash += tree->gtHWIntrinsic.gtSIMDBaseType;
+ break;
+#endif // FEATURE_HW_INTRINSICS
+
default:
assert(!"unexpected binary ExOp operator");
}
@@ -3011,13 +3106,12 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
/* Is this a FP value? */
- bool isflt = varTypeIsFloating(tree->TypeGet());
- unsigned FPlvlSave;
+ bool isflt = varTypeIsFloating(tree->TypeGet());
/* Figure out what kind of a node we have */
- genTreeOps oper = tree->OperGet();
- unsigned kind = tree->OperKind();
+ const genTreeOps oper = tree->OperGet();
+ const unsigned kind = tree->OperKind();
/* Assume no fixed registers will be trashed */
@@ -3026,8 +3120,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
int costEx;
int costSz;
- bool bRngChk;
-
#ifdef DEBUG
costEx = -1;
costSz = -1;
@@ -3039,7 +3131,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
{
switch (oper)
{
- bool iconNeedsReloc;
+ GenTreeIntConCommon* con;
#ifdef _TARGET_ARM_
case GT_CNS_LNG:
@@ -3059,9 +3151,9 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
// applied to it.
// Any constant that requires a reloc must use the movw/movt sequence
//
- iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
+ con = tree->AsIntConCommon();
- if (iconNeedsReloc || !codeGen->validImmForInstr(INS_mov, tree->gtIntCon.gtIconVal))
+ if (con->ImmedValNeedsReloc(this) || !codeGen->validImmForInstr(INS_mov, tree->gtIntCon.gtIconVal))
{
// Uses movw/movt
costSz = 7;
@@ -3094,20 +3186,21 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
goto COMMON_CNS;
case GT_CNS_INT:
-
+ {
// If the constant is a handle then it will need to have a relocation
// applied to it.
- // Any constant that requires a reloc must use the movw/movt sequence
//
- iconNeedsReloc = opts.compReloc && tree->IsIconHandle() && !tree->IsIconHandle(GTF_ICON_FIELD_HDL);
+ con = tree->AsIntConCommon();
+
+ bool iconNeedsReloc = con->ImmedValNeedsReloc(this);
- if (!iconNeedsReloc && (((signed char)tree->gtIntCon.gtIconVal) == tree->gtIntCon.gtIconVal))
+ if (!iconNeedsReloc && con->FitsInI8())
{
costSz = 1;
costEx = 1;
}
#if defined(_TARGET_AMD64_)
- else if (iconNeedsReloc || ((tree->gtIntCon.gtIconVal & 0xFFFFFFFF00000000LL) != 0))
+ else if (iconNeedsReloc || !con->FitsInI32())
{
costSz = 10;
costEx = 3;
@@ -3119,6 +3212,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
costEx = 1;
}
goto COMMON_CNS;
+ }
#elif defined(_TARGET_ARM64_)
case GT_CNS_LNG:
@@ -3864,7 +3958,6 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
(op2->gtOp.gtOp1->gtOper == GT_MUL &&
op2->gtOp.gtOp1->gtOp.gtOp1->gtOper == GT_NOP))
{
- // assert(bRngChk);
op2->gtFlags |= GTF_ADDRMODE_NO_CSE;
if (op2->gtOp.gtOp1->gtOper == GT_MUL)
{
@@ -4017,9 +4110,10 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
case GT_ADD:
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
case GT_ASG_SUB:
-
+#endif
if (isflt)
{
/* FP instructions are a bit more expensive */
@@ -4084,7 +4178,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
/* Assignments need a bit of special handling */
- if (kind & GTK_ASGOP)
+ if (GenTree::OperIsAssignment(oper))
{
/* Process the target */
@@ -4168,7 +4262,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
#endif // FEATURE_STACK_FP_X87
bool bReverseInAssignment = false;
- if (kind & GTK_ASGOP)
+ if (GenTree::OperIsAssignment(oper))
{
GenTreePtr op1Val = op1;
@@ -4267,10 +4361,11 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
case GT_RSZ:
case GT_ROL:
case GT_ROR:
+#ifdef LEGACY_BACKEND
case GT_ASG_LSH:
case GT_ASG_RSH:
case GT_ASG_RSZ:
-
+#endif
/* Variable sized shifts are more expensive and use REG_SHIFT */
if (!op2->IsCnsIntOrI())
@@ -4528,7 +4623,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
if (tree->gtCall.gtCallArgs)
{
#if FEATURE_STACK_FP_X87
- FPlvlSave = codeGen->genGetFPstkLevel();
+ unsigned FPlvlSave = codeGen->genGetFPstkLevel();
#endif // FEATURE_STACK_FP_X87
const bool isListCallArgs = true;
const bool callArgsInRegs = false;
@@ -4552,7 +4647,7 @@ unsigned Compiler::gtSetEvalOrder(GenTree* tree)
if (tree->gtCall.gtCallLateArgs)
{
#if FEATURE_STACK_FP_X87
- FPlvlSave = codeGen->genGetFPstkLevel();
+ unsigned FPlvlSave = codeGen->genGetFPstkLevel();
#endif // FEATURE_STACK_FP_X87
const bool isListCallArgs = true;
const bool callArgsInRegs = true;
@@ -5441,6 +5536,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use)
case GT_BLK:
case GT_BOX:
case GT_ALLOCOBJ:
+ case GT_RUNTIMELOOKUP:
case GT_INIT_VAL:
case GT_JTRUE:
case GT_SWITCH:
@@ -5773,7 +5869,7 @@ GenTreePtr GenTree::gtGetParent(GenTreePtr** parentChildPtrPtr) const
bool GenTree::OperRequiresAsgFlag()
{
- return ((OperKind() & GTK_ASGOP) || (gtOper == GT_XADD) || (gtOper == GT_XCHG) || (gtOper == GT_LOCKADD) ||
+ return (OperIsAssignment() || (gtOper == GT_XADD) || (gtOper == GT_XCHG) || (gtOper == GT_LOCKADD) ||
(gtOper == GT_CMPXCHG) || (gtOper == GT_MEMORYBARRIER));
}
@@ -5850,7 +5946,6 @@ bool GenTree::OperMayThrow(Compiler* comp)
case GT_ARR_ELEM:
case GT_ARR_INDEX:
case GT_ARR_OFFSET:
- case GT_CATCH_ARG:
case GT_LCLHEAP:
case GT_CKFINITE:
#ifdef FEATURE_SIMD
@@ -6049,6 +6144,50 @@ unsigned Compiler::gtTokenToIconFlags(unsigned token)
return flags;
}
+//-----------------------------------------------------------------------------------------
+// gtNewIndOfIconHandleNode: Creates an indirection GenTree node of a constant handle
+//
+// Arguments:
+// indType - The type returned by the indirection node
+// addr - The constant address to read from
+// iconFlags - The GTF_ICON flag value that specifies the kind of handle that we have
+// isInvariant - The indNode should also be marked as invariant
+//
+// Return Value:
+// Returns a GT_IND node representing value at the address provided by 'value'
+//
+// Notes:
+// The GT_IND node is marked as non-faulting
+// If the indType is GT_REF we also mark the indNode as GTF_GLOB_REF
+//
+
+GenTreePtr Compiler::gtNewIndOfIconHandleNode(var_types indType, size_t addr, unsigned iconFlags, bool isInvariant)
+{
+ GenTreePtr addrNode = gtNewIconHandleNode(addr, iconFlags);
+ GenTreePtr indNode = gtNewOperNode(GT_IND, indType, addrNode);
+
+ // This indirection won't cause an exception.
+ //
+ indNode->gtFlags |= GTF_IND_NONFAULTING;
+
+ // String Literal handles are indirections that return a TYP_REF.
+ // They are pointers into the GC heap and they are not invariant
+ // as the address is a reportable GC-root and as such it can be
+ // modified during a GC collection
+ //
+ if (indType == TYP_REF)
+ {
+ // This indirection points into the gloabal heap
+ indNode->gtFlags |= GTF_GLOB_REF;
+ }
+ if (isInvariant)
+ {
+ // This indirection also is invariant.
+ indNode->gtFlags |= GTF_IND_INVARIANT;
+ }
+ return indNode;
+}
+
/*****************************************************************************
*
* Allocates a integer constant entry that represents a HANDLE to something.
@@ -6057,26 +6196,48 @@ unsigned Compiler::gtTokenToIconFlags(unsigned token)
* If the handle needs to be accessed via an indirection, pValue points to it.
*/
-GenTreePtr Compiler::gtNewIconEmbHndNode(
- void* value, void* pValue, unsigned flags, unsigned handle1, void* handle2, void* compileTimeHandle)
+GenTreePtr Compiler::gtNewIconEmbHndNode(void* value, void* pValue, unsigned iconFlags, void* compileTimeHandle)
{
- GenTreePtr node;
-
- assert((!value) != (!pValue));
+ GenTreePtr iconNode;
+ GenTreePtr handleNode;
- if (value)
+ if (value != nullptr)
{
- node = gtNewIconHandleNode((size_t)value, flags, /*fieldSeq*/ FieldSeqStore::NotAField(), handle1, handle2);
- node->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
+ // When 'value' is non-null, pValue is required to be null
+ assert(pValue == nullptr);
+
+ // use 'value' to construct an integer constant node
+ iconNode = gtNewIconHandleNode((size_t)value, iconFlags);
+
+ // 'value' is the handle
+ handleNode = iconNode;
}
else
{
- node = gtNewIconHandleNode((size_t)pValue, flags, /*fieldSeq*/ FieldSeqStore::NotAField(), handle1, handle2);
- node->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
- node = gtNewOperNode(GT_IND, TYP_I_IMPL, node);
+ // When 'value' is null, pValue is required to be non-null
+ assert(pValue != nullptr);
+
+ // use 'pValue' to construct an integer constant node
+ iconNode = gtNewIconHandleNode((size_t)pValue, iconFlags);
+
+ // 'pValue' is an address of a location that contains the handle
+
+ // construct the indirection of 'pValue'
+ handleNode = gtNewOperNode(GT_IND, TYP_I_IMPL, iconNode);
+
+ // This indirection won't cause an exception.
+ handleNode->gtFlags |= GTF_IND_NONFAULTING;
+#if 0
+ // It should also be invariant, but marking it as such leads to bad diffs.
+
+ // This indirection also is invariant.
+ handleNode->gtFlags |= GTF_IND_INVARIANT;
+#endif
}
- return node;
+ iconNode->gtIntCon.gtCompileTimeHandle = (size_t)compileTimeHandle;
+
+ return handleNode;
}
/*****************************************************************************/
@@ -6086,30 +6247,31 @@ GenTreePtr Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue)
switch (iat)
{
- case IAT_VALUE: // The info value is directly available
- tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL);
+ case IAT_VALUE: // constructStringLiteral in CoreRT case can return IAT_VALUE
+ tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr);
tree->gtType = TYP_REF;
tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding
break;
- case IAT_PVALUE: // The value needs to be accessed via an indirection
- tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_STR_HDL);
- // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
- tree = gtNewOperNode(GT_IND, TYP_REF, tree);
- tree->gtFlags |= GTF_GLOB_REF;
+ case IAT_PVALUE: // The value needs to be accessed via an indirection
+ // Create an indirection
+ tree = gtNewIndOfIconHandleNode(TYP_REF, (size_t)pValue, GTF_ICON_STR_HDL, false);
break;
case IAT_PPVALUE: // The value needs to be accessed via a double indirection
- tree = gtNewIconHandleNode((size_t)pValue, GTF_ICON_PSTR_HDL);
- tree = gtNewOperNode(GT_IND, TYP_I_IMPL, tree);
- tree->gtFlags |= GTF_IND_INVARIANT;
- // An indirection of a string handle can't cause an exception so don't set GTF_EXCEPT
+ // Create the first indirection
+ tree = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pValue, GTF_ICON_PSTR_HDL, true);
+
+ // Create the second indirection
tree = gtNewOperNode(GT_IND, TYP_REF, tree);
+ // This indirection won't cause an exception.
+ tree->gtFlags |= GTF_IND_NONFAULTING;
+ // This indirection points into the gloabal heap (it is String Object)
tree->gtFlags |= GTF_GLOB_REF;
break;
default:
- assert(!"Unexpected InfoAccessType");
+ noway_assert(!"Unexpected InfoAccessType");
}
return tree;
@@ -7084,8 +7246,8 @@ GenTreePtr Compiler::gtNewPutArgReg(var_types type, GenTreePtr arg, regNumber ar
assert(arg != nullptr);
GenTreePtr node = nullptr;
-#if !defined(LEGACY_BACKEND) && defined(ARM_SOFTFP)
- // A PUTARG_REG could be a MultiRegOp on armel since we could move a double register to two int registers.
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+ // A PUTARG_REG could be a MultiRegOp on arm since we could move a double register to two int registers.
node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_PUTARG_REG, type, arg, nullptr);
#else
node = gtNewOperNode(GT_PUTARG_REG, type, arg);
@@ -7114,9 +7276,9 @@ GenTreePtr Compiler::gtNewBitCastNode(var_types type, GenTreePtr arg)
assert(arg != nullptr);
GenTreePtr node = nullptr;
-#if !defined(LEGACY_BACKEND) && defined(ARM_SOFTFP)
- // A BITCAST could be a MultiRegOp on armel since we could move a double register to two int registers.
- node = new (this, GT_PUTARG_REG) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+ // A BITCAST could be a MultiRegOp on arm since we could move a double register to two int registers.
+ node = new (this, GT_BITCAST) GenTreeMultiRegOp(GT_BITCAST, type, arg, nullptr);
#else
node = gtNewOperNode(GT_BITCAST, type, arg);
#endif
@@ -7147,8 +7309,7 @@ GenTreePtr Compiler::gtClone(GenTree* tree, bool complexOK)
#if defined(LATE_DISASM)
if (tree->IsIconHandle())
{
- copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq,
- tree->gtIntCon.gtIconHdl.gtIconHdl1, tree->gtIntCon.gtIconHdl.gtIconHdl2);
+ copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
copy->gtType = tree->gtType;
}
@@ -7312,8 +7473,7 @@ GenTreePtr Compiler::gtCloneExpr(
#if defined(LATE_DISASM)
if (tree->IsIconHandle())
{
- copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq,
- tree->gtIntCon.gtIconFld.gtIconCPX, tree->gtIntCon.gtIconFld.gtIconCls);
+ copy = gtNewIconHandleNode(tree->gtIntCon.gtIconVal, tree->gtFlags, tree->gtIntCon.gtFieldSeq);
copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
copy->gtType = tree->gtType;
}
@@ -7383,7 +7543,10 @@ GenTreePtr Compiler::gtCloneExpr(
goto DONE;
case GT_RET_EXPR:
- copy = gtNewInlineCandidateReturnExpr(tree->gtRetExpr.gtInlineCandidate, tree->gtType);
+ // GT_RET_EXPR is unique node, that contains a link to a gtInlineCandidate node,
+ // that is part of another statement. We cannot clone both here and cannot
+ // create another GT_RET_EXPR that points to the same gtInlineCandidate.
+ NO_WAY("Cloning of GT_RET_EXPR node not supported");
goto DONE;
case GT_MEMORYBARRIER:
@@ -7519,6 +7682,15 @@ GenTreePtr Compiler::gtCloneExpr(
}
break;
+ case GT_RUNTIMELOOKUP:
+ {
+ GenTreeRuntimeLookup* asRuntimeLookup = tree->AsRuntimeLookup();
+
+ copy = new (this, GT_RUNTIMELOOKUP)
+ GenTreeRuntimeLookup(asRuntimeLookup->gtHnd, asRuntimeLookup->gtHndType, asRuntimeLookup->gtOp1);
+ }
+ break;
+
case GT_ARR_LENGTH:
copy = gtNewArrLen(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtArrLen.ArrLenOffset());
break;
@@ -7598,6 +7770,18 @@ GenTreePtr Compiler::gtCloneExpr(
break;
#endif
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+ {
+ GenTreeHWIntrinsic* hwintrinsicOp = tree->AsHWIntrinsic();
+ copy = new (this, GT_HWIntrinsic)
+ GenTreeHWIntrinsic(hwintrinsicOp->TypeGet(), hwintrinsicOp->gtGetOp1(),
+ hwintrinsicOp->gtGetOp2IfPresent(), hwintrinsicOp->gtHWIntrinsicId,
+ hwintrinsicOp->gtSIMDBaseType, hwintrinsicOp->gtSIMDSize);
+ }
+ break;
+#endif
+
default:
assert(!GenTree::IsExOp(tree->OperKind()) && tree->OperIsSimple());
// We're in the SimpleOp case, so it's always unary or binary.
@@ -8838,6 +9022,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node)
case GT_BLK:
case GT_BOX:
case GT_ALLOCOBJ:
+ case GT_RUNTIMELOOKUP:
case GT_INIT_VAL:
case GT_JTRUE:
case GT_SWITCH:
@@ -9372,6 +9557,8 @@ bool GenTree::Precedes(GenTree* other)
/* static */ int GenTree::gtDispFlags(unsigned flags, unsigned debugFlags)
{
+ int charsDisplayed = 11; // 11 is the "baseline" number of flag characters displayed
+
#ifdef LEGACY_BACKEND
printf("%c", (flags & GTF_ASG) ? 'A' : '-');
#else // !LEGACY_BACKEND
@@ -9389,10 +9576,12 @@ bool GenTree::Precedes(GenTree* other)
printf("%c", (flags & GTF_UNSIGNED) ? 'U' : (flags & GTF_BOOLEAN) ? 'B' : '-');
#if FEATURE_SET_FLAGS
printf("%c", (flags & GTF_SET_FLAGS) ? 'S' : '-');
+ ++charsDisplayed;
#endif
printf("%c", (flags & GTF_LATE_ARG) ? 'L' : '-');
printf("%c", (flags & GTF_SPILLED) ? 'z' : (flags & GTF_SPILL) ? 'Z' : '-');
- return 12; // displayed 12 flag characters
+
+ return charsDisplayed;
}
/*****************************************************************************/
@@ -9749,6 +9938,12 @@ void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z
--msgLength;
break;
}
+ if (tree->gtFlags & GTF_IND_NONFAULTING)
+ {
+ printf("x");
+ --msgLength;
+ break;
+ }
}
__fallthrough;
@@ -9902,6 +10097,15 @@ void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z
printf((tree->gtFlags & GTF_JCMP_EQ) ? "EQ" : "NE");
goto DASH;
+ case GT_FIELD_LIST:
+ if (tree->gtFlags & GTF_FIELD_LIST_HEAD)
+ {
+ printf("H");
+ --msgLength;
+ break;
+ }
+ goto DASH;
+
default:
DASH:
printf("-");
@@ -10074,6 +10278,31 @@ void Compiler::gtDispNode(GenTreePtr tree, IndentStack* indentStack, __in __in_z
{
printf(" => [clsHnd=%08X]", dspPtr(tree->gtArgPlace.gtArgPlaceClsHnd));
}
+
+ if (tree->gtOper == GT_RUNTIMELOOKUP)
+ {
+#ifdef _TARGET_64BIT_
+ printf(" 0x%llx", dspPtr(tree->gtRuntimeLookup.gtHnd));
+#else
+ printf(" 0x%x", dspPtr(tree->gtRuntimeLookup.gtHnd));
+#endif
+
+ switch (tree->gtRuntimeLookup.gtHndType)
+ {
+ case CORINFO_HANDLETYPE_CLASS:
+ printf(" class");
+ break;
+ case CORINFO_HANDLETYPE_METHOD:
+ printf(" method");
+ break;
+ case CORINFO_HANDLETYPE_FIELD:
+ printf(" field");
+ break;
+ default:
+ printf(" unknown");
+ break;
+ }
+ }
}
// for tracking down problems in reguse prediction or liveness tracking
@@ -10150,7 +10379,7 @@ void Compiler::gtDispRegVal(GenTree* tree)
#endif
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
- if (tree->OperIsMultiRegOp() && tree->AsMultiRegOp()->gtOtherReg != REG_NA)
+ if (tree->OperIsMultiRegOp() && (tree->AsMultiRegOp()->gtOtherReg != REG_NA))
{
printf(",%s", compRegVarName(tree->AsMultiRegOp()->gtOtherReg));
}
@@ -10475,7 +10704,7 @@ void Compiler::gtDispConst(GenTree* tree)
printf(" ftn");
break;
case GTF_ICON_CIDMID_HDL:
- printf(" cid");
+ printf(" cid/mid");
break;
case GTF_ICON_BBC_PTR:
printf(" bbc");
@@ -10849,7 +11078,6 @@ void Compiler::gtDispChild(GenTreePtr child,
__in_opt const char* msg, /* = nullptr */
bool topOnly) /* = false */
{
- IndentInfo info;
indentStack->Push(arcType);
gtDispTree(child, indentStack, msg, topOnly);
indentStack->Pop();
@@ -10863,6 +11091,10 @@ extern const char* const simdIntrinsicNames[] = {
};
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic);
+#endif // FEATURE_HW_INTRINSICS
+
/*****************************************************************************/
void Compiler::gtDispTree(GenTreePtr tree,
@@ -10936,8 +11168,12 @@ void Compiler::gtDispTree(GenTreePtr tree,
indentStack->Push(IIEmbedded);
lowerArc = IIEmbedded;
break;
+ case IINone:
+ indentStack->Push(IINone);
+ lowerArc = IINone;
+ break;
default:
- // Should never get here; just use IINone.
+ unreached();
break;
}
}
@@ -11066,25 +11302,28 @@ void Compiler::gtDispTree(GenTreePtr tree,
tree->AsFieldList()->gtFieldOffset);
}
#if FEATURE_PUT_STRUCT_ARG_STK
- else if ((tree->OperGet() == GT_PUTARG_STK) &&
- (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid))
+ else if (tree->OperGet() == GT_PUTARG_STK)
{
- switch (tree->AsPutArgStk()->gtPutArgStkKind)
+ printf(" (%d slots)", tree->AsPutArgStk()->gtNumSlots);
+ if (tree->AsPutArgStk()->gtPutArgStkKind != GenTreePutArgStk::Kind::Invalid)
{
- case GenTreePutArgStk::Kind::RepInstr:
- printf(" (RepInstr)");
- break;
- case GenTreePutArgStk::Kind::Unroll:
- printf(" (Unroll)");
- break;
- case GenTreePutArgStk::Kind::Push:
- printf(" (Push)");
- break;
- case GenTreePutArgStk::Kind::PushAllSlots:
- printf(" (PushAllSlots)");
- break;
- default:
- unreached();
+ switch (tree->AsPutArgStk()->gtPutArgStkKind)
+ {
+ case GenTreePutArgStk::Kind::RepInstr:
+ printf(" (RepInstr)");
+ break;
+ case GenTreePutArgStk::Kind::Unroll:
+ printf(" (Unroll)");
+ break;
+ case GenTreePutArgStk::Kind::Push:
+ printf(" (Push)");
+ break;
+ case GenTreePutArgStk::Kind::PushAllSlots:
+ printf(" (PushAllSlots)");
+ break;
+ default:
+ unreached();
+ }
}
}
#endif // FEATURE_PUT_STRUCT_ARG_STK
@@ -11178,6 +11417,16 @@ void Compiler::gtDispTree(GenTreePtr tree,
}
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ if (tree->gtOper == GT_HWIntrinsic)
+ {
+ printf(" %s %s",
+ tree->gtHWIntrinsic.gtSIMDBaseType == TYP_UNKNOWN ? ""
+ : varTypeName(tree->gtHWIntrinsic.gtSIMDBaseType),
+ getHWIntrinsicName(tree->gtHWIntrinsic.gtHWIntrinsicId));
+ }
+#endif // FEATURE_HW_INTRINSICS
+
gtDispRegVal(tree);
gtDispVN(tree);
printf("\n");
@@ -11399,6 +11648,14 @@ void Compiler::gtDispTree(GenTreePtr tree,
case GT_STORE_DYN_BLK:
case GT_DYN_BLK:
+ if (tree->OperIsCopyBlkOp())
+ {
+ printf(" (copy)");
+ }
+ else if (tree->OperIsInitBlkOp())
+ {
+ printf(" (init)");
+ }
gtDispVN(tree);
printf("\n");
if (!topOnly)
@@ -11410,14 +11667,6 @@ void Compiler::gtDispTree(GenTreePtr tree,
gtDispChild(tree->gtDynBlk.Addr(), indentStack, IIArc, nullptr, topOnly);
gtDispChild(tree->gtDynBlk.gtDynamicSize, indentStack, IIArcBottom, nullptr, topOnly);
}
- if (tree->OperIsCopyBlkOp())
- {
- printf(" (copy)");
- }
- else if (tree->OperIsInitBlkOp())
- {
- printf(" (init)");
- }
break;
default:
@@ -12091,6 +12340,115 @@ GenTreePtr Compiler::gtFoldExpr(GenTreePtr tree)
return tree;
}
+//------------------------------------------------------------------------
+// gtFoldExprCall: see if a call is foldable
+//
+// Arguments:
+// call - call to examine
+//
+// Returns:
+// The original call if no folding happened.
+// An alternative tree if folding happens.
+//
+// Notes:
+// Checks for calls to Type.op_Equality, Type.op_Inequality, and
+// Enum.HasFlag, and if the call is to one of these,
+// attempts to optimize.
+
+GenTree* Compiler::gtFoldExprCall(GenTreeCall* call)
+{
+ // Can only fold calls to special intrinsics.
+ if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) == 0)
+ {
+ return call;
+ }
+
+ // Defer folding if not optimizing.
+ if (opts.compDbgCode || opts.MinOpts())
+ {
+ return call;
+ }
+
+ // Fetch id of the intrinsic.
+ const CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
+
+ switch (methodID)
+ {
+ case CORINFO_INTRINSIC_TypeEQ:
+ case CORINFO_INTRINSIC_TypeNEQ:
+ {
+ noway_assert(call->TypeGet() == TYP_INT);
+ GenTree* op1 = call->gtCallArgs->gtOp.gtOp1;
+ GenTree* op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
+
+ // If either operand is known to be a RuntimeType, this can be folded
+ GenTree* result = gtFoldTypeEqualityCall(methodID, op1, op2);
+ if (result != nullptr)
+ {
+ return result;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ // Check for a new-style jit intrinsic.
+ const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
+
+ if (ni == NI_System_Enum_HasFlag)
+ {
+ GenTree* thisOp = call->gtCallObjp;
+ GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
+ GenTree* result = gtOptimizeEnumHasFlag(thisOp, flagOp);
+
+ if (result != nullptr)
+ {
+ return result;
+ }
+ }
+
+ return call;
+}
+
+//------------------------------------------------------------------------
+// gtFoldTypeEqualityCall: see if a (potential) type equality call is foldable
+//
+// Arguments:
+// methodID -- type equality intrinsic ID
+// op1 -- first argument to call
+// op2 -- second argument to call
+//
+// Returns:
+// nulltpr if no folding happened.
+// An alternative tree if folding happens.
+//
+// Notes:
+// If either operand is known to be a a RuntimeType, then the type
+// equality methods will simply check object identity and so we can
+// fold the call into a simple compare of the call's operands.
+
+GenTree* Compiler::gtFoldTypeEqualityCall(CorInfoIntrinsics methodID, GenTree* op1, GenTree* op2)
+{
+ // The method must be be a type equality intrinsic
+ assert(methodID == CORINFO_INTRINSIC_TypeEQ || methodID == CORINFO_INTRINSIC_TypeNEQ);
+
+ if ((gtGetTypeProducerKind(op1) == TPK_Unknown) && (gtGetTypeProducerKind(op2) == TPK_Unknown))
+ {
+ return nullptr;
+ }
+
+ const genTreeOps simpleOp = (methodID == CORINFO_INTRINSIC_TypeEQ) ? GT_EQ : GT_NE;
+
+ JITDUMP("\nFolding call to Type:op_%s to a simple compare via %s\n",
+ methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
+
+ GenTree* compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
+
+ return compare;
+}
+
/*****************************************************************************
*
* Some comparisons can be folded:
@@ -12163,6 +12521,288 @@ GenTreePtr Compiler::gtFoldExprCompare(GenTreePtr tree)
return cons;
}
+//------------------------------------------------------------------------
+// gtFoldTypeCompare: see if a type comparison can be further simplified
+//
+// Arguments:
+// tree -- tree possibly comparing types
+//
+// Returns:
+// An alternative tree if folding happens.
+// Original tree otherwise.
+//
+// Notes:
+// Checks for
+// typeof(...) == obj.GetType()
+// typeof(...) == typeof(...)
+//
+// And potentially optimizes away the need to obtain actual
+// RuntimeType objects to do the comparison.
+
+GenTree* Compiler::gtFoldTypeCompare(GenTree* tree)
+{
+ // Only handle EQ and NE
+ // (maybe relop vs null someday)
+ const genTreeOps oper = tree->OperGet();
+ if ((oper != GT_EQ) && (oper != GT_NE))
+ {
+ return tree;
+ }
+
+ // Screen for the right kinds of operands
+ GenTree* const op1 = tree->gtOp.gtOp1;
+ const TypeProducerKind op1Kind = gtGetTypeProducerKind(op1);
+ if (op1Kind == TPK_Unknown)
+ {
+ return tree;
+ }
+
+ GenTree* const op2 = tree->gtOp.gtOp2;
+ const TypeProducerKind op2Kind = gtGetTypeProducerKind(op2);
+ if (op2Kind == TPK_Unknown)
+ {
+ return tree;
+ }
+
+ // We must have a handle on one side or the other here to optimize,
+ // otherwise we can't be sure that optimizing is sound.
+ const bool op1IsFromHandle = (op1Kind == TPK_Handle);
+ const bool op2IsFromHandle = (op2Kind == TPK_Handle);
+
+ if (!(op1IsFromHandle || op2IsFromHandle))
+ {
+ return tree;
+ }
+
+ // If both types are created via handles, we can simply compare
+ // handles (or the indirection cells for handles) instead of the
+ // types that they'd create.
+ if (op1IsFromHandle && op2IsFromHandle)
+ {
+ JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
+ GenTree* op1ClassFromHandle = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
+ GenTree* op2ClassFromHandle = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
+ GenTree* op1TunneledHandle = nullptr;
+ GenTree* op2TunneledHandle = nullptr;
+ CORINFO_CLASS_HANDLE cls1Hnd = nullptr;
+ CORINFO_CLASS_HANDLE cls2Hnd = nullptr;
+ unsigned runtimeLookupCount = 0;
+
+ // Try and find class handle for op1
+ if ((op1ClassFromHandle->gtOper == GT_CNS_INT) && (op1ClassFromHandle->gtType == TYP_I_IMPL))
+ {
+ assert(op1ClassFromHandle->IsIconHandle(GTF_ICON_CLASS_HDL));
+ cls1Hnd = (CORINFO_CLASS_HANDLE)op1ClassFromHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ else if (op1ClassFromHandle->OperGet() == GT_RUNTIMELOOKUP)
+ {
+ cls1Hnd = op1ClassFromHandle->AsRuntimeLookup()->GetClassHandle();
+ runtimeLookupCount++;
+ }
+ // Tunnel through indirs we may see when prejitting
+ else if (op1ClassFromHandle->gtOper == GT_IND)
+ {
+ // The handle indirs we can optimize will be marked as non-faulting.
+ // Certain others (eg from refanytype) may not be.
+ if (op1ClassFromHandle->gtFlags & GTF_IND_NONFAULTING)
+ {
+ GenTree* op1HandleLiteral = op1ClassFromHandle->gtOp.gtOp1;
+
+ // If, after tunneling, we have a constant handle,
+ // remember the class and the value tree for later.
+ if ((op1HandleLiteral->gtOper == GT_CNS_INT) && (op1HandleLiteral->gtType == TYP_I_IMPL))
+ {
+ JITDUMP("tunneling through indir on op1\n");
+ op1TunneledHandle = op1HandleLiteral;
+
+ // These handle constants should be class handles.
+ assert(op1TunneledHandle->IsIconHandle(GTF_ICON_CLASS_HDL));
+ cls1Hnd = (CORINFO_CLASS_HANDLE)op1TunneledHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ }
+ }
+
+ // Try and find class handle for op2
+ if ((op2ClassFromHandle->gtOper == GT_CNS_INT) && (op2ClassFromHandle->gtType == TYP_I_IMPL))
+ {
+ assert(op2ClassFromHandle->IsIconHandle(GTF_ICON_CLASS_HDL));
+ cls2Hnd = (CORINFO_CLASS_HANDLE)op2ClassFromHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ else if (op2ClassFromHandle->OperGet() == GT_RUNTIMELOOKUP)
+ {
+ cls2Hnd = op2ClassFromHandle->AsRuntimeLookup()->GetClassHandle();
+ runtimeLookupCount++;
+ }
+ // Tunnel through indirs we may see when prejitting
+ else if (op2ClassFromHandle->gtOper == GT_IND)
+ {
+ // The handle indirs we can optimize will be marked as non-faulting.
+ // Certain others (eg from refanytype) may not be.
+ if (op2ClassFromHandle->gtFlags & GTF_IND_NONFAULTING)
+ {
+ GenTree* op2HandleLiteral = op2ClassFromHandle->gtOp.gtOp1;
+
+ // If, after tunneling, we have a constant handle,
+ // remember the class and the value tree for later.
+ if ((op2HandleLiteral->gtOper == GT_CNS_INT) && (op2HandleLiteral->gtType == TYP_I_IMPL))
+ {
+ JITDUMP("tunneling through indir on op2\n");
+ op2TunneledHandle = op2HandleLiteral;
+
+ // These handle constants should be class handles.
+ assert(op2TunneledHandle->IsIconHandle(GTF_ICON_CLASS_HDL));
+ cls2Hnd = (CORINFO_CLASS_HANDLE)op2TunneledHandle->gtIntCon.gtCompileTimeHandle;
+ }
+ }
+ }
+
+ // If we have class handles, try and resolve the type equality test completely.
+ if ((cls1Hnd != nullptr) && (cls2Hnd != nullptr))
+ {
+ JITDUMP("Asking runtime to compare %p (%s) and %p (%s) for equality\n", cls1Hnd,
+ info.compCompHnd->getClassName(cls1Hnd), cls2Hnd, info.compCompHnd->getClassName(cls2Hnd));
+ TypeCompareState s = info.compCompHnd->compareTypesForEquality(cls1Hnd, cls2Hnd);
+
+ if (s != TypeCompareState::May)
+ {
+ // Type comparison result is known.
+ const bool typesAreEqual = (s == TypeCompareState::Must);
+ const bool operatorIsEQ = (oper == GT_EQ);
+ const int compareResult = operatorIsEQ ^ typesAreEqual ? 0 : 1;
+ JITDUMP("Runtime reports comparison is known at jit time: %u\n", compareResult);
+ GenTree* result = gtNewIconNode(compareResult);
+
+ // Any runtime lookups that fed into this compare are
+ // now dead code, so they no longer require the runtime context.
+ assert(lvaGenericsContextUseCount >= runtimeLookupCount);
+ lvaGenericsContextUseCount -= runtimeLookupCount;
+ return result;
+ }
+ }
+
+ JITDUMP("Could not find handle for %s%s\n", (cls1Hnd == nullptr) ? " cls1" : "",
+ (cls2Hnd == nullptr) ? " cls2" : "");
+
+ // We can't answer the equality comparison definitively at jit
+ // time, but can still simplfy the comparison.
+ //
+ // If we successfully tunneled through both operands, compare
+ // the tunnneled values, otherwise compare the orignal values.
+ GenTree* compare = nullptr;
+ if ((op1TunneledHandle != nullptr) && (op2TunneledHandle != nullptr))
+ {
+ compare = gtNewOperNode(oper, TYP_INT, op1TunneledHandle, op2TunneledHandle);
+ }
+ else
+ {
+ compare = gtNewOperNode(oper, TYP_INT, op1ClassFromHandle, op2ClassFromHandle);
+ }
+
+ // Drop any now-irrelvant flags
+ compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+
+ return compare;
+ }
+
+ // Just one operand creates a type from a handle.
+ //
+ // If the other operand is fetching the type from an object,
+ // we can sometimes optimize the type compare into a simpler
+ // method table comparison.
+ //
+ // TODO: if other operand is null...
+ if (op1Kind != TPK_GetType && op2Kind != TPK_GetType)
+ {
+ return tree;
+ }
+
+ GenTree* const opHandle = op1IsFromHandle ? op1 : op2;
+ GenTree* const opOther = op1IsFromHandle ? op2 : op1;
+
+ // Tunnel through the handle operand to get at the class handle involved.
+ GenTree* const opHandleArgument = opHandle->gtCall.gtCallArgs->gtOp.gtOp1;
+ GenTree* opHandleLiteral = opHandleArgument;
+ CORINFO_CLASS_HANDLE clsHnd = nullptr;
+
+ // Unwrap any GT_NOP node used to prevent constant folding
+ if ((opHandleLiteral->gtOper == GT_NOP) && (opHandleLiteral->gtType == TYP_I_IMPL))
+ {
+ opHandleLiteral = opHandleLiteral->gtOp.gtOp1;
+ }
+
+ // For runtime lookups we can get at the handle directly
+ if (opHandleLiteral->gtOper == GT_RUNTIMELOOKUP)
+ {
+ clsHnd = opHandleLiteral->AsRuntimeLookup()->GetClassHandle();
+ }
+ else
+ {
+ // Tunnel through prejit indirs if necessary
+ if (opHandleLiteral->gtOper == GT_IND)
+ {
+ // Handle indirs should be marked as nonfaulting.
+ assert((opHandleLiteral->gtFlags & GTF_IND_NONFAULTING) != 0);
+ opHandleLiteral = opHandleLiteral->gtOp.gtOp1;
+ }
+
+ if ((opHandleLiteral->gtOper == GT_CNS_INT) && (opHandleLiteral->gtType == TYP_I_IMPL))
+ {
+ assert(opHandleLiteral->IsIconHandle(GTF_ICON_CLASS_HDL));
+ clsHnd = CORINFO_CLASS_HANDLE(opHandleLiteral->gtIntCon.gtCompileTimeHandle);
+ }
+ }
+
+ // If we couldn't find the class handle, give up.
+ if (clsHnd == nullptr)
+ {
+ return tree;
+ }
+
+ // Ask the VM if this type can be equality tested by a simple method
+ // table comparison.
+ if (!info.compCompHnd->canInlineTypeCheckWithObjectVTable(clsHnd))
+ {
+ return tree;
+ }
+
+ // We're good to go.
+ JITDUMP("Optimizing compare of obj.GetType()"
+ " and type-from-handle to compare method table pointer\n");
+
+ // opHandleArgument is the method table we're looking for.
+ GenTree* const knownMT = opHandleArgument;
+
+ // Fetch object method table from the object itself.
+ GenTree* objOp = nullptr;
+
+ // Note we may see intrinsified or regular calls to GetType
+ if (opOther->OperGet() == GT_INTRINSIC)
+ {
+ objOp = opOther->gtUnOp.gtOp1;
+ }
+ else
+ {
+ assert(opOther->OperGet() == GT_CALL);
+ objOp = opOther->gtCall.gtCallObjp;
+ }
+
+ GenTree* const objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, objOp);
+
+ // Update various flags
+ objMT->gtFlags |= GTF_EXCEPT;
+ compCurBB->bbFlags |= BBF_HAS_VTABREF;
+ optMethodFlags |= OMF_HAS_VTABLEREF;
+
+ // Compare the two method tables
+ GenTree* const compare = gtNewOperNode(oper, TYP_INT, objMT, knownMT);
+
+ // Drop any any now irrelevant flags
+ compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+
+ // And we're done
+ return compare;
+}
+
/*****************************************************************************
*
* Some binary operators can be folded even if they have only one
@@ -12224,6 +12864,7 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
case GT_EQ:
case GT_NE:
case GT_GT:
+
// Optimize boxed value classes; these are always false. This IL is
// generated when a generic value is tested against null:
// <T> ... foo(T x) { ... if ((object)x == null) ...
@@ -12297,7 +12938,9 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
break;
case GT_ADD:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
if (val == 0)
{
goto DONE_FOLD;
@@ -12305,7 +12948,9 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
break;
case GT_MUL:
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
+#endif
if (val == 1)
{
goto DONE_FOLD;
@@ -12327,7 +12972,9 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
case GT_DIV:
case GT_UDIV:
+#ifdef LEGACY_BACKEND
case GT_ASG_DIV:
+#endif
if ((op2 == cons) && (val == 1) && !(op1->OperKind() & GTK_CONST))
{
goto DONE_FOLD;
@@ -12335,7 +12982,9 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
break;
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
if ((op2 == cons) && (val == 0) && !(op1->OperKind() & GTK_CONST))
{
goto DONE_FOLD;
@@ -12404,9 +13053,11 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
case GT_RSZ:
case GT_ROL:
case GT_ROR:
+#ifdef LEGACY_BACKEND
case GT_ASG_LSH:
case GT_ASG_RSH:
case GT_ASG_RSZ:
+#endif
if (val == 0)
{
if (op2 == cons)
@@ -12473,7 +13124,7 @@ DONE_FOLD:
// a use, update the flags appropriately
if (op->gtOper == GT_LCL_VAR)
{
- assert((tree->OperKind() & GTK_ASGOP) || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
+ assert(tree->OperIsAssignment() || (op->gtFlags & (GTF_VAR_USEASG | GTF_VAR_DEF)) == 0);
op->gtFlags &= ~(GTF_VAR_USEASG | GTF_VAR_DEF);
}
@@ -12528,27 +13179,21 @@ DONE_FOLD:
GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions options)
{
- JITDUMP("gtTryRemoveBoxUpstreamEffects called for [%06u]\n", dspTreeID(op));
assert(op->IsBoxedValue());
// grab related parts for the optimization
- GenTree* asgStmt = op->gtBox.gtAsgStmtWhenInlinedBoxValue;
+ GenTreeBox* box = op->AsBox();
+ GenTree* asgStmt = box->gtAsgStmtWhenInlinedBoxValue;
+ GenTree* copyStmt = box->gtCopyStmtWhenInlinedBoxValue;
+
assert(asgStmt->gtOper == GT_STMT);
- GenTree* copyStmt = op->gtBox.gtCopyStmtWhenInlinedBoxValue;
assert(copyStmt->gtOper == GT_STMT);
-#ifdef DEBUG
- if (verbose)
- {
- printf("\n%s to remove side effects of BOX (valuetype)\n",
- options == BR_DONT_REMOVE ? "Checking if it is possible" : "Attempting");
- gtDispTree(op);
- printf("\nWith assign\n");
- gtDispTree(asgStmt);
- printf("\nAnd copy\n");
- gtDispTree(copyStmt);
- }
-#endif
+ JITDUMP("gtTryRemoveBoxUpstreamEffects: %s to %s of BOX (valuetype)"
+ " [%06u] (assign/newobj [%06u] copy [%06u])\n",
+ (options == BR_DONT_REMOVE) ? "checking if it is possible" : "attempting",
+ (options == BR_MAKE_LOCAL_COPY) ? "make local unboxed version" : "remove side effects", dspTreeID(op),
+ dspTreeID(asgStmt), dspTreeID(copyStmt));
// If we don't recognize the form of the assign, bail.
GenTree* asg = asgStmt->gtStmt.gtStmtExpr;
@@ -12583,7 +13228,7 @@ GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions
if (newobjArgs == nullptr)
{
assert(newobjCall->IsHelperCall(this, CORINFO_HELP_READYTORUN_NEW));
- JITDUMP("bailing; newobj via R2R helper\n");
+ JITDUMP(" bailing; newobj via R2R helper\n");
return nullptr;
}
@@ -12619,6 +13264,73 @@ GenTree* Compiler::gtTryRemoveBoxUpstreamEffects(GenTree* op, BoxRemovalOptions
return nullptr;
}
+ // Handle case where we are optimizing the box into a local copy
+ if (options == BR_MAKE_LOCAL_COPY)
+ {
+ // Drill into the box to get at the box temp local and the box type
+ GenTree* boxTemp = box->BoxOp();
+ assert(boxTemp->IsLocal());
+ const unsigned boxTempLcl = boxTemp->AsLclVar()->GetLclNum();
+ assert(lvaTable[boxTempLcl].lvType == TYP_REF);
+ CORINFO_CLASS_HANDLE boxClass = lvaTable[boxTempLcl].lvClassHnd;
+ assert(boxClass != nullptr);
+
+ // Verify that the copyDst has the expected shape
+ // (blk|obj|ind (add (boxTempLcl, ptr-size)))
+ //
+ // The shape here is constrained to the patterns we produce
+ // over in impImportAndPushBox for the inlined box case.
+ GenTree* copyDst = copy->gtOp.gtOp1;
+
+ if (!copyDst->OperIs(GT_BLK, GT_IND, GT_OBJ))
+ {
+ JITDUMP("Unexpected copy dest operator %s\n", GenTree::OpName(copyDst->gtOper));
+ return nullptr;
+ }
+
+ GenTree* copyDstAddr = copyDst->gtOp.gtOp1;
+ if (copyDstAddr->OperGet() != GT_ADD)
+ {
+ JITDUMP("Unexpected copy dest address tree\n");
+ return nullptr;
+ }
+
+ GenTree* copyDstAddrOp1 = copyDstAddr->gtOp.gtOp1;
+ if ((copyDstAddrOp1->OperGet() != GT_LCL_VAR) || (copyDstAddrOp1->gtLclVarCommon.gtLclNum != boxTempLcl))
+ {
+ JITDUMP("Unexpected copy dest address 1st addend\n");
+ return nullptr;
+ }
+
+ GenTree* copyDstAddrOp2 = copyDstAddr->gtOp.gtOp2;
+ if (!copyDstAddrOp2->IsIntegralConst(TARGET_POINTER_SIZE))
+ {
+ JITDUMP("Unexpected copy dest address 2nd addend\n");
+ return nullptr;
+ }
+
+ // Screening checks have all passed. Do the transformation.
+ //
+ // Retype the box temp to be a struct
+ JITDUMP("Retyping box temp V%02u to struct %s\n", boxTempLcl, eeGetClassName(boxClass));
+ lvaTable[boxTempLcl].lvType = TYP_UNDEF;
+ const bool isUnsafeValueClass = false;
+ lvaSetStruct(boxTempLcl, boxClass, isUnsafeValueClass);
+
+ // Remove the newobj and assigment to box temp
+ JITDUMP("Bashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
+ asg->gtBashToNOP();
+
+ // Update the copy from the value to be boxed to the box temp
+ GenTree* newDst = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, TYP_STRUCT));
+ copyDst->gtOp.gtOp1 = newDst;
+
+ // Return the address of the now-struct typed box temp
+ GenTree* retValue = gtNewOperNode(GT_ADDR, TYP_BYREF, gtNewLclvNode(boxTempLcl, TYP_STRUCT));
+
+ return retValue;
+ }
+
// If the copy is a struct copy, make sure we know how to isolate
// any source side effects.
GenTree* copySrc = copy->gtOp.gtOp2;
@@ -12922,6 +13634,11 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
return tree;
}
+ if (tree->gtOper == GT_RUNTIMELOOKUP)
+ {
+ return tree;
+ }
+
if (kind & GTK_UNOP)
{
assert(op1->OperKind() & GTK_CONST);
@@ -12950,7 +13667,9 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
break;
case GT_NEG:
+#ifdef LEGACY_BACKEND
case GT_CHS:
+#endif
i1 = -i1;
break;
@@ -13079,7 +13798,9 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
break;
case GT_NEG:
+#ifdef LEGACY_BACKEND
case GT_CHS:
+#endif
lval1 = -lval1;
break;
@@ -13184,7 +13905,9 @@ GenTreePtr Compiler::gtFoldExprConst(GenTreePtr tree)
switch (tree->gtOper)
{
case GT_NEG:
+#ifdef LEGACY_BACKEND
case GT_CHS:
+#endif
d1 = -d1;
break;
@@ -14554,7 +15277,7 @@ bool Compiler::gtNodeHasSideEffects(GenTreePtr tree, unsigned flags)
{
if (flags & GTF_ASG)
{
- if ((tree->OperKind() & GTK_ASGOP))
+ if (tree->OperIsAssignment())
{
return true;
}
@@ -14768,6 +15491,7 @@ void Compiler::gtExtractSideEffList(GenTreePtr expr,
if (oper == GT_XADD)
{
expr->SetOperRaw(GT_LOCKADD);
+ assert(genActualType(expr->gtType) == genActualType(expr->gtOp.gtOp2->gtType));
expr->gtType = TYP_VOID;
}
@@ -15123,25 +15847,24 @@ void Compiler::gtCheckQuirkAddrExposedLclVar(GenTreePtr tree, GenTreeStack* pare
}
//------------------------------------------------------------------------
-// gtCanOptimizeTypeEquality: check if tree is a suitable input for a type
-// equality optimization
+// gtGetTypeProducerKind: determine if a tree produces a runtime type, and
+// if so, how.
//
// Arguments:
// tree - tree to examine
//
// Return Value:
-// True, if value of tree can be used to optimize type equality tests
+// TypeProducerKind for the tree.
//
// Notes:
-// Checks to see if the jit is able to optimize Type::op_Equality or
-// Type::op_Inequality calls that consume this tree.
+// Checks to see if this tree returns a RuntimeType value, and if so,
+// how that value is determined.
//
-// The jit can safely convert these methods to GT_EQ/GT_NE if one of
-// the operands is:
+// Currently handles these cases
// 1) The result of Object::GetType
// 2) The result of typeof(...)
-// 3) Is a null reference
-// 4) Is otherwise known to have type RuntimeType
+// 3) A null reference
+// 4) Tree is otherwise known to have type RuntimeType
//
// The null reference case is surprisingly common because operator
// overloading turns the otherwise innocuous
@@ -15151,7 +15874,7 @@ void Compiler::gtCheckQuirkAddrExposedLclVar(GenTreePtr tree, GenTreeStack* pare
//
// into a method call.
-bool Compiler::gtCanOptimizeTypeEquality(GenTreePtr tree)
+Compiler::TypeProducerKind Compiler::gtGetTypeProducerKind(GenTree* tree)
{
if (tree->gtOper == GT_CALL)
{
@@ -15159,24 +15882,24 @@ bool Compiler::gtCanOptimizeTypeEquality(GenTreePtr tree)
{
if (gtIsTypeHandleToRuntimeTypeHelper(tree->AsCall()))
{
- return true;
+ return TPK_Handle;
}
}
else if (tree->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC)
{
if (info.compCompHnd->getIntrinsicID(tree->gtCall.gtCallMethHnd) == CORINFO_INTRINSIC_Object_GetType)
{
- return true;
+ return TPK_GetType;
}
}
}
else if ((tree->gtOper == GT_INTRINSIC) && (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType))
{
- return true;
+ return TPK_GetType;
}
else if ((tree->gtOper == GT_CNS_INT) && (tree->gtIntCon.gtIconVal == 0))
{
- return true;
+ return TPK_Null;
}
else
{
@@ -15186,12 +15909,22 @@ bool Compiler::gtCanOptimizeTypeEquality(GenTreePtr tree)
if (clsHnd == info.compCompHnd->getBuiltinClass(CLASSID_RUNTIME_TYPE))
{
- return true;
+ return TPK_Other;
}
}
- return false;
+ return TPK_Unknown;
}
+//------------------------------------------------------------------------
+// gtIsTypeHandleToRuntimeTypeHelperCall -- see if tree is constructing
+// a RuntimeType from a handle
+//
+// Arguments:
+// tree - tree to examine
+//
+// Return Value:
+// True if so
+
bool Compiler::gtIsTypeHandleToRuntimeTypeHelper(GenTreeCall* call)
{
return call->gtCallMethHnd == eeFindHelper(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE) ||
@@ -15625,12 +16358,14 @@ unsigned GenTree::IsLclVarUpdateTree(GenTree** pOtherTree, genTreeOps* pOper)
*pOper = rhs->gtOper;
}
}
+#ifdef LEGACY_BACKEND
else
{
lclNum = lhsLclNum;
*pOper = GenTree::OpAsgToOper(gtOper);
*pOtherTree = gtOp.gtOp2;
}
+#endif
}
}
return lclNum;
@@ -15814,7 +16549,7 @@ ssize_t GenTreeIndir::Offset()
// comp - Compiler instance
//
// Return Value:
-// True if this immediate value needs recording a relocation with the VM; false otherwise.
+// True if this immediate value requires us to record a relocation for it; false otherwise.
bool GenTreeIntConCommon::ImmedValNeedsReloc(Compiler* comp)
{
@@ -16987,6 +17722,59 @@ bool GenTree::isCommutativeSIMDIntrinsic()
}
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
+ var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
+{
+ return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, baseType, size);
+}
+
+GenTreeHWIntrinsic* Compiler::gtNewSimdHWIntrinsicNode(
+ var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
+{
+ return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, baseType, size);
+}
+
+GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID)
+{
+ return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, hwIntrinsicID, TYP_UNKNOWN, 0);
+}
+
+GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode(var_types type,
+ GenTree* op1,
+ GenTree* op2,
+ NamedIntrinsic hwIntrinsicID)
+{
+ return new (this, GT_HWIntrinsic) GenTreeHWIntrinsic(type, op1, op2, hwIntrinsicID, TYP_UNKNOWN, 0);
+}
+
+//---------------------------------------------------------------------------------------
+// gtNewMustThrowException:
+// create a throw node (calling into JIT helper) that must be thrown.
+// The result would be a comma node: COMMA(jithelperthrow(void), x) where x's type should be specified.
+//
+// Arguments
+// helper - JIT helper ID
+// type - return type of the node
+//
+// Return Value
+// pointer to the throw node
+//
+GenTree* Compiler::gtNewMustThrowException(unsigned helper, var_types type)
+{
+ GenTreeCall* node = gtNewHelperCallNode(helper, TYP_VOID);
+ node->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN;
+ if (type != TYP_VOID)
+ {
+ unsigned dummyTemp = lvaGrabTemp(true DEBUGARG("dummy temp of must thrown exception"));
+ lvaTable[dummyTemp].lvType = type;
+ GenTree* dummyNode = gtNewLclvNode(dummyTemp, type);
+ return gtNewOperNode(GT_COMMA, type, node, dummyNode);
+ }
+ return node;
+}
+#endif // FEATURE_HW_INTRINSICS
+
//---------------------------------------------------------------------------------------
// InitializeStructReturnType:
// Initialize the Return Type Descriptor for a method that returns a struct type
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 82e5d70b94..830da20554 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -27,6 +27,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#include "simplerhash.h"
#include "nodeinfo.h"
#include "simd.h"
+#include "namedintrinsiclist.h"
// Debugging GenTree is much easier if we add a magic virtual function to make the debugger able to figure out what type
// it's got. This is enabled by default in DEBUG. To enable it in RET builds (temporarily!), you need to change the
@@ -105,7 +106,9 @@ enum genTreeKinds
GTK_BINOP = 0x0008, // binary operator
GTK_RELOP = 0x0010, // comparison operator
GTK_LOGOP = 0x0020, // logical operator
+#ifdef LEGACY_BACKEND
GTK_ASGOP = 0x0040, // assignment operator
+#endif
GTK_KINDMASK = 0x007F, // operator kind mask
@@ -856,11 +859,11 @@ public:
#ifdef LEGACY_BACKEND
#define GTF_SPILLED_OPER 0x00000100 // op1 has been spilled
#define GTF_SPILLED_OP2 0x00000200 // op2 has been spilled
+#define GTF_ZSF_SET 0x00000400 // the zero(ZF) and sign(SF) flags set to the operand
#else // !LEGACY_BACKEND
#define GTF_NOREG_AT_USE 0x00000100 // tree node is in memory at the point of use
#endif // !LEGACY_BACKEND
-#define GTF_ZSF_SET 0x00000400 // the zero(ZF) and sign(SF) flags set to the operand
#define GTF_SET_FLAGS 0x00000800 // Requires that codegen for this node set the flags. Use gtSetFlags() to check this flag.
#define GTF_USE_FLAGS 0x00001000 // Indicates that this node uses the flags bits.
@@ -940,7 +943,7 @@ public:
#define GTF_FLD_INITCLASS 0x20000000 // GT_FIELD/GT_CLS_VAR -- field access requires preceding class/static init helper
#define GTF_INX_RNGCHK 0x80000000 // GT_INDEX -- the array reference should be range-checked.
-#define GTF_INX_REFARR_LAYOUT 0x20000000 // GT_INDEX -- same as GTF_IND_REFARR_LAYOUT
+#define GTF_INX_REFARR_LAYOUT 0x20000000 // GT_INDEX
#define GTF_INX_STRING_LAYOUT 0x40000000 // GT_INDEX -- this uses the special string array layout
#define GTF_IND_ARR_LEN 0x80000000 // GT_IND -- the indirection represents an array length (of the REF
@@ -1015,7 +1018,7 @@ public:
#define GTF_ICON_TOKEN_HDL 0xB0000000 // GT_CNS_INT -- constant is a token handle
#define GTF_ICON_TLS_HDL 0xC0000000 // GT_CNS_INT -- constant is a TLS ref with offset
#define GTF_ICON_FTN_ADDR 0xD0000000 // GT_CNS_INT -- constant is a function address
-#define GTF_ICON_CIDMID_HDL 0xE0000000 // GT_CNS_INT -- constant is a class or module ID handle
+#define GTF_ICON_CIDMID_HDL 0xE0000000 // GT_CNS_INT -- constant is a class ID or a module ID
#define GTF_ICON_BBC_PTR 0xF0000000 // GT_CNS_INT -- constant is a basic block count pointer
#define GTF_ICON_FIELD_OFF 0x08000000 // GT_CNS_INT -- constant is a field offset
@@ -1122,9 +1125,12 @@ public:
return false;
}
- if (gtOper == GT_NOP || gtOper == GT_CALL)
+ if (gtType == TYP_VOID)
{
- return gtType != TYP_VOID;
+ // These are the only operators which can produce either VOID or non-VOID results.
+ assert(OperIs(GT_NOP, GT_CALL, GT_LOCKADD, GT_FIELD_LIST, GT_COMMA) || OperIsCompare() || OperIsLong() ||
+ OperIsSIMD());
+ return false;
}
if (gtOper == GT_FIELD_LIST)
@@ -1177,13 +1183,13 @@ public:
inline void ClearUnusedValue();
inline bool IsUnusedValue() const;
- bool OperIs(genTreeOps oper)
+ bool OperIs(genTreeOps oper) const
{
return OperGet() == oper;
}
template <typename... T>
- bool OperIs(genTreeOps oper, T... rest)
+ bool OperIs(genTreeOps oper, T... rest) const
{
return OperIs(oper) || OperIs(rest...);
}
@@ -1339,11 +1345,7 @@ public:
bool OperIsMultiRegOp() const
{
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
-#ifdef ARM_SOFTFP
- if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG)
-#else
- if (gtOper == GT_MUL_LONG)
-#endif
+ if ((gtOper == GT_MUL_LONG) || (gtOper == GT_PUTARG_REG) || (gtOper == GT_BITCAST))
{
return true;
}
@@ -1458,27 +1460,6 @@ public:
}
#endif // _TARGET_XARCH_
-#if !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
- static bool OperIsHigh(genTreeOps gtOper)
- {
- switch (gtOper)
- {
- case GT_ADD_HI:
- case GT_SUB_HI:
- case GT_DIV_HI:
- case GT_MOD_HI:
- return true;
- default:
- return false;
- }
- }
-
- bool OperIsHigh() const
- {
- return OperIsHigh(OperGet());
- }
-#endif // !defined(LEGACY_BACKEND) && !defined(_TARGET_64BIT_)
-
static bool OperIsUnary(genTreeOps gtOper)
{
return (OperKind(gtOper) & GTK_UNOP) != 0;
@@ -1535,7 +1516,11 @@ public:
static bool OperIsAssignment(genTreeOps gtOper)
{
+#ifdef LEGACY_BACKEND
return (OperKind(gtOper) & GTK_ASGOP) != 0;
+#else
+ return gtOper == GT_ASG;
+#endif
}
bool OperIsAssignment() const
@@ -1543,6 +1528,22 @@ public:
return OperIsAssignment(gtOper);
}
+ static bool OperMayOverflow(genTreeOps gtOper)
+ {
+ return ((gtOper == GT_ADD) || (gtOper == GT_SUB) || (gtOper == GT_MUL) || (gtOper == GT_CAST)
+#ifdef LEGACY_BACKEND
+ || (gtOper == GT_ASG_ADD) || (gtOper == GT_ASG_SUB)
+#elif !defined(_TARGET_64BIT_)
+ || (gtOper == GT_ADD_HI) || (gtOper == GT_SUB_HI)
+#endif
+ );
+ }
+
+ bool OperMayOverflow() const
+ {
+ return OperMayOverflow(gtOper);
+ }
+
static bool OperIsIndir(genTreeOps gtOper)
{
return gtOper == GT_IND || gtOper == GT_STOREIND || gtOper == GT_NULLCHECK || OperIsBlk(gtOper);
@@ -1613,7 +1614,7 @@ public:
return OperIsAtomicOp(gtOper);
}
- // This is basically here for cleaner FEATURE_SIMD #ifdefs.
+ // This is here for cleaner FEATURE_SIMD #ifdefs.
static bool OperIsSIMD(genTreeOps gtOper)
{
#ifdef FEATURE_SIMD
@@ -1623,11 +1624,26 @@ public:
#endif // !FEATURE_SIMD
}
- bool OperIsSIMD()
+ bool OperIsSIMD() const
{
return OperIsSIMD(gtOper);
}
+ // This is here for cleaner GT_LONG #ifdefs.
+ static bool OperIsLong(genTreeOps gtOper)
+ {
+#if defined(_TARGET_64BIT_) || defined(LEGACY_BACKEND)
+ return false;
+#else
+ return gtOper == GT_LONG;
+#endif
+ }
+
+ bool OperIsLong() const
+ {
+ return OperIsLong(gtOper);
+ }
+
bool OperIsFieldListHead()
{
return (gtOper == GT_FIELD_LIST) && ((gtFlags & GTF_FIELD_LIST_HEAD) != 0);
@@ -1658,9 +1674,11 @@ public:
return OperIsBoundsCheck(OperGet());
}
+#ifdef LEGACY_BACKEND
// Requires that "op" is an op= operator. Returns
// the corresponding "op".
static genTreeOps OpAsgToOper(genTreeOps op);
+#endif
#ifdef DEBUG
bool NullOp1Legal() const
@@ -1696,9 +1714,14 @@ public:
#ifdef FEATURE_SIMD
case GT_SIMD:
#endif // !FEATURE_SIMD
-#if !defined(LEGACY_BACKEND) && _TARGET_ARM_
+
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+#endif // FEATURE_HW_INTRINSICS
+
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
case GT_PUTARG_REG:
-#endif // !defined(LEGACY_BACKEND) && _TARGET_ARM_
+#endif // !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
return true;
default:
return false;
@@ -1829,7 +1852,7 @@ public:
bool IsNodeProperlySized() const;
- void CopyFrom(const GenTree* src, Compiler* comp);
+ void ReplaceWith(GenTree* src, Compiler* comp);
static genTreeOps ReverseRelop(genTreeOps relop);
@@ -2064,7 +2087,7 @@ public:
inline bool IsIntegralConst() const;
- inline bool IsIntCnsFitsInI32();
+ inline bool IsIntCnsFitsInI32(); // Constant fits in INT32
inline bool IsCnsFltOrDbl() const;
@@ -2126,12 +2149,14 @@ public:
bool gtSetFlags() const;
bool gtRequestSetFlags();
+#ifdef LEGACY_BACKEND
// Returns true if the codegen of this tree node
// sets ZF and SF flags.
bool gtSetZSFlags() const
{
return (gtFlags & GTF_ZSF_SET) != 0;
}
+#endif
#ifdef DEBUG
bool gtIsValid64RsltMul();
@@ -2553,15 +2578,25 @@ struct GenTreeIntConCommon : public GenTree
{
}
- bool FitsInI32()
+ bool FitsInI8() // IconValue() fits into 8-bit signed storage
+ {
+ return FitsInI8(IconValue());
+ }
+
+ static bool FitsInI8(ssize_t val) // Constant fits into 8-bit signed storage
+ {
+ return (int8_t)val == val;
+ }
+
+ bool FitsInI32() // IconValue() fits into 32-bit signed storage
{
return FitsInI32(IconValue());
}
- static bool FitsInI32(ssize_t val)
+ static bool FitsInI32(ssize_t val) // Constant fits into 32-bit signed storage
{
#ifdef _TARGET_64BIT_
- return (int)val == val;
+ return (int32_t)val == val;
#else
return true;
#endif
@@ -2652,34 +2687,6 @@ struct GenTreeIntCon : public GenTreeIntConCommon
// sequence of fields.
FieldSeqNode* gtFieldSeq;
-#if defined(LATE_DISASM)
-
- /* If the constant was morphed from some other node,
- these fields enable us to get back to what the node
- originally represented. See use of gtNewIconHandleNode()
- */
-
- union {
- /* Template struct - The significant field of the other
- * structs should overlap exactly with this struct
- */
-
- struct
- {
- unsigned gtIconHdl1;
- void* gtIconHdl2;
- } gtIconHdl;
-
- /* GT_FIELD, etc */
-
- struct
- {
- unsigned gtIconCPX;
- CORINFO_CLASS_HANDLE gtIconCls;
- } gtIconFld;
- };
-#endif
-
GenTreeIntCon(var_types type, ssize_t value DEBUGARG(bool largeNode = false))
: GenTreeIntConCommon(GT_CNS_INT, type DEBUGARG(largeNode))
, gtIconVal(value)
@@ -2733,7 +2740,6 @@ struct GenTreeLngCon : public GenTreeIntConCommon
INT32 HiVal()
{
return (INT32)(gtLconVal >> 32);
- ;
}
GenTreeLngCon(INT64 val) : GenTreeIntConCommon(GT_CNS_NATIVELONG, TYP_LONG)
@@ -3158,6 +3164,7 @@ struct GenTreeFieldList : public GenTreeArgList
assert(!arg->OperIsAnyList());
gtFieldOffset = fieldOffset;
gtFieldType = fieldType;
+ gtType = fieldType;
if (prevList == nullptr)
{
gtFlags |= GTF_FIELD_LIST_HEAD;
@@ -3971,7 +3978,7 @@ struct GenTreeMultiRegOp : public GenTreeOp
{
regNumber gtOtherReg;
- // GTF_SPILL or GTF_SPILLED flag on a multi-reg call node indicates that one or
+ // GTF_SPILL or GTF_SPILLED flag on a multi-reg node indicates that one or
// more of its result regs are in that state. The spill flag of each of the
// return register is stored here. We only need 2 bits per returned register,
// so this is treated as a 2-bit array. No architecture needs more than 8 bits.
@@ -4194,20 +4201,38 @@ struct GenTreeIntrinsic : public GenTreeOp
#endif
};
+struct GenTreeJitIntrinsic : public GenTreeOp
+{
+ var_types gtSIMDBaseType; // SIMD vector base type
+ unsigned gtSIMDSize; // SIMD vector size in bytes, use 0 for scalar intrinsics
+
+ GenTreeJitIntrinsic(
+ genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2, var_types baseType, unsigned size)
+ : GenTreeOp(oper, type, op1, op2), gtSIMDBaseType(baseType), gtSIMDSize(size)
+ {
+ }
+
+ bool isSIMD()
+ {
+ return gtSIMDSize != 0;
+ }
+
+#if DEBUGGABLE_GENTREE
+ GenTreeJitIntrinsic() : GenTreeOp()
+ {
+ }
+#endif
+};
+
#ifdef FEATURE_SIMD
/* gtSIMD -- SIMD intrinsic (possibly-binary op [NULL op2 is allowed] with additional fields) */
-struct GenTreeSIMD : public GenTreeOp
+struct GenTreeSIMD : public GenTreeJitIntrinsic
{
SIMDIntrinsicID gtSIMDIntrinsicID; // operation Id
- var_types gtSIMDBaseType; // SIMD vector base type
- unsigned gtSIMDSize; // SIMD vector size in bytes
GenTreeSIMD(var_types type, GenTreePtr op1, SIMDIntrinsicID simdIntrinsicID, var_types baseType, unsigned size)
- : GenTreeOp(GT_SIMD, type, op1, nullptr)
- , gtSIMDIntrinsicID(simdIntrinsicID)
- , gtSIMDBaseType(baseType)
- , gtSIMDSize(size)
+ : GenTreeJitIntrinsic(GT_SIMD, type, op1, nullptr, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID)
{
}
@@ -4217,21 +4242,42 @@ struct GenTreeSIMD : public GenTreeOp
SIMDIntrinsicID simdIntrinsicID,
var_types baseType,
unsigned size)
- : GenTreeOp(GT_SIMD, type, op1, op2)
- , gtSIMDIntrinsicID(simdIntrinsicID)
- , gtSIMDBaseType(baseType)
- , gtSIMDSize(size)
+ : GenTreeJitIntrinsic(GT_SIMD, type, op1, op2, baseType, size), gtSIMDIntrinsicID(simdIntrinsicID)
{
}
#if DEBUGGABLE_GENTREE
- GenTreeSIMD() : GenTreeOp()
+ GenTreeSIMD() : GenTreeJitIntrinsic()
{
}
#endif
};
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic
+{
+ NamedIntrinsic gtHWIntrinsicId;
+
+ GenTreeHWIntrinsic(var_types type, GenTree* op1, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
+ : GenTreeJitIntrinsic(GT_HWIntrinsic, type, op1, nullptr, baseType, size), gtHWIntrinsicId(hwIntrinsicID)
+ {
+ }
+
+ GenTreeHWIntrinsic(
+ var_types type, GenTree* op1, GenTree* op2, NamedIntrinsic hwIntrinsicID, var_types baseType, unsigned size)
+ : GenTreeJitIntrinsic(GT_HWIntrinsic, type, op1, op2, baseType, size), gtHWIntrinsicId(hwIntrinsicID)
+ {
+ }
+
+#if DEBUGGABLE_GENTREE
+ GenTreeHWIntrinsic() : GenTreeJitIntrinsic()
+ {
+ }
+#endif
+};
+#endif // FEATURE_HW_INTRINSICS
+
/* gtIndex -- array access */
struct GenTreeIndex : public GenTreeOp
@@ -5244,6 +5290,13 @@ struct GenTreePutArgStk : public GenTreeUnOp
return gtNumSlots * TARGET_POINTER_SIZE;
}
+ // Return true if this is a PutArgStk of a SIMD12 struct.
+ // This is needed because such values are re-typed to SIMD16, and the type of PutArgStk is VOID.
+ unsigned isSIMD12()
+ {
+ return (varTypeIsSIMD(gtOp1) && (gtNumSlots == 3));
+ }
+
//------------------------------------------------------------------------
// setGcPointers: Sets the number of references and the layout of the struct object returned by the VM.
//
@@ -5285,7 +5338,9 @@ struct GenTreePutArgStk : public GenTreeUnOp
unsigned gtNumberReferenceSlots; // Number of reference slots.
BYTE* gtGcPtrs; // gcPointers
-#endif // FEATURE_PUT_STRUCT_ARG_STK
+#elif !defined(LEGACY_BACKEND)
+ unsigned getArgSize();
+#endif // !LEGACY_BACKEND
#if defined(DEBUG) || defined(UNIX_X86_ABI)
GenTreeCall* gtCall; // the call node to which this argument belongs
@@ -5647,6 +5702,62 @@ struct GenTreeAllocObj final : public GenTreeUnOp
#endif
};
+// Represents GT_RUNTIMELOOKUP node
+
+struct GenTreeRuntimeLookup final : public GenTreeUnOp
+{
+ CORINFO_GENERIC_HANDLE gtHnd;
+ CorInfoGenericHandleType gtHndType;
+
+ GenTreeRuntimeLookup(CORINFO_GENERIC_HANDLE hnd, CorInfoGenericHandleType hndTyp, GenTree* tree)
+ : GenTreeUnOp(GT_RUNTIMELOOKUP, tree->gtType, tree DEBUGARG(/*largeNode*/ FALSE)), gtHnd(hnd), gtHndType(hndTyp)
+ {
+ assert(hnd != nullptr);
+ }
+#if DEBUGGABLE_GENTREE
+ GenTreeRuntimeLookup() : GenTreeUnOp()
+ {
+ }
+#endif
+
+ // Return reference to the actual tree that does the lookup
+ GenTree*& Lookup()
+ {
+ return gtOp1;
+ }
+
+ bool IsClassHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_CLASS;
+ }
+ bool IsMethodHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_METHOD;
+ }
+ bool IsFieldHandle() const
+ {
+ return gtHndType == CORINFO_HANDLETYPE_FIELD;
+ }
+
+ // Note these operations describe the handle that is input to the
+ // lookup, not the handle produced by the lookup.
+ CORINFO_CLASS_HANDLE GetClassHandle() const
+ {
+ assert(IsClassHandle());
+ return (CORINFO_CLASS_HANDLE)gtHnd;
+ }
+ CORINFO_METHOD_HANDLE GetMethodHandle() const
+ {
+ assert(IsMethodHandle());
+ return (CORINFO_METHOD_HANDLE)gtHnd;
+ }
+ CORINFO_FIELD_HANDLE GetFieldHandle() const
+ {
+ assert(IsMethodHandle());
+ return (CORINFO_FIELD_HANDLE)gtHnd;
+ }
+};
+
// Represents a GT_JCC or GT_SETCC node.
struct GenTreeCC final : public GenTree
@@ -5935,6 +6046,7 @@ inline bool GenTree::RequiresNonNullOp2(genTreeOps oper)
case GT_ROR:
case GT_INDEX:
case GT_ASG:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
case GT_ASG_SUB:
case GT_ASG_MUL:
@@ -5948,6 +6060,7 @@ inline bool GenTree::RequiresNonNullOp2(genTreeOps oper)
case GT_ASG_LSH:
case GT_ASG_RSH:
case GT_ASG_RSZ:
+#endif
case GT_EQ:
case GT_NE:
case GT_LT:
@@ -6058,7 +6171,7 @@ inline bool GenTree::IsMultiRegNode() const
}
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
- if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_BITCAST || OperIsPutArgSplit())
+ if (OperIsMultiRegOp() || OperIsPutArgSplit() || (gtOper == GT_COPY))
{
return true;
}
@@ -6114,10 +6227,11 @@ inline bool GenTree::IsIntegralConst() const
#endif // !_TARGET_64BIT_
}
+// Is this node an integer constant that fits in a 32-bit signed integer (INT32)
inline bool GenTree::IsIntCnsFitsInI32()
{
#ifdef _TARGET_64BIT_
- return IsCnsIntOrI() && ((int)gtIntConCommon.IconValue() == gtIntConCommon.IconValue());
+ return IsCnsIntOrI() && AsIntCon()->FitsInI32();
#else // !_TARGET_64BIT_
return IsCnsIntOrI();
#endif // !_TARGET_64BIT_
diff --git a/src/jit/gtlist.h b/src/jit/gtlist.h
index 939f00c334..e249a75de7 100644
--- a/src/jit/gtlist.h
+++ b/src/jit/gtlist.h
@@ -50,14 +50,16 @@ GTNODE(NEG , GenTreeOp ,0,GTK_UNOP)
GTNODE(COPY , GenTreeCopyOrReload,0,GTK_UNOP) // Copies a variable from its current location to a register that satisfies
// code generation constraints. The child is the actual lclVar node.
GTNODE(RELOAD , GenTreeCopyOrReload,0,GTK_UNOP)
+#ifdef LEGACY_BACKEND
GTNODE(CHS , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR) // GT_CHS is actually unary -- op2 is ignored.
// Changing to unary presently causes problems, though -- take a little work to fix.
+#endif
GTNODE(ARR_LENGTH , GenTreeArrLen ,0,GTK_UNOP|GTK_EXOP) // array-length
GTNODE(INTRINSIC , GenTreeIntrinsic ,0,GTK_BINOP|GTK_EXOP) // intrinsics
-GTNODE(LOCKADD , GenTreeOp ,0,GTK_BINOP|GTK_NOVALUE)
+GTNODE(LOCKADD , GenTreeOp ,0,GTK_BINOP)
GTNODE(XADD , GenTreeOp ,0,GTK_BINOP)
GTNODE(XCHG , GenTreeOp ,0,GTK_BINOP)
GTNODE(CMPXCHG , GenTreeCmpXchg ,0,GTK_SPECIAL)
@@ -99,6 +101,8 @@ GTNODE(ALLOCOBJ , GenTreeAllocObj ,0,GTK_UNOP|GTK_EXOP) // objec
GTNODE(INIT_VAL , GenTreeOp ,0,GTK_UNOP) // Initialization value for an initBlk
+GTNODE(RUNTIMELOOKUP , GenTreeRuntimeLookup, 0,GTK_UNOP|GTK_EXOP) // Runtime handle lookup
+
//-----------------------------------------------------------------------------
// Binary operators (2 operands):
//-----------------------------------------------------------------------------
@@ -126,6 +130,9 @@ GTNODE(MULHI , GenTreeOp ,1,GTK_BINOP) // returns high bits
// the div into a MULHI + some adjustments. In codegen, we only use the
// results of the high register, and we drop the low results.
+#ifndef LEGACY_BACKEND
+GTNODE(ASG , GenTreeOp ,0,GTK_BINOP|GTK_NOTLIR)
+#else
GTNODE(ASG , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
GTNODE(ASG_ADD , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
GTNODE(ASG_SUB , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
@@ -142,7 +149,7 @@ GTNODE(ASG_AND , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
GTNODE(ASG_LSH , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
GTNODE(ASG_RSH , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
GTNODE(ASG_RSZ , GenTreeOp ,0,GTK_BINOP|GTK_ASGOP|GTK_NOTLIR)
-
+#endif
GTNODE(EQ , GenTreeOp ,0,GTK_BINOP|GTK_RELOP)
GTNODE(NE , GenTreeOp ,0,GTK_BINOP|GTK_RELOP)
GTNODE(LT , GenTreeOp ,0,GTK_BINOP|GTK_RELOP)
@@ -190,8 +197,6 @@ GTNODE(ADD_LO , GenTreeOp ,1,GTK_BINOP)
GTNODE(ADD_HI , GenTreeOp ,1,GTK_BINOP)
GTNODE(SUB_LO , GenTreeOp ,0,GTK_BINOP)
GTNODE(SUB_HI , GenTreeOp ,0,GTK_BINOP)
-GTNODE(DIV_HI , GenTreeOp ,0,GTK_BINOP)
-GTNODE(MOD_HI , GenTreeOp ,0,GTK_BINOP)
// A mul that returns the 2N bit result of an NxN multiply. This op is used for
// multiplies that take two ints and return a long result. All other multiplies
@@ -219,6 +224,10 @@ GTNODE(RSH_LO , GenTreeOp ,0,GTK_BINOP)
GTNODE(SIMD , GenTreeSIMD ,0,GTK_BINOP|GTK_EXOP) // SIMD functions/operators/intrinsics
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+GTNODE(HWIntrinsic , GenTreeHWIntrinsic ,0,GTK_BINOP|GTK_EXOP) // hardware intrinsics
+#endif // FEATURE_HW_INTRINSICS
+
//-----------------------------------------------------------------------------
// LIR specific compare and conditional branch/set nodes:
//-----------------------------------------------------------------------------
diff --git a/src/jit/gtstructs.h b/src/jit/gtstructs.h
index 853ccebe9f..1277ac5b0d 100644
--- a/src/jit/gtstructs.h
+++ b/src/jit/gtstructs.h
@@ -104,14 +104,14 @@ GTSTRUCT_1(PhysReg , GT_PHYSREG)
#ifdef FEATURE_SIMD
GTSTRUCT_1(SIMD , GT_SIMD)
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+GTSTRUCT_1(HWIntrinsic , GT_HWIntrinsic)
+#endif // FEATURE_HW_INTRINSICS
GTSTRUCT_1(AllocObj , GT_ALLOCOBJ)
+GTSTRUCT_1(RuntimeLookup, GT_RUNTIMELOOKUP)
GTSTRUCT_2(CC , GT_JCC, GT_SETCC)
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
-#ifdef ARM_SOFTFP
GTSTRUCT_3(MultiRegOp , GT_MUL_LONG, GT_PUTARG_REG, GT_BITCAST)
-#else
-GTSTRUCT_1(MultiRegOp , GT_MUL_LONG)
-#endif
#endif
/*****************************************************************************/
#undef GTSTRUCT_0
diff --git a/src/jit/hashbv.cpp b/src/jit/hashbv.cpp
index fa06ec7b1e..db8dda1a7b 100644
--- a/src/jit/hashbv.cpp
+++ b/src/jit/hashbv.cpp
@@ -549,7 +549,6 @@ void hashBv::Resize(int newSize)
int oldSizeLog2 = log2_hashSize;
int log2_newSize = genLog2((unsigned)newSize);
- int size;
hashBvNode** newNodes = this->getNewVector(newSize);
diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp
new file mode 100644
index 0000000000..763647e7bf
--- /dev/null
+++ b/src/jit/hwintrinsiccodegenxarch.cpp
@@ -0,0 +1,220 @@
+// 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 Intel hardware intrinsic Code Generator XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+#include "jitpch.h"
+#ifdef _MSC_VER
+#pragma hdrstop
+#endif
+
+#if FEATURE_HW_INTRINSICS
+
+#include "emit.h"
+#include "codegen.h"
+#include "sideeffects.h"
+#include "lower.h"
+#include "gcinfo.h"
+#include "gcinfoencoder.h"
+
+void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
+ InstructionSet isa = compiler->isaOfHWIntrinsic(intrinsicID);
+ switch (isa)
+ {
+ case InstructionSet_SSE:
+ genSSEIntrinsic(node);
+ break;
+ case InstructionSet_SSE2:
+ genSSE2Intrinsic(node);
+ break;
+ case InstructionSet_SSE3:
+ genSSE3Intrinsic(node);
+ break;
+ case InstructionSet_SSSE3:
+ genSSSE3Intrinsic(node);
+ break;
+ case InstructionSet_SSE41:
+ genSSE41Intrinsic(node);
+ break;
+ case InstructionSet_SSE42:
+ genSSE42Intrinsic(node);
+ break;
+ case InstructionSet_AVX:
+ genAVXIntrinsic(node);
+ break;
+ case InstructionSet_AVX2:
+ genAVX2Intrinsic(node);
+ break;
+ case InstructionSet_AES:
+ genAESIntrinsic(node);
+ break;
+ case InstructionSet_BMI1:
+ genBMI1Intrinsic(node);
+ break;
+ case InstructionSet_BMI2:
+ genBMI2Intrinsic(node);
+ break;
+ case InstructionSet_FMA:
+ genFMAIntrinsic(node);
+ break;
+ case InstructionSet_LZCNT:
+ genLZCNTIntrinsic(node);
+ break;
+ case InstructionSet_PCLMULQDQ:
+ genPCLMULQDQIntrinsic(node);
+ break;
+ case InstructionSet_POPCNT:
+ genPOPCNTIntrinsic(node);
+ break;
+ default:
+ unreached();
+ break;
+ }
+}
+
+void CodeGen::genSSEIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement SSE intrinsic code generation");
+}
+
+void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement SSE2 intrinsic code generation");
+}
+
+void CodeGen::genSSE3Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement SSE3 intrinsic code generation");
+}
+
+void CodeGen::genSSSE3Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement SSSE3 intrinsic code generation");
+}
+
+void CodeGen::genSSE41Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement SSE41 intrinsic code generation");
+}
+
+void CodeGen::genSSE42Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
+ GenTree* op1 = node->gtGetOp1();
+ GenTree* op2 = node->gtGetOp2();
+ regNumber targetReg = node->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+ var_types baseType = node->gtSIMDBaseType;
+
+ regNumber op1Reg = op1->gtRegNum;
+ regNumber op2Reg = op2->gtRegNum;
+ genConsumeOperands(node);
+
+ switch (intrinsicID)
+ {
+ case NI_SSE42_Crc32:
+ if (op1Reg != targetReg)
+ {
+ inst_RV_RV(INS_mov, targetReg, op1Reg, targetType, emitTypeSize(targetType));
+ }
+
+ if (baseType == TYP_UBYTE || baseType == TYP_CHAR) // baseType is the type of the second argument
+ {
+ assert(targetType == TYP_INT);
+ inst_RV_RV(INS_crc32, targetReg, op2Reg, baseType, emitTypeSize(baseType));
+ }
+ else
+ {
+ assert(op1->TypeGet() == op2->TypeGet());
+ assert(targetType == TYP_INT || targetType == TYP_LONG);
+ inst_RV_RV(INS_crc32, targetReg, op2Reg, targetType, emitTypeSize(targetType));
+ }
+
+ break;
+ default:
+ unreached();
+ break;
+ }
+ genProduceReg(node);
+}
+
+void CodeGen::genAVXIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement AVX intrinsic code generation");
+}
+
+void CodeGen::genAVX2Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement AVX2 intrinsic code generation");
+}
+
+void CodeGen::genAESIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement AES intrinsic code generation");
+}
+
+void CodeGen::genBMI1Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement BMI1 intrinsic code generation");
+}
+
+void CodeGen::genBMI2Intrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement BMI2 intrinsic code generation");
+}
+
+void CodeGen::genFMAIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement FMA intrinsic code generation");
+}
+
+void CodeGen::genLZCNTIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
+ GenTree* op1 = node->gtGetOp1();
+ regNumber targetReg = node->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+ regNumber op1Reg = op1->gtRegNum;
+ genConsumeOperands(node);
+
+ assert(intrinsicID == NI_LZCNT_LeadingZeroCount);
+
+ inst_RV_RV(INS_lzcnt, targetReg, op1Reg, targetType, emitTypeSize(targetType));
+
+ genProduceReg(node);
+}
+
+void CodeGen::genPCLMULQDQIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NYI("Implement PCLMULQDQ intrinsic code generation");
+}
+
+void CodeGen::genPOPCNTIntrinsic(GenTreeHWIntrinsic* node)
+{
+ NamedIntrinsic intrinsicID = node->gtHWIntrinsicId;
+ GenTree* op1 = node->gtGetOp1();
+ regNumber targetReg = node->gtRegNum;
+ assert(targetReg != REG_NA);
+ var_types targetType = node->TypeGet();
+ regNumber op1Reg = op1->gtRegNum;
+ genConsumeOperands(node);
+
+ assert(intrinsicID == NI_POPCNT_PopCount);
+
+ inst_RV_RV(INS_popcnt, targetReg, op1Reg, targetType, emitTypeSize(targetType));
+
+ genProduceReg(node);
+}
+
+#endif // FEATURE_HW_INTRINSICS
diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h
index d066d10289..7db3e5c78f 100644
--- a/src/jit/hwintrinsiclistxarch.h
+++ b/src/jit/hwintrinsiclistxarch.h
@@ -10,7 +10,7 @@
// clang-format off
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
// Intrinsic ID Function name ISA
// SSE Intrinsics
HARDWARE_INTRINSIC(SSE_IsSupported, "get_IsSupported", SSE)
@@ -29,6 +29,7 @@ HARDWARE_INTRINSIC(SSE41_IsSupported, "get_IsSupported",
// SSE42 Intrinsics
HARDWARE_INTRINSIC(SSE42_IsSupported, "get_IsSupported", SSE42)
+HARDWARE_INTRINSIC(SSE42_Crc32, "Crc32", SSE42)
// AVX Intrinsics
HARDWARE_INTRINSIC(AVX_IsSupported, "get_IsSupported", AVX)
@@ -50,13 +51,15 @@ HARDWARE_INTRINSIC(FMA_IsSupported, "get_IsSupported",
// LZCNT Intrinsics
HARDWARE_INTRINSIC(LZCNT_IsSupported, "get_IsSupported", LZCNT)
+HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT)
// PCLMULQDQ Intrinsics
HARDWARE_INTRINSIC(PCLMULQDQ_IsSupported, "get_IsSupported", PCLMULQDQ)
// POPCNT Intrinsics
HARDWARE_INTRINSIC(POPCNT_IsSupported, "get_IsSupported", POPCNT)
-#endif
+HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT)
+#endif // FEATURE_HW_INTRINSICS
#undef HARDWARE_INTRINSIC
diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp
index 45ee468174..15888c98c8 100644
--- a/src/jit/hwintrinsicxarch.cpp
+++ b/src/jit/hwintrinsicxarch.cpp
@@ -4,7 +4,7 @@
#include "jitpch.h"
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
struct HWIntrinsicInfo
{
@@ -18,6 +18,11 @@ static const hwIntrinsicInfoArray[] = {
#include "hwintrinsiclistxarch.h"
};
+extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic)
+{
+ return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].intrinsicName;
+}
+
//------------------------------------------------------------------------
// lookupHWIntrinsicISA: map class name to InstructionSet value
//
@@ -162,6 +167,14 @@ InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
InstructionSet isa = isaOfHWIntrinsic(intrinsic);
+ if (!compSupports(isa) && strcmp("get_IsSupported", getHWIntrinsicName(intrinsic)) != 0)
+ {
+ for (unsigned i = 0; i < sig->numArgs; i++)
+ {
+ impPopStack();
+ }
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType));
+ }
switch (isa)
{
case InstructionSet_SSE:
@@ -262,14 +275,45 @@ GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HA
GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
+ GenTree* retNode = nullptr;
+ GenTree* op1 = nullptr;
+ GenTree* op2 = nullptr;
+ var_types callType = JITtype2varType(sig->retType);
+
+ CORINFO_ARG_LIST_HANDLE argLst = sig->args;
+ CORINFO_CLASS_HANDLE argClass;
+ CorInfoType corType;
switch (intrinsic)
{
case NI_SSE42_IsSupported:
- return gtNewIconNode(compSupports(InstructionSet_SSE42));
+ retNode = gtNewIconNode(compSupports(InstructionSet_SSE42));
+ break;
+
+ case NI_SSE42_Crc32:
+ assert(sig->numArgs == 2);
+ op2 = impPopStack().val;
+ op1 = impPopStack().val;
+#ifdef _TARGET_X86_
+ if (varTypeIsLong(callType))
+ {
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
+ }
+#endif
+ argLst = info.compCompHnd->getArgNext(argLst); // the second argument
+ corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
+
+ retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
+
+ // TODO - currently we use the BaseType to bring the type of the second argument
+ // to the code generator. May encode the overload info in other way.
+ retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType);
+ break;
default:
- return nullptr;
+ JITDUMP("Not implemented hardware intrinsic");
+ break;
}
+ return retNode;
}
GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
@@ -346,14 +390,33 @@ GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HAND
GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
+ GenTree* retNode = nullptr;
+ GenTree* op1 = nullptr;
+ var_types callType = JITtype2varType(sig->retType);
+
switch (intrinsic)
{
case NI_LZCNT_IsSupported:
- return gtNewIconNode(compSupports(InstructionSet_LZCNT));
+ retNode = gtNewIconNode(compSupports(InstructionSet_LZCNT));
+ break;
+
+ case NI_LZCNT_LeadingZeroCount:
+ assert(sig->numArgs == 1);
+ op1 = impPopStack().val;
+#ifdef _TARGET_X86_
+ if (varTypeIsLong(callType))
+ {
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
+ }
+#endif
+ retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_LZCNT_LeadingZeroCount);
+ break;
default:
- return nullptr;
+ JITDUMP("Not implemented hardware intrinsic");
+ break;
}
+ return retNode;
}
GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
@@ -370,14 +433,33 @@ GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHO
GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
{
+ GenTree* retNode = nullptr;
+ GenTree* op1 = nullptr;
+ var_types callType = JITtype2varType(sig->retType);
+
switch (intrinsic)
{
case NI_POPCNT_IsSupported:
- return gtNewIconNode(compSupports(InstructionSet_POPCNT));
+ retNode = gtNewIconNode(compSupports(InstructionSet_POPCNT));
+ break;
+
+ case NI_POPCNT_PopCount:
+ assert(sig->numArgs == 1);
+ op1 = impPopStack().val;
+#ifdef _TARGET_X86_
+ if (varTypeIsLong(callType))
+ {
+ return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
+ }
+#endif
+ retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_POPCNT_PopCount);
+ break;
default:
- return nullptr;
+ JITDUMP("Not implemented hardware intrinsic");
+ break;
}
+ return retNode;
}
-#endif // _TARGET_XARCH_ \ No newline at end of file
+#endif // FEATURE_HW_INTRINSICS
diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
index 714e6fe21f..b5df87b0ec 100644
--- a/src/jit/importer.cpp
+++ b/src/jit/importer.cpp
@@ -876,7 +876,6 @@ GenTreeArgList* Compiler::impPopList(unsigned count, CORINFO_SIG_INFO* sig, GenT
CORINFO_CLASS_HANDLE argClass;
CORINFO_CLASS_HANDLE argRealClass;
GenTreeArgList* args;
- unsigned sigSize;
for (args = treeList, count = sig->numArgs; count > 0; args = args->Rest(), count--)
{
@@ -1742,8 +1741,17 @@ GenTreePtr Compiler::impTokenToHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
}
- return impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token),
- embedInfo.compileTimeHandle);
+ // Generate the full lookup tree. May be null if we're abandoning an inline attempt.
+ GenTree* result = impLookupToTree(pResolvedToken, &embedInfo.lookup, gtTokenToIconFlags(pResolvedToken->token),
+ embedInfo.compileTimeHandle);
+
+ // If we have a result and it requires runtime lookup, wrap it in a runtime lookup node.
+ if ((result != nullptr) && embedInfo.lookup.lookupKind.needsRuntimeLookup)
+ {
+ result = gtNewRuntimeLookup(embedInfo.compileTimeHandle, embedInfo.handleType, result);
+ }
+
+ return result;
}
GenTreePtr Compiler::impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
@@ -1768,7 +1776,7 @@ GenTreePtr Compiler::impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
{
pIndirection = pLookup->constLookup.addr;
}
- return gtNewIconEmbHndNode(handle, pIndirection, handleFlags, 0, nullptr, compileTimeHandle);
+ return gtNewIconEmbHndNode(handle, pIndirection, handleFlags, compileTimeHandle);
}
else if (compIsForInlining())
{
@@ -1803,7 +1811,7 @@ GenTreePtr Compiler::impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup,
{
pIndirection = pLookup->addr;
}
- return gtNewIconEmbHndNode(handle, pIndirection, handleFlags, 0, nullptr, compileTimeHandle);
+ return gtNewIconEmbHndNode(handle, pIndirection, handleFlags, compileTimeHandle);
}
GenTreeCall* Compiler::impReadyToRunHelperToTree(
@@ -1948,10 +1956,9 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedTok
gtNewArgList(ctxTree), &pLookup->lookupKind);
}
#endif
-
- GenTreeArgList* helperArgs =
- gtNewArgList(ctxTree, gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, 0,
- nullptr, compileTimeHandle));
+ GenTree* argNode =
+ gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
+ GenTreeArgList* helperArgs = gtNewArgList(ctxTree, argNode);
return gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
}
@@ -2052,10 +2059,10 @@ GenTreePtr Compiler::impRuntimeLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedTok
nullptr DEBUGARG("impRuntimeLookup typehandle"));
// Call to helper
- GenTreeArgList* helperArgs =
- gtNewArgList(ctxTree, gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, 0, nullptr,
- compileTimeHandle));
- GenTreePtr helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
+ GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_TOKEN_HDL, compileTimeHandle);
+
+ GenTreeArgList* helperArgs = gtNewArgList(ctxTree, argNode);
+ GenTreePtr helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, helperArgs);
// Check for null and possibly call helper
GenTreePtr relop = gtNewOperNode(GT_NE, TYP_INT, handle, gtNewIconNode(0, TYP_I_IMPL));
@@ -2587,9 +2594,9 @@ inline IL_OFFSETX Compiler::impCurILOffset(IL_OFFSET offs, bool callInstruction)
// true if it is legal, false if it could be a sequence that we do not want to divide.
bool Compiler::impCanSpillNow(OPCODE prevOpcode)
{
- // Don't spill after ldtoken, because it could be a part of the InitializeArray sequence.
+ // Don't spill after ldtoken, newarr and newobj, because it could be a part of the InitializeArray sequence.
// Avoid breaking up to guarantee that impInitializeArrayIntrinsic can succeed.
- return prevOpcode != CEE_LDTOKEN;
+ return (prevOpcode != CEE_LDTOKEN) && (prevOpcode != CEE_NEWARR) && (prevOpcode != CEE_NEWOBJ);
}
/*****************************************************************************
@@ -3260,10 +3267,9 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
dataOffset = eeGetArrayDataOffset(elementType);
}
- GenTreePtr dst = gtNewOperNode(GT_ADD, TYP_BYREF, arrayLocalNode, gtNewIconNode(dataOffset, TYP_I_IMPL));
- GenTreePtr blk = gtNewBlockVal(dst, blkSize);
- GenTreePtr srcAddr = gtNewIconHandleNode((size_t)initData, GTF_ICON_STATIC_HDL);
- GenTreePtr src = gtNewOperNode(GT_IND, TYP_STRUCT, srcAddr);
+ GenTreePtr dst = gtNewOperNode(GT_ADD, TYP_BYREF, arrayLocalNode, gtNewIconNode(dataOffset, TYP_I_IMPL));
+ GenTreePtr blk = gtNewBlockVal(dst, blkSize);
+ GenTreePtr src = gtNewIndOfIconHandleNode(TYP_STRUCT, (size_t)initData, GTF_ICON_STATIC_HDL, false);
return gtNewBlkOpNode(blk, // dst
src, // src
@@ -3272,34 +3278,85 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO* sig)
true); // copyBlock
}
-/*****************************************************************************/
-// Returns the GenTree that should be used to do the intrinsic instead of the call.
-// Returns NULL if an intrinsic cannot be used
-
-GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
- CORINFO_CLASS_HANDLE clsHnd,
- CORINFO_METHOD_HANDLE method,
- CORINFO_SIG_INFO* sig,
- int memberRef,
- bool readonlyCall,
- bool tailCall,
- bool isJitIntrinsic,
- CorInfoIntrinsics* pIntrinsicID,
- bool* isSpecialIntrinsic)
+//------------------------------------------------------------------------
+// impIntrinsic: possibly expand intrinsic call into alternate IR sequence
+//
+// Arguments:
+// newobjThis - for constructor calls, the tree for the newly allocated object
+// clsHnd - handle for the intrinsic method's class
+// method - handle for the intrinsic method
+// sig - signature of the intrinsic method
+// methodFlags - CORINFO_FLG_XXX flags of the intrinsic method
+// memberRef - the token for the intrinsic method
+// readonlyCall - true if call has a readonly prefix
+// tailCall - true if call is in tail position
+// pConstrainedResolvedToken -- resolved token for constrained call, or nullptr
+// if call is not constrained
+// constraintCallThisTransform -- this transform to apply for a constrained call
+// pIntrinsicID [OUT] -- intrinsic ID (see enumeration in corinfo.h)
+// for "traditional" jit intrinsics
+// isSpecialIntrinsic [OUT] -- set true if intrinsic expansion is a call
+// that is amenable to special downstream optimization opportunities
+//
+// Returns:
+// IR tree to use in place of the call, or nullptr if the jit should treat
+// the intrinsic call like a normal call.
+//
+// pIntrinsicID set to non-illegal value if the call is recognized as a
+// traditional jit intrinsic, even if the intrinsic is not expaned.
+//
+// isSpecial set true if the expansion is subject to special
+// optimizations later in the jit processing
+//
+// Notes:
+// On success the IR tree may be a call to a different method or an inline
+// sequence. If it is a call, then the intrinsic processing here is responsible
+// for handling all the special cases, as upon return to impImportCall
+// expanded intrinsics bypass most of the normal call processing.
+//
+// Intrinsics are generally not recognized in minopts and debug codegen.
+//
+// However, certain traditional intrinsics are identifed as "must expand"
+// if there is no fallback implmentation to invoke; these must be handled
+// in all codegen modes.
+//
+// New style intrinsics (where the fallback implementation is in IL) are
+// identified as "must expand" if they are invoked from within their
+// own method bodies.
+//
+
+GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
+ CORINFO_CLASS_HANDLE clsHnd,
+ CORINFO_METHOD_HANDLE method,
+ CORINFO_SIG_INFO* sig,
+ unsigned methodFlags,
+ int memberRef,
+ bool readonlyCall,
+ bool tailCall,
+ CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken,
+ CORINFO_THIS_TRANSFORM constraintCallThisTransform,
+ CorInfoIntrinsics* pIntrinsicID,
+ bool* isSpecialIntrinsic)
{
+ assert((methodFlags & (CORINFO_FLG_INTRINSIC | CORINFO_FLG_JIT_INTRINSIC)) != 0);
+
bool mustExpand = false;
bool isSpecial = false;
- CorInfoIntrinsics intrinsicID = info.compCompHnd->getIntrinsicID(method, &mustExpand);
- *pIntrinsicID = intrinsicID;
+ CorInfoIntrinsics intrinsicID = CORINFO_INTRINSIC_Illegal;
+
+ if ((methodFlags & CORINFO_FLG_INTRINSIC) != 0)
+ {
+ intrinsicID = info.compCompHnd->getIntrinsicID(method, &mustExpand);
+ }
- // Jit intrinsics are always optional to expand, and won't have an
- // Intrinsic ID.
- if (isJitIntrinsic)
+ if ((methodFlags & CORINFO_FLG_JIT_INTRINSIC) != 0)
{
- assert(!mustExpand);
- assert(intrinsicID == CORINFO_INTRINSIC_Illegal);
+ // The recursive calls to Jit intrinsics are must-expand by convention.
+ mustExpand = mustExpand || gtIsRecursiveCall(method);
}
+ *pIntrinsicID = intrinsicID;
+
#ifndef _TARGET_ARM_
genTreeOps interlockedOperator;
#endif
@@ -3321,21 +3378,13 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
GenTreePtr retNode = nullptr;
- //
- // We disable the inlining of intrinsic for MinOpts,
- // but we should always expand hardware intrinsics whose managed method body
- // is a directly recursive call site. This design makes hardware intrinsic
- // be able to work with debugger and reflection.
- if (!mustExpand && (opts.compDbgCode || opts.MinOpts()) && !gtIsRecursiveCall(method))
+ // Under debug and minopts, only expand what is required.
+ if (!mustExpand && (opts.compDbgCode || opts.MinOpts()))
{
*pIntrinsicID = CORINFO_INTRINSIC_Illegal;
return retNode;
}
- // Currently we don't have CORINFO_INTRINSIC_Exp because it does not
- // seem to work properly for Infinity values, we don't do
- // CORINFO_INTRINSIC_Pow because it needs a Helper which we currently don't have
-
var_types callType = JITtype2varType(sig->retType);
/* First do the intrinsics which are always smaller than a call */
@@ -3365,7 +3414,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
retNode = impMathIntrinsic(method, sig, callType, intrinsicID, tailCall);
break;
-#ifdef _TARGET_XARCH_
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
// TODO-ARM-CQ: reenable treating Interlocked operation as intrinsic
case CORINFO_INTRINSIC_InterlockedAdd32:
interlockedOperator = GT_LOCKADD;
@@ -3377,7 +3426,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
interlockedOperator = GT_XCHG;
goto InterlockedBinOpCommon;
-#ifdef _TARGET_AMD64_
+#ifdef _TARGET_64BIT_
case CORINFO_INTRINSIC_InterlockedAdd64:
interlockedOperator = GT_LOCKADD;
goto InterlockedBinOpCommon;
@@ -3410,7 +3459,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
op1->gtFlags |= GTF_GLOB_REF | GTF_ASG;
retNode = op1;
break;
-#endif // _TARGET_XARCH_
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
case CORINFO_INTRINSIC_MemoryBarrier:
@@ -3421,10 +3470,10 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
retNode = op1;
break;
-#ifdef _TARGET_XARCH_
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
// TODO-ARM-CQ: reenable treating InterlockedCmpXchg32 operation as intrinsic
case CORINFO_INTRINSIC_InterlockedCmpXchg32:
-#ifdef _TARGET_AMD64_
+#ifdef _TARGET_64BIT_
case CORINFO_INTRINSIC_InterlockedCmpXchg64:
#endif
{
@@ -3442,7 +3491,7 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
retNode = node;
break;
}
-#endif
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
case CORINFO_INTRINSIC_StringLength:
op1 = impPopStack().val;
@@ -3525,45 +3574,74 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
#ifndef LEGACY_BACKEND
case CORINFO_INTRINSIC_Object_GetType:
{
- op1 = impPopStack().val;
+ JITDUMP("\n impIntrinsic: call to Object.GetType\n");
+ op1 = impStackTop(0).val;
// If we're calling GetType on a boxed value, just get the type directly.
- if (!opts.MinOpts() && !opts.compDbgCode)
+ if (op1->IsBoxedValue())
{
- if (op1->IsBoxedValue())
+ JITDUMP("Attempting to optimize box(...).getType() to direct type construction\n");
+
+ // Try and clean up the box. Obtain the handle we
+ // were going to pass to the newobj.
+ GenTree* boxTypeHandle = gtTryRemoveBoxUpstreamEffects(op1, BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE);
+
+ if (boxTypeHandle != nullptr)
{
-#ifdef DEBUG
- JITDUMP("Attempting to optimize box(...).getType() to direct type construction\n");
-#endif
+ // Note we don't need to play the TYP_STRUCT games here like
+ // do for LDTOKEN since the return value of this operator is Type,
+ // not RuntimeTypeHandle.
+ impPopStack();
+ GenTreeArgList* helperArgs = gtNewArgList(boxTypeHandle);
+ GenTree* runtimeType =
+ gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
+ retNode = runtimeType;
+ }
+ }
- // Try and clean up the box. Obtain the handle we
- // were going to pass to the newobj.
- GenTree* boxTypeHandle = gtTryRemoveBoxUpstreamEffects(op1, BR_REMOVE_AND_NARROW_WANT_TYPE_HANDLE);
+ // If we have a constrained callvirt with a "box this" transform
+ // we know we have a value class and hence an exact type.
+ //
+ // If so, instead of boxing and then extracting the type, just
+ // construct the type directly.
+ if ((retNode == nullptr) && (pConstrainedResolvedToken != nullptr) &&
+ (constraintCallThisTransform == CORINFO_BOX_THIS))
+ {
+ // Ensure this is one of the is simple box cases (in particular, rule out nullables).
+ const CorInfoHelpFunc boxHelper = info.compCompHnd->getBoxHelper(pConstrainedResolvedToken->hClass);
+ const bool isSafeToOptimize = (boxHelper == CORINFO_HELP_BOX);
- if (boxTypeHandle != nullptr)
- {
- // Note we don't need to play the TYP_STRUCT games here like
- // do for LDTOKEN since the return value of this operator is Type,
- // not RuntimeTypeHandle.
- GenTreeArgList* helperArgs = gtNewArgList(boxTypeHandle);
- GenTree* runtimeType =
- gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
- retNode = runtimeType;
+ if (isSafeToOptimize)
+ {
+ JITDUMP("Optimizing constrained box-this obj.getType() to direct type construction\n");
+ impPopStack();
+ GenTree* typeHandleOp =
+ impTokenToHandle(pConstrainedResolvedToken, nullptr, TRUE /* mustRestoreHandle */);
+ GenTreeArgList* helperArgs = gtNewArgList(typeHandleOp);
+ GenTree* runtimeType =
+ gtNewHelperCallNode(CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE, TYP_REF, helperArgs);
+ retNode = runtimeType;
+ }
+ }
#ifdef DEBUG
- JITDUMP("Optimized; result is\n");
- if (verbose)
- {
- gtDispTree(retNode);
- }
-#endif
- }
+ if (retNode != nullptr)
+ {
+ JITDUMP("Optimized result for call to GetType is\n");
+ if (verbose)
+ {
+ gtDispTree(retNode);
}
}
+#endif
- // Else expand as an intrinsic
- if (retNode == nullptr)
+ // Else expand as an intrinsic, unless the call is constrained,
+ // in which case we defer expansion to allow impImportCall do the
+ // special constraint processing.
+ if ((retNode == nullptr) && (pConstrainedResolvedToken == nullptr))
{
+ JITDUMP("Expanding as special intrinsic\n");
+ impPopStack();
op1 = new (this, GT_INTRINSIC) GenTreeIntrinsic(genActualType(callType), op1, intrinsicID, method);
// Set the CALL flag to indicate that the operator is implemented by a call.
@@ -3571,11 +3649,20 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
// CORINFO_INTRINSIC_Object_GetType intrinsic can throw NullReferenceException.
op1->gtFlags |= (GTF_CALL | GTF_EXCEPT);
retNode = op1;
- // Might be further optimizable during morph
+ // Might be further optimizable, so arrange to leave a mark behind
+ isSpecial = true;
+ }
+
+ if (retNode == nullptr)
+ {
+ JITDUMP("Leaving as normal call\n");
+ // Might be further optimizable, so arrange to leave a mark behind
isSpecial = true;
}
+
break;
}
+
#endif
// Implement ByReference Ctor. This wraps the assignment of the ref into a byref-like field
// in a value type. The canonical example of this is Span<T>. In effect this is just a
@@ -3719,6 +3806,33 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
case CORINFO_INTRINSIC_TypeEQ:
case CORINFO_INTRINSIC_TypeNEQ:
+ {
+ JITDUMP("Importing Type.op_*Equality intrinsic\n");
+ op1 = impStackTop(1).val;
+ op2 = impStackTop(0).val;
+ GenTree* optTree = gtFoldTypeEqualityCall(intrinsicID, op1, op2);
+ if (optTree != nullptr)
+ {
+ // Success, clean up the evaluation stack.
+ impPopStack();
+ impPopStack();
+
+ // See if we can optimize even further, to a handle compare.
+ optTree = gtFoldTypeCompare(optTree);
+
+ // See if we can now fold a handle compare to a constant.
+ optTree = gtFoldExpr(optTree);
+
+ retNode = optTree;
+ }
+ else
+ {
+ // Retry optimizing these later
+ isSpecial = true;
+ }
+ break;
+ }
+
case CORINFO_INTRINSIC_GetCurrentManagedThread:
case CORINFO_INTRINSIC_GetManagedThreadId:
{
@@ -3729,20 +3843,21 @@ GenTreePtr Compiler::impIntrinsic(GenTreePtr newobjThis,
default:
/* Unknown intrinsic */
+ intrinsicID = CORINFO_INTRINSIC_Illegal;
break;
}
// Look for new-style jit intrinsics by name
- if (isJitIntrinsic)
+ if ((intrinsicID == CORINFO_INTRINSIC_Illegal) && ((methodFlags & CORINFO_FLG_JIT_INTRINSIC) != 0))
{
assert(retNode == nullptr);
const NamedIntrinsic ni = lookupNamedIntrinsic(method);
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
if (ni > NI_HW_INTRINSIC_START && ni < NI_HW_INTRINSIC_END)
{
- retNode = impX86HWIntrinsic(ni, method, sig);
+ return impX86HWIntrinsic(ni, method, sig);
}
-#endif
+#endif // FEATURE_HW_INTRINSICS
switch (ni)
{
case NI_System_Enum_HasFlag:
@@ -3965,13 +4080,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method)
}
}
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
if ((namespaceName != nullptr) && strcmp(namespaceName, "System.Runtime.Intrinsics.X86") == 0)
{
InstructionSet isa = lookupHWIntrinsicISA(className);
result = lookupHWIntrinsic(methodName, isa);
}
-#endif
+#endif // FEATURE_HW_INTRINSICS
return result;
}
@@ -5655,7 +5770,6 @@ void Compiler::impImportNewObjArray(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORI
if (!opts.IsReadyToRun() || IsTargetAbi(CORINFO_CORERT_ABI))
{
- LclVarDsc* newObjArrayArgsVar;
// Reuse the temp used to pass the array dimensions to avoid bloating
// the stack frame in case there are multiple calls to multi-dim array
@@ -6753,6 +6867,9 @@ bool Compiler::impIsImplicitTailCallCandidate(
//
// Returns:
// Type of the call's return value.
+// If we're importing an inlinee and have realized the inline must fail, the call return type should be TYP_UNDEF.
+// However we can't assert for this here yet because there are cases we miss. See issue #13272.
+//
//
// Notes:
// opcode can be CEE_CALL, CEE_CALLI, CEE_CALLVIRT, or CEE_NEWOBJ.
@@ -6918,7 +7035,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (impInlineInfo->inlineCandidateInfo->dwRestrictions & INLINE_RESPECT_BOUNDARY)
{
compInlineResult->NoteFatal(InlineObservation::CALLSITE_CROSS_BOUNDARY_SECURITY);
- return callRetTyp;
+ return TYP_UNDEF;
}
/* Does the inlinee need a security check token on the frame */
@@ -6926,7 +7043,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (mflags & CORINFO_FLG_SECURITYCHECK)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_NEEDS_SECURITY_CHECK);
- return callRetTyp;
+ return TYP_UNDEF;
}
/* Does the inlinee use StackCrawlMark */
@@ -6934,7 +7051,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (mflags & CORINFO_FLG_DONT_INLINE_CALLER)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_STACK_CRAWL_MARK);
- return callRetTyp;
+ return TYP_UNDEF;
}
/* For now ignore delegate invoke */
@@ -6942,26 +7059,26 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (mflags & CORINFO_FLG_DELEGATE_INVOKE)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_HAS_DELEGATE_INVOKE);
- return callRetTyp;
+ return TYP_UNDEF;
}
/* For now ignore varargs */
if ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_NATIVEVARARG)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_HAS_NATIVE_VARARGS);
- return callRetTyp;
+ return TYP_UNDEF;
}
if ((sig->callConv & CORINFO_CALLCONV_MASK) == CORINFO_CALLCONV_VARARG)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_HAS_MANAGED_VARARGS);
- return callRetTyp;
+ return TYP_UNDEF;
}
if ((mflags & CORINFO_FLG_VIRTUAL) && (sig->sigInst.methInstCount != 0) && (opcode == CEE_CALLVIRT))
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_IS_GENERIC_VIRTUAL);
- return callRetTyp;
+ return TYP_UNDEF;
}
}
@@ -6986,17 +7103,17 @@ var_types Compiler::impImportCall(OPCODE opcode,
#endif // DEBUG
// <NICE> Factor this into getCallInfo </NICE>
- const bool isIntrinsic = (mflags & CORINFO_FLG_INTRINSIC) != 0;
- const bool isJitIntrinsic = (mflags & CORINFO_FLG_JIT_INTRINSIC) != 0;
- bool isSpecialIntrinsic = false;
- if ((isIntrinsic || isJitIntrinsic) && !pConstrainedResolvedToken)
+ bool isSpecialIntrinsic = false;
+ if ((mflags & (CORINFO_FLG_INTRINSIC | CORINFO_FLG_JIT_INTRINSIC)) != 0)
{
- call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, pResolvedToken->token, readonlyCall,
- (canTailCall && (tailCall != 0)), isJitIntrinsic, &intrinsicID, &isSpecialIntrinsic);
+ const bool isTail = canTailCall && (tailCall != 0);
+
+ call = impIntrinsic(newobjThis, clsHnd, methHnd, sig, mflags, pResolvedToken->token, readonlyCall, isTail,
+ pConstrainedResolvedToken, callInfo->thisTransform, &intrinsicID, &isSpecialIntrinsic);
- if (compIsForInlining() && compInlineResult->IsFailure())
+ if (compDonotInline())
{
- return callRetTyp;
+ return TYP_UNDEF;
}
if (call != nullptr)
@@ -7095,7 +7212,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
* failing here.
*/
compInlineResult->NoteFatal(InlineObservation::CALLSITE_HAS_COMPLEX_HANDLE);
- return callRetTyp;
+ return TYP_UNDEF;
}
GenTreePtr stubAddr = impRuntimeLookupToTree(pResolvedToken, &callInfo->stubLookup, methHnd);
@@ -7171,7 +7288,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (compIsForInlining())
{
compInlineResult->NoteFatal(InlineObservation::CALLSITE_HAS_CALL_VIA_LDVIRTFTN);
- return callRetTyp;
+ return TYP_UNDEF;
}
assert(!(mflags & CORINFO_FLG_STATIC)); // can't call a static method
@@ -7183,10 +7300,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
GenTreePtr thisPtr = impPopStack().val;
thisPtr = impTransformThis(thisPtr, pConstrainedResolvedToken, callInfo->thisTransform);
- if (compDonotInline())
- {
- return callRetTyp;
- }
+ assert(thisPtr != nullptr);
// Clone the (possibly transformed) "this" pointer
GenTreePtr thisPtrCopy;
@@ -7194,11 +7308,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
nullptr DEBUGARG("LDVIRTFTN this pointer"));
GenTreePtr fptr = impImportLdvirtftn(thisPtr, pResolvedToken, callInfo);
-
- if (compDonotInline())
- {
- return callRetTyp;
- }
+ assert(fptr != nullptr);
thisPtr = nullptr; // can't reuse it
@@ -7273,7 +7383,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (compDonotInline())
{
- return callRetTyp;
+ return TYP_UNDEF;
}
// Now make an indirect call through the function pointer
@@ -7463,7 +7573,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
// Because inlinee method does not have its own frame.
compInlineResult->NoteFatal(InlineObservation::CALLEE_NEEDS_SECURITY_CHECK);
- return callRetTyp;
+ return TYP_UNDEF;
}
else
{
@@ -7526,7 +7636,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
IMPL_LIMITATION("Can't get PInvoke cookie (cross module generics)");
}
- return callRetTyp;
+ return TYP_UNDEF;
}
GenTreePtr cookie = eeGetPInvokeCookie(sig);
@@ -7571,12 +7681,12 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (!info.compCompHnd->canGetVarArgsHandle(sig))
{
compInlineResult->NoteFatal(InlineObservation::CALLSITE_CANT_EMBED_VARARGS_COOKIE);
- return callRetTyp;
+ return TYP_UNDEF;
}
varCookie = info.compCompHnd->getVarArgsHandle(sig, &pVarCookie);
assert((!varCookie) != (!pVarCookie));
- GenTreePtr cookie = gtNewIconEmbHndNode(varCookie, pVarCookie, GTF_ICON_VARG_HDL);
+ GenTreePtr cookie = gtNewIconEmbHndNode(varCookie, pVarCookie, GTF_ICON_VARG_HDL, sig);
assert(extraArg == nullptr);
extraArg = gtNewArgList(cookie);
@@ -7627,7 +7737,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_METHOD_HDL, exactMethodHandle);
if (instParam == nullptr)
{
- return callRetTyp;
+ assert(compDonotInline());
+ return TYP_UNDEF;
}
}
else
@@ -7642,7 +7753,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
instParam = impTokenToHandle(pResolvedToken, &runtimeLookup, TRUE /*mustRestoreHandle*/);
if (instParam == nullptr)
{
- return callRetTyp;
+ assert(compDonotInline());
+ return TYP_UNDEF;
}
}
}
@@ -7658,7 +7770,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (compIsForInlining() && (clsFlags & CORINFO_FLG_ARRAY) != 0)
{
compInlineResult->NoteFatal(InlineObservation::CALLEE_IS_ARRAY_METHOD);
- return callRetTyp;
+ return TYP_UNDEF;
}
if ((clsFlags & CORINFO_FLG_ARRAY) && readonlyCall)
@@ -7676,7 +7788,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
impReadyToRunLookupToTree(&callInfo->instParamLookup, GTF_ICON_CLASS_HDL, exactClassHandle);
if (instParam == nullptr)
{
- return callRetTyp;
+ assert(compDonotInline());
+ return TYP_UNDEF;
}
}
else
@@ -7703,7 +7816,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (instParam == nullptr)
{
- return callRetTyp;
+ assert(compDonotInline());
+ return TYP_UNDEF;
}
}
}
@@ -7765,7 +7879,7 @@ var_types Compiler::impImportCall(OPCODE opcode,
obj = impTransformThis(obj, pConstrainedResolvedToken, constraintCallThisTransform);
if (compDonotInline())
{
- return callRetTyp;
+ return TYP_UNDEF;
}
}
@@ -9643,6 +9757,99 @@ var_types Compiler::impGetByRefResultType(genTreeOps oper, bool fUnsigned, GenTr
}
//------------------------------------------------------------------------
+// impOptimizeCastClassOrIsInst: attempt to resolve a cast when jitting
+//
+// Arguments:
+// op1 - value to cast
+// pResolvedToken - resolved token for type to cast to
+// isCastClass - true if this is a castclass, false if isinst
+//
+// Return Value:
+// tree representing optimized cast, or null if no optimization possible
+
+GenTree* Compiler::impOptimizeCastClassOrIsInst(GenTree* op1, CORINFO_RESOLVED_TOKEN* pResolvedToken, bool isCastClass)
+{
+ assert(op1->TypeGet() == TYP_REF);
+
+ // Don't optimize for minopts or debug codegen.
+ if (opts.compDbgCode || opts.MinOpts())
+ {
+ return nullptr;
+ }
+
+ // See what we know about the type of the object being cast.
+ bool isExact = false;
+ bool isNonNull = false;
+ CORINFO_CLASS_HANDLE fromClass = gtGetClassHandle(op1, &isExact, &isNonNull);
+ GenTree* optResult = nullptr;
+
+ if (fromClass != nullptr)
+ {
+ CORINFO_CLASS_HANDLE toClass = pResolvedToken->hClass;
+ JITDUMP("\nConsidering optimization of %s from %s%p (%s) to %p (%s)\n", isCastClass ? "castclass" : "isinst",
+ isExact ? "exact " : "", fromClass, info.compCompHnd->getClassName(fromClass), toClass,
+ info.compCompHnd->getClassName(toClass));
+
+ // Perhaps we know if the cast will succeed or fail.
+ TypeCompareState castResult = info.compCompHnd->compareTypesForCast(fromClass, toClass);
+
+ if (castResult == TypeCompareState::Must)
+ {
+ // Cast will succeed, result is simply op1.
+ JITDUMP("Cast will succeed, optimizing to simply return input\n");
+ return op1;
+ }
+ else if (castResult == TypeCompareState::MustNot)
+ {
+ // See if we can sharpen exactness by looking for final classes
+ if (!isExact)
+ {
+ DWORD flags = info.compCompHnd->getClassAttribs(fromClass);
+ DWORD flagsMask = CORINFO_FLG_FINAL | CORINFO_FLG_MARSHAL_BYREF | CORINFO_FLG_CONTEXTFUL |
+ CORINFO_FLG_VARIANCE | CORINFO_FLG_ARRAY;
+ isExact = ((flags & flagsMask) == CORINFO_FLG_FINAL);
+ }
+
+ // Cast to exact type will fail. Handle case where we have
+ // an exact type (that is, fromClass is not a subtype)
+ // and we're not going to throw on failure.
+ if (isExact && !isCastClass)
+ {
+ JITDUMP("Cast will fail, optimizing to return null\n");
+ GenTree* result = gtNewIconNode(0, TYP_REF);
+
+ // If the cast was fed by a box, we can remove that too.
+ if (op1->IsBoxedValue())
+ {
+ JITDUMP("Also removing upstream box\n");
+ gtTryRemoveBoxUpstreamEffects(op1);
+ }
+
+ return result;
+ }
+ else if (isExact)
+ {
+ JITDUMP("Not optimizing failing castclass (yet)\n");
+ }
+ else
+ {
+ JITDUMP("Can't optimize since fromClass is inexact\n");
+ }
+ }
+ else
+ {
+ JITDUMP("Result of cast unknown, must generate runtime test\n");
+ }
+ }
+ else
+ {
+ JITDUMP("\nCan't optimize since fromClass is unknown\n");
+ }
+
+ return nullptr;
+}
+
+//------------------------------------------------------------------------
// impCastClassOrIsInstToTree: build and import castclass/isinst
//
// Arguments:
@@ -10145,7 +10352,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
int val;
CORINFO_SIG_INFO sig;
- unsigned flags;
IL_OFFSET jmpAddr;
bool ovfl, unordered, callNode;
bool ldstruct;
@@ -10810,8 +11016,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
BADCODE("Incompatible target for CEE_JMPs");
}
-#if defined(_TARGET_XARCH_) || defined(_TARGET_ARMARCH_)
-
op1 = new (this, GT_JMP) GenTreeVal(GT_JMP, TYP_VOID, (size_t)resolvedToken.hMethod);
/* Mark the basic block as being a JUMP instead of RETURN */
@@ -10827,44 +11031,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
goto APPEND;
-#else // !_TARGET_XARCH_ && !_TARGET_ARMARCH_
-
- // Import this just like a series of LDARGs + tail. + call + ret
-
- if (info.compIsVarArgs)
- {
- // For now we don't implement true tail calls, so this breaks varargs.
- // So warn the user instead of generating bad code.
- // This is a semi-temporary workaround for DevDiv 173860, until we can properly
- // implement true tail calls.
- IMPL_LIMITATION("varags + CEE_JMP doesn't work yet");
- }
-
- // First load up the arguments (0 - N)
- for (unsigned argNum = 0; argNum < info.compILargsCount; argNum++)
- {
- impLoadArg(argNum, opcodeOffs + sz + 1);
- }
-
- // Now generate the tail call
- noway_assert(prefixFlags == 0);
- prefixFlags = PREFIX_TAILCALL_EXPLICIT;
- opcode = CEE_CALL;
-
- eeGetCallInfo(&resolvedToken, NULL,
- combine(CORINFO_CALLINFO_ALLOWINSTPARAM, CORINFO_CALLINFO_SECURITYCHECKS), &callInfo);
-
- // All calls and delegates need a security callout.
- impHandleAccessAllowed(callInfo.accessAllowed, &callInfo.callsiteCalloutHelper);
-
- callTyp = impImportCall(CEE_CALL, &resolvedToken, NULL, NULL, PREFIX_TAILCALL_EXPLICIT, &callInfo,
- opcodeOffs);
-
- // And finish with the ret
- goto RET;
-
-#endif // _TARGET_XARCH_ || _TARGET_ARMARCH_
-
case CEE_LDELEMA:
assertImp(sz == sizeof(unsigned));
@@ -11197,6 +11363,8 @@ void Compiler::impImportBlockCode(BasicBlock* block)
Verify(tiArray.IsNullObjRef() || verGetArrayElemType(tiArray).IsType(TI_REF), "bad array");
}
+ STELEM_REF_POST_VERIFY:
+
arrayNodeTo = impStackTop(2).val;
arrayNodeToIndex = impStackTop(1).val;
arrayNodeFrom = impStackTop().val;
@@ -11208,28 +11376,25 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// Check for assignment to same array, ie. arrLcl[i] = arrLcl[j]
// This does not need CORINFO_HELP_ARRADDR_ST
-
if (arrayNodeFrom->OperGet() == GT_INDEX && arrayNodeFrom->gtOp.gtOp1->gtOper == GT_LCL_VAR &&
arrayNodeTo->gtOper == GT_LCL_VAR &&
arrayNodeTo->gtLclVarCommon.gtLclNum == arrayNodeFrom->gtOp.gtOp1->gtLclVarCommon.gtLclNum &&
!lvaTable[arrayNodeTo->gtLclVarCommon.gtLclNum].lvAddrExposed)
{
+ JITDUMP("\nstelem of ref from same array: skipping covariant store check\n");
lclTyp = TYP_REF;
goto ARR_ST_POST_VERIFY;
}
// Check for assignment of NULL. This does not need CORINFO_HELP_ARRADDR_ST
-
if (arrayNodeFrom->OperGet() == GT_CNS_INT)
{
+ JITDUMP("\nstelem of null: skipping covariant store check\n");
assert(arrayNodeFrom->gtType == TYP_REF && arrayNodeFrom->gtIntCon.gtIconVal == 0);
-
lclTyp = TYP_REF;
goto ARR_ST_POST_VERIFY;
}
- STELEM_REF_POST_VERIFY:
-
/* Call a helper function to do the assignment */
op1 = gtNewHelperCallNode(CORINFO_HELP_ARRADDR_ST, TYP_VOID, impPopList(3, nullptr));
@@ -12364,9 +12529,10 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// If the expression to dup is simple, just clone it.
// Otherwise spill it to a temp, and reload the temp
// twice.
- StackEntry se = impPopStack();
- tiRetVal = se.seTypeInfo;
- op1 = se.val;
+ StackEntry se = impPopStack();
+ GenTree* tree = se.val;
+ tiRetVal = se.seTypeInfo;
+ op1 = tree;
if (!opts.compDbgCode && !op1->IsIntegralConst(0) && !op1->IsFPZero() && !op1->IsLocal())
{
@@ -12375,10 +12541,10 @@ void Compiler::impImportBlockCode(BasicBlock* block)
var_types type = genActualType(lvaTable[tmpNum].TypeGet());
op1 = gtNewLclvNode(tmpNum, type);
- // Propagate type info to the temp
+ // Propagate type info to the temp from the stack and the original tree
if (type == TYP_REF)
{
- lvaSetClass(tmpNum, op1, tiRetVal.GetClassHandle());
+ lvaSetClass(tmpNum, tree, tiRetVal.GetClassHandle());
}
}
@@ -13277,6 +13443,9 @@ void Compiler::impImportBlockCode(BasicBlock* block)
newObjThisPtr, prefixFlags, &callInfo, opcodeOffs);
if (compDonotInline())
{
+ // We do not check fails after lvaGrabTemp. It is covered with CoreCLR_13272 issue.
+ assert((callTyp == TYP_UNDEF) ||
+ (compInlineResult->GetObservation() == InlineObservation::CALLSITE_TOO_MANY_LOCALS));
return;
}
@@ -14110,8 +14279,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
break;
case CEE_LOCALLOC:
- assert(!compIsForInlining());
-
if (tiVerificationNeeded)
{
Verify(false, "bad opcode");
@@ -14123,11 +14290,6 @@ void Compiler::impImportBlockCode(BasicBlock* block)
BADCODE("Localloc can't be inside handler");
}
- /* The FP register may not be back to the original value at the end
- of the method, even if the frame size is 0, as localloc may
- have modified it. So we will HAVE to reset it */
-
- compLocallocUsed = true;
setNeedsGSSecurityCookie();
// Get the size to allocate
@@ -14140,17 +14302,87 @@ void Compiler::impImportBlockCode(BasicBlock* block)
BADCODE("Localloc can only be used when the stack is empty");
}
- op1 = gtNewOperNode(GT_LCLHEAP, TYP_I_IMPL, op2);
+ // If the localloc is not in a loop and its size is a small constant,
+ // create a new local var of TYP_BLK and return its address.
+ {
+ bool convertedToLocal = false;
+
+ // Need to aggressively fold here, as even fixed-size locallocs
+ // will have casts in the way.
+ op2 = gtFoldExpr(op2);
+
+ if (op2->IsIntegralConst())
+ {
+ const ssize_t allocSize = op2->AsIntCon()->IconValue();
+
+ if (allocSize == 0)
+ {
+ // Result is nullptr
+ JITDUMP("Converting stackalloc of 0 bytes to push null unmanaged pointer\n");
+ op1 = gtNewIconNode(0, TYP_I_IMPL);
+ convertedToLocal = true;
+ }
+ else if ((allocSize > 0) && ((compCurBB->bbFlags & BBF_BACKWARD_JUMP) == 0))
+ {
+ // Get the size threshold for local conversion
+ ssize_t maxSize = DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE;
+
+#ifdef DEBUG
+ // Optionally allow this to be modified
+ maxSize = JitConfig.JitStackAllocToLocalSize();
+#endif // DEBUG
+
+ if (allocSize <= maxSize)
+ {
+ const unsigned stackallocAsLocal = lvaGrabTemp(false DEBUGARG("stackallocLocal"));
+ JITDUMP("Converting stackalloc of %lld bytes to new local V%02u\n", allocSize,
+ stackallocAsLocal);
+ lvaTable[stackallocAsLocal].lvType = TYP_BLK;
+ lvaTable[stackallocAsLocal].lvExactSize = (unsigned)allocSize;
+ lvaTable[stackallocAsLocal].lvIsUnsafeBuffer = true;
+ op1 = gtNewLclvNode(stackallocAsLocal, TYP_BLK);
+ op1 = gtNewOperNode(GT_ADDR, TYP_I_IMPL, op1);
+ convertedToLocal = true;
+ compGSReorderStackLayout = true;
+ }
+ }
+ }
+
+ if (!convertedToLocal)
+ {
+ // Bail out if inlining and the localloc was not converted.
+ //
+ // Note we might consider allowing the inline, if the call
+ // site is not in a loop.
+ if (compIsForInlining())
+ {
+ InlineObservation obs = op2->IsIntegralConst()
+ ? InlineObservation::CALLEE_LOCALLOC_TOO_LARGE
+ : InlineObservation::CALLSITE_LOCALLOC_SIZE_UNKNOWN;
+ compInlineResult->NoteFatal(obs);
+ return;
+ }
- // May throw a stack overflow exception. Obviously, we don't want locallocs to be CSE'd.
+ op1 = gtNewOperNode(GT_LCLHEAP, TYP_I_IMPL, op2);
+ // May throw a stack overflow exception. Obviously, we don't want locallocs to be CSE'd.
+ op1->gtFlags |= (GTF_EXCEPT | GTF_DONT_CSE);
- op1->gtFlags |= (GTF_EXCEPT | GTF_DONT_CSE);
+ /* The FP register may not be back to the original value at the end
+ of the method, even if the frame size is 0, as localloc may
+ have modified it. So we will HAVE to reset it */
+ compLocallocUsed = true;
+ }
+ else
+ {
+ compLocallocOptimized = true;
+ }
+ }
impPushOnStack(op1, tiRetVal);
break;
case CEE_ISINST:
-
+ {
/* Get the type token */
assertImp(sz == sizeof(unsigned));
@@ -14179,45 +14411,56 @@ void Compiler::impImportBlockCode(BasicBlock* block)
op1 = impPopStack().val;
-#ifdef FEATURE_READYTORUN_COMPILER
- if (opts.IsReadyToRun())
+ GenTree* optTree = impOptimizeCastClassOrIsInst(op1, &resolvedToken, false);
+
+ if (optTree != nullptr)
+ {
+ impPushOnStack(optTree, tiRetVal);
+ }
+ else
{
- GenTreeCall* opLookup =
- impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_ISINSTANCEOF, TYP_REF,
- gtNewArgList(op1));
- usingReadyToRunHelper = (opLookup != nullptr);
- op1 = (usingReadyToRunHelper ? opLookup : op1);
- if (!usingReadyToRunHelper)
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (opts.IsReadyToRun())
{
- // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
- // and the isinstanceof_any call with a single call to a dynamic R2R cell that will:
- // 1) Load the context
- // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
- // 3) Perform the 'is instance' check on the input object
- // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
+ GenTreeCall* opLookup =
+ impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_ISINSTANCEOF, TYP_REF,
+ gtNewArgList(op1));
+ usingReadyToRunHelper = (opLookup != nullptr);
+ op1 = (usingReadyToRunHelper ? opLookup : op1);
- op2 = impTokenToHandle(&resolvedToken, nullptr, FALSE);
- if (op2 == nullptr)
- { // compDonotInline()
- return;
+ if (!usingReadyToRunHelper)
+ {
+ // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
+ // and the isinstanceof_any call with a single call to a dynamic R2R cell that will:
+ // 1) Load the context
+ // 2) Perform the generic dictionary lookup and caching, and generate the appropriate
+ // stub
+ // 3) Perform the 'is instance' check on the input object
+ // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
+
+ op2 = impTokenToHandle(&resolvedToken, nullptr, FALSE);
+ if (op2 == nullptr)
+ { // compDonotInline()
+ return;
+ }
}
}
- }
- if (!usingReadyToRunHelper)
+ if (!usingReadyToRunHelper)
#endif
- {
- op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, false);
- }
- if (compDonotInline())
- {
- return;
- }
-
- impPushOnStack(op1, tiRetVal);
+ {
+ op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, false);
+ }
+ if (compDonotInline())
+ {
+ return;
+ }
+ impPushOnStack(op1, tiRetVal);
+ }
break;
+ }
case CEE_REFANYVAL:
@@ -14627,20 +14870,21 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// Look ahead for unbox.any
if (codeAddr + (sz + 1 + sizeof(mdToken)) <= codeEndp && codeAddr[sz] == CEE_UNBOX_ANY)
{
- DWORD classAttribs = info.compCompHnd->getClassAttribs(resolvedToken.hClass);
- if (!(classAttribs & CORINFO_FLG_SHAREDINST))
- {
- CORINFO_RESOLVED_TOKEN unboxResolvedToken;
+ CORINFO_RESOLVED_TOKEN unboxResolvedToken;
- impResolveToken(codeAddr + (sz + 1), &unboxResolvedToken, CORINFO_TOKENKIND_Class);
+ impResolveToken(codeAddr + (sz + 1), &unboxResolvedToken, CORINFO_TOKENKIND_Class);
- if (unboxResolvedToken.hClass == resolvedToken.hClass)
- {
- JITDUMP("\n Importing BOX; UNBOX.ANY as NOP\n");
- // Skip the next unbox.any instruction
- sz += sizeof(mdToken) + 1;
- break;
- }
+ // See if the resolved tokens describe types that are equal.
+ const TypeCompareState compare =
+ info.compCompHnd->compareTypesForEquality(unboxResolvedToken.hClass, resolvedToken.hClass);
+
+ // If so, box/unbox.any is a nop.
+ if (compare == TypeCompareState::Must)
+ {
+ JITDUMP("\n Importing BOX; UNBOX.ANY as NOP\n");
+ // Skip the next unbox.any instruction
+ sz += sizeof(mdToken) + 1;
+ break;
}
}
@@ -14707,45 +14951,58 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// At this point we expect typeRef to contain the token, op1 to contain the value being cast,
// and op2 to contain code that creates the type handle corresponding to typeRef
CASTCLASS:
+ {
+ GenTree* optTree = impOptimizeCastClassOrIsInst(op1, &resolvedToken, true);
-#ifdef FEATURE_READYTORUN_COMPILER
- if (opts.IsReadyToRun())
+ if (optTree != nullptr)
+ {
+ impPushOnStack(optTree, tiRetVal);
+ }
+ else
{
- GenTreeCall* opLookup = impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_CHKCAST,
- TYP_REF, gtNewArgList(op1));
- usingReadyToRunHelper = (opLookup != nullptr);
- op1 = (usingReadyToRunHelper ? opLookup : op1);
- if (!usingReadyToRunHelper)
+#ifdef FEATURE_READYTORUN_COMPILER
+ if (opts.IsReadyToRun())
{
- // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
- // and the chkcastany call with a single call to a dynamic R2R cell that will:
- // 1) Load the context
- // 2) Perform the generic dictionary lookup and caching, and generate the appropriate stub
- // 3) Check the object on the stack for the type-cast
- // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
+ GenTreeCall* opLookup =
+ impReadyToRunHelperToTree(&resolvedToken, CORINFO_HELP_READYTORUN_CHKCAST, TYP_REF,
+ gtNewArgList(op1));
+ usingReadyToRunHelper = (opLookup != nullptr);
+ op1 = (usingReadyToRunHelper ? opLookup : op1);
- op2 = impTokenToHandle(&resolvedToken, nullptr, FALSE);
- if (op2 == nullptr)
- { // compDonotInline()
- return;
+ if (!usingReadyToRunHelper)
+ {
+ // TODO: ReadyToRun: When generic dictionary lookups are necessary, replace the lookup call
+ // and the chkcastany call with a single call to a dynamic R2R cell that will:
+ // 1) Load the context
+ // 2) Perform the generic dictionary lookup and caching, and generate the appropriate
+ // stub
+ // 3) Check the object on the stack for the type-cast
+ // Reason: performance (today, we'll always use the slow helper for the R2R generics case)
+
+ op2 = impTokenToHandle(&resolvedToken, nullptr, FALSE);
+ if (op2 == nullptr)
+ { // compDonotInline()
+ return;
+ }
}
}
- }
- if (!usingReadyToRunHelper)
+ if (!usingReadyToRunHelper)
#endif
- {
- op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, true);
- }
- if (compDonotInline())
- {
- return;
- }
+ {
+ op1 = impCastClassOrIsInstToTree(op1, op2, &resolvedToken, true);
+ }
+ if (compDonotInline())
+ {
+ return;
+ }
- /* Push the result back on the stack */
- impPushOnStack(op1, tiRetVal);
- break;
+ /* Push the result back on the stack */
+ impPushOnStack(op1, tiRetVal);
+ }
+ }
+ break;
case CEE_THROW:
@@ -18876,6 +19133,12 @@ bool Compiler::IsMathIntrinsic(GenTreePtr tree)
// code after inlining, if the return value of the inlined call is
// the 'this obj' of a subsequent virtual call.
//
+// If devirtualization succeeds and the call's this object is the
+// result of a box, the jit will ask the EE for the unboxed entry
+// point. If this exists, the jit will see if it can rework the box
+// to instead make a local copy. If that is doable, the call is
+// updated to invoke the unboxed entry on the local copy.
+//
void Compiler::impDevirtualizeCall(GenTreeCall* call,
CORINFO_METHOD_HANDLE* method,
unsigned* methodFlags,
@@ -19156,12 +19419,95 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
// stubs)
call->gtInlineCandidateInfo = nullptr;
+#if defined(DEBUG)
+ if (verbose)
+ {
+ printf("... after devirt...\n");
+ gtDispTree(call);
+ }
+
+ if (doPrint)
+ {
+ printf("Devirtualized %s call to %s:%s; now direct call to %s:%s [%s]\n", callKind, baseClassName,
+ baseMethodName, derivedClassName, derivedMethodName, note);
+ }
+#endif // defined(DEBUG)
+
+ // If the 'this' object is a box, see if we can find the unboxed entry point for the call.
+ if (thisObj->IsBoxedValue())
+ {
+ JITDUMP("Now have direct call to boxed entry point, looking for unboxed entry point\n");
+
+ // Note for some shared methods the unboxed entry point requires an extra parameter.
+ // We defer optimizing if so.
+ bool requiresInstMethodTableArg = false;
+ CORINFO_METHOD_HANDLE unboxedEntryMethod =
+ info.compCompHnd->getUnboxedEntry(derivedMethod, &requiresInstMethodTableArg);
+
+ if (unboxedEntryMethod != nullptr)
+ {
+ // Since the call is the only consumer of the box, we know the box can't escape
+ // since it is being passed an interior pointer.
+ //
+ // So, revise the box to simply create a local copy, use the address of that copy
+ // as the this pointer, and update the entry point to the unboxed entry.
+ //
+ // Ideally, we then inline the boxed method and and if it turns out not to modify
+ // the copy, we can undo the copy too.
+ if (requiresInstMethodTableArg)
+ {
+ // We can likely handle this case by grabbing the argument passed to
+ // the newobj in the box. But defer for now.
+ JITDUMP("Found unboxed entry point, but it needs method table arg, deferring\n");
+ }
+ else
+ {
+ JITDUMP("Found unboxed entry point, trying to simplify box to a local copy\n");
+ GenTree* localCopyThis = gtTryRemoveBoxUpstreamEffects(thisObj, BR_MAKE_LOCAL_COPY);
+
+ if (localCopyThis != nullptr)
+ {
+ JITDUMP("Success! invoking unboxed entry point on local copy\n");
+ call->gtCallObjp = localCopyThis;
+ call->gtCallMethHnd = unboxedEntryMethod;
+ derivedMethod = unboxedEntryMethod;
+ }
+ else
+ {
+ JITDUMP("Sorry, failed to undo the box\n");
+ }
+ }
+ }
+ else
+ {
+ // Many of the low-level methods on value classes won't have unboxed entries,
+ // as they need access to the type of the object.
+ //
+ // Note this may be a cue for us to stack allocate the boxed object, since
+ // we probably know that these objects don't escape.
+ JITDUMP("Sorry, failed to find unboxed entry point\n");
+ }
+ }
+
// Fetch the class that introduced the derived method.
//
// Note this may not equal objClass, if there is a
// final method that objClass inherits.
CORINFO_CLASS_HANDLE derivedClass = info.compCompHnd->getMethodClass(derivedMethod);
+ // Need to update call info too. This is fragile
+ // but hopefully the derived method conforms to
+ // the base in most other ways.
+ *method = derivedMethod;
+ *methodFlags = derivedMethodAttribs;
+ *contextHandle = MAKE_METHODCONTEXT(derivedMethod);
+
+ // Update context handle.
+ if ((exactContextHandle != nullptr) && (*exactContextHandle != nullptr))
+ {
+ *exactContextHandle = MAKE_METHODCONTEXT(derivedMethod);
+ }
+
#ifdef FEATURE_READYTORUN_COMPILER
if (opts.IsReadyToRun())
{
@@ -19188,33 +19534,6 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call,
call->setEntryPoint(derivedCallInfo.codePointerLookup.constLookup);
}
#endif // FEATURE_READYTORUN_COMPILER
-
- // Need to update call info too. This is fragile
- // but hopefully the derived method conforms to
- // the base in most other ways.
- *method = derivedMethod;
- *methodFlags = derivedMethodAttribs;
- *contextHandle = MAKE_METHODCONTEXT(derivedMethod);
-
- // Update context handle.
- if ((exactContextHandle != nullptr) && (*exactContextHandle != nullptr))
- {
- *exactContextHandle = MAKE_METHODCONTEXT(derivedMethod);
- }
-
-#if defined(DEBUG)
- if (verbose)
- {
- printf("... after devirt...\n");
- gtDispTree(call);
- }
-
- if (doPrint)
- {
- printf("Devirtualized %s call to %s:%s; now direct call to %s:%s [%s]\n", callKind, baseClassName,
- baseMethodName, derivedClassName, derivedMethodName, note);
- }
-#endif // defined(DEBUG)
}
//------------------------------------------------------------------------
@@ -19246,11 +19565,17 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(CORINFO_MET
assert(sig.sigInst.classInstCount == 1);
CORINFO_CLASS_HANDLE typeHnd = sig.sigInst.classInst[0];
assert(typeHnd != nullptr);
+
+ // Lookup can incorrect when we have __Canon as it won't appear
+ // to implement any interface types.
+ //
+ // And if we do not have a final type, devirt & inlining is
+ // unlikely to result in much simplification.
+ //
+ // We can use CORINFO_FLG_FINAL to screen out both of these cases.
const DWORD typeAttribs = info.compCompHnd->getClassAttribs(typeHnd);
const bool isFinalType = ((typeAttribs & CORINFO_FLG_FINAL) != 0);
- // If we do not have a final type, devirt & inlining is
- // unlikely to result in much simplification.
if (isFinalType)
{
result = info.compCompHnd->getDefaultEqualityComparerClass(typeHnd);
@@ -19289,3 +19614,74 @@ CORINFO_RESOLVED_TOKEN* Compiler::impAllocateToken(CORINFO_RESOLVED_TOKEN token)
*memory = token;
return memory;
}
+
+//------------------------------------------------------------------------
+// SpillRetExprHelper: iterate through arguments tree and spill ret_expr to local varibales.
+//
+class SpillRetExprHelper
+{
+public:
+ SpillRetExprHelper(Compiler* comp) : comp(comp)
+ {
+ }
+
+ void StoreRetExprResultsInArgs(GenTreeCall* call)
+ {
+ GenTreePtr args = call->gtCallArgs;
+ if (args != nullptr)
+ {
+ comp->fgWalkTreePre(&args, SpillRetExprVisitor, this);
+ }
+ GenTreePtr thisArg = call->gtCallObjp;
+ if (thisArg != nullptr)
+ {
+ comp->fgWalkTreePre(&thisArg, SpillRetExprVisitor, this);
+ }
+ }
+
+private:
+ static Compiler::fgWalkResult SpillRetExprVisitor(GenTree** pTree, Compiler::fgWalkData* fgWalkPre)
+ {
+ assert((pTree != nullptr) && (*pTree != nullptr));
+ GenTreePtr tree = *pTree;
+ if ((tree->gtFlags & GTF_CALL) == 0)
+ {
+ // Trees with ret_expr are marked as GTF_CALL.
+ return Compiler::WALK_SKIP_SUBTREES;
+ }
+ if (tree->OperGet() == GT_RET_EXPR)
+ {
+ SpillRetExprHelper* walker = static_cast<SpillRetExprHelper*>(fgWalkPre->pCallbackData);
+ walker->StoreRetExprAsLocalVar(pTree);
+ }
+ return Compiler::WALK_CONTINUE;
+ }
+
+ void StoreRetExprAsLocalVar(GenTreePtr* pRetExpr)
+ {
+ GenTreePtr retExpr = *pRetExpr;
+ assert(retExpr->OperGet() == GT_RET_EXPR);
+ JITDUMP("Store return expression %u as a local var.\n", retExpr->gtTreeID);
+ unsigned tmp = comp->lvaGrabTemp(true DEBUGARG("spilling ret_expr"));
+ comp->impAssignTempGen(tmp, retExpr, (unsigned)Compiler::CHECK_SPILL_NONE);
+ *pRetExpr = comp->gtNewLclvNode(tmp, retExpr->TypeGet());
+ }
+
+private:
+ Compiler* comp;
+};
+
+//------------------------------------------------------------------------
+// addFatPointerCandidate: mark the call and the method, that they have a fat pointer candidate.
+// Spill ret_expr in the call node, because they can't be cloned.
+//
+// Arguments:
+// call - fat calli candidate
+//
+void Compiler::addFatPointerCandidate(GenTreeCall* call)
+{
+ setMethodHasFatPointer();
+ call->SetFatPointerCandidate();
+ SpillRetExprHelper helper(this);
+ helper.StoreRetExprResultsInArgs(call);
+}
diff --git a/src/jit/inline.def b/src/jit/inline.def
index ff0b21100e..0a13950b48 100644
--- a/src/jit/inline.def
+++ b/src/jit/inline.def
@@ -48,6 +48,7 @@ INLINE_OBSERVATION(IS_SYNCHRONIZED, bool, "is synchronized",
INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLEE)
INLINE_OBSERVATION(LACKS_RETURN, bool, "no return opcode", FATAL, CALLEE)
INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLEE)
+INLINE_OBSERVATION(LOCALLOC_TOO_LARGE, bool, "localloc size too large", FATAL, CALLEE)
INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLEE)
INLINE_OBSERVATION(MARKED_AS_SKIPPED, bool, "skipped by complus request", FATAL, CALLEE)
INLINE_OBSERVATION(MAXSTACK_TOO_BIG, bool, "maxstack too big" , FATAL, CALLEE)
@@ -78,6 +79,7 @@ INLINE_OBSERVATION(CLASS_PROMOTABLE, bool, "promotable value class",
INLINE_OBSERVATION(DOES_NOT_RETURN, bool, "does not return", INFORMATION, CALLEE)
INLINE_OBSERVATION(END_OPCODE_SCAN, bool, "done looking at opcodes", INFORMATION, CALLEE)
INLINE_OBSERVATION(HAS_GC_STRUCT, bool, "has gc field in struct local", INFORMATION, CALLEE)
+INLINE_OBSERVATION(HAS_LOCALLOC, bool, "has localloc", INFORMATION, CALLEE)
INLINE_OBSERVATION(HAS_PINNED_LOCALS, bool, "has pinned locals", INFORMATION, CALLEE)
INLINE_OBSERVATION(HAS_SIMD, bool, "has SIMD arg, local, or ret", INFORMATION, CALLEE)
INLINE_OBSERVATION(HAS_SWITCH, bool, "has switch", INFORMATION, CALLEE)
@@ -143,6 +145,8 @@ INLINE_OBSERVATION(IS_WITHIN_FILTER, bool, "within filter region",
INLINE_OBSERVATION(LDARGA_NOT_LOCAL_VAR, bool, "ldarga not on local var", FATAL, CALLSITE)
INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLSITE)
INLINE_OBSERVATION(LDVIRTFN_ON_NON_VIRTUAL, bool, "ldvirtfn on non-virtual", FATAL, CALLSITE)
+INLINE_OBSERVATION(LOCALLOC_IN_LOOP, bool, "within loop, has localloc", FATAL, CALLSITE)
+INLINE_OBSERVATION(LOCALLOC_SIZE_UNKNOWN, bool, "localloc size unknown", FATAL, CALLSITE)
INLINE_OBSERVATION(LOG_REPLAY_REJECT, bool, "rejected by log replay", FATAL, CALLSITE)
INLINE_OBSERVATION(NOT_CANDIDATE, bool, "not inline candidate", FATAL, CALLSITE)
INLINE_OBSERVATION(NOT_PROFITABLE_INLINE, bool, "unprofitable inline", FATAL, CALLSITE)
@@ -164,7 +168,8 @@ INLINE_OBSERVATION(RARE_GC_STRUCT, bool, "rarely called, has gc str
INLINE_OBSERVATION(CONSTANT_ARG_FEEDS_TEST, bool, "constant argument feeds test", INFORMATION, CALLSITE)
INLINE_OBSERVATION(DEPTH, int, "depth", INFORMATION, CALLSITE)
INLINE_OBSERVATION(FREQUENCY, int, "rough call site frequency", INFORMATION, CALLSITE)
-INLINE_OBSERVATION(IN_TRY_REGION, bool, "call site in try region", INFORMATION, CALLSITE)
+INLINE_OBSERVATION(IN_LOOP, bool, "call site is in a loop", INFORMATION, CALLSITE)
+INLINE_OBSERVATION(IN_TRY_REGION, bool, "call site is in a try region", INFORMATION, CALLSITE)
INLINE_OBSERVATION(IS_PROFITABLE_INLINE, bool, "profitable inline", INFORMATION, CALLSITE)
INLINE_OBSERVATION(IS_SAME_THIS, bool, "same this as root caller", INFORMATION, CALLSITE)
INLINE_OBSERVATION(IS_SIZE_DECREASING_INLINE, bool, "size decreasing inline", INFORMATION, CALLSITE)
diff --git a/src/jit/inlinepolicy.cpp b/src/jit/inlinepolicy.cpp
index 61e70c3ed4..a4f51c9ee9 100644
--- a/src/jit/inlinepolicy.cpp
+++ b/src/jit/inlinepolicy.cpp
@@ -384,11 +384,20 @@ void LegacyPolicy::NoteBool(InlineObservation obs, bool value)
}
case InlineObservation::CALLEE_HAS_PINNED_LOCALS:
+ case InlineObservation::CALLEE_HAS_LOCALLOC:
// The legacy policy is to never inline methods with
- // pinned locals.
+ // pinned locals or localloc.
SetNever(obs);
break;
+ case InlineObservation::CALLSITE_IN_TRY_REGION:
+ m_CallsiteIsInTryRegion = true;
+ break;
+
+ case InlineObservation::CALLSITE_IN_LOOP:
+ m_CallsiteIsInLoop = true;
+ break;
+
default:
// Ignore the remainder for now
break;
@@ -900,6 +909,11 @@ void EnhancedLegacyPolicy::NoteBool(InlineObservation obs, bool value)
}
break;
+ case InlineObservation::CALLEE_HAS_LOCALLOC:
+ // We see this during the IL prescan. Ignore for now, we will
+ // bail out, if necessary, during importation
+ break;
+
default:
// Pass all other information to the legacy policy
LegacyPolicy::NoteBool(obs, value);
diff --git a/src/jit/inlinepolicy.h b/src/jit/inlinepolicy.h
index 3239dcbe89..2af99b580b 100644
--- a/src/jit/inlinepolicy.h
+++ b/src/jit/inlinepolicy.h
@@ -99,6 +99,7 @@ public:
, m_LooksLikeWrapperMethod(false)
, m_MethodIsMostlyLoadStore(false)
, m_CallsiteIsInTryRegion(false)
+ , m_CallsiteIsInLoop(false)
{
// empty
}
@@ -167,10 +168,11 @@ protected:
bool m_LooksLikeWrapperMethod : 1;
bool m_MethodIsMostlyLoadStore : 1;
bool m_CallsiteIsInTryRegion : 1;
+ bool m_CallsiteIsInLoop : 1;
};
-// EnhancedLegacyPolicy extends the legacy policy by rejecting
-// inlining of methods that never return because they throw.
+// EnhancedLegacyPolicy extends the legacy policy by
+// relaxing various restrictions.
class EnhancedLegacyPolicy : public LegacyPolicy
{
diff --git a/src/jit/instr.cpp b/src/jit/instr.cpp
index e9b001cc4a..f83bd45719 100644
--- a/src/jit/instr.cpp
+++ b/src/jit/instr.cpp
@@ -440,7 +440,7 @@ void CodeGen::inst_RV_RV_RV(instruction ins,
{
#ifdef _TARGET_ARM_
getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3, flags);
-#elif defined(_TARGET_XARCH_) && defined(FEATURE_AVX_SUPPORT)
+#elif defined(_TARGET_XARCH_)
getEmitter()->emitIns_R_R_R(ins, size, reg1, reg2, reg3);
#else
NYI("inst_RV_RV_RV");
@@ -1214,35 +1214,17 @@ void CodeGen::sched_AM(instruction ins,
assert(baseReg != REG_NA);
reg = baseReg;
-#ifdef LATE_DISASM
- /*
- Keep in mind that non-static data members (GT_FIELD nodes) were
- transformed into GT_IND nodes - we keep the CLS/CPX information
- in the GT_CNS_INT node representing the field offset of the
- class member
- */
-
- if (addr->gtOper != GT_LEA && (addr->gtOp.gtOp2->gtOper == GT_CNS_INT) &&
- addr->gtOp.gtOp2->IsIconHandle(GTF_ICON_FIELD_HDL))
- {
- /* This is a field offset - set the CPX/CLS values to emit a fixup */
-
- cpx = addr->gtOp.gtOp2->gtIntCon.gtIconFld.gtIconCPX;
- cls = addr->gtOp.gtOp2->gtIntCon.gtIconFld.gtIconCls;
- }
-#endif
-
if (cons)
{
- getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs, cpx, cls);
+ getEmitter()->emitIns_I_AR(ins, size, imm, reg, offs);
}
else if (rdst)
{
- getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs, cpx, cls);
+ getEmitter()->emitIns_R_AR(ins, size, ireg, reg, offs);
}
else
{
- getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs, cpx, cls);
+ getEmitter()->emitIns_AR_R(ins, size, ireg, reg, offs);
}
}
}
@@ -1888,18 +1870,13 @@ AGAIN:
}
}
+#ifdef LEGACY_BACKEND
regNumber CodeGen::genGetZeroRegister()
{
- regNumber zeroReg = REG_NA;
-
-#if REDUNDANT_LOAD
-
// Is the constant already in some register?
- zeroReg = regTracker.rsIconIsInReg(0);
-#endif
+ regNumber zeroReg = regTracker.rsIconIsInReg(0);
-#ifdef LEGACY_BACKEND
if (zeroReg == REG_NA)
{
regMaskTP freeMask = regSet.rsRegMaskFree();
@@ -1924,7 +1901,6 @@ regNumber CodeGen::genGetZeroRegister()
genSetRegToIcon(zeroReg, 0, TYP_INT);
}
}
-#endif // !LEGACY_BACKEND
return zeroReg;
}
@@ -1934,7 +1910,6 @@ regNumber CodeGen::genGetZeroRegister()
* Generate an instruction that has one operand given by a tree (which has
* been made addressable) and another that is an integer constant.
*/
-#ifdef LEGACY_BACKEND
void CodeGen::inst_TT_IV(instruction ins, GenTreePtr tree, ssize_t val, unsigned offs, emitAttr size, insFlags flags)
{
bool sizeInferred = false;
@@ -2265,9 +2240,7 @@ AGAIN:
assert(!"invalid address");
}
}
-#endif // LEGACY_BACKEND
-#ifdef LEGACY_BACKEND
/*****************************************************************************
*
* Generate an instruction that has one operand given by a register and the
@@ -3310,6 +3283,8 @@ instruction CodeGenInterface::ins_Load(var_types srcType, bool aligned /*=false*
// latter.
return (aligned) ? INS_movaps : INS_movups;
}
+#elif defined(_TARGET_ARM64_)
+ return INS_ldr;
#else
assert(!"ins_Load with SIMD type");
#endif
@@ -3585,19 +3560,24 @@ instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
switch (oper)
{
case GT_ADD:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
return type == TYP_DOUBLE ? INS_addsd : INS_addss;
- break;
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
return type == TYP_DOUBLE ? INS_subsd : INS_subss;
- break;
case GT_MUL:
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
+#endif
return type == TYP_DOUBLE ? INS_mulsd : INS_mulss;
- break;
case GT_DIV:
+#ifdef LEGACY_BACKEND
case GT_ASG_DIV:
+#endif
return type == TYP_DOUBLE ? INS_divsd : INS_divss;
case GT_AND:
return type == TYP_DOUBLE ? INS_andpd : INS_andps;
@@ -3759,19 +3739,25 @@ instruction CodeGen::ins_MathOp(genTreeOps oper, var_types type)
switch (oper)
{
case GT_ADD:
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
return INS_vadd;
- break;
case GT_SUB:
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
return INS_vsub;
- break;
case GT_MUL:
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
+#endif
return INS_vmul;
break;
case GT_DIV:
+#ifdef LEGACY_BACKEND
case GT_ASG_DIV:
+#endif
return INS_vdiv;
case GT_NEG:
return INS_vneg;
diff --git a/src/jit/instr.h b/src/jit/instr.h
index eac425634c..ec58f61458 100644
--- a/src/jit/instr.h
+++ b/src/jit/instr.h
@@ -277,23 +277,19 @@ enum emitAttr : unsigned
enum InstructionSet
{
#ifdef _TARGET_XARCH_
- // Linear order start
InstructionSet_ILLEGAL = 0,
+ // Start linear order SIMD instruction sets
+ // These ISAs have strictly generation to generation order.
InstructionSet_SSE = 1,
InstructionSet_SSE2 = 2,
InstructionSet_SSE3 = 3,
InstructionSet_SSSE3 = 4,
InstructionSet_SSE41 = 5,
InstructionSet_SSE42 = 6,
- InstructionSet_SSE3_4 = 7, // SSE3, SSSE3, SSE4.1 and SSE4.2 instruction set
- InstructionSet_AVX = 8,
- InstructionSet_AVX2 = 9,
- // Linear order end
- // TODO - Instruction sets have the linear order only in above area.
- // We should no long compare the return value of getSIMDInstructionSet()
- // or getFloatingPointInstructionSet() to the InstructionSet values.
- // Should refactor SIMD code only to be aware of SIMD feature levels
- // (SSE2, SSE3_4, AVX, and AVX2, etc.) rather than concrete ISA.
+ InstructionSet_AVX = 7,
+ InstructionSet_AVX2 = 8,
+ // Reserve values <32 for future SIMD instruction sets (i.e., AVX512),
+ // End linear order SIMD instruction sets.
InstructionSet_AES = 32,
InstructionSet_BMI1 = 33,
diff --git a/src/jit/instrsarm64.h b/src/jit/instrsarm64.h
index d8c66b344c..433bde7f5f 100644
--- a/src/jit/instrsarm64.h
+++ b/src/jit/instrsarm64.h
@@ -225,6 +225,44 @@ INST4(neg, "neg", 0, 0, IF_EN4G, 0x4B0003E0, 0x4B0003E0, 0x2E20B800,
// neg Vd,Vn DV_2M 0Q101110XX100000 101110nnnnnddddd 2E20 B800 Vd,Vn (vector)
// neg Vd,Vn DV_2L 01111110XX100000 101110nnnnnddddd 7E20 B800 Vd,Vn (scalar)
+// enum name FP LD/ST DV_3E DV_3A DV_2L DV_2M
+INST4(cmeq, "cmeq", 0, 0, IF_EN4H, 0x7EE08C00, 0x2E208C00, 0x5E209800, 0x0E209800)
+ // cmeq Vd,Vn,Vm DV_3E 01111110111mmmmm 100011nnnnnddddd 7EE0 8C00 Vd,Vn,Vm (scalar)
+ // cmeq Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 100011nnnnnddddd 2E20 8C00 Vd,Vn,Vm (vector)
+ // cmeq Vd,Vn DV_2L 01011110XX100000 100110nnnnnddddd 5E20 9800 Vd,Vn (scalar)
+ // cmeq Vd,Vn DV_2M 0Q001110XX100000 100110nnnnnddddd 0E20 9800 Vd,Vn (vector)
+
+INST4(cmge, "cmge", 0, 0, IF_EN4H, 0x5EE03C00, 0x0E203C00, 0x7E208800, 0x2E208800)
+ // cmge Vd,Vn,Vm DV_3E 01011110111mmmmm 001111nnnnnddddd 5EE0 3C00 Vd,Vn,Vm (scalar)
+ // cmge Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001111nnnnnddddd 0E20 3C00 Vd,Vn,Vm (vector)
+ // cmge Vd,Vn DV_2L 01111110XX100000 100010nnnnnddddd 5E20 8800 Vd,Vn (scalar)
+ // cmge Vd,Vn DV_2M 0Q101110XX100000 100010nnnnnddddd 2E20 8800 Vd,Vn (vector)
+
+INST4(cmgt, "cmgt", 0, 0, IF_EN4H, 0x5EE03400, 0x0E203400, 0x5E208800, 0x0E208800)
+ // cmgt Vd,Vn,Vm DV_3E 01011110111mmmmm 001101nnnnnddddd 5EE0 3400 Vd,Vn,Vm (scalar)
+ // cmgt Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 001101nnnnnddddd 0E20 3400 Vd,Vn,Vm (vector)
+ // cmgt Vd,Vn DV_2L 01011110XX100000 100010nnnnnddddd 5E20 8800 Vd,Vn (scalar)
+ // cmgt Vd,Vn DV_2M 0Q001110XX100000 101110nnnnnddddd 0E20 8800 Vd,Vn (vector)
+
+// enum name FP LD/ST DV_3D DV_3B DV_2G DV_2A
+INST4(fcmeq, "fcmeq", 0, 0, IF_EN4I, 0x5E20E400, 0x0E20E400, 0x5EA0D800, 0x0EA0D800)
+ // fcmeq Vd,Vn,Vm DV_3D 010111100X1mmmmm 111001nnnnnddddd 5E20 E400 Vd Vn Vm (scalar)
+ // fcmeq Vd,Vn,Vm DV_3B 0Q0011100X1mmmmm 111001nnnnnddddd 0E20 E400 Vd,Vn,Vm (vector)
+ // fcmeq Vd,Vn DV_2G 010111101X100000 110110nnnnnddddd 5EA0 D800 Vd Vn (scalar)
+ // fcmeq Vd,Vn DV_2A 0Q0011101X100000 110110nnnnnddddd 0EA0 D800 Vd Vn (vector)
+
+INST4(fcmge, "fcmge", 0, 0, IF_EN4I, 0x7E20E400, 0x2E20E400, 0x7EA0C800, 0x2EA0C800)
+ // fcmge Vd,Vn,Vm DV_3D 011111100X1mmmmm 111001nnnnnddddd 7E20 E400 Vd Vn Vm (scalar)
+ // fcmge Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 111001nnnnnddddd 2E20 E400 Vd,Vn,Vm (vector)
+ // fcmge Vd,Vn DV_2G 011111101X100000 110010nnnnnddddd 7EA0 E800 Vd Vn (scalar)
+ // fcmge Vd,Vn DV_2A 0Q1011101X100000 110010nnnnnddddd 2EA0 C800 Vd Vn (vector)
+
+INST4(fcmgt, "fcmgt", 0, 0, IF_EN4I, 0x7EA0E400, 0x2EA0E400, 0x5EA0C800, 0x0EA0C800)
+ // fcmgt Vd,Vn,Vm DV_3D 011111101X1mmmmm 111001nnnnnddddd 7EA0 E400 Vd Vn Vm (scalar)
+ // fcmgt Vd,Vn,Vm DV_3B 0Q1011101X1mmmmm 111001nnnnnddddd 2EA0 E400 Vd,Vn,Vm (vector)
+ // fcmgt Vd,Vn DV_2G 010111101X100000 110010nnnnnddddd 5EA0 E800 Vd Vn (scalar)
+ // fcmgt Vd,Vn DV_2A 0Q0011101X100000 110010nnnnnddddd 0EA0 C800 Vd Vn (vector)
+
// enum name FP LD/ST DR_3A DR_3B DI_2C
INST3(ands, "ands", 0, 0, IF_EN3A, 0x6A000000, 0x6A000000, 0x72000000)
// ands Rd,Rn,Rm DR_3A X1101010000mmmmm 000000nnnnnddddd 6A00 0000
@@ -244,7 +282,7 @@ INST3(orn, "orn", 0, 0, IF_EN3C, 0x2A200000, 0x2A200000, 0x0EE01C00)
// orn Vd,Vn,Vm DV_3C 0Q001110111mmmmm 000111nnnnnddddd 0EE0 1C00 Vd,Vn,Vm
// enum name FP LD/ST DV_2C DV_2D DV_2E
-INST3(dup, "dup", 0, 0, IF_EN3D, 0x0E000C00, 0x0E004000, 0x5E000400)
+INST3(dup, "dup", 0, 0, IF_EN3D, 0x0E000C00, 0x0E000400, 0x5E000400)
// dup Vd,Rn DV_2C 0Q001110000iiiii 000011nnnnnddddd 0E00 0C00 Vd,Rn (vector from general)
// dup Vd,Vn[] DV_2D 0Q001110000iiiii 000001nnnnnddddd 0E00 0400 Vd,Vn[] (vector by elem)
// dup Vd,Vn[] DV_2E 01011110000iiiii 000001nnnnnddddd 5E00 0400 Vd,Vn[] (scalar by elem)
@@ -439,6 +477,14 @@ INST2(fabs, "fabs", 0, 0, IF_EN2J, 0x0EA0F800, 0x1E20C000)
// fabs Vd,Vn DV_2A 0Q0011101X100000 111110nnnnnddddd 0EA0 F800 Vd,Vn (vector)
// fabs Vd,Vn DV_2G 000111100X100000 110000nnnnnddddd 1E20 C000 Vd,Vn (scalar)
+INST2(fcmle, "fcmle", 0, 0, IF_EN2J, 0x2EA0D800, 0x7EA0D800)
+ // fcmle Vd,Vn DV_2A 0Q1011101X100000 111110nnnnnddddd 2EA0 D800 Vd,Vn (vector)
+ // fcmle Vd,Vn DV_2G 011111101X100000 110110nnnnnddddd 7EA0 D800 Vd,Vn (scalar)
+
+INST2(fcmlt, "fcmlt", 0, 0, IF_EN2J, 0x0EA0E800, 0x5EA0E800)
+ // fcmlt Vd,Vn DV_2A 0Q0011101X100000 111110nnnnnddddd 0EA0 E800 Vd,Vn (vector)
+ // fcmlt Vd,Vn DV_2G 010111101X100000 111010nnnnnddddd 5EA0 E800 Vd,Vn (scalar)
+
INST2(fneg, "fneg", 0, 0, IF_EN2J, 0x2EA0F800, 0x1E214000)
// fneg Vd,Vn DV_2A 0Q1011101X100000 111110nnnnnddddd 2EA0 F800 Vd,Vn (vector)
// fneg Vd,Vn DV_2G 000111100X100001 010000nnnnnddddd 1E21 4000 Vd,Vn (scalar)
@@ -480,6 +526,14 @@ INST2(abs, "abs", 0, 0, IF_EN2K, 0x0E20B800, 0x5E20B800)
// abs Vd,Vn DV_2M 0Q001110XX100000 101110nnnnnddddd 0E20 B800 Vd,Vn (vector)
// abs Vd,Vn DV_2L 01011110XX100000 101110nnnnnddddd 5E20 B800 Vd,Vn (scalar)
+INST2(cmle, "cmle", 0, 0, IF_EN2K, 0x2E209800, 0x7E209800)
+ // cmle Vd,Vn DV_2M 0Q101110XX100000 100110nnnnnddddd 2E20 9800 Vd,Vn (vector)
+ // cmle Vd,Vn DV_2L 01111110XX100000 100110nnnnnddddd 7E20 9800 Vd,Vn (scalar)
+
+INST2(cmlt, "cmlt", 0, 0, IF_EN2K, 0x0E20A800, 0x5E20A800)
+ // cmlt Vd,Vn DV_2M 0Q101110XX100000 101010nnnnnddddd 0E20 A800 Vd,Vn (vector)
+ // cmlt Vd,Vn DV_2L 01011110XX100000 101010nnnnnddddd 5E20 A800 Vd,Vn (scalar)
+
// enum name FP LD/ST DR_2G DV_2M
INST2(cls, "cls", 0, 0, IF_EN2L, 0x5AC01400, 0x0E204800)
// cls Rd,Rm DR_2G X101101011000000 000101nnnnnddddd 5AC0 1400 Rd Rn (general)
@@ -555,6 +609,24 @@ INST2(sli, "sli", 0, 0, IF_EN2N, 0x7F005400, 0x2F005400)
// sli Vd,Vn,imm DV_2N 011111110iiiiiii 010101nnnnnddddd 7F00 5400 Vd Vn imm (shift - scalar)
// sli Vd,Vn,imm DV_2O 0Q1011110iiiiiii 010101nnnnnddddd 2F00 5400 Vd,Vn imm (shift - vector)
+// enum name FP LD/ST DV_3E DV_3A
+INST2(cmhi, "cmhi", 0, 0, IF_EN2O, 0x7EE03400, 0x2E203400)
+ // cmhi Vd,Vn,Vm DV_3E 01111110111mmmmm 001101nnnnnddddd 7EE0 3400 Vd,Vn,Vm (scalar)
+ // cmhi Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001101nnnnnddddd 2E20 3400 Vd,Vn,Vm (vector)
+
+INST2(cmhs, "cmhs", 0, 0, IF_EN2O, 0x7EE03C00, 0x2E203C00)
+ // cmhs Vd,Vn,Vm DV_3E 01111110111mmmmm 001111nnnnnddddd 7EE0 3C00 Vd,Vn,Vm (scalar)
+ // cmhs Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 001111nnnnnddddd 2E20 3C00 Vd,Vn,Vm (vector)
+
+INST2(ctst, "ctst", 0, 0, IF_EN2O, 0x5EE08C00, 0x0E208C00)
+ // ctst Vd,Vn,Vm DV_3E 01011110111mmmmm 100011nnnnnddddd 5EE0 8C00 Vd,Vn,Vm (scalar)
+ // ctst Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 100011nnnnnddddd 0E20 8C00 Vd,Vn,Vm (vector)
+
+// enum name FP LD/ST DV_2G DV_3B
+INST2(faddp, "faddp", 0, 0, IF_EN2P, 0x7E30D800, 0x2E20D400)
+ // faddp Vd,Vn DV_2G 011111100X110000 110110nnnnnddddd 7E30 D800 Vd,Vn (scalar)
+ // faddp Vd,Vn,Vm DV_3B 0Q1011100X1mmmmm 110101nnnnnddddd 2E20 D400 Vd,Vn,Vm (vector)
+
INST1(ldar, "ldar", 0,LD, IF_LS_2A, 0x88DFFC00)
// ldar Rt,[Xn] LS_2A 1X00100011011111 111111nnnnnttttt 88DF FC00
@@ -564,6 +636,24 @@ INST1(ldarb, "ldarb", 0,LD, IF_LS_2A, 0x08DFFC00)
INST1(ldarh, "ldarh", 0,LD, IF_LS_2A, 0x48DFFC00)
// ldarh Rt,[Xn] LS_2A 0100100011011111 111111nnnnnttttt 48DF FC00
+INST1(ldxr, "ldxr", 0,LD, IF_LS_2A, 0x885F7C00)
+ // ldxr Rt,[Xn] LS_2A 1X00100001011111 011111nnnnnttttt 885F 7C00
+
+INST1(ldxrb, "ldxrb", 0,LD, IF_LS_2A, 0x085F7C00)
+ // ldxrb Rt,[Xn] LS_2A 0000100001011111 011111nnnnnttttt 085F 7C00
+
+INST1(ldxrh, "ldxrh", 0,LD, IF_LS_2A, 0x485F7C00)
+ // ldxrh Rt,[Xn] LS_2A 0100100001011111 011111nnnnnttttt 485F 7C00
+
+INST1(ldaxr, "ldaxr", 0,LD, IF_LS_2A, 0x885FFC00)
+ // ldaxr Rt,[Xn] LS_2A 1X00100001011111 111111nnnnnttttt 885F FC00
+
+INST1(ldaxrb, "ldaxrb", 0,LD, IF_LS_2A, 0x085FFC00)
+ // ldaxrb Rt,[Xn] LS_2A 0000100001011111 111111nnnnnttttt 085F FC00
+
+INST1(ldaxrh, "ldaxrh", 0,LD, IF_LS_2A, 0x485FFC00)
+ // ldaxrh Rt,[Xn] LS_2A 0100100001011111 111111nnnnnttttt 485F FC00
+
INST1(ldur, "ldur", 0,LD, IF_LS_2C, 0xB8400000)
// ldur Rt,[Xn+simm9] LS_2C 1X111000010iiiii iiii00nnnnnttttt B840 0000 [Xn imm(-256..+255)]
@@ -591,6 +681,24 @@ INST1(stlrb, "stlrb", 0,ST, IF_LS_2A, 0x089FFC00)
INST1(stlrh, "stlrh", 0,ST, IF_LS_2A, 0x489FFC00)
// stlrh Rt,[Xn] LS_2A 0100100010011111 111111nnnnnttttt 489F FC00
+INST1(stxr, "stxr", 0,ST, IF_LS_3D, 0x88007C00)
+ // stxr Ws, Rt,[Xn] LS_3D 1X001000000sssss 011111nnnnnttttt 8800 7C00
+
+INST1(stxrb, "stxrb", 0,ST, IF_LS_3D, 0x08007C00)
+ // stxrb Ws, Rt,[Xn] LS_3D 00001000000sssss 011111nnnnnttttt 0800 7C00
+
+INST1(stxrh, "stxrh", 0,ST, IF_LS_3D, 0x48007C00)
+ // stxrh Ws, Rt,[Xn] LS_3D 01001000000sssss 011111nnnnnttttt 4800 7C00
+
+INST1(stlxr, "stlxr", 0,ST, IF_LS_3D, 0x8800FC00)
+ // stlxr Ws, Rt,[Xn] LS_3D 1X001000000sssss 111111nnnnnttttt 8800 FC00
+
+INST1(stlxrb, "stlxrb", 0,ST, IF_LS_3D, 0x0800FC00)
+ // stlxrb Ws, Rt,[Xn] LS_3D 00001000000sssss 111111nnnnnttttt 0800 FC00
+
+INST1(stlxrh, "stlxrh", 0,ST, IF_LS_3D, 0x4800FC00)
+ // stlxrh Ws, Rt,[Xn] LS_3D 01001000000sssss 111111nnnnnttttt 4800 FC00
+
INST1(stur, "stur", 0,ST, IF_LS_2C, 0xB8000000)
// stur Rt,[Xn+simm9] LS_2C 1X111000000iiiii iiii00nnnnnttttt B800 0000 [Xn imm(-256..+255)]
@@ -879,12 +987,39 @@ INST1(bit, "bit", 0, 0, IF_DV_3C, 0x2EA01C00)
INST1(bif, "bif", 0, 0, IF_DV_3C, 0x2EE01C00)
// bif Vd,Vn,Vm DV_3C 0Q101110111mmmmm 000111nnnnnddddd 2EE0 1C00 Vd,Vn,Vm
+INST1(addv, "addv", 0, 0, IF_DV_2M, 0x0E31B800)
+ // addv Vd,Vn DV_2M 0Q001110XX110001 101110nnnnnddddd 0E31 B800 Vd,Vn (vector)
+
INST1(cnt, "cnt", 0, 0, IF_DV_2M, 0x0E205800)
// cnt Vd,Vn DV_2M 0Q00111000100000 010110nnnnnddddd 0E20 5800 Vd,Vn (vector)
INST1(not, "not", 0, 0, IF_DV_2M, 0x2E205800)
// not Vd,Vn DV_2M 0Q10111000100000 010110nnnnnddddd 2E20 5800 Vd,Vn (vector)
+INST1(saddlv, "saddlv", 0, 0, IF_DV_2M, 0x0E303800)
+ // saddlv Vd,Vn DV_2M 0Q001110XX110000 001110nnnnnddddd 0E30 3800 Vd,Vn (vector)
+
+INST1(smaxv, "smaxv", 0, 0, IF_DV_2M, 0x0E30A800)
+ // smaxv Vd,Vn DV_2M 0Q001110XX110000 101010nnnnnddddd 0E30 A800 Vd,Vn (vector)
+
+INST1(sminv, "sminv", 0, 0, IF_DV_2M, 0x0E31A800)
+ // sminv Vd,Vn DV_2M 0Q001110XX110001 101010nnnnnddddd 0E31 A800 Vd,Vn (vector)
+
+INST1(uaddlv, "uaddlv", 0, 0, IF_DV_2M, 0x2E303800)
+ // uaddlv Vd,Vn DV_2M 0Q101110XX110000 001110nnnnnddddd 2E30 3800 Vd,Vn (vector)
+
+INST1(umaxv, "umaxv", 0, 0, IF_DV_2M, 0x2E30A800)
+ // umaxv Vd,Vn DV_2M 0Q101110XX110000 101010nnnnnddddd 2E30 A800 Vd,Vn (vector)
+
+INST1(uminv, "uminv", 0, 0, IF_DV_2M, 0x2E31A800)
+ // uminv Vd,Vn DV_2M 0Q101110XX110001 101010nnnnnddddd 2E31 A800 Vd,Vn (vector)
+
+INST1(xtn, "xtn", 0, 0, IF_DV_2M, 0x0E212800)
+ // xtn Vd,Vn DV_2M 00101110XX110000 001110nnnnnddddd 0E21 2800 Vd,Vn (vector)
+
+INST1(xtn2, "xtn2", 0, 0, IF_DV_2M, 0x4E212800)
+ // xtn2 Vd,Vn DV_2M 01101110XX110000 001110nnnnnddddd 4E21 2800 Vd,Vn (vector)
+
INST1(fnmul, "fnmul", 0, 0, IF_DV_3D, 0x1E208800)
// fnmul Vd,Vn,Vm DV_3D 000111100X1mmmmm 100010nnnnnddddd 1E20 8800 Vd,Vn,Vm (scalar)
@@ -912,12 +1047,36 @@ INST1(saba, "saba", 0, 0, IF_DV_3A, 0x0E207C00)
INST1(sabd, "sabd", 0, 0, IF_DV_3A, 0x0E207400)
// sabd Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011101nnnnnddddd 0E20 7400 Vd,Vn,Vm (vector)
+INST1(smax, "smax", 0, 0, IF_DV_3A, 0x0E206400)
+ // smax Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011001nnnnnddddd 0E20 6400 Vd,Vn,Vm (vector)
+
+INST1(smin, "smin", 0, 0, IF_DV_3A, 0x0E206C00)
+ // smax Vd,Vn,Vm DV_3A 0Q001110XX1mmmmm 011011nnnnnddddd 0E20 6C00 Vd,Vn,Vm (vector)
+
INST1(uaba, "uaba", 0, 0, IF_DV_3A, 0x2E207C00)
// uaba Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011111nnnnnddddd 2E20 7C00 Vd,Vn,Vm (vector)
INST1(uabd, "uabd", 0, 0, IF_DV_3A, 0x2E207400)
// uabd Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011101nnnnnddddd 2E20 7400 Vd,Vn,Vm (vector)
+INST1(umax, "umax", 0, 0, IF_DV_3A, 0x2E206400)
+ // umax Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011001nnnnnddddd 2E20 6400 Vd,Vn,Vm (vector)
+
+INST1(umin, "umin", 0, 0, IF_DV_3A, 0x2E206C00)
+ // umin Vd,Vn,Vm DV_3A 0Q101110XX1mmmmm 011011nnnnnddddd 2E20 6C00 Vd,Vn,Vm (vector)
+
+INST1(fcvtl, "fcvtl", 0, 0, IF_DV_2G, 0x0E217800)
+ // fcvtl Vd,Vn DV_2G 000011100X100001 011110nnnnnddddd 0E21 7800 Vd,Vn (scalar)
+
+INST1(fcvtl2, "fcvtl2", 0, 0, IF_DV_2G, 0x4E217800)
+ // fcvtl2 Vd,Vn DV_2G 040011100X100001 011110nnnnnddddd 4E21 7800 Vd,Vn (scalar)
+
+INST1(fcvtn, "fcvtn", 0, 0, IF_DV_2G, 0x0E216800)
+ // fcvtn Vd,Vn DV_2G 000011100X100001 011010nnnnnddddd 0E21 6800 Vd,Vn (scalar)
+
+INST1(fcvtn2, "fcvtn2", 0, 0, IF_DV_2G, 0x4E216800)
+ // fcvtn2 Vd,Vn DV_2G 040011100X100001 011010nnnnnddddd 4E21 6800 Vd,Vn (scalar)
+
INST1(shll, "shll", 0, 0, IF_DV_2M, 0x2F00A400)
// shll Vd,Vn,imm DV_2M 0Q101110XX100001 001110nnnnnddddd 2E21 3800 Vd,Vn, {8/16/32}
diff --git a/src/jit/instrsxarch.h b/src/jit/instrsxarch.h
index 225539ae39..8d6dd6a3e8 100644
--- a/src/jit/instrsxarch.h
+++ b/src/jit/instrsxarch.h
@@ -382,6 +382,15 @@ INST3( vzeroupper, "zeroupper" , 0, IUM_WR, 0, 0, 0xC577F8, BAD_CODE, BA
INST3( vperm2i128, "perm2i128" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x46)) // Permute 128-bit halves of input register
INST3( vpermq, "permq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x00)) // Permute 64-bit of input register
INST3(LAST_AVX_INSTRUCTION, "LAST_AVX_INSTRUCTION", 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, BAD_CODE)
+
+// Scalar instructions in SSE4.2
+INST3( crc32, "crc32" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, PACK4(0xF2, 0x0F, 0x38, 0xF0))
+
+// LZCNT
+INST3( lzcnt, "lzcnt" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0xBD))
+
+// POPCNT
+INST3( popcnt, "popcnt" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSEFLT(0xB8))
#endif // !LEGACY_BACKEND
// enum name FP updmode rf wf R/M,R/M[reg] R/M,icon
diff --git a/src/jit/jit.h b/src/jit/jit.h
index 40533c04d7..140d26395b 100644
--- a/src/jit/jit.h
+++ b/src/jit/jit.h
@@ -414,8 +414,7 @@ typedef ptrdiff_t ssize_t;
//=============================================================================
-#define OPT_MULT_ADDSUB 1 // optimize consecutive "lclVar += or -= icon"
-#define OPT_BOOL_OPS 1 // optimize boolean operations
+#define OPT_BOOL_OPS 1 // optimize boolean operations
//=============================================================================
diff --git a/src/jit/jit.settings.targets b/src/jit/jit.settings.targets
index ee1df74c62..2d2cc71c2f 100644
--- a/src/jit/jit.settings.targets
+++ b/src/jit/jit.settings.targets
@@ -104,6 +104,7 @@
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\SIMD.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\SIMDCodeGenXArch.cpp" />
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\hwintrinsicxarch.cpp" />
+ <CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\hwintrinsiccodegenxarch.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(TargetArch)'=='amd64'">
<!-- AMD64 target is always RyuJIT backend -->
@@ -116,6 +117,7 @@
<CppCompile Include="..\SIMDCodeGenXArch.cpp" />
<CppCompile Include="..\unwindAmd64.cpp" />
<CppCompile Include="..\hwintrinsicxarch.cpp" />
+ <CppCompile Include="..\hwintrinsiccodegenxarch.cpp" />
</ItemGroup>
<ItemGroup Condition="'$(TargetArch)'=='arm'">
<CppCompile Include="..\emitarm.cpp" />
diff --git a/src/jit/jitconfigvalues.h b/src/jit/jitconfigvalues.h
index cb503659fa..65d670f0cf 100644
--- a/src/jit/jitconfigvalues.h
+++ b/src/jit/jitconfigvalues.h
@@ -101,6 +101,7 @@ CONFIG_INTEGER(JitPrintInlinedMethods, W("JitPrintInlinedMethods"), 0)
CONFIG_INTEGER(JitPrintDevirtualizedMethods, W("JitPrintDevirtualizedMethods"), 0)
CONFIG_INTEGER(JitRequired, W("JITRequired"), -1)
CONFIG_INTEGER(JitRoundFloat, W("JITRoundFloat"), DEFAULT_ROUND_LEVEL)
+CONFIG_INTEGER(JitStackAllocToLocalSize, W("JitStackAllocToLocalSize"), DEFAULT_MAX_LOCALLOC_TO_LOCAL_SIZE)
CONFIG_INTEGER(JitSkipArrayBoundCheck, W("JitSkipArrayBoundCheck"), 0)
CONFIG_INTEGER(JitSlowDebugChecksEnabled, W("JitSlowDebugChecksEnabled"), 1) // Turn on slow debug checks
CONFIG_INTEGER(JitSplitFunctionSize, W("JitSplitFunctionSize"), 0) // On ARM, use this as the maximum function/funclet
@@ -186,7 +187,26 @@ CONFIG_STRING(NgenDumpFgDir, W("NgenDumpFgDir")) // Ngen Xml Flo
CONFIG_STRING(NgenDumpFgFile, W("NgenDumpFgFile")) // Ngen Xml Flowgraph support
CONFIG_STRING(NgenDumpIRFormat, W("NgenDumpIRFormat")) // Same as JitDumpIRFormat, but for ngen
CONFIG_STRING(NgenDumpIRPhase, W("NgenDumpIRPhase")) // Same as JitDumpIRPhase, but for ngen
-#endif // defined(DEBUG)
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+CONFIG_INTEGER(EnableSSE, W("EnableSSE"), 1) // Enable SSE
+CONFIG_INTEGER(EnableSSE2, W("EnableSSE2"), 1) // Enable SSE2
+CONFIG_INTEGER(EnableSSE3, W("EnableSSE3"), 1) // Enable SSE3
+CONFIG_INTEGER(EnableSSSE3, W("EnableSSSE3"), 1) // Enable SSSE3
+CONFIG_INTEGER(EnableSSE41, W("EnableSSE41"), 1) // Enable SSE41
+CONFIG_INTEGER(EnableSSE42, W("EnableSSE42"), 1) // Enable SSE42
+// EnableAVX is already defined for DEBUG and non-DEBUG mode both
+CONFIG_INTEGER(EnableAVX2, W("EnableAVX2"), 1) // Enable AVX2
+
+CONFIG_INTEGER(EnableAES, W("EnableAES"), 1) // Enable AES
+CONFIG_INTEGER(EnableBMI1, W("EnableBMI1"), 1) // Enable BMI1
+CONFIG_INTEGER(EnableBMI2, W("EnableBMI2"), 1) // Enable BMI2
+CONFIG_INTEGER(EnableFMA, W("EnableFMA"), 1) // Enable FMA
+CONFIG_INTEGER(EnableLZCNT, W("EnableLZCNT"), 1) // Enable AES
+CONFIG_INTEGER(EnablePCLMULQDQ, W("EnablePCLMULQDQ"), 1) // Enable PCLMULQDQ
+CONFIG_INTEGER(EnablePOPCNT, W("EnablePOPCNT"), 1) // Enable POPCNT
+#endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
+#endif // defined(DEBUG)
#ifdef FEATURE_ENABLE_NO_RANGE_CHECKS
CONFIG_INTEGER(JitNoRangeChks, W("JitNoRngChks"), 0) // If 1, don't generate range checks
diff --git a/src/jit/jitee.h b/src/jit/jitee.h
index 4c2359a7a3..3da1093b01 100644
--- a/src/jit/jitee.h
+++ b/src/jit/jitee.h
@@ -45,7 +45,6 @@ public:
JIT_FLAG_USE_AVX = 14,
JIT_FLAG_USE_AVX2 = 15,
JIT_FLAG_USE_AVX_512 = 16,
- JIT_FLAG_FEATURE_SIMD = 17,
#else // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
@@ -53,10 +52,15 @@ public:
JIT_FLAG_UNUSED7 = 14,
JIT_FLAG_UNUSED8 = 15,
JIT_FLAG_UNUSED9 = 16,
- JIT_FLAG_UNUSED10 = 17,
#endif // !defined(_TARGET_X86_) && !defined(_TARGET_AMD64_)
+ #if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+ JIT_FLAG_FEATURE_SIMD = 17,
+ #else
+ JIT_FLAG_UNUSED10 = 17,
+ #endif // !(defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
+
JIT_FLAG_MAKEFINALCODE = 18, // Use the final code generator, i.e., not the interpreter.
JIT_FLAG_READYTORUN = 19, // Use version-resilient code generation
JIT_FLAG_PROF_ENTERLEAVE = 20, // Instrument prologues/epilogues
@@ -203,6 +207,11 @@ public:
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX, JIT_FLAG_USE_AVX);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX2, JIT_FLAG_USE_AVX2);
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_USE_AVX_512, JIT_FLAG_USE_AVX_512);
+
+#endif
+
+#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+
FLAGS_EQUAL(CORJIT_FLAGS::CORJIT_FLAG_FEATURE_SIMD, JIT_FLAG_FEATURE_SIMD);
#endif
diff --git a/src/jit/lclvars.cpp b/src/jit/lclvars.cpp
index e5165bad31..c7f15d8908 100644
--- a/src/jit/lclvars.cpp
+++ b/src/jit/lclvars.cpp
@@ -1460,9 +1460,13 @@ void Compiler::lvaCanPromoteStructType(CORINFO_CLASS_HANDLE typeHnd,
// In the future this may be changing to XMM_REGSIZE_BYTES.
// Note: MaxOffset is used below to declare a local array, and therefore must be a compile-time constant.
CLANG_FORMAT_COMMENT_ANCHOR;
-#ifdef FEATURE_SIMD
+#if defined(FEATURE_SIMD)
+#if defined(_TARGET_XARCH_)
// This will allow promotion of 2 Vector<T> fields on AVX2, or 4 Vector<T> fields on SSE2.
const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * XMM_REGSIZE_BYTES;
+#elif defined(_TARGET_ARM64_)
+ const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * FP_REGSIZE_BYTES;
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
#else // !FEATURE_SIMD
const int MaxOffset = MAX_NumOfFieldsInPromotableStruct * sizeof(double);
#endif // !FEATURE_SIMD
@@ -3610,7 +3614,7 @@ void Compiler::lvaMarkLclRefs(GenTreePtr tree)
/* Is this an assigment? */
- if (tree->OperKind() & GTK_ASGOP)
+ if (tree->OperIsAssignment())
{
GenTreePtr op1 = tree->gtOp.gtOp1;
GenTreePtr op2 = tree->gtOp.gtOp2;
@@ -3622,6 +3626,7 @@ void Compiler::lvaMarkLclRefs(GenTreePtr tree)
unsigned lclNum;
LclVarDsc* varDsc = nullptr;
+#ifdef LEGACY_BACKEND
/* GT_CHS is special it doesn't have a valid op2 */
if (tree->gtOper == GT_CHS)
{
@@ -3633,6 +3638,7 @@ void Compiler::lvaMarkLclRefs(GenTreePtr tree)
}
}
else
+#endif
{
if (op2->gtOper == GT_LCL_VAR)
{
@@ -6148,8 +6154,8 @@ int Compiler::lvaAllocLocalAndSetVirtualOffset(unsigned lclNum, unsigned size, i
#endif
))
{
- // Note that stack offsets are negative
- assert(stkOffs < 0);
+ // Note that stack offsets are negative or equal to zero
+ assert(stkOffs <= 0);
// alignment padding
unsigned pad = 0;
@@ -7325,11 +7331,10 @@ Compiler::fgWalkResult Compiler::lvaStressLclFldCB(GenTreePtr* pTree, fgWalkData
/* Change addr(lclVar) to addr(lclVar)+padding */
noway_assert(oper == GT_ADDR);
- GenTreePtr newAddr = new (pComp, GT_NONE) GenTreeOp(*tree->AsOp());
+ GenTreePtr paddingTree = pComp->gtNewIconNode(padding);
+ GenTreePtr newAddr = pComp->gtNewOperNode(GT_ADD, tree->gtType, tree, paddingTree);
- tree->ChangeOper(GT_ADD);
- tree->gtOp.gtOp1 = newAddr;
- tree->gtOp.gtOp2 = pComp->gtNewIconNode(padding);
+ *pTree = newAddr;
lcl->gtType = TYP_BLK;
}
diff --git a/src/jit/legacyjit/CMakeLists.txt b/src/jit/legacyjit/CMakeLists.txt
index 84fb42ecd1..4a14d0f15b 100644
--- a/src/jit/legacyjit/CMakeLists.txt
+++ b/src/jit/legacyjit/CMakeLists.txt
@@ -9,7 +9,9 @@ remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
# No SIMD in legacy back-end.
remove_definitions(-DFEATURE_SIMD)
-remove_definitions(-DFEATURE_AVX_SUPPORT)
+
+# No hardware intrinsic in legacy back-end.
+remove_definitions(-DFEATURE_HW_INTRINSICS)
if(WIN32)
add_definitions(-DFX_VER_INTERNALNAME_STR=legacyjit.dll)
diff --git a/src/jit/legacynonjit/CMakeLists.txt b/src/jit/legacynonjit/CMakeLists.txt
index 00fd9e5b9f..b36800d329 100644
--- a/src/jit/legacynonjit/CMakeLists.txt
+++ b/src/jit/legacynonjit/CMakeLists.txt
@@ -6,7 +6,8 @@ add_definitions(-DSELF_NO_HOST)
remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
remove_definitions(-DFEATURE_SIMD)
-remove_definitions(-DFEATURE_AVX_SUPPORT)
+
+remove_definitions(-DFEATURE_HW_INTRINSICS)
add_definitions(-DLEGACY_BACKEND)
diff --git a/src/jit/linuxnonjit/CMakeLists.txt b/src/jit/linuxnonjit/CMakeLists.txt
index 34899f2e37..feec36b8af 100644
--- a/src/jit/linuxnonjit/CMakeLists.txt
+++ b/src/jit/linuxnonjit/CMakeLists.txt
@@ -11,7 +11,7 @@ endif(FEATURE_READYTORUN)
if (CLR_CMAKE_PLATFORM_ARCH_I386)
remove_definitions(-DFEATURE_SIMD)
- remove_definitions(-DFEATURE_AVX_SUPPORT)
+ remove_definitions(-DFEATURE_HW_INTRINSICS)
add_definitions(-DUNIX_X86_ABI)
set(JIT_ARCH_ALTJIT_SOURCES ${JIT_I386_SOURCES})
elseif(CLR_CMAKE_PLATFORM_ARCH_AMD64)
diff --git a/src/jit/lir.cpp b/src/jit/lir.cpp
index a2343ad313..80b9c34f2c 100644
--- a/src/jit/lir.cpp
+++ b/src/jit/lir.cpp
@@ -981,7 +981,11 @@ void LIR::Range::Remove(GenTree* node, bool markOperandsUnused)
if (markOperandsUnused)
{
node->VisitOperands([](GenTree* operand) -> GenTree::VisitResult {
- operand->SetUnusedValue();
+ // The operand of JTRUE does not produce a value (just sets the flags).
+ if (operand->IsValue())
+ {
+ operand->SetUnusedValue();
+ }
return GenTree::VisitResult::Continue;
});
}
@@ -1608,8 +1612,11 @@ bool LIR::Range::CheckLIR(Compiler* compiler, bool checkUnusedValues) const
// The GT_NOP case is because sometimes we eliminate stack argument stores as dead, but
// instead of removing them we replace with a NOP.
// ARGPLACE nodes are not represented in the LIR sequence. Ignore them.
- assert((node->OperGet() == GT_CALL) &&
- (def->OperIsStore() || def->OperIs(GT_PUTARG_STK, GT_NOP, GT_ARGPLACE)));
+ // The argument of a JTRUE doesn't produce a value (just sets a flag).
+ assert(((node->OperGet() == GT_CALL) &&
+ (def->OperIsStore() || def->OperIs(GT_PUTARG_STK, GT_NOP, GT_ARGPLACE))) ||
+ ((node->OperGet() == GT_JTRUE) && (def->TypeGet() == TYP_VOID) &&
+ ((def->gtFlags & GTF_SET_FLAGS) != 0)));
continue;
}
diff --git a/src/jit/liveness.cpp b/src/jit/liveness.cpp
index 90aa0d1c7c..3f4d3a18ca 100644
--- a/src/jit/liveness.cpp
+++ b/src/jit/liveness.cpp
@@ -1935,7 +1935,6 @@ void Compiler::fgComputeLife(VARSET_TP& life,
bool* pStmtInfoDirty DEBUGARG(bool* treeModf))
{
GenTreePtr tree;
- unsigned lclNum;
// Don't kill vars in scope
VARSET_TP keepAliveVars(VarSetOps::Union(this, volatileVars, compCurBB->bbScope));
@@ -2694,6 +2693,9 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree,
noway_assert(rhsNode);
noway_assert(tree->gtFlags & GTF_VAR_DEF);
+#ifndef LEGACY_BACKEND
+ assert(asgNode->OperIs(GT_ASG));
+#else
if (asgNode->gtOper != GT_ASG && asgNode->gtOverflowEx())
{
// asgNode may be <op_ovf>= (with GTF_OVERFLOW). In that case, we need to keep the <op_ovf>
@@ -2761,7 +2763,7 @@ bool Compiler::fgRemoveDeadStore(GenTree** pTree,
}
return false;
}
-
+#endif
// Do not remove if this local variable represents
// a promoted struct field of an address exposed local.
if (varDsc->lvIsStructField && lvaTable[varDsc->lvParentLcl].lvAddrExposed)
diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
index 39d69638cf..f62efd1fb3 100644
--- a/src/jit/lower.cpp
+++ b/src/jit/lower.cpp
@@ -142,16 +142,6 @@ GenTree* Lowering::LowerNode(GenTree* node)
ContainCheckBinary(node->AsOp());
break;
-#ifdef _TARGET_XARCH_
- case GT_NEG:
- // Codegen of this tree node sets ZF and SF flags.
- if (!varTypeIsFloating(node))
- {
- node->gtFlags |= GTF_ZSF_SET;
- }
- break;
-#endif // _TARGET_XARCH_
-
case GT_MUL:
case GT_MULHI:
#if defined(_TARGET_X86_) && !defined(LEGACY_BACKEND)
@@ -188,13 +178,10 @@ GenTree* Lowering::LowerNode(GenTree* node)
case GT_TEST_EQ:
case GT_TEST_NE:
case GT_CMP:
- case GT_JCMP:
- LowerCompare(node);
- break;
+ return LowerCompare(node);
case GT_JTRUE:
- ContainCheckJTrue(node->AsOp());
- break;
+ return LowerJTrue(node->AsOp());
case GT_JMP:
LowerJmpMethod(node);
@@ -311,6 +298,13 @@ GenTree* Lowering::LowerNode(GenTree* node)
LowerStoreLoc(node->AsLclVarCommon());
break;
+#ifdef _TARGET_ARM64_
+ case GT_CMPXCHG:
+ CheckImmedAndMakeContained(node, node->AsCmpXchg()->gtOpComparand);
+ break;
+
+ case GT_XADD:
+#endif
case GT_LOCKADD:
CheckImmedAndMakeContained(node, node->gtOp.gtOp2);
break;
@@ -774,20 +768,20 @@ GenTree* Lowering::LowerSwitch(GenTree* node)
// NOTE: this method deliberately does not update the call arg table. It must only
// be used by NewPutArg and LowerArg; these functions are responsible for updating
// the call arg table as necessary.
-void Lowering::ReplaceArgWithPutArgOrCopy(GenTree** argSlot, GenTree* putArgOrCopy)
+void Lowering::ReplaceArgWithPutArgOrBitcast(GenTree** argSlot, GenTree* putArgOrBitcast)
{
assert(argSlot != nullptr);
assert(*argSlot != nullptr);
- assert(putArgOrCopy->OperIsPutArg() || putArgOrCopy->OperIs(GT_BITCAST));
+ assert(putArgOrBitcast->OperIsPutArg() || putArgOrBitcast->OperIs(GT_BITCAST));
GenTree* arg = *argSlot;
// Replace the argument with the putarg/copy
- *argSlot = putArgOrCopy;
- putArgOrCopy->gtOp.gtOp1 = arg;
+ *argSlot = putArgOrBitcast;
+ putArgOrBitcast->gtOp.gtOp1 = arg;
// Insert the putarg/copy into the block
- BlockRange().InsertAfter(arg, putArgOrCopy);
+ BlockRange().InsertAfter(arg, putArgOrBitcast);
}
//------------------------------------------------------------------------
@@ -1015,7 +1009,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
fieldListPtr->gtOp.gtOp1, (ctr == 0) ? info->regNum : info->otherRegNum);
// Splice in the new GT_PUTARG_REG node in the GT_FIELD_LIST
- ReplaceArgWithPutArgOrCopy(&fieldListPtr->gtOp.gtOp1, newOper);
+ ReplaceArgWithPutArgOrBitcast(&fieldListPtr->gtOp.gtOp1, newOper);
// Initialize all the gtRegNum's since the list won't be traversed in an LIR traversal.
fieldListPtr->gtRegNum = REG_NA;
@@ -1052,7 +1046,7 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
GenTreePtr newOper = comp->gtNewPutArgReg(curTyp, curOp, argReg);
// Splice in the new GT_PUTARG_REG node in the GT_FIELD_LIST
- ReplaceArgWithPutArgOrCopy(&fieldListPtr->gtOp.gtOp1, newOper);
+ ReplaceArgWithPutArgOrBitcast(&fieldListPtr->gtOp.gtOp1, newOper);
// Update argReg for the next putarg_reg (if any)
argReg = genRegArgNext(argReg);
@@ -1085,11 +1079,29 @@ GenTreePtr Lowering::NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryP
// This provides the info to put this argument in in-coming arg area slot
// instead of in out-going arg area slot.
- PUT_STRUCT_ARG_STK_ONLY(assert(info->isStruct == varTypeIsStruct(type))); // Make sure state is correct
+ // Make sure state is correct. The PUTARG_STK has TYP_VOID, as it doesn't produce
+ // a result. So the type of its operand must be the correct type to push on the stack.
+ // For a FIELD_LIST, this will be the type of the field (not the type of the arg),
+ // but otherwise it is generally the type of the operand.
+ PUT_STRUCT_ARG_STK_ONLY(assert(info->isStruct == varTypeIsStruct(type)));
+ if ((arg->OperGet() != GT_FIELD_LIST))
+ {
+#if defined(FEATURE_SIMD) && defined(FEATURE_PUT_STRUCT_ARG_STK)
+ if (type == TYP_SIMD12)
+ {
+ assert(info->numSlots == 3);
+ }
+ else
+#endif // defined(FEATURE_SIMD) && defined(FEATURE_PUT_STRUCT_ARG_STK)
+ {
+ assert(genActualType(arg->TypeGet()) == type);
+ }
+ }
- putArg = new (comp, GT_PUTARG_STK)
- GenTreePutArgStk(GT_PUTARG_STK, type, arg, info->slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(info->numSlots),
- call->IsFastTailCall(), call);
+ putArg =
+ new (comp, GT_PUTARG_STK) GenTreePutArgStk(GT_PUTARG_STK, TYP_VOID, arg,
+ info->slotNum PUT_STRUCT_ARG_STK_ONLY_ARG(info->numSlots),
+ call->IsFastTailCall(), call);
#ifdef FEATURE_PUT_STRUCT_ARG_STK
// If the ArgTabEntry indicates that this arg is a struct
@@ -1207,8 +1219,7 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
fgArgTabEntryPtr info = comp->gtArgEntryByNode(call, arg);
assert(info->node == arg);
- bool isReg = (info->regNum != REG_STK);
- var_types type = arg->TypeGet();
+ var_types type = arg->TypeGet();
if (varTypeIsSmall(type))
{
@@ -1253,14 +1264,13 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
#endif // defined(_TARGET_X86_)
#endif // defined(FEATURE_SIMD)
- GenTreePtr putArg;
-
// If we hit this we are probably double-lowering.
assert(!arg->OperIsPutArg());
#if !defined(_TARGET_64BIT_)
if (varTypeIsLong(type))
{
+ bool isReg = (info->regNum != REG_STK);
if (isReg)
{
noway_assert(arg->OperGet() == GT_LONG);
@@ -1272,7 +1282,7 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr);
// Only the first fieldList node (GTF_FIELD_LIST_HEAD) is in the instruction sequence.
(void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList);
- putArg = NewPutArg(call, fieldList, info, TYP_VOID);
+ GenTreePtr putArg = NewPutArg(call, fieldList, info, type);
BlockRange().InsertBefore(arg, putArg);
BlockRange().Remove(arg);
@@ -1281,20 +1291,21 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
}
else
{
+ assert(arg->OperGet() == GT_LONG);
// For longs, we will replace the GT_LONG with a GT_FIELD_LIST, and put that under a PUTARG_STK.
// Although the hi argument needs to be pushed first, that will be handled by the general case,
// in which the fields will be reversed.
- noway_assert(arg->OperGet() == GT_LONG);
assert(info->numSlots == 2);
GenTreePtr argLo = arg->gtGetOp1();
GenTreePtr argHi = arg->gtGetOp2();
GenTreeFieldList* fieldList = new (comp, GT_FIELD_LIST) GenTreeFieldList(argLo, 0, TYP_INT, nullptr);
// Only the first fieldList node (GTF_FIELD_LIST_HEAD) is in the instruction sequence.
(void)new (comp, GT_FIELD_LIST) GenTreeFieldList(argHi, 4, TYP_INT, fieldList);
- putArg = NewPutArg(call, fieldList, info, TYP_VOID);
- putArg->gtRegNum = info->regNum;
+ GenTreePtr putArg = NewPutArg(call, fieldList, info, type);
+ putArg->gtRegNum = info->regNum;
- // We can't call ReplaceArgWithPutArgOrCopy here because it presumes that we are keeping the original arg.
+ // We can't call ReplaceArgWithPutArgOrBitcast here because it presumes that we are keeping the original
+ // arg.
BlockRange().InsertBefore(arg, fieldList, putArg);
BlockRange().Remove(arg);
*ppArg = putArg;
@@ -1305,43 +1316,141 @@ void Lowering::LowerArg(GenTreeCall* call, GenTreePtr* ppArg)
{
#ifdef _TARGET_ARMARCH_
- // For vararg call or on armel, reg args should be all integer.
- // Insert a copy to move float value to integer register.
- if ((call->IsVarargs() || comp->opts.compUseSoftFP) && varTypeIsFloating(type))
+ if (call->IsVarargs() || comp->opts.compUseSoftFP)
{
- var_types intType = (type == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
- GenTreePtr intArg = comp->gtNewBitCastNode(intType, arg);
- intArg->gtRegNum = info->regNum;
-#ifdef ARM_SOFTFP
- if (intType == TYP_LONG)
+ // For vararg call or on armel, reg args should be all integer.
+ // Insert a copy to move float value to integer register.
+ if (varTypeIsFloating(type))
{
- assert(info->numRegs == 2);
- intArg->AsMultiRegOp()->gtOtherReg = REG_NEXT(info->regNum);
- }
-#endif // ARM_SOFTFP
+#ifdef _TARGET_ARM_
+#ifdef DEBUG
+ if (type == TYP_DOUBLE)
+ {
+ unsigned numRegs = info->numRegs;
+ regNumber regCurr = info->regNum;
+ assert(numRegs % 2 == 0);
+ for (unsigned i = 0; i < numRegs;)
+ {
+ regNumber regNext = REG_NEXT(regCurr);
+ // double type arg regs can only be either r0:r1 or r2:r3.
+ assert((regCurr == REG_R0 && regNext == REG_R1) || (regCurr == REG_R2 && regNext == REG_R3));
- info->node = intArg;
- ReplaceArgWithPutArgOrCopy(ppArg, intArg);
+ i += 2;
+ regCurr = REG_NEXT(regNext);
+ }
+ }
+#endif // DEBUG
+#endif // _TARGET_ARM_
- // Update arg/type with new ones.
- arg = intArg;
- type = intType;
+ GenTreePtr intArg = LowerFloatArg(arg, info);
+ if (intArg != nullptr)
+ {
+ if (intArg != arg)
+ {
+ ReplaceArgWithPutArgOrBitcast(ppArg, intArg);
+ arg = intArg;
+ info->node = intArg;
+ }
+
+ // update local variables.
+ type = arg->TypeGet();
+ }
+ }
}
-#endif
+#endif // _TARGET_ARMARCH_
- putArg = NewPutArg(call, arg, info, type);
+ GenTreePtr putArg = NewPutArg(call, arg, info, type);
// In the case of register passable struct (in one or two registers)
// the NewPutArg returns a new node (GT_PUTARG_REG or a GT_FIELD_LIST with two GT_PUTARG_REGs.)
// If an extra node is returned, splice it in the right place in the tree.
if (arg != putArg)
{
- ReplaceArgWithPutArgOrCopy(ppArg, putArg);
+ ReplaceArgWithPutArgOrBitcast(ppArg, putArg);
}
}
}
+#ifdef _TARGET_ARMARCH_
+//------------------------------------------------------------------------
+// LowerFloatArg: Lower the float call argument on the arm platform.
+//
+// Arguments:
+// arg - The arg node
+// info - call argument info
+//
+// Return Value:
+// Return nullptr, if no transformation was done;
+// return arg if there was in place transformation;
+// return a new tree if the root was changed.
+//
+GenTree* Lowering::LowerFloatArg(GenTree* arg, fgArgTabEntry* info)
+{
+ if (info->regNum != REG_STK)
+ {
+ if (arg->OperIsFieldList())
+ {
+ GenTreeFieldList* currListNode = arg->AsFieldList();
+ regNumber currRegNumber = info->regNum;
+
+ // Transform fields that are passed as registers in place.
+ for (unsigned i = 0; i < info->numRegs; ++i)
+ {
+ assert(currListNode != nullptr);
+ GenTree* node = currListNode->Current();
+ GenTree* intNode = LowerFloatArgReg(node, currRegNumber);
+ assert(intNode != nullptr);
+
+ ReplaceArgWithPutArgOrBitcast(currListNode->pCurrent(), intNode);
+ currListNode->ChangeType(intNode->TypeGet());
+
+ currListNode = currListNode->Rest();
+ currRegNumber = REG_NEXT(currRegNumber);
+ }
+ // List fields were replaced in place.
+ return arg;
+ }
+ else
+ {
+ return LowerFloatArgReg(arg, info->regNum);
+ }
+ }
+ else
+ {
+ // Do not change stack nodes.
+ return nullptr;
+ }
+}
+
+//------------------------------------------------------------------------
+// LowerFloatArgReg: Lower the float call argument node that is passed via register.
+//
+// Arguments:
+// arg - The arg node
+// regNum - register number
+//
+// Return Value:
+// Return new bitcast node, that moves float to int register.
+//
+GenTree* Lowering::LowerFloatArgReg(GenTree* arg, regNumber regNum)
+{
+ var_types floatType = arg->TypeGet();
+ assert(varTypeIsFloating(floatType));
+ var_types intType = (floatType == TYP_DOUBLE) ? TYP_LONG : TYP_INT;
+ GenTree* intArg = comp->gtNewBitCastNode(intType, arg);
+ intArg->gtRegNum = regNum;
+#ifdef _TARGET_ARM_
+ if (floatType == TYP_DOUBLE)
+ {
+ regNumber nextReg = REG_NEXT(regNum);
+ intArg->AsMultiRegOp()->gtOtherReg = nextReg;
+ }
+#endif
+ return intArg;
+}
+#endif
+
// do lowering steps for each arg of a call
void Lowering::LowerArgsForCall(GenTreeCall* call)
{
@@ -1367,21 +1476,17 @@ void Lowering::LowerArgsForCall(GenTreeCall* call)
}
// helper that create a node representing a relocatable physical address computation
-// (optionally specifying the register to place it in)
-GenTree* Lowering::AddrGen(ssize_t addr, regNumber reg)
+GenTree* Lowering::AddrGen(ssize_t addr)
{
// this should end up in codegen as : instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, reg, addr)
GenTree* result = comp->gtNewIconHandleNode(addr, GTF_ICON_FTN_ADDR);
-
- result->gtRegNum = reg;
-
return result;
}
// variant that takes a void*
-GenTree* Lowering::AddrGen(void* addr, regNumber reg)
+GenTree* Lowering::AddrGen(void* addr)
{
- return AddrGen((ssize_t)addr, reg);
+ return AddrGen((ssize_t)addr);
}
// do lowering steps for a call
@@ -1735,7 +1840,10 @@ void Lowering::LowerFastTailCall(GenTreeCall* call)
assert(!comp->opts.compNeedSecurityCheck); // tail call from methods that need security check
assert(!call->IsUnmanaged()); // tail calls to unamanaged methods
assert(!comp->compLocallocUsed); // tail call from methods that also do localloc
- assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
+
+#ifdef _TARGET_AMD64_
+ assert(!comp->getNeedsGSSecurityCookie()); // jit64 compat: tail calls from methods that need GS check
+#endif // _TARGET_AMD64_
// We expect to see a call that meets the following conditions
assert(call->IsFastTailCall());
@@ -2148,6 +2256,9 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
// Arguments:
// cmp - the compare node
//
+// Return Value:
+// The next node to lower.
+//
// Notes:
// - Decomposes long comparisons that feed a GT_JTRUE (32 bit specific).
// - Decomposes long comparisons that produce a value (X86 specific).
@@ -2156,8 +2267,11 @@ GenTree* Lowering::LowerTailCallViaHelper(GenTreeCall* call, GenTree* callTarget
// - Transform cmp(and(x, y), 0) into test(x, y) (XARCH/Arm64 specific but could
// be used for ARM as well if support for GT_TEST_EQ/GT_TEST_NE is added).
// - Transform TEST(x, LSH(1, y)) into BT(x, y) (XARCH specific)
+// - Transform RELOP(OP, 0) into SETCC(OP) or JCC(OP) if OP can set the
+// condition flags appropriately (XARCH/ARM64 specific but could be extended
+// to ARM32 as well if ARM32 codegen supports GTF_SET_FLAGS).
-void Lowering::LowerCompare(GenTree* cmp)
+GenTree* Lowering::LowerCompare(GenTree* cmp)
{
#ifndef _TARGET_64BIT_
if (cmp->gtGetOp1()->TypeGet() == TYP_LONG)
@@ -2363,7 +2477,7 @@ void Lowering::LowerCompare(GenTree* cmp)
cmp->AsCC()->gtCondition = condition;
}
- return;
+ return cmp->gtNext;
}
#endif
@@ -2567,11 +2681,10 @@ void Lowering::LowerCompare(GenTree* cmp)
}
}
}
-#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
-#ifdef _TARGET_XARCH_
if (cmp->OperIs(GT_TEST_EQ, GT_TEST_NE))
{
+#ifdef _TARGET_XARCH_
//
// Transform TEST_EQ|NE(x, LSH(1, y)) into BT(x, y) when possible. Using BT
// results in smaller and faster code. It also doesn't have special register
@@ -2614,10 +2727,72 @@ void Lowering::LowerCompare(GenTree* cmp)
cc->gtFlags |= GTF_USE_FLAGS | GTF_UNSIGNED;
- return;
+ return cmp->gtNext;
+ }
+#endif // _TARGET_XARCH_
+ }
+ else if (cmp->OperIs(GT_EQ, GT_NE))
+ {
+ GenTree* op1 = cmp->gtGetOp1();
+ GenTree* op2 = cmp->gtGetOp2();
+
+ // TODO-CQ: right now the below peep is inexpensive and gets the benefit in most
+ // cases because in majority of cases op1, op2 and cmp would be in that order in
+ // execution. In general we should be able to check that all the nodes that come
+ // after op1 do not modify the flags so that it is safe to avoid generating a
+ // test instruction.
+
+ if (op2->IsIntegralConst(0) && (op1->gtNext == op2) && (op2->gtNext == cmp) &&
+#ifdef _TARGET_XARCH_
+ op1->OperIs(GT_AND, GT_OR, GT_XOR, GT_ADD, GT_SUB, GT_NEG))
+#else // _TARGET_ARM64_
+ op1->OperIs(GT_AND, GT_ADD, GT_SUB))
+#endif
+ {
+ op1->gtFlags |= GTF_SET_FLAGS;
+ op1->SetUnusedValue();
+
+ BlockRange().Remove(op2);
+
+ GenTree* next = cmp->gtNext;
+ GenTree* cc;
+ genTreeOps ccOp;
+ LIR::Use cmpUse;
+
+ // Fast check for the common case - relop used by a JTRUE that immediately follows it.
+ if ((next != nullptr) && next->OperIs(GT_JTRUE) && (next->gtGetOp1() == cmp))
+ {
+ cc = next;
+ ccOp = GT_JCC;
+ next = nullptr;
+ BlockRange().Remove(cmp);
+ }
+ else if (BlockRange().TryGetUse(cmp, &cmpUse) && cmpUse.User()->OperIs(GT_JTRUE))
+ {
+ cc = cmpUse.User();
+ ccOp = GT_JCC;
+ next = nullptr;
+ BlockRange().Remove(cmp);
+ }
+ else // The relop is not used by a JTRUE or it is not used at all.
+ {
+ // Transform the relop node it into a SETCC. If it's not used we could remove
+ // it completely but that means doing more work to handle a rare case.
+ cc = cmp;
+ ccOp = GT_SETCC;
+ }
+
+ genTreeOps condition = cmp->OperGet();
+ cc->ChangeOper(ccOp);
+ cc->AsCC()->gtCondition = condition;
+ cc->gtFlags |= GTF_USE_FLAGS | (cmp->gtFlags & GTF_UNSIGNED);
+
+ return next;
}
}
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
+#ifdef _TARGET_XARCH_
if (cmp->gtGetOp1()->TypeGet() == cmp->gtGetOp2()->TypeGet())
{
if (varTypeIsSmall(cmp->gtGetOp1()->TypeGet()) && varTypeIsUnsigned(cmp->gtGetOp1()->TypeGet()))
@@ -2635,6 +2810,67 @@ void Lowering::LowerCompare(GenTree* cmp)
}
#endif // _TARGET_XARCH_
ContainCheckCompare(cmp->AsOp());
+ return cmp->gtNext;
+}
+
+//------------------------------------------------------------------------
+// Lowering::LowerJTrue: Lowers a JTRUE node.
+//
+// Arguments:
+// jtrue - the JTRUE node
+//
+// Return Value:
+// The next node to lower (usually nullptr).
+//
+// Notes:
+// On ARM64 this may remove the JTRUE node and transform its associated
+// relop into a JCMP node.
+//
+GenTree* Lowering::LowerJTrue(GenTreeOp* jtrue)
+{
+#ifdef _TARGET_ARM64_
+ GenTree* relop = jtrue->gtGetOp1();
+ GenTree* relopOp2 = relop->gtOp.gtGetOp2();
+
+ if ((relop->gtNext == jtrue) && relopOp2->IsCnsIntOrI())
+ {
+ bool useJCMP = false;
+ unsigned flags = 0;
+
+ if (relop->OperIs(GT_EQ, GT_NE) && relopOp2->IsIntegralConst(0))
+ {
+ // Codegen will use cbz or cbnz in codegen which do not affect the flag register
+ flags = relop->OperIs(GT_EQ) ? GTF_JCMP_EQ : 0;
+ useJCMP = true;
+ }
+ else if (relop->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(relopOp2->AsIntCon()->IconValue()))
+ {
+ // Codegen will use tbz or tbnz in codegen which do not affect the flag register
+ flags = GTF_JCMP_TST | (relop->OperIs(GT_TEST_EQ) ? GTF_JCMP_EQ : 0);
+ useJCMP = true;
+ }
+
+ if (useJCMP)
+ {
+ relop->SetOper(GT_JCMP);
+ relop->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ);
+ relop->gtFlags |= flags;
+ relop->gtType = TYP_VOID;
+
+ relopOp2->SetContained();
+
+ BlockRange().Remove(jtrue);
+
+ assert(relop->gtNext == nullptr);
+ return nullptr;
+ }
+ }
+#endif // _TARGET_ARM64_
+
+ ContainCheckJTrue(jtrue);
+
+ assert(jtrue->gtNext == nullptr);
+ return nullptr;
}
// Lower "jmp <method>" tail call to insert PInvoke method epilog if required.
@@ -5143,7 +5379,6 @@ bool Lowering::IndirsAreEquivalent(GenTreePtr candidate, GenTreePtr storeInd)
pTreeB = pTreeB->gtSkipReloadOrCopy();
genTreeOps oper;
- unsigned kind;
if (pTreeA->OperGet() != pTreeB->OperGet())
{
@@ -5381,16 +5616,6 @@ void Lowering::ContainCheckNode(GenTree* node)
ContainCheckBinary(node->AsOp());
break;
-#ifdef _TARGET_XARCH_
- case GT_NEG:
- // Codegen of this tree node sets ZF and SF flags.
- if (!varTypeIsFloating(node))
- {
- node->gtFlags |= GTF_ZSF_SET;
- }
- break;
-#endif // _TARGET_XARCH_
-
#if defined(_TARGET_X86_)
case GT_MUL_LONG:
#endif
@@ -5608,58 +5833,9 @@ void Lowering::ContainCheckRet(GenTreeOp* ret)
void Lowering::ContainCheckJTrue(GenTreeOp* node)
{
// The compare does not need to be generated into a register.
- GenTree* cmp = node->gtGetOp1();
- cmp->gtLsraInfo.isNoRegCompare = true;
-
-#ifdef FEATURE_SIMD
- assert(node->OperIs(GT_JTRUE));
-
- // Say we have the following IR
- // simdCompareResult = GT_SIMD((In)Equality, v1, v2)
- // integerCompareResult = GT_EQ/NE(simdCompareResult, true/false)
- // GT_JTRUE(integerCompareResult)
- //
- // In this case we don't need to generate code for GT_EQ_/NE, since SIMD (In)Equality
- // intrinsic will set or clear the Zero flag.
- genTreeOps cmpOper = cmp->OperGet();
- if (cmpOper == GT_EQ || cmpOper == GT_NE)
- {
- GenTree* cmpOp1 = cmp->gtGetOp1();
- GenTree* cmpOp2 = cmp->gtGetOp2();
-
- if (cmpOp1->IsSIMDEqualityOrInequality() && (cmpOp2->IsIntegralConst(0) || cmpOp2->IsIntegralConst(1)))
- {
- // We always generate code for a SIMD equality comparison, though it produces no value.
- // Neither the GT_JTRUE nor the immediate need to be evaluated.
- MakeSrcContained(cmp, cmpOp2);
- cmpOp1->gtLsraInfo.isNoRegCompare = true;
- // We have to reverse compare oper in the following cases:
- // 1) SIMD Equality: Sets Zero flag on equal otherwise clears it.
- // Therefore, if compare oper is == or != against false(0), we will
- // be checking opposite of what is required.
- //
- // 2) SIMD inEquality: Clears Zero flag on true otherwise sets it.
- // Therefore, if compare oper is == or != against true(1), we will
- // be checking opposite of what is required.
- GenTreeSIMD* simdNode = cmpOp1->AsSIMD();
- if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality)
- {
- if (cmpOp2->IsIntegralConst(0))
- {
- cmp->SetOper(GenTree::ReverseRelop(cmpOper));
- }
- }
- else
- {
- assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpInEquality);
- if (cmpOp2->IsIntegralConst(1))
- {
- cmp->SetOper(GenTree::ReverseRelop(cmpOper));
- }
- }
- }
- }
-#endif // FEATURE_SIMD
+ GenTree* cmp = node->gtGetOp1();
+ cmp->gtType = TYP_VOID;
+ cmp->gtFlags |= GTF_SET_FLAGS;
}
#endif // !LEGACY_BACKEND
diff --git a/src/jit/lower.h b/src/jit/lower.h
index ce6bb94831..2be57655e6 100644
--- a/src/jit/lower.h
+++ b/src/jit/lower.h
@@ -137,7 +137,8 @@ private:
// Call Lowering
// ------------------------------
void LowerCall(GenTree* call);
- void LowerCompare(GenTree* tree);
+ GenTree* LowerCompare(GenTree* tree);
+ GenTree* LowerJTrue(GenTreeOp* jtrue);
void LowerJmpMethod(GenTree* jmp);
void LowerRet(GenTree* ret);
GenTree* LowerDelegateInvoke(GenTreeCall* call);
@@ -150,9 +151,14 @@ private:
GenTree* LowerVirtualVtableCall(GenTreeCall* call);
GenTree* LowerVirtualStubCall(GenTreeCall* call);
void LowerArgsForCall(GenTreeCall* call);
- void ReplaceArgWithPutArgOrCopy(GenTreePtr* ppChild, GenTreePtr newNode);
+ void ReplaceArgWithPutArgOrBitcast(GenTreePtr* ppChild, GenTreePtr newNode);
GenTree* NewPutArg(GenTreeCall* call, GenTreePtr arg, fgArgTabEntryPtr info, var_types type);
void LowerArg(GenTreeCall* call, GenTreePtr* ppTree);
+#ifdef _TARGET_ARMARCH_
+ GenTree* LowerFloatArg(GenTree* arg, fgArgTabEntry* info);
+ GenTree* LowerFloatArgReg(GenTree* arg, regNumber regNum);
+#endif
+
void InsertPInvokeCallProlog(GenTreeCall* call);
void InsertPInvokeCallEpilog(GenTreeCall* call);
void InsertPInvokeMethodProlog();
@@ -165,8 +171,8 @@ private:
PopFrame
};
GenTree* CreateFrameLinkUpdate(FrameLinkAction);
- GenTree* AddrGen(ssize_t addr, regNumber reg = REG_NA);
- GenTree* AddrGen(void* addr, regNumber reg = REG_NA);
+ GenTree* AddrGen(ssize_t addr);
+ GenTree* AddrGen(void* addr);
GenTree* Ind(GenTree* tree)
{
@@ -281,12 +287,6 @@ private:
GenTree* LowerConstIntDivOrMod(GenTree* node);
GenTree* LowerSignedDivOrMod(GenTree* node);
void LowerBlockStore(GenTreeBlk* blkNode);
-#ifdef _TARGET_ARM64_
- void LowerPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntryPtr info);
-#endif // _TARGET_ARM64_
-#ifdef _TARGET_ARM_
- void LowerPutArgStk(GenTreePutArgStk* argNode, fgArgTabEntryPtr info);
-#endif // _TARGET_ARM64_
void LowerPutArgStk(GenTreePutArgStk* tree);
GenTree* TryCreateAddrMode(LIR::Use&& use, bool isIndir);
diff --git a/src/jit/lowerarmarch.cpp b/src/jit/lowerarmarch.cpp
index 8986f2f23e..9f73fb47e1 100644
--- a/src/jit/lowerarmarch.cpp
+++ b/src/jit/lowerarmarch.cpp
@@ -108,6 +108,9 @@ bool Lowering::IsContainableImmed(GenTree* parentNode, GenTree* childNode)
case GT_ADD:
case GT_SUB:
#ifdef _TARGET_ARM64_
+ case GT_CMPXCHG:
+ case GT_LOCKADD:
+ case GT_XADD:
return emitter::emitIns_valid_imm_for_add(immVal, size);
#elif defined(_TARGET_ARM_)
return emitter::emitIns_valid_imm_for_add(immVal, flags);
@@ -481,6 +484,28 @@ void Lowering::LowerRotate(GenTreePtr tree)
ContainCheckShiftRotate(tree->AsOp());
}
+#ifdef FEATURE_SIMD
+//----------------------------------------------------------------------------------------------
+// Lowering::LowerSIMD: Perform containment analysis for a SIMD intrinsic node.
+//
+// Arguments:
+// simdNode - The SIMD intrinsic node.
+//
+void Lowering::LowerSIMD(GenTreeSIMD* simdNode)
+{
+ assert(simdNode->gtType != TYP_SIMD32);
+
+ if (simdNode->TypeGet() == TYP_SIMD12)
+ {
+ // GT_SIMD node requiring to produce TYP_SIMD12 in fact
+ // produces a TYP_SIMD16 result
+ simdNode->gtType = TYP_SIMD16;
+ }
+
+ ContainCheckSIMD(simdNode);
+}
+#endif // FEATURE_SIMD
+
//------------------------------------------------------------------------
// Containment analysis
//------------------------------------------------------------------------
@@ -694,68 +719,7 @@ void Lowering::ContainCheckCast(GenTreeCast* node)
//
void Lowering::ContainCheckCompare(GenTreeOp* cmp)
{
- if (CheckImmedAndMakeContained(cmp, cmp->gtOp2))
- {
-#ifdef _TARGET_ARM64_
- GenTreePtr op1 = cmp->gtOp.gtOp1;
- GenTreePtr op2 = cmp->gtOp.gtOp2;
-
- // If op1 codegen can set flags op2 is an immediate 0
- // we don't need to generate cmp instruction,
- // provided we don't have another GenTree node between op1
- // and cmp that could potentially modify flags.
- //
- // TODO-CQ: right now the below peep is inexpensive and
- // gets the benefit in most of cases because in majority
- // of cases op1, op2 and cmp would be in that order in
- // execution. In general we should be able to check that all
- // the nodes that come after op1 in execution order do not
- // modify the flags so that it is safe to avoid generating a
- // test instruction. Such a check requires that on each
- // GenTree node we need to set the info whether its codegen
- // will modify flags.
- if (op2->IsIntegralConst(0) && (op1->gtNext == op2) && (op2->gtNext == cmp) &&
- !cmp->OperIs(GT_TEST_EQ, GT_TEST_NE) && op1->OperIs(GT_ADD, GT_AND, GT_SUB))
- {
- assert(!op1->gtSetFlags());
- op1->gtFlags |= GTF_SET_FLAGS;
- cmp->gtFlags |= GTF_USE_FLAGS;
- }
-
- if (!varTypeIsFloating(cmp) && op2->IsCnsIntOrI() && ((cmp->gtFlags & GTF_USE_FLAGS) == 0))
- {
- LIR::Use cmpUse;
- bool useJCMP = false;
- uint64_t flags = 0;
-
- if (cmp->OperIs(GT_EQ, GT_NE) && op2->IsIntegralConst(0) && BlockRange().TryGetUse(cmp, &cmpUse) &&
- cmpUse.User()->OperIs(GT_JTRUE))
- {
- // Codegen will use cbz or cbnz in codegen which do not affect the flag register
- flags = cmp->OperIs(GT_EQ) ? GTF_JCMP_EQ : 0;
- useJCMP = true;
- }
- else if (cmp->OperIs(GT_TEST_EQ, GT_TEST_NE) && isPow2(op2->gtIntCon.IconValue()) &&
- BlockRange().TryGetUse(cmp, &cmpUse) && cmpUse.User()->OperIs(GT_JTRUE))
- {
- // Codegen will use tbz or tbnz in codegen which do not affect the flag register
- flags = GTF_JCMP_TST | (cmp->OperIs(GT_TEST_EQ) ? GTF_JCMP_EQ : 0);
- useJCMP = true;
- }
-
- if (useJCMP)
- {
- cmp->gtLsraInfo.isNoRegCompare = true;
- cmp->SetOper(GT_JCMP);
-
- cmp->gtFlags &= ~(GTF_JCMP_TST | GTF_JCMP_EQ);
- cmp->gtFlags |= flags;
-
- BlockRange().Remove(cmpUse.User());
- }
- }
-#endif // _TARGET_ARM64_
- }
+ CheckImmedAndMakeContained(cmp, cmp->gtOp2);
}
//------------------------------------------------------------------------
@@ -774,6 +738,55 @@ void Lowering::ContainCheckBoundsChk(GenTreeBoundsChk* node)
}
}
+#ifdef FEATURE_SIMD
+//----------------------------------------------------------------------------------------------
+// ContainCheckSIMD: Perform containment analysis for a SIMD intrinsic node.
+//
+// Arguments:
+// simdNode - The SIMD intrinsic node.
+//
+void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode)
+{
+ switch (simdNode->gtSIMDIntrinsicID)
+ {
+ GenTree* op1;
+ GenTree* op2;
+
+ case SIMDIntrinsicInit:
+ // TODO-ARM64-CQ Support containing 0
+ break;
+
+ case SIMDIntrinsicInitArray:
+ // We have an array and an index, which may be contained.
+ CheckImmedAndMakeContained(simdNode, simdNode->gtGetOp2());
+ break;
+
+ case SIMDIntrinsicOpEquality:
+ case SIMDIntrinsicOpInEquality:
+ // TODO-ARM64-CQ Support containing 0
+ break;
+
+ case SIMDIntrinsicGetItem:
+ {
+ // TODO-ARM64-CQ Support containing op1 memory ops
+
+ // This implements get_Item method. The sources are:
+ // - the source SIMD struct
+ // - index (which element to get)
+ // The result is baseType of SIMD struct.
+ op2 = simdNode->gtOp.gtOp2;
+
+ // If the index is a constant, mark it as contained.
+ CheckImmedAndMakeContained(simdNode, op2);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+#endif // FEATURE_SIMD
+
#endif // _TARGET_ARMARCH_
#endif // !LEGACY_BACKEND
diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp
index bb45279887..65a1ef3661 100644
--- a/src/jit/lowerxarch.cpp
+++ b/src/jit/lowerxarch.cpp
@@ -474,8 +474,9 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
BlockRange().InsertAfter(fieldList, head);
BlockRange().Remove(fieldList);
- fieldList = head;
- putArgStk->gtOp1 = fieldList;
+ fieldList = head;
+ putArgStk->gtOp1 = fieldList;
+ putArgStk->gtType = fieldList->gtType;
}
// Now that the fields have been sorted, the kind of code we will generate.
@@ -557,7 +558,7 @@ void Lowering::LowerPutArgStk(GenTreePutArgStk* putArgStk)
GenTreePtr src = putArgStk->gtOp1;
#ifdef FEATURE_PUT_STRUCT_ARG_STK
- if (putArgStk->TypeGet() != TYP_STRUCT)
+ if (src->TypeGet() != TYP_STRUCT)
#endif // FEATURE_PUT_STRUCT_ARG_STK
{
// If the child of GT_PUTARG_STK is a constant, we don't need a register to
@@ -794,6 +795,72 @@ void Lowering::LowerSIMD(GenTreeSIMD* simdNode)
// the addr of SIMD vector with the given index.
simdNode->gtOp1->gtFlags |= GTF_IND_REQ_ADDR_IN_REG;
}
+ else if (simdNode->IsSIMDEqualityOrInequality())
+ {
+ LIR::Use simdUse;
+
+ if (BlockRange().TryGetUse(simdNode, &simdUse))
+ {
+ //
+ // Try to transform JTRUE(EQ|NE(SIMD<OpEquality|OpInEquality>(x, y), 0|1)) into
+ // JCC(SIMD<OpEquality|OpInEquality>(x, y)). SIMD<OpEquality|OpInEquality>(x, y)
+ // is expected to set the Zero flag appropriately.
+ // All the involved nodes must form a continuous range, there's no other way to
+ // guarantee that condition flags aren't changed between the SIMD node and the JCC
+ // node.
+ //
+
+ bool transformed = false;
+ GenTree* simdUser = simdUse.User();
+
+ if (simdUser->OperIs(GT_EQ, GT_NE) && simdUser->gtGetOp2()->IsCnsIntOrI() &&
+ (simdNode->gtNext == simdUser->gtGetOp2()) && (simdUser->gtGetOp2()->gtNext == simdUser))
+ {
+ ssize_t relopOp2Value = simdUser->gtGetOp2()->AsIntCon()->IconValue();
+
+ if ((relopOp2Value == 0) || (relopOp2Value == 1))
+ {
+ GenTree* jtrue = simdUser->gtNext;
+
+ if ((jtrue != nullptr) && jtrue->OperIs(GT_JTRUE) && (jtrue->gtGetOp1() == simdUser))
+ {
+ if ((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) != simdUser->OperIs(GT_EQ))
+ {
+ relopOp2Value ^= 1;
+ }
+
+ jtrue->ChangeOper(GT_JCC);
+ GenTreeCC* jcc = jtrue->AsCC();
+ jcc->gtFlags |= GTF_USE_FLAGS;
+ jcc->gtCondition = (relopOp2Value == 0) ? GT_NE : GT_EQ;
+
+ BlockRange().Remove(simdUser->gtGetOp2());
+ BlockRange().Remove(simdUser);
+ transformed = true;
+ }
+ }
+ }
+
+ if (!transformed)
+ {
+ //
+ // The code generated for SIMD SIMD<OpEquality|OpInEquality>(x, y) nodes sets
+ // the Zero flag like integer compares do so we can simply use SETCC<EQ|NE>
+ // to produce the desired result. This avoids the need for subsequent phases
+ // to have to handle 2 cases (set flags/set destination register).
+ //
+
+ genTreeOps condition = (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) ? GT_EQ : GT_NE;
+ GenTreeCC* setcc = new (comp, GT_SETCC) GenTreeCC(GT_SETCC, condition, simdNode->TypeGet());
+ setcc->gtFlags |= GTF_USE_FLAGS;
+ BlockRange().InsertAfter(simdNode, setcc);
+ simdUse.ReplaceWith(comp, setcc);
+ }
+ }
+
+ simdNode->gtFlags |= GTF_SET_FLAGS;
+ simdNode->gtType = TYP_VOID;
+ }
#endif
ContainCheckSIMD(simdNode);
}
@@ -1803,41 +1870,6 @@ void Lowering::ContainCheckCompare(GenTreeOp* cmp)
{
MakeSrcContained(cmp, op1);
}
- // If op1 codegen sets ZF and SF flags and ==/!= against
- // zero, we don't need to generate test instruction,
- // provided we don't have another GenTree node between op1
- // and cmp that could potentially modify flags.
- //
- // TODO-CQ: right now the below peep is inexpensive and
- // gets the benefit in most of cases because in majority
- // of cases op1, op2 and cmp would be in that order in
- // execution. In general we should be able to check that all
- // the nodes that come after op1 in execution order do not
- // modify the flags so that it is safe to avoid generating a
- // test instruction. Such a check requires that on each
- // GenTree node we need to set the info whether its codegen
- // will modify flags.
- //
- // TODO-CQ: We can optimize compare against zero in the
- // following cases by generating the branch as indicated
- // against each case.
- // 1) unsigned compare
- // < 0 - always FALSE
- // <= 0 - ZF=1 and jne
- // > 0 - ZF=0 and je
- // >= 0 - always TRUE
- //
- // 2) signed compare
- // < 0 - SF=1 and js
- // >= 0 - SF=0 and jns
- else if (cmp->OperIs(GT_EQ, GT_NE) && op1->gtSetZSFlags() && op2->IsIntegralConst(0) &&
- (op1->gtNext == op2) && (op2->gtNext == cmp))
- {
- // Require codegen of op1 to set the flags.
- assert(!op1->gtSetFlags());
- op1->gtFlags |= GTF_SET_FLAGS;
- cmp->gtFlags |= GTF_USE_FLAGS;
- }
else
{
SetRegOptional(op1);
@@ -2010,9 +2042,6 @@ void Lowering::ContainCheckBinary(GenTreeOp* node)
return;
}
- // Codegen of these tree nodes sets ZF and SF flags.
- node->gtFlags |= GTF_ZSF_SET;
-
// We're not marking a constant hanging on the left of an add
// as containable so we assign it to a register having CQ impact.
// TODO-XArch-CQ: Detect this case and support both generating a single instruction
@@ -2178,7 +2207,7 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode)
{
MakeSrcContained(simdNode, op1);
}
- else if ((comp->getSIMDInstructionSet() == InstructionSet_AVX) &&
+ else if ((comp->getSIMDSupportLevel() == SIMD_AVX2_Supported) &&
((simdNode->gtSIMDSize == 16) || (simdNode->gtSIMDSize == 32)))
{
// Either op1 is a float or dbl constant or an addr
@@ -2202,7 +2231,7 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode)
// for integral vectors but not for floating-point for the reason
// that we have +0.0 and -0.0 and +0.0 == -0.0
op2 = simdNode->gtGetOp2();
- if ((comp->getSIMDInstructionSet() >= InstructionSet_SSE3_4) && op2->IsIntegralConstVector(0))
+ if ((comp->getSIMDSupportLevel() >= SIMD_SSE4_Supported) && op2->IsIntegralConstVector(0))
{
MakeSrcContained(simdNode, op2);
}
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index db6e699134..1ac414c210 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -134,13 +134,19 @@ void lsraAssignRegToTree(GenTreePtr tree, regNumber reg, unsigned regIdx)
tree->gtRegNum = reg;
}
#if defined(_TARGET_ARM_)
- else if (tree->OperGet() == GT_MUL_LONG || tree->OperGet() == GT_PUTARG_REG || tree->OperGet() == GT_BITCAST)
+ else if (tree->OperIsMultiRegOp())
{
assert(regIdx == 1);
GenTreeMultiRegOp* mul = tree->AsMultiRegOp();
mul->gtOtherReg = reg;
}
- else if (tree->OperGet() == GT_PUTARG_SPLIT)
+ else if (tree->OperGet() == GT_COPY)
+ {
+ assert(regIdx == 1);
+ GenTreeCopyOrReload* copy = tree->AsCopyOrReload();
+ copy->gtOtherRegs[0] = (regNumberSmall)reg;
+ }
+ else if (tree->OperIsPutArgSplit())
{
GenTreePutArgSplit* putArg = tree->AsPutArgSplit();
putArg->SetRegNumByIdx(reg, regIdx);
@@ -1164,7 +1170,11 @@ LinearScan::LinearScan(Compiler* theCompiler)
#endif // DEBUG
enregisterLocalVars = ((compiler->opts.compFlags & CLFLG_REGVAR) != 0) && compiler->lvaTrackedCount > 0;
- availableIntRegs = (RBM_ALLINT & ~compiler->codeGen->regSet.rsMaskResvd);
+#ifdef _TARGET_ARM64_
+ availableIntRegs = (RBM_ALLINT & ~(RBM_PR | RBM_FP | RBM_LR) & ~compiler->codeGen->regSet.rsMaskResvd);
+#else
+ availableIntRegs = (RBM_ALLINT & ~compiler->codeGen->regSet.rsMaskResvd);
+#endif
#if ETW_EBP_FRAMED
availableIntRegs &= ~RBM_FPBASE;
@@ -3073,7 +3083,7 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
}
}
- if (killGCRefs(tree))
+ if (compiler->killGCRefs(tree))
{
RefPosition* pos = newRefPosition((Interval*)nullptr, currentLoc, RefTypeKillGCRefs, tree,
(allRegs(TYP_REF) & ~RBM_ARG_REGS));
@@ -3084,35 +3094,6 @@ bool LinearScan::buildKillPositionsForNode(GenTree* tree, LsraLocation currentLo
return false;
}
-//------------------------------------------------------------------------
-// killGCRefs:
-// Given some tree node return does it need all GC refs to be spilled from
-// callee save registers.
-//
-// Arguments:
-// tree - the tree for which we ask about gc refs.
-//
-// Return Value:
-// true - tree kills GC refs on callee save registers
-// false - tree doesn't affect GC refs on callee save registers
-bool LinearScan::killGCRefs(GenTree* tree)
-{
- if (tree->IsCall())
- {
- if ((tree->gtFlags & GTF_CALL_UNMANAGED) != 0)
- {
- return true;
- }
-
- if (tree->AsCall()->gtCallMethHnd == compiler->eeFindHelper(CORINFO_HELP_JIT_PINVOKE_BEGIN))
- {
- assert(compiler->opts.ShouldUsePInvokeHelpers());
- return true;
- }
- }
- return false;
-}
-
//----------------------------------------------------------------------------
// defineNewInternalTemp: Defines a ref position for an internal temp.
//
@@ -3592,7 +3573,6 @@ static int ComputeOperandDstCount(GenTree* operand)
// pointers to argument setup stores.
return 0;
}
-#ifdef _TARGET_ARMARCH_
else if (operand->OperIsPutArgStk())
{
// A PUTARG_STK argument is an operand of a call, but is neither contained, nor does it produce
@@ -3600,7 +3580,6 @@ static int ComputeOperandDstCount(GenTree* operand)
assert(!operand->isContained());
return 0;
}
-#endif // _TARGET_ARMARCH_
else
{
// If a field list or non-void-typed operand is not an unused value and does not have source registers,
@@ -4074,8 +4053,7 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
regMaskTP candidates = getUseCandidates(useNode);
#ifdef _TARGET_ARM_
- if (useNode->OperIsPutArgSplit() ||
- (compiler->opts.compUseSoftFP && (useNode->OperIsPutArgReg() || useNode->OperGet() == GT_BITCAST)))
+ if (useNode->OperIsPutArgSplit() || useNode->OperIsMultiRegOp())
{
// get i-th candidate, set bits in useCandidates must be in sequential order.
candidates = genFindLowestReg(candidates & ~currCandidates);
@@ -4168,20 +4146,13 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
}
#ifdef _TARGET_ARM_
- if (tree->OperIsPutArgSplit())
- {
- // get i-th candidate
- currCandidates = genFindLowestReg(candidates);
- candidates &= ~currCandidates;
- }
-#ifdef ARM_SOFTFP
// If oper is GT_PUTARG_REG, set bits in useCandidates must be in sequential order.
- else if (tree->OperIsMultiRegOp() || tree->OperGet() == GT_BITCAST)
+ if (tree->OperIsPutArgSplit() || tree->OperIsMultiRegOp())
{
+ // get i-th candidate
currCandidates = genFindLowestReg(candidates);
candidates &= ~currCandidates;
}
-#endif // ARM_SOFTFP
#endif // _TARGET_ARM_
if (interval == nullptr)
@@ -5341,6 +5312,68 @@ RegisterType LinearScan::getRegisterType(Interval* currentInterval, RefPosition*
}
//------------------------------------------------------------------------
+// isMatchingConstant: Check to see whether a given register contains the constant referenced
+// by the given RefPosition
+//
+// Arguments:
+// physRegRecord: The RegRecord for the register we're interested in.
+// refPosition: The RefPosition for a constant interval.
+//
+// Return Value:
+// True iff the register was defined by an identical constant node as the current interval.
+//
+bool LinearScan::isMatchingConstant(RegRecord* physRegRecord, RefPosition* refPosition)
+{
+ if ((physRegRecord->assignedInterval == nullptr) || !physRegRecord->assignedInterval->isConstant)
+ {
+ return false;
+ }
+ noway_assert(refPosition->treeNode != nullptr);
+ GenTree* otherTreeNode = physRegRecord->assignedInterval->firstRefPosition->treeNode;
+ noway_assert(otherTreeNode != nullptr);
+
+ if (refPosition->treeNode->OperGet() == otherTreeNode->OperGet())
+ {
+ switch (otherTreeNode->OperGet())
+ {
+ case GT_CNS_INT:
+ if ((refPosition->treeNode->AsIntCon()->IconValue() == otherTreeNode->AsIntCon()->IconValue()) &&
+ (varTypeGCtype(refPosition->treeNode) == varTypeGCtype(otherTreeNode)))
+ {
+#ifdef _TARGET_64BIT_
+ // If the constant is negative, only reuse registers of the same type.
+ // This is because, on a 64-bit system, we do not sign-extend immediates in registers to
+ // 64-bits unless they are actually longs, as this requires a longer instruction.
+ // This doesn't apply to a 32-bit system, on which long values occupy multiple registers.
+ // (We could sign-extend, but we would have to always sign-extend, because if we reuse more
+ // than once, we won't have access to the instruction that originally defines the constant).
+ if ((refPosition->treeNode->TypeGet() == otherTreeNode->TypeGet()) ||
+ (refPosition->treeNode->AsIntCon()->IconValue() >= 0))
+#endif // _TARGET_64BIT_
+ {
+ return true;
+ }
+ }
+ break;
+ case GT_CNS_DBL:
+ {
+ // For floating point constants, the values must be identical, not simply compare
+ // equal. So we compare the bits.
+ if (refPosition->treeNode->AsDblCon()->isBitwiseEqual(otherTreeNode->AsDblCon()) &&
+ (refPosition->treeNode->TypeGet() == otherTreeNode->TypeGet()))
+ {
+ return true;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------
// tryAllocateFreeReg: Find a free register that satisfies the requirements for refPosition,
// and takes into account the preferences for the given Interval
//
@@ -5430,7 +5463,6 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
#ifdef DEBUG
candidates = stressLimitRegs(refPosition, candidates);
#endif
- bool mustAssignARegister = true;
assert(candidates != RBM_NONE);
// If the related interval has no further references, it is possible that it is a source of the
@@ -5553,6 +5585,9 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
}
}
+ //-------------------------------------------------------------------------
+ // Register Selection
+
RegRecord* availablePhysRegInterval = nullptr;
bool unassignInterval = false;
@@ -5653,52 +5688,9 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
// If this is a definition of a constant interval, check to see if its value is already in this register.
if (currentInterval->isConstant && RefTypeIsDef(refPosition->refType) &&
- (physRegRecord->assignedInterval != nullptr) && physRegRecord->assignedInterval->isConstant)
+ isMatchingConstant(physRegRecord, refPosition))
{
- noway_assert(refPosition->treeNode != nullptr);
- GenTree* otherTreeNode = physRegRecord->assignedInterval->firstRefPosition->treeNode;
- noway_assert(otherTreeNode != nullptr);
-
- if (refPosition->treeNode->OperGet() == otherTreeNode->OperGet())
- {
- switch (otherTreeNode->OperGet())
- {
- case GT_CNS_INT:
- if ((refPosition->treeNode->AsIntCon()->IconValue() ==
- otherTreeNode->AsIntCon()->IconValue()) &&
- (varTypeGCtype(refPosition->treeNode) == varTypeGCtype(otherTreeNode)))
- {
-#ifdef _TARGET_64BIT_
- // If the constant is negative, only reuse registers of the same type.
- // This is because, on a 64-bit system, we do not sign-extend immediates in registers to
- // 64-bits unless they are actually longs, as this requires a longer instruction.
- // This doesn't apply to a 32-bit system, on which long values occupy multiple registers.
- // (We could sign-extend, but we would have to always sign-extend, because if we reuse more
- // than once, we won't have access to the instruction that originally defines the constant).
- if ((refPosition->treeNode->TypeGet() == otherTreeNode->TypeGet()) ||
- (refPosition->treeNode->AsIntCon()->IconValue() >= 0))
-#endif // _TARGET_64BIT_
- {
- score |= VALUE_AVAILABLE;
- }
- }
- break;
- case GT_CNS_DBL:
- {
- // For floating point constants, the values must be identical, not simply compare
- // equal. So we compare the bits.
- if (refPosition->treeNode->AsDblCon()->isBitwiseEqual(otherTreeNode->AsDblCon()) &&
- (refPosition->treeNode->TypeGet() == otherTreeNode->TypeGet()))
- {
- score |= VALUE_AVAILABLE;
- }
- break;
- }
- default:
- // for all other 'otherTreeNode->OperGet()' kinds, we leave 'score' unchanged
- break;
- }
- }
+ score |= VALUE_AVAILABLE;
}
// If the nextPhysRefLocation is a fixedRef for the rangeEndRefPosition, increment it so that
@@ -5838,6 +5830,7 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
return foundReg;
}
+
//------------------------------------------------------------------------
// canSpillReg: Determine whether we can spill physRegRecord
//
@@ -5853,27 +5846,16 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition*
//
// Note: This helper is designed to be used only from allocateBusyReg() and canSpillDoubleReg()
//
-bool LinearScan::canSpillReg(RegRecord* physRegRecord,
- LsraLocation refLocation,
- unsigned* recentAssignedRefWeight,
- unsigned farthestRefPosWeight)
+bool LinearScan::canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight)
{
assert(physRegRecord->assignedInterval != nullptr);
RefPosition* recentAssignedRef = physRegRecord->assignedInterval->recentRefPosition;
if (recentAssignedRef != nullptr)
{
- if (recentAssignedRef->nodeLocation == refLocation)
- {
- // We can't spill a register that's being used at the current location
- return false;
- }
-
- // If the current position has the candidate register marked to be delayed,
- // check if the previous location is using this register, if that's the case we have to skip
- // since we can't spill this register.
- if (recentAssignedRef->delayRegFree && (refLocation == recentAssignedRef->nodeLocation + 1))
+ if (isRefPositionActive(recentAssignedRef, refLocation))
{
+ // We can't spill a register that's active at the current location
return false;
}
@@ -5881,141 +5863,68 @@ bool LinearScan::canSpillReg(RegRecord* physRegRecord,
// of the spill candidate found so far. We would consider spilling a greater weight
// ref position only if the refPosition being allocated must need a reg.
*recentAssignedRefWeight = getWeight(recentAssignedRef);
- if (*recentAssignedRefWeight > farthestRefPosWeight)
- {
- return false;
- }
}
return true;
}
#ifdef _TARGET_ARM_
+//------------------------------------------------------------------------
+// canSpillDoubleReg: Determine whether we can spill physRegRecord
+//
+// Arguments:
+// physRegRecord - reg to spill (must be a valid double register)
+// refLocation - Location of RefPosition where this register will be spilled
+// recentAssignedRefWeight - Weight of recent assigned RefPosition which will be determined in this function
+//
+// Return Value:
+// True - if we can spill physRegRecord
+// False - otherwise
+//
+// Notes:
+// This helper is designed to be used only from allocateBusyReg() and canSpillDoubleReg().
+// The recentAssignedRefWeight is not updated if either register cannot be spilled.
+//
bool LinearScan::canSpillDoubleReg(RegRecord* physRegRecord,
LsraLocation refLocation,
- unsigned* recentAssignedRefWeight,
- unsigned farthestRefPosWeight)
+ unsigned* recentAssignedRefWeight)
{
+ assert(genIsValidDoubleReg(physRegRecord->regNum));
bool retVal = true;
unsigned weight = BB_ZERO_WEIGHT;
unsigned weight2 = BB_ZERO_WEIGHT;
RegRecord* physRegRecord2 = findAnotherHalfRegRec(physRegRecord);
- if (physRegRecord->assignedInterval != nullptr)
- retVal &= canSpillReg(physRegRecord, refLocation, &weight, farthestRefPosWeight);
-
- if (physRegRecord2->assignedInterval != nullptr)
- retVal &= canSpillReg(physRegRecord2, refLocation, &weight2, farthestRefPosWeight);
-
- if (!(weight == BB_ZERO_WEIGHT && weight2 == BB_ZERO_WEIGHT))
+ if ((physRegRecord->assignedInterval != nullptr) && !canSpillReg(physRegRecord, refLocation, &weight))
{
- // weight and/or weight2 have been updated.
- *recentAssignedRefWeight = (weight > weight2) ? weight : weight2;
+ return false;
}
-
- return retVal;
-}
-#endif
-
-//----------------------------------------------------------------------------
-// checkActiveInterval: Test activness of an interval
-// and check assertions if the interval is not active
-//
-// Arguments:
-// interval - An interval to be tested
-// refLocation - Location where the interval is being tested
-//
-// Return Value:
-// True - iff the interval is active
-// False - otherwise
-//
-// Note: This helper is designed to be used only from checkActiveIntervals()
-//
-bool LinearScan::checkActiveInterval(Interval* interval, LsraLocation refLocation)
-{
- if (!interval->isActive)
+ if (physRegRecord2->assignedInterval != nullptr)
{
- RefPosition* recentAssignedRef = interval->recentRefPosition;
- // Note that we may or may not have actually handled the reference yet, so it could either
- // be recentAssignedRef, or the next reference.
- assert(recentAssignedRef != nullptr);
- if (recentAssignedRef->nodeLocation != refLocation)
+ if (!canSpillReg(physRegRecord2, refLocation, &weight2))
{
- if (recentAssignedRef->nodeLocation + 1 == refLocation)
- {
- assert(recentAssignedRef->delayRegFree);
- }
- else
- {
- RefPosition* nextAssignedRef = recentAssignedRef->nextRefPosition;
-#ifdef _TARGET_ARM_
- // This function is invoked only from allocateBusyReg() through checkActiveIntervals().
- //
- // For ARM32, when we try to allocate a double register which consists of two float registers,
- // tryAllocateFreeReg() may fail to allocate a double register even if one of two float
- // reigsters is assigned to a inactive constant interval.
- // https://github.com/dotnet/coreclr/pull/14080
- //
- // Therefore an inactive constant interval may be encountered here.
- assert(nextAssignedRef != nullptr || interval->isConstant);
- if (nextAssignedRef != nullptr)
- assert(nextAssignedRef->nodeLocation == refLocation ||
- (nextAssignedRef->nodeLocation + 1 == refLocation && nextAssignedRef->delayRegFree));
-#else // !_TARGET_ARM_
- assert(nextAssignedRef != nullptr);
- assert(nextAssignedRef->nodeLocation == refLocation ||
- (nextAssignedRef->nodeLocation + 1 == refLocation && nextAssignedRef->delayRegFree));
-#endif // !_TARGET_ARM_
- }
+ return false;
+ }
+ if (weight2 > weight)
+ {
+ weight = weight2;
}
- return false;
}
+ *recentAssignedRefWeight = weight;
return true;
}
+#endif
-//----------------------------------------------------------------------------------------
-// checkActiveIntervals: Test activness of a interval assinged to a register
-// and check assertions if the interval is not active.
-// We look into all intervals of two float registers consisting
-// a double regsiter for ARM32.
+#ifdef _TARGET_ARM_
+//------------------------------------------------------------------------
+// unassignDoublePhysReg: unassign a double register (pair)
//
// Arguments:
-// physRegRecord - A register
-// refLocation - Location where intervsl is being tested
-// registerType - Type of regsiter
+// doubleRegRecord - reg to unassign
//
-// Return Value:
-// True - iff the all intervals are active
-// False - otherwise
-//
-// Note: This helper is designed to be used only from allocateBusyReg()
+// Note:
+// The given RegRecord must be a valid (even numbered) double register.
//
-bool LinearScan::checkActiveIntervals(RegRecord* physRegRecord, LsraLocation refLocation, RegisterType registerType)
-{
- Interval* assignedInterval = physRegRecord->assignedInterval;
-
-#ifdef _TARGET_ARM_
- // Check two intervals for a double register in ARM32
- Interval* assignedInterval2 = nullptr;
- if (registerType == TYP_DOUBLE)
- assignedInterval2 = findAnotherHalfRegRec(physRegRecord)->assignedInterval;
-
- // Both intervals should not be nullptr at the same time, becasue we already handle this case before.
- assert(!(assignedInterval == nullptr && assignedInterval2 == nullptr));
-
- if (assignedInterval != nullptr && !checkActiveInterval(assignedInterval, refLocation))
- return false;
-
- if (assignedInterval2 != nullptr && !checkActiveInterval(assignedInterval2, refLocation))
- return false;
-
- return true;
-#else
- return checkActiveInterval(assignedInterval, refLocation);
-#endif
-}
-
-#ifdef _TARGET_ARM_
void LinearScan::unassignDoublePhysReg(RegRecord* doubleRegRecord)
{
assert(genIsValidDoubleReg(doubleRegRecord->regNum));
@@ -6062,35 +5971,79 @@ void LinearScan::unassignDoublePhysReg(RegRecord* doubleRegRecord)
#endif // _TARGET_ARM_
+//------------------------------------------------------------------------
+// isRefPositionActive: Determine whether a given RefPosition is active at the given location
+//
+// Arguments:
+// refPosition - the RefPosition of interest
+// refLocation - the LsraLocation at which we want to know if it is active
+//
+// Return Value:
+// True - if this RefPosition occurs at the given location, OR
+// if it occurs at the previous location and is marked delayRegFree.
+// False - otherwise
+//
+bool LinearScan::isRefPositionActive(RefPosition* refPosition, LsraLocation refLocation)
+{
+ return (refPosition->nodeLocation == refLocation ||
+ ((refPosition->nodeLocation + 1 == refLocation) && refPosition->delayRegFree));
+}
+
//----------------------------------------------------------------------------------------
// isRegInUse: Test whether regRec is being used at the refPosition
//
// Arguments:
// regRec - A register to be tested
// refPosition - RefPosition where regRec is tested
-// nextLocation - next RefPosition of interval assigned to regRec
//
// Return Value:
-// True - if regRec is beding used
+// True - if regRec is being used
// False - otherwise
//
-// Note: This helper is designed to be used only from allocateBusyReg()
+// Notes:
+// This helper is designed to be used only from allocateBusyReg().
+// The caller must have already checked for the case where 'refPosition' is a fixed ref.
//
-bool LinearScan::isRegInUse(RegRecord* regRec, RefPosition* refPosition, LsraLocation* nextLocation)
+bool LinearScan::isRegInUse(RegRecord* regRec, RefPosition* refPosition)
{
+ // We shouldn't reach this check if 'refPosition' is a FixedReg of this register.
+ assert(!refPosition->isFixedRefOfReg(regRec->regNum));
Interval* assignedInterval = regRec->assignedInterval;
if (assignedInterval != nullptr)
{
- LsraLocation refLocation = refPosition->nodeLocation;
- RefPosition* nextRefPosition = assignedInterval->getNextRefPosition();
- *nextLocation = assignedInterval->getNextRefLocation();
+ if (!assignedInterval->isActive)
+ {
+ // This can only happen if we have a recentRefPosition active at this location that hasn't yet been freed
+ // (Or, in the case of ARM, the other half of a double is either active or has an active recentRefPosition).
+ CLANG_FORMAT_COMMENT_ANCHOR;
+
+#ifdef _TARGET_ARM_
+ if (refPosition->getInterval()->registerType == TYP_DOUBLE)
+ {
+ if (!isRefPositionActive(assignedInterval->recentRefPosition, refPosition->nodeLocation))
+ {
+ RegRecord* otherHalfRegRec = findAnotherHalfRegRec(regRec);
+ assert(otherHalfRegRec->assignedInterval->isActive ||
+ isRefPositionActive(otherHalfRegRec->assignedInterval->recentRefPosition,
+ refPosition->nodeLocation));
+ }
+ }
+ else
+#endif
+ {
+ assert(isRefPositionActive(assignedInterval->recentRefPosition, refPosition->nodeLocation));
+ }
+ return true;
+ }
+ RefPosition* nextAssignedRef = assignedInterval->getNextRefPosition();
// We should never spill a register that's occupied by an Interval with its next use at the current
// location.
// Normally this won't occur (unless we actually had more uses in a single node than there are registers),
// because we'll always find something with a later nextLocation, but it can happen in stress when
// we have LSRA_SELECT_NEAREST.
- if ((*nextLocation == refLocation) && !refPosition->isFixedRegRef && nextRefPosition->RequiresRegister())
+ if ((nextAssignedRef != nullptr) && isRefPositionActive(nextAssignedRef, refPosition->nodeLocation) &&
+ nextAssignedRef->RequiresRegister())
{
return true;
}
@@ -6099,6 +6052,116 @@ bool LinearScan::isRegInUse(RegRecord* regRec, RefPosition* refPosition, LsraLoc
}
//------------------------------------------------------------------------
+// isSpillCandidate: Determine if a register is a spill candidate for a given RefPosition.
+//
+// Arguments:
+// current The interval for the current allocation
+// refPosition The RefPosition of the current Interval for which a register is being allocated
+// physRegRecord The RegRecord for the register we're considering for spill
+// nextLocation An out (reference) parameter in which the next use location of the
+// given RegRecord will be returned.
+//
+// Return Value:
+// True iff the given register can be spilled to accommodate the given RefPosition.
+//
+bool LinearScan::isSpillCandidate(Interval* current,
+ RefPosition* refPosition,
+ RegRecord* physRegRecord,
+ LsraLocation& nextLocation)
+{
+ regMaskTP candidateBit = genRegMask(physRegRecord->regNum);
+ LsraLocation refLocation = refPosition->nodeLocation;
+ if (physRegRecord->isBusyUntilNextKill)
+ {
+ return false;
+ }
+ Interval* assignedInterval = physRegRecord->assignedInterval;
+ if (assignedInterval != nullptr)
+ {
+ nextLocation = assignedInterval->getNextRefLocation();
+ }
+#ifdef _TARGET_ARM_
+ RegRecord* physRegRecord2 = nullptr;
+ Interval* assignedInterval2 = nullptr;
+
+ // For ARM32, a double occupies a consecutive even/odd pair of float registers.
+ if (current->registerType == TYP_DOUBLE)
+ {
+ assert(genIsValidDoubleReg(physRegRecord->regNum));
+ physRegRecord2 = findAnotherHalfRegRec(physRegRecord);
+ if (physRegRecord2->isBusyUntilNextKill)
+ {
+ return false;
+ }
+ assignedInterval2 = physRegRecord2->assignedInterval;
+ if ((assignedInterval2 != nullptr) && (assignedInterval2->getNextRefLocation() > nextLocation))
+ {
+ nextLocation = assignedInterval2->getNextRefLocation();
+ }
+ }
+#endif
+
+ // If there is a fixed reference at the same location (and it's not due to this reference),
+ // don't use it.
+ if (physRegRecord->conflictingFixedRegReference(refPosition))
+ {
+ return false;
+ }
+
+ if (refPosition->isFixedRefOfRegMask(candidateBit))
+ {
+ // Either:
+ // - there is a fixed reference due to this node, OR
+ // - or there is a fixed use fed by a def at this node, OR
+ // - or we have restricted the set of registers for stress.
+ // In any case, we must use this register as it's the only candidate
+ // TODO-CQ: At the time we allocate a register to a fixed-reg def, if it's not going
+ // to remain live until the use, we should set the candidates to allRegs(regType)
+ // to avoid a spill - codegen can then insert the copy.
+ // If this is marked as allocateIfProfitable, the caller will compare the weights
+ // of this RefPosition and the RefPosition to which it is currently assigned.
+ assert(refPosition->isFixedRegRef ||
+ (refPosition->nextRefPosition != nullptr && refPosition->nextRefPosition->isFixedRegRef) ||
+ candidatesAreStressLimited());
+ return true;
+ }
+
+ // If this register is not assigned to an interval, either
+ // - it has a FixedReg reference at the current location that is not this reference, OR
+ // - this is the special case of a fixed loReg, where this interval has a use at the same location
+ // In either case, we cannot use it
+ CLANG_FORMAT_COMMENT_ANCHOR;
+
+#ifdef _TARGET_ARM_
+ if (assignedInterval == nullptr && assignedInterval2 == nullptr)
+#else
+ if (assignedInterval == nullptr)
+#endif
+ {
+ RefPosition* nextPhysRegPosition = physRegRecord->getNextRefPosition();
+ assert((nextPhysRegPosition->nodeLocation == refLocation && candidateBit != refPosition->registerAssignment)
+ ARM64_ONLY(|| (physRegRecord->regNum == REG_IP0) || (physRegRecord->regNum == REG_IP1)));
+ return false;
+ }
+
+ if (isRegInUse(physRegRecord, refPosition))
+ {
+ return false;
+ }
+
+#ifdef _TARGET_ARM_
+ if (current->registerType == TYP_DOUBLE)
+ {
+ if (isRegInUse(physRegRecord2, refPosition))
+ {
+ return false;
+ }
+ }
+#endif
+ return true;
+}
+
+//------------------------------------------------------------------------
// allocateBusyReg: Find a busy register that satisfies the requirements for refPosition,
// and that can be spilled.
//
@@ -6123,6 +6186,7 @@ bool LinearScan::isRegInUse(RegRecord* regRec, RefPosition* refPosition, LsraLoc
// 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 allocateIfProfitable)
{
regNumber foundReg = REG_NA;
@@ -6180,148 +6244,49 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio
{
continue;
}
- RegRecord* physRegRecord = getRegisterRecord(regNum);
-#ifdef _TARGET_ARM_
- RegRecord* physRegRecord2 = nullptr;
- // For ARM32, let's consider two float registers consisting a double reg together,
- // when allocaing a double register.
- if (current->registerType == TYP_DOUBLE)
- {
- assert(genIsValidDoubleReg(regNum));
- physRegRecord2 = findAnotherHalfRegRec(physRegRecord);
- }
-#endif
-
- if (physRegRecord->isBusyUntilNextKill)
- {
- continue;
- }
- Interval* assignedInterval = physRegRecord->assignedInterval;
-#ifdef _TARGET_ARM_
- Interval* assignedInterval2 = (physRegRecord2 == nullptr) ? nullptr : physRegRecord2->assignedInterval;
-#endif
-
- // If there is a fixed reference at the same location (and it's not due to this reference),
- // don't use it.
-
- if (physRegRecord->conflictingFixedRegReference(refPosition))
+ RegRecord* physRegRecord = getRegisterRecord(regNum);
+ RegRecord* physRegRecord2 = nullptr; // only used for _TARGET_ARM_
+ LsraLocation nextLocation = MinLocation;
+ LsraLocation physRegNextLocation;
+ if (!isSpillCandidate(current, refPosition, physRegRecord, nextLocation))
{
assert(candidates != candidateBit);
continue;
}
- LsraLocation physRegNextLocation = MaxLocation;
- if (refPosition->isFixedRefOfRegMask(candidateBit))
+ // We've passed the preliminary checks for a spill candidate.
+ // Now, if we have a recentAssignedRef, check that it is going to be OK to spill it.
+ Interval* assignedInterval = physRegRecord->assignedInterval;
+ unsigned recentAssignedRefWeight = BB_ZERO_WEIGHT;
+ RefPosition* recentAssignedRef = nullptr;
+ RefPosition* recentAssignedRef2 = nullptr;
+#ifdef _TARGET_ARM_
+ if (current->registerType == TYP_DOUBLE)
{
- // Either there is a fixed reference due to this node, or one associated with a
- // fixed use fed by a def at this node.
- // In either case, we must use this register as it's the only candidate
- // TODO-CQ: At the time we allocate a register to a fixed-reg def, if it's not going
- // to remain live until the use, we should set the candidates to allRegs(regType)
- // to avoid a spill - codegen can then insert the copy.
- assert(candidates == candidateBit);
-
- // If a refPosition has a fixed reg as its candidate and is also marked
- // as allocateIfProfitable, we should allocate fixed reg only if the
- // weight of this ref position is greater than the weight of the ref
- // position to which fixed reg is assigned. Such a case would arise
- // on x86 under LSRA stress.
- if (!allocateIfProfitable)
+ recentAssignedRef = (assignedInterval == nullptr) ? nullptr : assignedInterval->recentRefPosition;
+ physRegRecord2 = findAnotherHalfRegRec(physRegRecord);
+ Interval* assignedInterval2 = physRegRecord2->assignedInterval;
+ recentAssignedRef2 = (assignedInterval2 == nullptr) ? nullptr : assignedInterval2->recentRefPosition;
+ if (!canSpillDoubleReg(physRegRecord, refLocation, &recentAssignedRefWeight))
{
- physRegNextLocation = MaxLocation;
- farthestRefPosWeight = BB_MAX_WEIGHT;
+ continue;
}
}
else
+#endif
{
- physRegNextLocation = physRegRecord->getNextRefLocation();
-
- // If refPosition requires a fixed register, we should reject all others.
- // Otherwise, we will still evaluate all phyRegs though their next location is
- // not better than farthestLocation found so far.
- //
- // TODO: this method should be using an approach similar to tryAllocateFreeReg()
- // where it uses a regOrder array to avoid iterating over any but the single
- // fixed candidate.
- if (refPosition->isFixedRegRef && physRegNextLocation < farthestLocation)
+ recentAssignedRef = assignedInterval->recentRefPosition;
+ if (!canSpillReg(physRegRecord, refLocation, &recentAssignedRefWeight))
{
continue;
}
}
-
- // If this register is not assigned to an interval, either
- // - it has a FixedReg reference at the current location that is not this reference, OR
- // - this is the special case of a fixed loReg, where this interval has a use at the same location
- // In either case, we cannot use it
- CLANG_FORMAT_COMMENT_ANCHOR;
-
-#ifdef _TARGET_ARM_
- if (assignedInterval == nullptr && assignedInterval2 == nullptr)
-#else
- if (assignedInterval == nullptr)
-#endif
+ if (recentAssignedRefWeight > farthestRefPosWeight)
{
- RefPosition* nextPhysRegPosition = physRegRecord->getNextRefPosition();
-
-#ifndef _TARGET_ARM64_
- // TODO-Cleanup: Revisit this after Issue #3524 is complete
- // On ARM64 the nodeLocation is not always == refLocation, Disabling this assert for now.
- assert(nextPhysRegPosition->nodeLocation == refLocation && candidateBit != candidates);
-#endif
continue;
}
-#ifdef _TARGET_ARM_
- RefPosition* recentAssignedRef = (assignedInterval == nullptr) ? nullptr : assignedInterval->recentRefPosition;
- RefPosition* recentAssignedRef2 =
- (assignedInterval2 == nullptr) ? nullptr : assignedInterval2->recentRefPosition;
-#else
- RefPosition* recentAssignedRef = assignedInterval->recentRefPosition;
-#endif
-
- if (!checkActiveIntervals(physRegRecord, refLocation, current->registerType))
- {
- continue;
- }
-
- // If we have a recentAssignedRef, check that it is going to be OK to spill it
- //
- // TODO-Review: Under what conditions recentAssginedRef would be null?
- unsigned recentAssignedRefWeight = BB_ZERO_WEIGHT;
-
-#ifdef _TARGET_ARM_
- if (current->registerType == TYP_DOUBLE)
- {
- if (!canSpillDoubleReg(physRegRecord, refLocation, &recentAssignedRefWeight, farthestRefPosWeight))
- continue;
- }
- else
-#endif
- // This if-stmt is associated with the above else
- if (!canSpillReg(physRegRecord, refLocation, &recentAssignedRefWeight, farthestRefPosWeight))
- {
- continue;
- }
-
- LsraLocation nextLocation = MinLocation;
-
- if (isRegInUse(physRegRecord, refPosition, &nextLocation))
- {
- continue;
- }
-
-#ifdef _TARGET_ARM_
- if (current->registerType == TYP_DOUBLE)
- {
- LsraLocation nextLocation2 = MinLocation;
- if (isRegInUse(physRegRecord2, refPosition, &nextLocation2))
- {
- continue;
- }
- nextLocation = (nextLocation > nextLocation2) ? nextLocation : nextLocation2;
- }
-#endif
-
+ physRegNextLocation = physRegRecord->getNextRefLocation();
if (nextLocation > physRegNextLocation)
{
nextLocation = physRegNextLocation;
@@ -6384,7 +6349,7 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio
if (recentAssignedRef2 != nullptr)
isBetterLocation &= (recentAssignedRef2->reload && recentAssignedRef2->AllocateIfProfitable());
#else
- isBetterLocation = (recentAssignedRef != nullptr) && recentAssignedRef->reload &&
+ isBetterLocation = (recentAssignedRef != nullptr) && recentAssignedRef->reload &&
recentAssignedRef->AllocateIfProfitable();
#endif
}
@@ -6417,41 +6382,50 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio
{
// Must have found a spill candidate.
assert(farthestRefPhysRegRecord != nullptr);
- if ((farthestLocation == refLocation) && !refPosition->isFixedRegRef)
+
+ if (farthestLocation == refLocation)
{
-#ifdef _TARGET_ARM_
- Interval* assignedInterval =
- (farthestRefPhysRegRecord == nullptr) ? nullptr : farthestRefPhysRegRecord->assignedInterval;
- Interval* assignedInterval2 =
- (farthestRefPhysRegRecord2 == nullptr) ? nullptr : farthestRefPhysRegRecord2->assignedInterval;
- RefPosition* nextRefPosition =
- (assignedInterval == nullptr) ? nullptr : assignedInterval->getNextRefPosition();
- RefPosition* nextRefPosition2 =
- (assignedInterval2 == nullptr) ? nullptr : assignedInterval2->getNextRefPosition();
- if (nextRefPosition != nullptr)
+ // This must be a RefPosition that is constrained to use a single register, either directly,
+ // or at the use, or by stress.
+ bool isConstrained = (refPosition->isFixedRegRef || (refPosition->nextRefPosition != nullptr &&
+ refPosition->nextRefPosition->isFixedRegRef) ||
+ candidatesAreStressLimited());
+ if (!isConstrained)
{
- if (nextRefPosition2 != nullptr)
- {
- assert(!nextRefPosition->RequiresRegister() || !nextRefPosition2->RequiresRegister());
+#ifdef _TARGET_ARM_
+ Interval* assignedInterval =
+ (farthestRefPhysRegRecord == nullptr) ? nullptr : farthestRefPhysRegRecord->assignedInterval;
+ Interval* assignedInterval2 =
+ (farthestRefPhysRegRecord2 == nullptr) ? nullptr : farthestRefPhysRegRecord2->assignedInterval;
+ RefPosition* nextRefPosition =
+ (assignedInterval == nullptr) ? nullptr : assignedInterval->getNextRefPosition();
+ RefPosition* nextRefPosition2 =
+ (assignedInterval2 == nullptr) ? nullptr : assignedInterval2->getNextRefPosition();
+ if (nextRefPosition != nullptr)
+ {
+ if (nextRefPosition2 != nullptr)
+ {
+ assert(!nextRefPosition->RequiresRegister() || !nextRefPosition2->RequiresRegister());
+ }
+ else
+ {
+ assert(!nextRefPosition->RequiresRegister());
+ }
}
else
{
- assert(!nextRefPosition->RequiresRegister());
+ assert(nextRefPosition2 != nullptr && !nextRefPosition2->RequiresRegister());
}
- }
- else
- {
- assert(nextRefPosition2 != nullptr && !nextRefPosition2->RequiresRegister());
- }
#else // !_TARGET_ARM_
- Interval* assignedInterval = farthestRefPhysRegRecord->assignedInterval;
- RefPosition* nextRefPosition = assignedInterval->getNextRefPosition();
- assert(!nextRefPosition->RequiresRegister());
+ Interval* assignedInterval = farthestRefPhysRegRecord->assignedInterval;
+ RefPosition* nextRefPosition = assignedInterval->getNextRefPosition();
+ assert(!nextRefPosition->RequiresRegister());
#endif // !_TARGET_ARM_
+ }
}
else
{
- assert(farthestLocation > refLocation || refPosition->isFixedRegRef);
+ assert(farthestLocation > refLocation);
}
}
#endif // DEBUG
@@ -6898,9 +6872,11 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
{
Interval* assignedInterval = regRec->assignedInterval;
assert(assignedInterval != nullptr);
-
regNumber thisRegNum = regRec->regNum;
+ // Is assignedInterval actually still assigned to this register?
+ bool intervalIsAssigned = (assignedInterval->physReg == thisRegNum);
+
#ifdef _TARGET_ARM_
RegRecord* anotherRegRec = nullptr;
@@ -6913,6 +6889,10 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
// Both two RegRecords should have been assigned to the same interval.
assert(assignedInterval == anotherRegRec->assignedInterval);
+ if (!intervalIsAssigned && (assignedInterval->physReg == anotherRegRec->regNum))
+ {
+ intervalIsAssigned = true;
+ }
}
#endif // _TARGET_ARM_
@@ -6942,7 +6922,7 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio
nextRefPosition = spillRefPosition->nextRefPosition;
}
- if (assignedInterval->physReg != REG_NA && assignedInterval->physReg != thisRegNum)
+ if (!intervalIsAssigned && assignedInterval->physReg != REG_NA)
{
// This must have been a temporary copy reg, but we can't assert that because there
// may have been intervening RefPositions that were not copyRegs.
@@ -7292,6 +7272,42 @@ bool LinearScan::isAssignedToInterval(Interval* interval, RegRecord* regRec)
return isAssigned;
}
+void LinearScan::unassignIntervalBlockStart(RegRecord* regRecord, VarToRegMap inVarToRegMap)
+{
+ // Is there another interval currently assigned to this register? If so unassign it.
+ Interval* assignedInterval = regRecord->assignedInterval;
+ if (assignedInterval != nullptr)
+ {
+ if (isAssignedToInterval(assignedInterval, regRecord))
+ {
+ // Only localVars or constants should be assigned to registers at block boundaries.
+ if (!assignedInterval->isLocalVar)
+ {
+ assert(assignedInterval->isConstant);
+ // Don't need to update the VarToRegMap.
+ inVarToRegMap = nullptr;
+ }
+
+ regNumber assignedRegNum = assignedInterval->assignedReg->regNum;
+
+ // If the interval is active, it will be set to active when we reach its new
+ // register assignment (which we must not yet have done, or it wouldn't still be
+ // assigned to this register).
+ assignedInterval->isActive = false;
+ unassignPhysReg(assignedInterval->assignedReg, nullptr);
+ if ((inVarToRegMap != nullptr) && inVarToRegMap[assignedInterval->getVarIndex(compiler)] == assignedRegNum)
+ {
+ inVarToRegMap[assignedInterval->getVarIndex(compiler)] = REG_STK;
+ }
+ }
+ else
+ {
+ // This interval is no longer assigned to this register.
+ updateAssignedInterval(regRecord, nullptr, assignedInterval->registerType);
+ }
+ }
+}
+
//------------------------------------------------------------------------
// processBlockStartLocations: Update var locations on entry to 'currentBlock' and clear constant
// registers.
@@ -7469,33 +7485,22 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock, bool alloc
interval->physReg = targetReg;
interval->assignedReg = targetRegRecord;
}
- Interval* assignedInterval = targetRegRecord->assignedInterval;
- if (assignedInterval != interval)
+ if (targetRegRecord->assignedInterval != interval)
{
- // Is there another interval currently assigned to this register? If so unassign it.
- if (assignedInterval != nullptr)
+#ifdef _TARGET_ARM_
+ // If this is a TYP_DOUBLE interval, and the assigned interval is either null or is TYP_FLOAT,
+ // we also need to unassign the other half of the register.
+ // Note that if the assigned interval is TYP_DOUBLE, it will be unassigned below.
+ if ((interval->registerType == TYP_DOUBLE) &&
+ ((targetRegRecord->assignedInterval == nullptr) ||
+ (targetRegRecord->assignedInterval->registerType == TYP_FLOAT)))
{
- if (isAssignedToInterval(assignedInterval, targetRegRecord))
- {
- regNumber assignedRegNum = assignedInterval->assignedReg->regNum;
-
- // If the interval is active, it will be set to active when we reach its new
- // register assignment (which we must not yet have done, or it wouldn't still be
- // assigned to this register).
- assignedInterval->isActive = false;
- unassignPhysReg(assignedInterval->assignedReg, nullptr);
- if (allocationPass && assignedInterval->isLocalVar &&
- inVarToRegMap[assignedInterval->getVarIndex(compiler)] == assignedRegNum)
- {
- inVarToRegMap[assignedInterval->getVarIndex(compiler)] = REG_STK;
- }
- }
- else
- {
- // This interval is no longer assigned to this register.
- updateAssignedInterval(targetRegRecord, nullptr, assignedInterval->registerType);
- }
+ assert(genIsValidDoubleReg(targetReg));
+ unassignIntervalBlockStart(findAnotherHalfRegRec(targetRegRecord),
+ allocationPass ? inVarToRegMap : nullptr);
}
+#endif // _TARGET_ARM_
+ unassignIntervalBlockStart(targetRegRecord, allocationPass ? inVarToRegMap : nullptr);
assignPhysReg(targetRegRecord, interval);
}
if (interval->recentRefPosition != nullptr && !interval->recentRefPosition->copyReg &&
@@ -8522,17 +8527,23 @@ void LinearScan::allocateRegisters()
//
void LinearScan::updateAssignedInterval(RegRecord* reg, Interval* interval, RegisterType regType)
{
- reg->assignedInterval = interval;
-
#ifdef _TARGET_ARM_
- // Update overlapping floating point register for TYP_DOUBLE
+ // Update overlapping floating point register for TYP_DOUBLE.
+ Interval* oldAssignedInterval = reg->assignedInterval;
if (regType == TYP_DOUBLE)
{
RegRecord* anotherHalfReg = findAnotherHalfRegRec(reg);
anotherHalfReg->assignedInterval = interval;
}
+ else if ((oldAssignedInterval != nullptr) && (oldAssignedInterval->registerType == TYP_DOUBLE))
+ {
+ RegRecord* anotherHalfReg = findAnotherHalfRegRec(reg);
+
+ anotherHalfReg->assignedInterval = nullptr;
+ }
#endif
+ reg->assignedInterval = interval;
}
//-----------------------------------------------------------------------------
@@ -9177,8 +9188,6 @@ void LinearScan::updateMaxSpill(RefPosition* refPosition)
{
typ = treeNode->AsPutArgSplit()->GetRegType(refPosition->getMultiRegIdx());
}
-#endif
-#ifdef ARM_SOFTFP
else if (treeNode->OperIsPutArgReg())
{
// For double arg regs, the type is changed to long since they must be passed via `r0-r3`.
@@ -9186,7 +9195,7 @@ void LinearScan::updateMaxSpill(RefPosition* refPosition)
var_types typNode = treeNode->TypeGet();
typ = (typNode == TYP_LONG) ? TYP_INT : typNode;
}
-#endif // ARM_SOFTFP
+#endif // _TARGET_ARM_
else
{
typ = treeNode->TypeGet();
@@ -9949,7 +9958,21 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, BasicBlock*
VarToRegMap fromVarToRegMap = getOutVarToRegMap(fromBlock->bbNum);
VarToRegMap toVarToRegMap = getInVarToRegMap(toBlock->bbNum);
+#ifdef _TARGET_ARM_
+ regMaskTP freeRegs;
+ if (type == TYP_DOUBLE)
+ {
+ // We have to consider all float registers for TYP_DOUBLE
+ freeRegs = allRegs(TYP_FLOAT);
+ }
+ else
+ {
+ freeRegs = allRegs(type);
+ }
+#else // !_TARGET_ARM_
regMaskTP freeRegs = allRegs(type);
+#endif // !_TARGET_ARM_
+
#ifdef DEBUG
if (getStressLimitRegs() == LSRA_LIMIT_SMALL_SET)
{
@@ -9968,13 +9991,22 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, BasicBlock*
assert(fromReg != REG_NA && toReg != REG_NA);
if (fromReg != REG_STK)
{
- freeRegs &= ~genRegMask(fromReg);
+ freeRegs &= ~genRegMask(fromReg, getIntervalForLocalVar(varIndex)->registerType);
}
if (toReg != REG_STK)
{
- freeRegs &= ~genRegMask(toReg);
+ freeRegs &= ~genRegMask(toReg, getIntervalForLocalVar(varIndex)->registerType);
}
}
+
+#ifdef _TARGET_ARM_
+ if (type == TYP_DOUBLE)
+ {
+ // Exclude any doubles for which the odd half isn't in freeRegs.
+ freeRegs = freeRegs & ((freeRegs << 1) & RBM_ALLDOUBLE);
+ }
+#endif
+
if (freeRegs == RBM_NONE)
{
return REG_NA;
@@ -9986,6 +10018,73 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, BasicBlock*
}
}
+#ifdef _TARGET_ARM_
+//------------------------------------------------------------------------
+// addResolutionForDouble: Add resolution move(s) for TYP_DOUBLE interval
+// and update location.
+//
+// Arguments:
+// block - the BasicBlock into which the move will be inserted.
+// insertionPoint - the instruction before which to insert the move
+// sourceIntervals - maintains sourceIntervals[reg] which each 'reg' is associated with
+// location - maintains location[reg] which is the location of the var that was originally in 'reg'.
+// toReg - the register to which the var is moving
+// fromReg - the register from which the var is moving
+// resolveType - the type of resolution to be performed
+//
+// Return Value:
+// None.
+//
+// Notes:
+// It inserts at least one move and updates incoming parameter 'location'.
+//
+void LinearScan::addResolutionForDouble(BasicBlock* block,
+ GenTreePtr insertionPoint,
+ Interval** sourceIntervals,
+ regNumberSmall* location,
+ regNumber toReg,
+ regNumber fromReg,
+ ResolveType resolveType)
+{
+ regNumber secondHalfTargetReg = REG_NEXT(fromReg);
+ Interval* intervalToBeMoved1 = sourceIntervals[fromReg];
+ Interval* intervalToBeMoved2 = sourceIntervals[secondHalfTargetReg];
+
+ assert(!(intervalToBeMoved1 == nullptr && intervalToBeMoved2 == nullptr));
+
+ if (intervalToBeMoved1 != nullptr)
+ {
+ if (intervalToBeMoved1->registerType == TYP_DOUBLE)
+ {
+ // TYP_DOUBLE interval occupies a double register, i.e. two float registers.
+ assert(intervalToBeMoved2 == nullptr);
+ assert(genIsValidDoubleReg(toReg));
+ }
+ else
+ {
+ // TYP_FLOAT interval occupies 1st half of double register, i.e. 1st float register
+ assert(genIsValidFloatReg(toReg));
+ }
+ addResolution(block, insertionPoint, intervalToBeMoved1, toReg, fromReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[fromReg] = (regNumberSmall)toReg;
+ }
+
+ if (intervalToBeMoved2 != nullptr)
+ {
+ // TYP_FLOAT interval occupies 2nd half of double register.
+ assert(intervalToBeMoved2->registerType == TYP_FLOAT);
+ regNumber secondHalfTempReg = REG_NEXT(toReg);
+
+ addResolution(block, insertionPoint, intervalToBeMoved2, secondHalfTempReg, secondHalfTargetReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[secondHalfTargetReg] = (regNumberSmall)secondHalfTempReg;
+ }
+
+ return;
+}
+#endif // _TARGET_ARM_
+
//------------------------------------------------------------------------
// addResolution: Add a resolution move of the given interval
//
@@ -10582,20 +10681,21 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock,
(resolveType == ResolveSharedCritical) ? REG_NA : getTempRegForResolution(fromBlock, toBlock, TYP_INT);
#endif // !_TARGET_XARCH_
regNumber tempRegFlt = REG_NA;
+ regNumber tempRegDbl = REG_NA; // Used only for ARM
if ((compiler->compFloatingPointUsed) && (resolveType != ResolveSharedCritical))
{
-
#ifdef _TARGET_ARM_
- // Let's try to reserve a double register for TYP_FLOAT and TYP_DOUBLE
- tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_DOUBLE);
- if (tempRegFlt == REG_NA)
+ // Try to reserve a double register for TYP_DOUBLE and use it for TYP_FLOAT too if available.
+ tempRegDbl = getTempRegForResolution(fromBlock, toBlock, TYP_DOUBLE);
+ if (tempRegDbl != REG_NA)
+ {
+ tempRegFlt = tempRegDbl;
+ }
+ else
+#endif // _TARGET_ARM_
{
- // If fails, try to reserve a float register for TYP_FLOAT
tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_FLOAT);
}
-#else
- tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_FLOAT);
-#endif
}
regMaskTP targetRegsToDo = RBM_NONE;
@@ -10703,7 +10803,24 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock,
regNumber targetReg = genRegNumFromMask(targetRegMask);
if (location[targetReg] == REG_NA)
{
- targetRegsReady |= targetRegMask;
+#ifdef _TARGET_ARM_
+ regNumber sourceReg = (regNumber)source[targetReg];
+ Interval* interval = sourceIntervals[sourceReg];
+ if (interval->registerType == TYP_DOUBLE)
+ {
+ // For ARM32, make sure that both of the float halves of the double register are available.
+ assert(genIsValidDoubleReg(targetReg));
+ regNumber anotherHalfRegNum = REG_NEXT(targetReg);
+ if (location[anotherHalfRegNum] == REG_NA)
+ {
+ targetRegsReady |= targetRegMask;
+ }
+ }
+ else
+#endif // _TARGET_ARM_
+ {
+ targetRegsReady |= targetRegMask;
+ }
}
}
@@ -10757,8 +10874,7 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock,
if (sourceIntervals[fromReg]->registerType == TYP_DOUBLE)
{
// ARM32 requires a double temp register for TYP_DOUBLE.
- // We tried to reserve a double temp register first, but sometimes we can't.
- tempReg = genIsValidDoubleReg(tempRegFlt) ? tempRegFlt : REG_NA;
+ tempReg = tempRegDbl;
}
else
#endif // _TARGET_ARM_
@@ -10849,10 +10965,24 @@ void LinearScan::resolveEdge(BasicBlock* fromBlock,
else
{
compiler->codeGen->regSet.rsSetRegsModified(genRegMask(tempReg) DEBUGARG(dumpTerse));
- assert(sourceIntervals[targetReg] != nullptr);
- addResolution(block, insertionPoint, sourceIntervals[targetReg], tempReg, targetReg);
- JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
- location[targetReg] = (regNumberSmall)tempReg;
+#ifdef _TARGET_ARM_
+ if (sourceIntervals[fromReg]->registerType == TYP_DOUBLE)
+ {
+ assert(genIsValidDoubleReg(targetReg));
+ assert(genIsValidDoubleReg(tempReg));
+
+ addResolutionForDouble(block, insertionPoint, sourceIntervals, location, tempReg, targetReg,
+ resolveType);
+ }
+ else
+#endif // _TARGET_ARM_
+ {
+ assert(sourceIntervals[targetReg] != nullptr);
+
+ addResolution(block, insertionPoint, sourceIntervals[targetReg], tempReg, targetReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[targetReg] = (regNumberSmall)tempReg;
+ }
targetRegsReady |= targetRegMask;
}
}
@@ -11399,8 +11529,6 @@ void TreeNodeInfo::dump(LinearScan* lsra)
void LinearScan::lsraDumpIntervals(const char* msg)
{
- Interval* interval;
-
printf("\nLinear scan intervals %s:\n", msg);
for (auto& interval : intervals)
{
diff --git a/src/jit/lsra.h b/src/jit/lsra.h
index d149b3207a..72c54593a5 100644
--- a/src/jit/lsra.h
+++ b/src/jit/lsra.h
@@ -445,6 +445,15 @@ public:
InsertAtBottom
};
+#ifdef _TARGET_ARM_
+ void addResolutionForDouble(BasicBlock* block,
+ GenTreePtr insertionPoint,
+ Interval** sourceIntervals,
+ regNumberSmall* location,
+ regNumber toReg,
+ regNumber fromReg,
+ ResolveType resolveType);
+#endif
void addResolution(
BasicBlock* block, GenTreePtr insertionPoint, Interval* interval, regNumber outReg, regNumber inReg);
@@ -630,6 +639,11 @@ private:
return getLsraRegOptionalControl() == LSRA_REG_OPTIONAL_NO_ALLOC;
}
+ bool candidatesAreStressLimited()
+ {
+ return ((lsraStressMask & (LSRA_LIMIT_MASK | LSRA_SELECT_MASK)) != 0);
+ }
+
// Dump support
void lsraDumpIntervals(const char* msg);
void dumpRefPositions(const char* msg);
@@ -666,6 +680,10 @@ private:
{
return false;
}
+ bool candidatesAreStressLimited()
+ {
+ return false;
+ }
#endif // !DEBUG
public:
@@ -690,6 +708,7 @@ private:
void setFrameType();
// Update allocations at start/end of block
+ void unassignIntervalBlockStart(RegRecord* regRecord, VarToRegMap inVarToRegMap);
void processBlockEndAllocation(BasicBlock* current);
// Record variable locations at start/end of block
@@ -699,23 +718,16 @@ private:
#ifdef _TARGET_ARM_
bool isSecondHalfReg(RegRecord* regRec, Interval* interval);
RegRecord* findAnotherHalfRegRec(RegRecord* regRec);
- bool canSpillDoubleReg(RegRecord* physRegRecord,
- LsraLocation refLocation,
- unsigned* recentAssignedRefWeight,
- unsigned farthestRefPosWeight);
+ bool canSpillDoubleReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight);
void unassignDoublePhysReg(RegRecord* doubleRegRecord);
#endif
void updateAssignedInterval(RegRecord* reg, Interval* interval, RegisterType regType);
void updatePreviousInterval(RegRecord* reg, Interval* interval, RegisterType regType);
bool canRestorePreviousInterval(RegRecord* regRec, Interval* assignedInterval);
bool isAssignedToInterval(Interval* interval, RegRecord* regRec);
- bool checkActiveInterval(Interval* interval, LsraLocation refLocation);
- bool checkActiveIntervals(RegRecord* physRegRecord, LsraLocation refLocation, RegisterType registerType);
- bool canSpillReg(RegRecord* physRegRecord,
- LsraLocation refLocation,
- unsigned* recentAssignedRefWeight,
- unsigned farthestRefPosWeight);
- bool isRegInUse(RegRecord* regRec, RefPosition* refPosition, LsraLocation* nextLocation);
+ bool isRefPositionActive(RefPosition* refPosition, LsraLocation refLocation);
+ bool canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight);
+ bool isRegInUse(RegRecord* regRec, RefPosition* refPosition);
RefType CheckBlockType(BasicBlock* block, BasicBlock* prevBlock);
@@ -777,8 +789,6 @@ private:
// Given some tree node add refpositions for all the registers this node kills
bool buildKillPositionsForNode(GenTree* tree, LsraLocation currentLoc);
- bool killGCRefs(GenTree* tree);
-
regMaskTP allRegs(RegisterType rt);
regMaskTP allRegs(GenTree* tree);
regMaskTP allMultiRegCallNodeRegs(GenTreeCall* tree);
@@ -888,13 +898,14 @@ private:
****************************************************************************/
RegisterType getRegisterType(Interval* currentInterval, RefPosition* refPosition);
regNumber tryAllocateFreeReg(Interval* current, RefPosition* refPosition);
- RegRecord* findBestPhysicalReg(RegisterType regType,
- LsraLocation endLocation,
- regMaskTP candidates,
- regMaskTP preferences);
regNumber allocateBusyReg(Interval* current, RefPosition* refPosition, bool allocateIfProfitable);
regNumber assignCopyReg(RefPosition* refPosition);
+ bool isMatchingConstant(RegRecord* physRegRecord, RefPosition* refPosition);
+ bool isSpillCandidate(Interval* current,
+ RefPosition* refPosition,
+ RegRecord* physRegRecord,
+ LsraLocation& nextLocation);
void checkAndAssignInterval(RegRecord* regRec, Interval* interval);
void assignPhysReg(RegRecord* regRec, Interval* interval);
void assignPhysReg(regNumber reg, Interval* interval)
@@ -1225,7 +1236,7 @@ private:
void TreeNodeInfoInitCheckByteable(GenTree* tree);
- void SetDelayFree(GenTree* delayUseSrc);
+ bool CheckAndSetDelayFree(GenTree* delayUseSrc);
void TreeNodeInfoInitSimple(GenTree* tree);
int GetOperandSourceCount(GenTree* node);
@@ -1262,6 +1273,10 @@ private:
void TreeNodeInfoInitSIMD(GenTreeSIMD* tree);
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ void TreeNodeInfoInitHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree);
+#endif // FEATURE_HW_INTRINSICS
+
void TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode);
#ifdef _TARGET_ARM_
void TreeNodeInfoInitPutArgSplit(GenTreePutArgSplit* tree);
diff --git a/src/jit/lsraarm.cpp b/src/jit/lsraarm.cpp
index f35a23a72b..19d745fbfa 100644
--- a/src/jit/lsraarm.cpp
+++ b/src/jit/lsraarm.cpp
@@ -83,7 +83,8 @@ void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
useCandidates = RBM_FLOATRET;
break;
case TYP_DOUBLE:
- useCandidates = RBM_DOUBLERET;
+ // We ONLY want the valid double register in the RBM_DOUBLERET mask.
+ useCandidates = (RBM_DOUBLERET & RBM_ALLDOUBLE);
break;
case TYP_LONG:
useCandidates = RBM_LNGRET;
@@ -214,7 +215,18 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
}
// Set the default dstCount. This may be modified below.
- info->dstCount = tree->IsValue() ? 1 : 0;
+ if (tree->IsValue())
+ {
+ info->dstCount = 1;
+ if (tree->IsUnusedValue())
+ {
+ info->isLocalDefUse = true;
+ }
+ }
+ else
+ {
+ info->dstCount = 0;
+ }
switch (tree->OperGet())
{
@@ -364,8 +376,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_ASG:
- case GT_ASG_ADD:
- case GT_ASG_SUB:
noway_assert(!"We should never hit any assignment operator in lowering");
info->srcCount = 0;
break;
@@ -442,6 +452,10 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_LONG:
assert(tree->IsUnusedValue()); // Contained nodes are already processed, only unused GT_LONG can reach here.
+ // An unused GT_LONG doesn't produce any registers.
+ tree->gtType = TYP_VOID;
+ tree->ClearUnusedValue();
+ info->isLocalDefUse = false;
// An unused GT_LONG node needs to consume its sources.
info->srcCount = 2;
@@ -690,7 +704,18 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_COPY:
info->srcCount = 1;
- assert(info->dstCount == 1);
+#ifdef _TARGET_ARM_
+ // This case currently only occurs for double types that are passed as TYP_LONG;
+ // actual long types would have been decomposed by now.
+ if (tree->TypeGet() == TYP_LONG)
+ {
+ info->dstCount = 2;
+ }
+ else
+#endif
+ {
+ assert(info->dstCount == 1);
+ }
break;
case GT_PUTARG_SPLIT:
@@ -711,7 +736,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
assert(info->dstCount == 1);
regNumber argReg = tree->gtRegNum;
regMaskTP argMask = genRegMask(argReg);
-#ifdef ARM_SOFTFP
+
// If type of node is `long` then it is actually `double`.
// The actual `long` types must have been transformed as a field list with two fields.
if (tree->TypeGet() == TYP_LONG)
@@ -720,7 +745,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
assert(genRegArgNext(argReg) == REG_NEXT(argReg));
argMask |= genRegMask(REG_NEXT(argReg));
}
-#endif // ARM_SOFTFP
+
info->setDstCandidates(this, argMask);
info->setSrcCandidates(this, argMask);
tree->AsUnOp()->gtOp1->gtLsraInfo.isTgtPref = true;
@@ -785,6 +810,8 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
}
// We need to be sure that we've set info->srcCount and info->dstCount appropriately
assert((info->dstCount < 2) || tree->IsMultiRegNode());
+ assert(info->isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
+ assert(!tree->IsUnusedValue() || (info->dstCount != 0));
}
#endif // _TARGET_ARM_
diff --git a/src/jit/lsraarm64.cpp b/src/jit/lsraarm64.cpp
index 83f6d64983..cf00f6d17c 100644
--- a/src/jit/lsraarm64.cpp
+++ b/src/jit/lsraarm64.cpp
@@ -58,7 +58,18 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
}
// Set the default dstCount. This may be modified below.
- info->dstCount = tree->IsValue() ? 1 : 0;
+ if (tree->IsValue())
+ {
+ info->dstCount = 1;
+ if (tree->IsUnusedValue())
+ {
+ info->isLocalDefUse = true;
+ }
+ }
+ else
+ {
+ info->dstCount = 0;
+ }
switch (tree->OperGet())
{
@@ -198,8 +209,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_ASG:
- case GT_ASG_ADD:
- case GT_ASG_SUB:
noway_assert(!"We should never hit any assignment operator in lowering");
info->srcCount = 0;
break;
@@ -278,7 +287,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
#ifdef FEATURE_SIMD
case GT_SIMD:
- TreeNodeInfoInitSIMD(tree);
+ TreeNodeInfoInitSIMD(tree->AsSIMD());
break;
#endif // FEATURE_SIMD
@@ -365,16 +374,46 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_CMPXCHG:
- info->srcCount = 3;
+ {
+ GenTreeCmpXchg* cmpXchgNode = tree->AsCmpXchg();
+ info->srcCount = cmpXchgNode->gtOpComparand->isContained() ? 2 : 3;
assert(info->dstCount == 1);
- // TODO-ARM64-NYI
- NYI("CMPXCHG");
- break;
+ info->internalIntCount = 1;
+
+ // For ARMv8 exclusives the lifetime of the addr and data must be extended because
+ // it may be used used multiple during retries
+ cmpXchgNode->gtOpLocation->gtLsraInfo.isDelayFree = true;
+ cmpXchgNode->gtOpValue->gtLsraInfo.isDelayFree = true;
+ if (!cmpXchgNode->gtOpComparand->isContained())
+ {
+ cmpXchgNode->gtOpComparand->gtLsraInfo.isDelayFree = true;
+ }
+ info->hasDelayFreeSrc = true;
+
+ // Internals may not collide with target
+ info->isInternalRegDelayFree = true;
+ }
+ break;
case GT_LOCKADD:
- info->srcCount = tree->gtOp.gtOp2->isContained() ? 1 : 2;
- assert(info->dstCount == 1);
+ case GT_XADD:
+ case GT_XCHG:
+ assert(info->dstCount == (tree->TypeGet() == TYP_VOID) ? 0 : 1);
+ info->srcCount = tree->gtOp.gtOp2->isContained() ? 1 : 2;
+ info->internalIntCount = (tree->OperGet() == GT_XCHG) ? 1 : 2;
+
+ // For ARMv8 exclusives the lifetime of the addr and data must be extended because
+ // it may be used used multiple during retries
+ tree->gtOp.gtOp1->gtLsraInfo.isDelayFree = true;
+ if (!tree->gtOp.gtOp2->isContained())
+ {
+ tree->gtOp.gtOp2->gtLsraInfo.isDelayFree = true;
+ }
+ info->hasDelayFreeSrc = true;
+
+ // Internals may not collide with target
+ info->isInternalRegDelayFree = true;
break;
case GT_PUTARG_STK:
@@ -667,6 +706,8 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
}
// We need to be sure that we've set info->srcCount and info->dstCount appropriately
assert((info->dstCount < 2) || tree->IsMultiRegCall());
+ assert(info->isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
+ assert(!tree->IsUnusedValue() || (info->dstCount != 0));
}
//------------------------------------------------------------------------
@@ -729,6 +770,147 @@ void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
}
}
+#ifdef FEATURE_SIMD
+//------------------------------------------------------------------------
+// TreeNodeInfoInitSIMD: Set the NodeInfo for a GT_SIMD tree.
+//
+// Arguments:
+// tree - The GT_SIMD node of interest
+//
+// Return Value:
+// None.
+
+void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
+{
+ TreeNodeInfo* info = &(simdTree->gtLsraInfo);
+
+ // Only SIMDIntrinsicInit can be contained
+ if (simdTree->isContained())
+ {
+ assert(simdTree->gtSIMDIntrinsicID == SIMDIntrinsicInit);
+ }
+ assert(info->dstCount == 1);
+
+ switch (simdTree->gtSIMDIntrinsicID)
+ {
+ GenTree* op1;
+ GenTree* op2;
+
+ case SIMDIntrinsicCast:
+ case SIMDIntrinsicInit:
+ case SIMDIntrinsicSqrt:
+ case SIMDIntrinsicAbs:
+ case SIMDIntrinsicConvertToSingle:
+ case SIMDIntrinsicConvertToInt32:
+ case SIMDIntrinsicConvertToUInt32:
+ case SIMDIntrinsicConvertToDouble:
+ case SIMDIntrinsicConvertToInt64:
+ case SIMDIntrinsicConvertToUInt64:
+ case SIMDIntrinsicWidenLo:
+ case SIMDIntrinsicWidenHi:
+ info->srcCount = 1;
+ break;
+
+ case SIMDIntrinsicGetItem:
+ info->srcCount = 1;
+ break;
+
+ case SIMDIntrinsicAdd:
+ case SIMDIntrinsicSub:
+ case SIMDIntrinsicMul:
+ case SIMDIntrinsicDiv:
+ case SIMDIntrinsicBitwiseAnd:
+ case SIMDIntrinsicBitwiseAndNot:
+ case SIMDIntrinsicBitwiseOr:
+ case SIMDIntrinsicBitwiseXor:
+ case SIMDIntrinsicMin:
+ case SIMDIntrinsicMax:
+ case SIMDIntrinsicSetX:
+ case SIMDIntrinsicSetY:
+ case SIMDIntrinsicSetZ:
+ case SIMDIntrinsicSetW:
+ case SIMDIntrinsicEqual:
+ case SIMDIntrinsicLessThan:
+ case SIMDIntrinsicGreaterThan:
+ case SIMDIntrinsicLessThanOrEqual:
+ case SIMDIntrinsicGreaterThanOrEqual:
+ info->srcCount = 2;
+ break;
+
+ case SIMDIntrinsicNarrow:
+ info->srcCount = 2;
+
+ // Op1 will write to dst before Op2 is free
+ simdTree->gtOp.gtOp2->gtLsraInfo.isDelayFree = true;
+ info->hasDelayFreeSrc = true;
+ break;
+
+ case SIMDIntrinsicInitN:
+ {
+ info->srcCount = (short)(simdTree->gtSIMDSize / genTypeSize(simdTree->gtSIMDBaseType));
+
+ if (varTypeIsFloating(simdTree->gtSIMDBaseType))
+ {
+ // Need an internal register to stitch together all the values into a single vector in a SIMD reg.
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ }
+ break;
+ }
+
+ case SIMDIntrinsicInitArray:
+ // We have an array and an index, which may be contained.
+ info->srcCount = simdTree->gtGetOp2()->isContained() ? 1 : 2;
+ break;
+
+ case SIMDIntrinsicOpEquality:
+ case SIMDIntrinsicOpInEquality:
+ info->srcCount = simdTree->gtGetOp2()->isContained() ? 1 : 2;
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ break;
+
+ case SIMDIntrinsicDotProduct:
+ info->srcCount = 2;
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ break;
+
+ case SIMDIntrinsicSelect:
+ // TODO-ARM64-CQ Allow lowering to see SIMDIntrinsicSelect so we can generate BSL VC, VA, VB
+ // bsl target register must be VC. Reserve a temp in case we need to shuffle things
+ info->setInternalCandidates(this, RBM_ALLFLOAT);
+ info->internalFloatCount = 1;
+ info->srcCount = 3;
+ break;
+
+ case SIMDIntrinsicInitArrayX:
+ case SIMDIntrinsicInitFixed:
+ case SIMDIntrinsicCopyToArray:
+ case SIMDIntrinsicCopyToArrayX:
+ case SIMDIntrinsicNone:
+ case SIMDIntrinsicGetCount:
+ case SIMDIntrinsicGetOne:
+ case SIMDIntrinsicGetZero:
+ case SIMDIntrinsicGetAllOnes:
+ case SIMDIntrinsicGetX:
+ case SIMDIntrinsicGetY:
+ case SIMDIntrinsicGetZ:
+ case SIMDIntrinsicGetW:
+ case SIMDIntrinsicInstEquals:
+ case SIMDIntrinsicHWAccel:
+ case SIMDIntrinsicWiden:
+ case SIMDIntrinsicInvalid:
+ assert(!"These intrinsics should not be seen during register allocation");
+ __fallthrough;
+
+ default:
+ noway_assert(!"Unimplemented SIMD node type.");
+ unreached();
+ }
+}
+#endif // FEATURE_SIMD
+
#endif // _TARGET_ARM64_
#endif // !LEGACY_BACKEND
diff --git a/src/jit/lsraarmarch.cpp b/src/jit/lsraarmarch.cpp
index 53e223dab6..b13362d5be 100644
--- a/src/jit/lsraarmarch.cpp
+++ b/src/jit/lsraarmarch.cpp
@@ -92,15 +92,8 @@ void LinearScan::TreeNodeInfoInitCmp(GenTreePtr tree)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);
+ assert((info->dstCount == 1) || (tree->TypeGet() == TYP_VOID));
info->srcCount = tree->gtOp.gtOp2->isContained() ? 1 : 2;
- if (info->isNoRegCompare)
- {
- info->dstCount = 0;
- }
- else
- {
- assert((info->dstCount == 1) || tree->OperIs(GT_CMP, GT_TEST_EQ, GT_TEST_NE));
- }
}
void LinearScan::TreeNodeInfoInitGCWriteBarrier(GenTree* tree)
@@ -293,7 +286,8 @@ void LinearScan::TreeNodeInfoInitPutArgReg(GenTreeUnOp* node)
// Set the register requirements for the node.
regMaskTP argMask = genRegMask(argReg);
-#ifdef ARM_SOFTFP
+
+#ifdef _TARGET_ARM_
// If type of node is `long` then it is actually `double`.
// The actual `long` types must have been transformed as a field list with two fields.
if (node->TypeGet() == TYP_LONG)
@@ -303,7 +297,8 @@ void LinearScan::TreeNodeInfoInitPutArgReg(GenTreeUnOp* node)
assert(genRegArgNext(argReg) == REG_NEXT(argReg));
argMask |= genRegMask(REG_NEXT(argReg));
}
-#endif // ARM_SOFTFP
+#endif // _TARGET_ARM_
+
node->gtLsraInfo.setDstCandidates(this, argMask);
node->gtLsraInfo.setSrcCandidates(this, argMask);
@@ -400,15 +395,9 @@ void LinearScan::TreeNodeInfoInitCall(GenTreeCall* call)
// computed into a register.
if (call->IsFastTailCall())
{
-#ifdef _TARGET_ARM64_
- // Fast tail call - make sure that call target is always computed in IP0
- // so that epilog sequence can generate "br xip0" to achieve fast tail call.
- ctrlExpr->gtLsraInfo.setSrcCandidates(this, genRegMask(REG_IP0));
-#else // !_TARGET_ARM64_
- // Fast tail call - make sure that call target is always computed in r12
- // so that epilog sequence can generate "br r12" to achieve fast tail call.
- ctrlExpr->gtLsraInfo.setSrcCandidates(this, RBM_R12);
-#endif // !_TARGET_ARM64_
+ // Fast tail call - make sure that call target is always computed in R12(ARM32)/IP0(ARM64)
+ // so that epilog sequence can generate "br xip0/r12" to achieve fast tail call.
+ ctrlExpr->gtLsraInfo.setSrcCandidates(this, RBM_FASTTAILCALL_TARGET);
}
}
#ifdef _TARGET_ARM_
@@ -474,31 +463,22 @@ void LinearScan::TreeNodeInfoInitCall(GenTreeCall* call)
GenTree* putArgChild = argNode->gtGetOp1();
if (!varTypeIsStruct(putArgChild) && !putArgChild->OperIs(GT_FIELD_LIST))
{
-#ifdef ARM_SOFTFP
- // The `double` types have been transformed to `long` on armel, while the actual longs
+ unsigned expectedSlots = 1;
+#ifdef _TARGET_ARM_
+ // The `double` types could been transformed to `long` on arm, while the actual longs
// have been decomposed.
- const bool isDouble = putArgChild->TypeGet() == TYP_LONG;
- if (isDouble)
+ if (putArgChild->TypeGet() == TYP_LONG)
{
argNode->gtLsraInfo.srcCount = 2;
+ expectedSlots = 2;
+ }
+ else if (putArgChild->TypeGet() == TYP_DOUBLE)
+ {
+ expectedSlots = 2;
}
-#endif // ARM_SOFT_FP
-
-#ifdef DEBUG
-// Validate the slot count for this arg.
-#ifdef _TARGET_ARM_
-#ifndef ARM_SOFTFP
- const bool isDouble = (curArgTabEntry->numSlots == 2) && (putArgChild->TypeGet() == TYP_DOUBLE);
-#endif // !ARM_SOFTFP
-
- // We must not have a multi-reg struct; double uses 2 slots and isn't a multi-reg struct
- assert((curArgTabEntry->numSlots == 1) || isDouble);
-
-#else // !_TARGET_ARM_
- // We must not have a multi-reg struct
- assert(curArgTabEntry->numSlots == 1);
#endif // !_TARGET_ARM_
-#endif
+ // Validate the slot count for this arg.
+ assert(curArgTabEntry->numSlots == expectedSlots);
}
continue;
}
@@ -541,14 +521,15 @@ void LinearScan::TreeNodeInfoInitCall(GenTreeCall* call)
assert(argNode->gtRegNum == argReg);
HandleFloatVarArgs(call, argNode, &callHasFloatRegArgs);
info->srcCount++;
-#ifdef ARM_SOFTFP
- // The `double` types have been transformed to `long` on armel,
+
+#ifdef _TARGET_ARM_
+ // The `double` types have been transformed to `long` on arm,
// while the actual long types have been decomposed.
if (argNode->TypeGet() == TYP_LONG)
{
info->srcCount++;
}
-#endif // ARM_SOFTFP
+#endif // _TARGET_ARM_
}
}
@@ -679,7 +660,7 @@ void LinearScan::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode)
}
else
{
-#if defined(_TARGET_ARM_) && defined(ARM_SOFTFP)
+#if defined(_TARGET_ARM_)
// The `double` types have been transformed to `long` on armel,
// while the actual long types have been decomposed.
const bool isDouble = (putArgChild->TypeGet() == TYP_LONG);
@@ -688,7 +669,7 @@ void LinearScan::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* argNode)
argNode->gtLsraInfo.srcCount = 2;
}
else
-#endif // defined(_TARGET_ARM_) && defined(ARM_SOFTFP)
+#endif // defined(_TARGET_ARM_)
{
argNode->gtLsraInfo.srcCount = 1;
}
diff --git a/src/jit/lsraxarch.cpp b/src/jit/lsraxarch.cpp
index 8ac8e235b5..617642cd2c 100644
--- a/src/jit/lsraxarch.cpp
+++ b/src/jit/lsraxarch.cpp
@@ -116,20 +116,27 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
{
info->dstCount = 0;
assert(info->srcCount == 0);
- TreeNodeInfoInitCheckByteable(tree);
return;
}
// Set the default dstCount. This may be modified below.
- info->dstCount = tree->IsValue() ? 1 : 0;
+ if (tree->IsValue())
+ {
+ info->dstCount = 1;
+ if (tree->IsUnusedValue())
+ {
+ info->isLocalDefUse = true;
+ }
+ }
+ else
+ {
+ info->dstCount = 0;
+ }
// floating type generates AVX instruction (vmovss etc.), set the flag
SetContainsAVXFlags(varTypeIsFloating(tree->TypeGet()));
switch (tree->OperGet())
{
- GenTree* op1;
- GenTree* op2;
-
default:
TreeNodeInfoInitSimple(tree);
break;
@@ -150,6 +157,7 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
info->regOptional = false;
tree->SetContained();
info->dstCount = 0;
+ return;
}
}
__fallthrough;
@@ -194,6 +202,10 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
case GT_LONG:
assert(tree->IsUnusedValue()); // Contained nodes are already processed, only unused GT_LONG can reach here.
+ // An unused GT_LONG doesn't produce any registers.
+ tree->gtType = TYP_VOID;
+ tree->ClearUnusedValue();
+ info->isLocalDefUse = false;
// An unused GT_LONG node needs to consume its sources.
info->srcCount = 2;
@@ -254,20 +266,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
GenTree* cmp = tree->gtGetOp1();
assert(cmp->gtLsraInfo.dstCount == 0);
-
-#ifdef FEATURE_SIMD
- GenTree* cmpOp1 = cmp->gtGetOp1();
- GenTree* cmpOp2 = cmp->gtGetOp2();
- if (cmpOp1->IsSIMDEqualityOrInequality() && cmpOp2->isContained())
- {
- genTreeOps cmpOper = cmp->OperGet();
-
- // We always generate code for a SIMD equality comparison, but the compare itself produces no value.
- // Neither the SIMD node nor the immediate need to be evaluated into a register.
- assert(cmpOp1->gtLsraInfo.dstCount == 0);
- assert(cmpOp2->gtLsraInfo.dstCount == 0);
- }
-#endif // FEATURE_SIMD
}
break;
@@ -308,8 +306,6 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
case GT_ASG:
- case GT_ASG_ADD:
- case GT_ASG_SUB:
noway_assert(!"We should never hit any assignment operator in lowering");
info->srcCount = 0;
break;
@@ -374,6 +370,12 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
break;
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+ case GT_HWIntrinsic:
+ TreeNodeInfoInitHWIntrinsic(tree->AsHWIntrinsic());
+ break;
+#endif // FEATURE_HW_INTRINSICS
+
case GT_CAST:
TreeNodeInfoInitCast(tree);
break;
@@ -453,14 +455,16 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
tree->gtCmpXchg.gtOpComparand->gtLsraInfo.setSrcCandidates(this, RBM_RAX);
tree->gtCmpXchg.gtOpLocation->gtLsraInfo.setSrcCandidates(this, allRegs(TYP_INT) & ~RBM_RAX);
tree->gtCmpXchg.gtOpValue->gtLsraInfo.setSrcCandidates(this, allRegs(TYP_INT) & ~RBM_RAX);
- tree->gtLsraInfo.setDstCandidates(this, RBM_RAX);
+ info->setDstCandidates(this, RBM_RAX);
break;
case GT_LOCKADD:
- op2 = tree->gtOp.gtOp2;
+ {
+ GenTreePtr op2 = tree->gtOp.gtOp2;
info->srcCount = op2->isContained() ? 1 : 2;
assert(info->dstCount == (tree->TypeGet() == TYP_VOID) ? 0 : 1);
- break;
+ }
+ break;
case GT_PUTARG_REG:
TreeNodeInfoInitPutArgReg(tree->AsUnOp());
@@ -646,16 +650,18 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// Commutative opers like add/mul/and/or/xor could reverse the order of
// operands if it is safe to do so. In such a case we would like op2 to be
// target preferenced instead of op1.
- if (tree->OperIsCommutative() && op1->gtLsraInfo.dstCount == 0 && op2 != nullptr)
+ if (tree->OperIsCommutative() && op1->isContained() && op2 != nullptr)
{
op1 = op2;
op2 = tree->gtOp.gtOp1;
}
- // If we have a read-modify-write operation, we want to preference op1 to the target.
- // If op1 is contained, we don't want to preference it, but it won't
- // show up as a source in that case, so it will be ignored.
- op1->gtLsraInfo.isTgtPref = true;
+ // If we have a read-modify-write operation, we want to preference op1 to the target,
+ // if it is not contained.
+ if (!op1->isContained())
+ {
+ op1->gtLsraInfo.isTgtPref = true;
+ }
// Is this a non-commutative operator, or is op2 a contained memory op?
// In either case, we need to make op2 remain live until the op is complete, by marking
@@ -686,29 +692,28 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
// which allows its second operand to be a contained
// immediate wheres xadd instruction requires its
// second operand to be in a register.
- assert(tree->gtLsraInfo.dstCount == 0);
-
- // Give it an artificial type and mark it isLocalDefUse = true.
- // This would result in a Def position created but not considered
- // consumed by its parent node.
- tree->gtType = TYP_INT;
- tree->gtLsraInfo.isLocalDefUse = true;
+ assert(info->dstCount == 0);
+
+ // Give it an artificial type and mark it as an unused value.
+ // This results in a Def position created but not considered consumed by its parent node.
+ tree->gtType = TYP_INT;
+ info->dstCount = 1;
+ info->isLocalDefUse = true;
+ tree->SetUnusedValue();
}
else
{
- assert(tree->gtLsraInfo.dstCount != 0);
+ assert(info->dstCount != 0);
}
delayUseSrc = op1;
}
- else if ((op2 != nullptr) &&
- (!tree->OperIsCommutative() || (isContainableMemoryOp(op2) && (op2->gtLsraInfo.srcCount == 0))))
+ else if ((op2 != nullptr) && (!tree->OperIsCommutative() || (op2->isContained() && !op2->IsCnsIntOrI())))
{
delayUseSrc = op2;
}
- if (delayUseSrc != nullptr)
+ if ((delayUseSrc != nullptr) && CheckAndSetDelayFree(delayUseSrc))
{
- SetDelayFree(delayUseSrc);
info->hasDelayFreeSrc = true;
}
}
@@ -716,36 +721,55 @@ void LinearScan::TreeNodeInfoInit(GenTree* tree)
TreeNodeInfoInitCheckByteable(tree);
- if (tree->IsUnusedValue() && (info->dstCount != 0))
- {
- info->isLocalDefUse = true;
- }
// We need to be sure that we've set info->srcCount and info->dstCount appropriately
assert((info->dstCount < 2) || (tree->IsMultiRegCall() && info->dstCount == MAX_RET_REG_COUNT));
+ assert(info->isLocalDefUse == (tree->IsValue() && tree->IsUnusedValue()));
+ assert(!tree->IsUnusedValue() || (info->dstCount != 0));
}
-void LinearScan::SetDelayFree(GenTree* delayUseSrc)
+//---------------------------------------------------------------------
+// CheckAndSetDelayFree - Set isDelayFree on the given operand or its child(ren), if appropriate
+//
+// Arguments
+// delayUseSrc - a node that may have a delayed use
+//
+// Return Value:
+// True iff the node or one of its children has been marked isDelayFree
+//
+// Notes:
+// Only register operands should be marked isDelayFree, not contained immediates or memory.
+//
+bool LinearScan::CheckAndSetDelayFree(GenTree* delayUseSrc)
{
// If delayUseSrc is an indirection and it doesn't produce a result, then we need to set "delayFree'
// on the base & index, if any.
// Otherwise, we set it on delayUseSrc itself.
- if (delayUseSrc->isIndir() && (delayUseSrc->gtLsraInfo.dstCount == 0))
+ bool returnValue = false;
+ if (delayUseSrc->isContained())
{
- GenTree* base = delayUseSrc->AsIndir()->Base();
- GenTree* index = delayUseSrc->AsIndir()->Index();
- if (base != nullptr)
- {
- base->gtLsraInfo.isDelayFree = true;
- }
- if (index != nullptr)
+ // If delayUseSrc is a non-Indir contained node (e.g. a local) there's no register use to delay.
+ if (delayUseSrc->isIndir())
{
- index->gtLsraInfo.isDelayFree = true;
+ GenTree* base = delayUseSrc->AsIndir()->Base();
+ GenTree* index = delayUseSrc->AsIndir()->Index();
+ if (base != nullptr)
+ {
+ base->gtLsraInfo.isDelayFree = true;
+ returnValue = true;
+ }
+ if (index != nullptr)
+ {
+ index->gtLsraInfo.isDelayFree = true;
+ returnValue = true;
+ }
}
}
else
{
delayUseSrc->gtLsraInfo.isDelayFree = true;
+ returnValue = true;
}
+ return returnValue;
}
//------------------------------------------------------------------------
@@ -900,7 +924,8 @@ void LinearScan::TreeNodeInfoInitSimple(GenTree* tree)
void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
{
TreeNodeInfo* info = &(tree->gtLsraInfo);
- GenTree* op1 = tree->gtGetOp1();
+ assert(info->dstCount == 0);
+ GenTree* op1 = tree->gtGetOp1();
#if !defined(_TARGET_64BIT_)
if (tree->TypeGet() == TYP_LONG)
@@ -911,15 +936,14 @@ void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
info->srcCount = 2;
loVal->gtLsraInfo.setSrcCandidates(this, RBM_LNGRET_LO);
hiVal->gtLsraInfo.setSrcCandidates(this, RBM_LNGRET_HI);
- assert(info->dstCount == 0);
}
else
#endif // !defined(_TARGET_64BIT_)
+ if ((tree->TypeGet() != TYP_VOID) && !op1->isContained())
{
regMaskTP useCandidates = RBM_NONE;
- info->srcCount = ((tree->TypeGet() == TYP_VOID) || op1->isContained()) ? 0 : 1;
- assert(info->dstCount == 0);
+ info->srcCount = 1;
#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING
if (varTypeIsStruct(tree))
@@ -940,8 +964,7 @@ void LinearScan::TreeNodeInfoInitReturn(GenTree* tree)
switch (tree->TypeGet())
{
case TYP_VOID:
- useCandidates = RBM_NONE;
- break;
+ unreached();
case TYP_FLOAT:
useCandidates = RBM_FLOATRET;
break;
@@ -989,56 +1012,60 @@ void LinearScan::TreeNodeInfoInitShiftRotate(GenTree* tree)
// We will allow whatever can be encoded - hope you know what you are doing.
if (!shiftBy->isContained())
{
- source->gtLsraInfo.setSrcCandidates(this, allRegs(TYP_INT) & ~RBM_RCX);
shiftBy->gtLsraInfo.setSrcCandidates(this, RBM_RCX);
- info->setDstCandidates(this, allRegs(TYP_INT) & ~RBM_RCX);
- if (!tree->isContained())
- {
- info->srcCount = 2;
- }
- }
- else
- {
- // Note that Rotate Left/Right instructions don't set ZF and SF flags.
- //
- // If the operand being shifted is 32-bits then upper three bits are masked
- // by hardware to get actual shift count. Similarly for 64-bit operands
- // shift count is narrowed to [0..63]. If the resulting shift count is zero,
- // then shift operation won't modify flags.
- //
- // TODO-CQ-XARCH: We can optimize generating 'test' instruction for GT_EQ/NE(shift, 0)
- // if the shift count is known to be non-zero and in the range depending on the
- // operand size.
- if (!tree->isContained())
+ if (!source->isContained())
{
- info->srcCount = 1;
+ source->gtLsraInfo.setSrcCandidates(this, allRegs(TYP_INT) & ~RBM_RCX);
}
+ info->setDstCandidates(this, allRegs(TYP_INT) & ~RBM_RCX);
}
-#ifdef _TARGET_X86_
- // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
- // we can have a three operand form. Increment the srcCount.
- if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
+ // Note that Rotate Left/Right instructions don't set ZF and SF flags.
+ //
+ // If the operand being shifted is 32-bits then upper three bits are masked
+ // by hardware to get actual shift count. Similarly for 64-bit operands
+ // shift count is narrowed to [0..63]. If the resulting shift count is zero,
+ // then shift operation won't modify flags.
+ //
+ // TODO-CQ-XARCH: We can optimize generating 'test' instruction for GT_EQ/NE(shift, 0)
+ // if the shift count is known to be non-zero and in the range depending on the
+ // operand size.
+
+ if (!tree->isContained())
{
- assert((source->OperGet() == GT_LONG) && source->isContained());
+#ifdef _TARGET_X86_
+ // The first operand of a GT_LSH_HI and GT_RSH_LO oper is a GT_LONG so that
+ // we can have a three operand form. Increment the srcCount.
+ if (tree->OperGet() == GT_LSH_HI || tree->OperGet() == GT_RSH_LO)
+ {
+ assert((source->OperGet() == GT_LONG) && source->isContained());
- info->srcCount++;
+ if (tree->OperGet() == GT_LSH_HI)
+ {
+ GenTreePtr sourceLo = source->gtOp.gtOp1;
+ sourceLo->gtLsraInfo.isDelayFree = true;
+ }
+ else
+ {
+ GenTreePtr sourceHi = source->gtOp.gtOp2;
+ sourceHi->gtLsraInfo.isDelayFree = true;
+ }
- if (tree->OperGet() == GT_LSH_HI)
- {
- GenTreePtr sourceLo = source->gtOp.gtOp1;
- sourceLo->gtLsraInfo.isDelayFree = true;
+ source->gtLsraInfo.hasDelayFreeSrc = true;
+ info->hasDelayFreeSrc = true;
+ info->srcCount += 2;
}
else
+#endif
+ if (!source->isContained())
{
- GenTreePtr sourceHi = source->gtOp.gtOp2;
- sourceHi->gtLsraInfo.isDelayFree = true;
+ info->srcCount++;
+ }
+ if (!shiftBy->isContained())
+ {
+ info->srcCount++;
}
-
- source->gtLsraInfo.hasDelayFreeSrc = true;
- info->hasDelayFreeSrc = true;
}
-#endif
}
//------------------------------------------------------------------------
@@ -1663,9 +1690,12 @@ void LinearScan::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* putArgStk)
#endif // _TARGET_X86_
}
+ GenTreePtr src = putArgStk->gtOp1;
+ var_types type = src->TypeGet();
+
#if defined(FEATURE_SIMD) && defined(_TARGET_X86_)
// For PutArgStk of a TYP_SIMD12, we need an extra register.
- if (putArgStk->TypeGet() == TYP_SIMD12)
+ if (putArgStk->isSIMD12())
{
info->srcCount = putArgStk->gtOp1->gtLsraInfo.dstCount;
info->internalFloatCount = 1;
@@ -1674,14 +1704,13 @@ void LinearScan::TreeNodeInfoInitPutArgStk(GenTreePutArgStk* putArgStk)
}
#endif // defined(FEATURE_SIMD) && defined(_TARGET_X86_)
- if (putArgStk->TypeGet() != TYP_STRUCT)
+ if (type != TYP_STRUCT)
{
TreeNodeInfoInitSimple(putArgStk);
return;
}
GenTreePtr dst = putArgStk;
- GenTreePtr src = putArgStk->gtOp1;
GenTreePtr srcAddr = nullptr;
info->srcCount = GetOperandSourceCount(src);
@@ -2084,7 +2113,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
// Must be a Vector<int> or Vector<short> Vector<sbyte>
assert(simdTree->gtSIMDBaseType == TYP_INT || simdTree->gtSIMDBaseType == TYP_SHORT ||
simdTree->gtSIMDBaseType == TYP_BYTE);
- assert(compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4);
+ assert(compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported);
info->srcCount = 1;
break;
@@ -2107,7 +2136,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
// SSE2 32-bit integer multiplication requires two temp regs
if (simdTree->gtSIMDIntrinsicID == SIMDIntrinsicMul && simdTree->gtSIMDBaseType == TYP_INT &&
- compiler->getSIMDInstructionSet() == InstructionSet_SSE2)
+ compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported)
{
info->internalFloatCount = 2;
info->setInternalCandidates(this, allSIMDRegs());
@@ -2136,41 +2165,26 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
case SIMDIntrinsicOpEquality:
case SIMDIntrinsicOpInEquality:
-
- // On SSE4/AVX, we can generate optimal code for (in)equality
- // against zero using ptest. We can safely do this optimization
- // for integral vectors but not for floating-point for the reason
- // that we have +0.0 and -0.0 and +0.0 == -0.0
if (simdTree->gtGetOp2()->isContained())
{
+ // If the second operand is contained then ContainCheckSIMD has determined
+ // that PTEST can be used. We only need a single source register and no
+ // internal registers.
info->srcCount = 1;
}
else
{
- info->srcCount = 2;
- // Need one SIMD register as scratch.
- // See genSIMDIntrinsicRelOp() for details on code sequence generated and
- // the need for one scratch register.
- //
- // Note these intrinsics produce a BOOL result, hence internal float
- // registers reserved are guaranteed to be different from target
- // integer register without explicitly specifying.
+ // Can't use PTEST so we need 2 source registers, 1 internal SIMD register
+ // (to hold the result of PCMPEQD or other similar SIMD compare instruction)
+ // and one internal INT register (to hold the result of PMOVMSKB).
+ info->srcCount = 2;
info->internalFloatCount = 1;
info->setInternalCandidates(this, allSIMDRegs());
+ info->internalIntCount = 1;
+ info->addInternalCandidates(this, allRegs(TYP_INT));
}
- if (info->isNoRegCompare)
- {
- info->dstCount = 0;
- // Codegen of SIMD (in)Equality uses target integer reg only for setting flags.
- // A target reg is not needed on AVX when comparing against Vector Zero.
- // In all other cases we need to reserve an int type internal register if we
- // don't have a target register on the compare.
- if (!compiler->canUseAVX() || !simdTree->gtGetOp2()->IsIntegralConstVector(0))
- {
- info->internalIntCount = 1;
- info->addInternalCandidates(this, allRegs(TYP_INT));
- }
- }
+ // These SIMD nodes only set the condition flags.
+ info->dstCount = 0;
break;
case SIMDIntrinsicDotProduct:
@@ -2189,7 +2203,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
// and the need for scratch registers.
if (varTypeIsFloating(simdTree->gtSIMDBaseType))
{
- if ((compiler->getSIMDInstructionSet() == InstructionSet_SSE2) ||
+ if ((compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported) ||
(simdTree->gtOp.gtOp1->TypeGet() == TYP_SIMD32))
{
info->internalFloatCount = 1;
@@ -2200,8 +2214,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
}
else
{
- assert(simdTree->gtSIMDBaseType == TYP_INT &&
- compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4);
+ assert(simdTree->gtSIMDBaseType == TYP_INT && compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported);
// No need to set isInternalRegDelayFree since targetReg is a
// an int type reg and guaranteed to be different from xmm/ymm
@@ -2259,7 +2272,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
{
bool needFloatTemp;
if (varTypeIsSmallInt(simdTree->gtSIMDBaseType) &&
- (compiler->getSIMDInstructionSet() == InstructionSet_AVX))
+ (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported))
{
int byteShiftCnt = (int)op2->AsIntCon()->gtIconVal * genTypeSize(simdTree->gtSIMDBaseType);
needFloatTemp = (byteShiftCnt >= 16);
@@ -2286,7 +2299,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
info->srcCount = 2;
// We need an internal integer register for SSE2 codegen
- if (compiler->getSIMDInstructionSet() == InstructionSet_SSE2)
+ if (compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported)
{
info->internalIntCount = 1;
info->setInternalCandidates(this, allRegs(TYP_INT));
@@ -2333,7 +2346,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
info->isInternalRegDelayFree = true;
info->srcCount = 1;
info->internalIntCount = 1;
- if (compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
info->internalFloatCount = 2;
}
@@ -2356,8 +2369,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
}
else
#endif
- if ((compiler->getSIMDInstructionSet() == InstructionSet_AVX) ||
- (simdTree->gtSIMDBaseType == TYP_ULONG))
+ if ((compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported) || (simdTree->gtSIMDBaseType == TYP_ULONG))
{
info->internalFloatCount = 2;
}
@@ -2372,7 +2384,7 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
// We need an internal register different from targetReg.
info->isInternalRegDelayFree = true;
info->srcCount = 2;
- if ((compiler->getSIMDInstructionSet() == InstructionSet_AVX) && (simdTree->gtSIMDBaseType != TYP_DOUBLE))
+ if ((compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported) && (simdTree->gtSIMDBaseType != TYP_DOUBLE))
{
info->internalFloatCount = 2;
}
@@ -2407,6 +2419,42 @@ void LinearScan::TreeNodeInfoInitSIMD(GenTreeSIMD* simdTree)
}
#endif // FEATURE_SIMD
+#if FEATURE_HW_INTRINSICS
+//------------------------------------------------------------------------
+// TreeNodeInfoInitHWIntrinsic: Set the NodeInfo for a GT_HWIntrinsic tree.
+//
+// Arguments:
+// tree - The GT_HWIntrinsic node of interest
+//
+// Return Value:
+// None.
+
+void LinearScan::TreeNodeInfoInitHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree)
+{
+ TreeNodeInfo* info = &(intrinsicTree->gtLsraInfo);
+ if (intrinsicTree->gtGetOp2IfPresent() != nullptr)
+ {
+ info->srcCount += GetOperandSourceCount(intrinsicTree->gtOp.gtOp2);
+ }
+ info->srcCount += GetOperandSourceCount(intrinsicTree->gtOp.gtOp1);
+
+#ifdef _TARGET_X86_
+ if (intrinsicTree->gtHWIntrinsicId == NI_SSE42_Crc32)
+ {
+ // CRC32 may operate over "byte" but on x86 only RBM_BYTE_REGS can be used as byte registers.
+ //
+ // TODO - currently we use the BaseType to bring the type of the second argument
+ // to the code generator. May encode the overload info in other way.
+ var_types srcType = intrinsicTree->gtSIMDBaseType;
+ if (varTypeIsByte(srcType))
+ {
+ intrinsicTree->gtOp.gtOp2->gtLsraInfo.setSrcCandidates(this, RBM_BYTE_REGS);
+ }
+ }
+#endif
+}
+#endif
+
//------------------------------------------------------------------------
// TreeNodeInfoInitCast: Set the NodeInfo for a GT_CAST.
//
@@ -2636,14 +2684,7 @@ void LinearScan::TreeNodeInfoInitCmp(GenTreePtr tree)
TreeNodeInfo* info = &(tree->gtLsraInfo);
info->srcCount = 0;
- if (info->isNoRegCompare)
- {
- info->dstCount = 0;
- }
- else
- {
- assert((info->dstCount == 1) || tree->OperIs(GT_CMP));
- }
+ assert((info->dstCount == 1) || (tree->TypeGet() == TYP_VOID));
#ifdef _TARGET_X86_
// If the compare is used by a jump, we just need to set the condition codes. If not, then we need
@@ -2659,7 +2700,7 @@ void LinearScan::TreeNodeInfoInitCmp(GenTreePtr tree)
var_types op1Type = op1->TypeGet();
var_types op2Type = op2->TypeGet();
- if (!op1->gtLsraInfo.isNoRegCompare)
+ if (op1->TypeGet() != TYP_VOID)
{
info->srcCount += GetOperandSourceCount(op1);
}
@@ -2747,9 +2788,8 @@ void LinearScan::TreeNodeInfoInitMul(GenTreePtr tree)
{
containedMemOp = op2;
}
- if (containedMemOp != nullptr)
+ if ((containedMemOp != nullptr) && CheckAndSetDelayFree(containedMemOp))
{
- SetDelayFree(containedMemOp);
info->hasDelayFreeSrc = true;
}
}
@@ -2764,19 +2804,17 @@ void LinearScan::TreeNodeInfoInitMul(GenTreePtr tree)
//
void LinearScan::SetContainsAVXFlags(bool isFloatingPointType /* = true */, unsigned sizeOfSIMDVector /* = 0*/)
{
-#ifdef FEATURE_AVX_SUPPORT
if (isFloatingPointType)
{
- if (compiler->getFloatingPointInstructionSet() == InstructionSet_AVX)
+ if (compiler->getFloatingPointCodegenLevel() == SIMD_AVX2_Supported)
{
compiler->getEmitter()->SetContainsAVX(true);
}
- if (sizeOfSIMDVector == 32 && compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (sizeOfSIMDVector == 32 && compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
compiler->getEmitter()->SetContains256bitAVX(true);
}
}
-#endif
}
#ifdef _TARGET_X86_
diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
index 1d04913242..9d6d0d3ce5 100644
--- a/src/jit/morph.cpp
+++ b/src/jit/morph.cpp
@@ -4735,8 +4735,6 @@ void Compiler::fgMorphSystemVStructArgs(GenTreeCall* call, bool hasStructArgumen
//
void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
{
- GenTreePtr args;
- GenTreePtr argx;
bool foundStructArg = false;
unsigned initialFlags = call->gtFlags;
unsigned flagsSummary = 0;
@@ -4757,7 +4755,7 @@ void Compiler::fgMorphMultiregStructArgs(GenTreeCall* call)
#endif // !UNIX_AMD64_ABI
#endif
- for (args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
+ for (GenTreePtr args = call->gtCallArgs; args != nullptr; args = args->gtOp.gtOp2)
{
// For late arguments the arg tree that is overridden is in the gtCallLateArgs list.
// For such late args the gtCallArgList contains the setup arg node (evaluating the arg.)
@@ -5311,7 +5309,33 @@ GenTreePtr Compiler::fgMorphMultiregStructArg(GenTreePtr arg, fgArgTabEntryPtr f
gtDispTree(argValue);
assert(!"Missing case in fgMorphMultiregStructArg");
}
+#endif
+
+ noway_assert(newArg != nullptr);
+ noway_assert(newArg->OperIsFieldList());
+
+ // We need to propagate any GTF_ALL_EFFECT flags from the end of the list back to the beginning.
+ // This is verified in fgDebugCheckFlags().
+
+ ArrayStack<GenTree*> stack(this);
+ GenTree* tree;
+ for (tree = newArg; (tree->gtGetOp2() != nullptr) && tree->gtGetOp2()->OperIsFieldList(); tree = tree->gtGetOp2())
+ {
+ stack.Push(tree);
+ }
+ unsigned propFlags = (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
+ tree->gtFlags |= propFlags;
+
+ while (stack.Height() > 0)
+ {
+ tree = stack.Pop();
+ propFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
+ propFlags |= (tree->gtGetOp2()->gtFlags & GTF_ALL_EFFECT);
+ tree->gtFlags |= propFlags;
+ }
+
+#ifdef DEBUG
if (verbose)
{
printf("fgMorphMultiregStructArg created tree:\n");
@@ -6645,15 +6669,19 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
#ifdef FEATURE_READYTORUN_COMPILER
if (tree->gtField.gtFieldLookup.addr != nullptr)
{
- GenTreePtr baseOffset = gtNewIconEmbHndNode(tree->gtField.gtFieldLookup.addr, nullptr, GTF_ICON_FIELD_HDL);
-
+ GenTree* offsetNode = nullptr;
if (tree->gtField.gtFieldLookup.accessType == IAT_PVALUE)
{
- baseOffset = gtNewOperNode(GT_IND, TYP_I_IMPL, baseOffset);
+ offsetNode = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)tree->gtField.gtFieldLookup.addr,
+ GTF_ICON_FIELD_HDL, false);
+ }
+ else
+ {
+ noway_assert(!"unexpected accessType for R2R field access");
}
- addr =
- gtNewOperNode(GT_ADD, (var_types)(objRefType == TYP_I_IMPL ? TYP_I_IMPL : TYP_BYREF), addr, baseOffset);
+ var_types addType = (objRefType == TYP_I_IMPL) ? TYP_I_IMPL : TYP_BYREF;
+ addr = gtNewOperNode(GT_ADD, addType, addr, offsetNode);
}
#endif
if (fldOffset != 0)
@@ -6745,12 +6773,9 @@ GenTreePtr Compiler::fgMorphField(GenTreePtr tree, MorphAddrContext* mac)
}
else
{
- dllRef = gtNewIconHandleNode((size_t)pIdAddr, GTF_ICON_STATIC_HDL);
- dllRef = gtNewOperNode(GT_IND, TYP_I_IMPL, dllRef);
- dllRef->gtFlags |= GTF_IND_INVARIANT;
-
- /* Multiply by 4 */
+ dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_STATIC_HDL, true);
+ // Next we multiply by 4
dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(4, TYP_I_IMPL));
}
@@ -7269,7 +7294,7 @@ bool Compiler::fgCanFastTailCall(GenTreeCall* callee)
if (callee->HasRetBufArg()) // RetBuf
{
- ++calleeArgRegCount;
+ // We don't increment calleeArgRegCount here, since it is already in callee->gtCallArgs.
// If callee has RetBuf param, caller too must have it.
// Otherwise go the slow route.
@@ -8247,7 +8272,7 @@ GenTreePtr Compiler::fgMorphCall(GenTreeCall* call)
{
szFailReason = "Needs security check";
}
- else if (compLocallocUsed)
+ else if (compLocallocUsed || compLocallocOptimized)
{
szFailReason = "Localloc used";
}
@@ -8858,61 +8883,13 @@ NO_TAIL_CALL:
// We need to do these before the arguments are morphed
if ((call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC))
{
- CorInfoIntrinsics methodID = info.compCompHnd->getIntrinsicID(call->gtCallMethHnd);
-
- if (methodID == CORINFO_INTRINSIC_Illegal)
- {
- // Check for a new-style jit intrinsic.
- const NamedIntrinsic ni = lookupNamedIntrinsic(call->gtCallMethHnd);
-
- if (ni == NI_System_Enum_HasFlag)
- {
- GenTree* thisOp = call->gtCallObjp;
- GenTree* flagOp = call->gtCallArgs->gtOp.gtOp1;
- GenTree* optTree = gtOptimizeEnumHasFlag(thisOp, flagOp);
- if (optTree != nullptr)
- {
- return fgMorphTree(optTree);
- }
- }
- }
-
- genTreeOps simpleOp = GT_CALL;
- if (methodID == CORINFO_INTRINSIC_TypeEQ)
- {
- simpleOp = GT_EQ;
- }
- else if (methodID == CORINFO_INTRINSIC_TypeNEQ)
- {
- simpleOp = GT_NE;
- }
+ // See if this is foldable
+ GenTree* optTree = gtFoldExprCall(call);
- if (simpleOp == GT_EQ || simpleOp == GT_NE)
+ // If we optimized, morph the result
+ if (optTree != call)
{
- noway_assert(call->TypeGet() == TYP_INT);
-
- // Check for GetClassFromHandle(handle) and obj.GetType() both of which will only return RuntimeType
- // objects. Then if either operand is one of these two calls we can simplify op_Equality/op_Inequality to
- // GT_NE/GT_NE: One important invariance that should never change is that type equivalency is always
- // equivalent to object identity equality for runtime type objects in reflection. This is also reflected
- // in RuntimeTypeHandle::TypeEquals. If this invariance would ever be broken, we need to remove the
- // optimization below.
-
- GenTreePtr op1 = call->gtCallArgs->gtOp.gtOp1;
- GenTreePtr op2 = call->gtCallArgs->gtOp.gtOp2->gtOp.gtOp1;
-
- if (gtCanOptimizeTypeEquality(op1) || gtCanOptimizeTypeEquality(op2))
- {
- JITDUMP("Optimizing call to Type:op_%s to simple compare via %s\n",
- methodID == CORINFO_INTRINSIC_TypeEQ ? "Equality" : "Inequality", GenTree::OpName(simpleOp));
-
- GenTreePtr compare = gtNewOperNode(simpleOp, TYP_INT, op1, op2);
-
- // fgMorphSmpOp will further optimize the following patterns:
- // 1. typeof(...) == typeof(...)
- // 2. typeof(...) == obj.GetType()
- return fgMorphTree(compare);
- }
+ return fgMorphTree(optTree);
}
}
@@ -11464,2138 +11441,2055 @@ GenTreePtr Compiler::fgMorphFieldAssignToSIMDIntrinsicSet(GenTreePtr tree)
#endif
GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
{
- // this extra scope is a workaround for a gcc bug
- // the inline destructor for ALLOCA_CHECK confuses the control
- // flow and gcc thinks that the function never returns
- {
- ALLOCA_CHECK();
- assert(tree->OperKind() & GTK_SMPOP);
-
- /* The steps in this function are :
- o Perform required preorder processing
- o Process the first, then second operand, if any
- o Perform required postorder morphing
- o Perform optional postorder morphing if optimizing
- */
+ ALLOCA_CHECK();
+ assert(tree->OperKind() & GTK_SMPOP);
+
+ /* The steps in this function are :
+ o Perform required preorder processing
+ o Process the first, then second operand, if any
+ o Perform required postorder morphing
+ o Perform optional postorder morphing if optimizing
+ */
- bool isQmarkColon = false;
+ bool isQmarkColon = false;
#if LOCAL_ASSERTION_PROP
- AssertionIndex origAssertionCount = DUMMY_INIT(0);
- AssertionDsc* origAssertionTab = DUMMY_INIT(NULL);
+ AssertionIndex origAssertionCount = DUMMY_INIT(0);
+ AssertionDsc* origAssertionTab = DUMMY_INIT(NULL);
- AssertionIndex thenAssertionCount = DUMMY_INIT(0);
- AssertionDsc* thenAssertionTab = DUMMY_INIT(NULL);
+ AssertionIndex thenAssertionCount = DUMMY_INIT(0);
+ AssertionDsc* thenAssertionTab = DUMMY_INIT(NULL);
#endif
- if (fgGlobalMorph)
- {
- tree = fgMorphForRegisterFP(tree);
- }
+ if (fgGlobalMorph)
+ {
+ tree = fgMorphForRegisterFP(tree);
+ }
- genTreeOps oper = tree->OperGet();
- var_types typ = tree->TypeGet();
- GenTreePtr op1 = tree->gtOp.gtOp1;
- GenTreePtr op2 = tree->gtGetOp2IfPresent();
+ genTreeOps oper = tree->OperGet();
+ var_types typ = tree->TypeGet();
+ GenTreePtr op1 = tree->gtOp.gtOp1;
+ GenTreePtr op2 = tree->gtGetOp2IfPresent();
- /*-------------------------------------------------------------------------
- * First do any PRE-ORDER processing
- */
+ /*-------------------------------------------------------------------------
+ * First do any PRE-ORDER processing
+ */
- switch (oper)
- {
- // Some arithmetic operators need to use a helper call to the EE
- int helper;
+ switch (oper)
+ {
+ // Some arithmetic operators need to use a helper call to the EE
+ int helper;
- case GT_ASG:
- tree = fgDoNormalizeOnStore(tree);
- /* fgDoNormalizeOnStore can change op2 */
- noway_assert(op1 == tree->gtOp.gtOp1);
- op2 = tree->gtOp.gtOp2;
+ case GT_ASG:
+ tree = fgDoNormalizeOnStore(tree);
+ /* fgDoNormalizeOnStore can change op2 */
+ noway_assert(op1 == tree->gtOp.gtOp1);
+ op2 = tree->gtOp.gtOp2;
#ifdef FEATURE_SIMD
- {
- // We should check whether op2 should be assigned to a SIMD field or not.
- // If it is, we should tranlate the tree to simd intrinsic.
- assert(!fgGlobalMorph || ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) == 0));
- GenTreePtr newTree = fgMorphFieldAssignToSIMDIntrinsicSet(tree);
- typ = tree->TypeGet();
- op1 = tree->gtGetOp1();
- op2 = tree->gtGetOp2();
+ {
+ // We should check whether op2 should be assigned to a SIMD field or not.
+ // If it is, we should tranlate the tree to simd intrinsic.
+ assert(!fgGlobalMorph || ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) == 0));
+ GenTreePtr newTree = fgMorphFieldAssignToSIMDIntrinsicSet(tree);
+ typ = tree->TypeGet();
+ op1 = tree->gtGetOp1();
+ op2 = tree->gtGetOp2();
#ifdef DEBUG
- assert((tree == newTree) && (tree->OperGet() == oper));
- if ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) != 0)
- {
- tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
- }
-#endif // DEBUG
+ assert((tree == newTree) && (tree->OperGet() == oper));
+ if ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) != 0)
+ {
+ tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
}
+#endif // DEBUG
+ }
#endif
- __fallthrough;
-
- case GT_ASG_ADD:
- case GT_ASG_SUB:
- case GT_ASG_MUL:
- case GT_ASG_DIV:
- case GT_ASG_MOD:
- case GT_ASG_UDIV:
- case GT_ASG_UMOD:
- case GT_ASG_OR:
- case GT_ASG_XOR:
- case GT_ASG_AND:
- case GT_ASG_LSH:
- case GT_ASG_RSH:
- case GT_ASG_RSZ:
- case GT_CHS:
-
- // We can't CSE the LHS of an assignment. Only r-values can be CSEed.
- // Previously, the "lhs" (addr) of a block op was CSE'd. So, to duplicate the former
- // behavior, allow CSE'ing if is a struct type (or a TYP_REF transformed from a struct type)
- // TODO-1stClassStructs: improve this.
- if (op1->IsLocal() || (op1->TypeGet() != TYP_STRUCT))
- {
- op1->gtFlags |= GTF_DONT_CSE;
- }
- break;
+#ifdef LEGACY_BACKEND
+ __fallthrough;
- case GT_ADDR:
+ case GT_ASG_ADD:
+ case GT_ASG_SUB:
+ case GT_ASG_MUL:
+ case GT_ASG_DIV:
+ case GT_ASG_MOD:
+ case GT_ASG_UDIV:
+ case GT_ASG_UMOD:
+ case GT_ASG_OR:
+ case GT_ASG_XOR:
+ case GT_ASG_AND:
+ case GT_ASG_LSH:
+ case GT_ASG_RSH:
+ case GT_ASG_RSZ:
+ case GT_CHS:
+#endif
- /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
+ // We can't CSE the LHS of an assignment. Only r-values can be CSEed.
+ // Previously, the "lhs" (addr) of a block op was CSE'd. So, to duplicate the former
+ // behavior, allow CSE'ing if is a struct type (or a TYP_REF transformed from a struct type)
+ // TODO-1stClassStructs: improve this.
+ if (op1->IsLocal() || (op1->TypeGet() != TYP_STRUCT))
+ {
op1->gtFlags |= GTF_DONT_CSE;
- break;
+ }
+ break;
- case GT_QMARK:
- case GT_JTRUE:
+ case GT_ADDR:
- noway_assert(op1);
+ /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
+ op1->gtFlags |= GTF_DONT_CSE;
+ break;
- if (op1->OperKind() & GTK_RELOP)
- {
- noway_assert((oper == GT_JTRUE) || (op1->gtFlags & GTF_RELOP_QMARK));
- /* Mark the comparison node with GTF_RELOP_JMP_USED so it knows that it does
- not need to materialize the result as a 0 or 1. */
+ case GT_QMARK:
+ case GT_JTRUE:
- /* We also mark it as DONT_CSE, as we don't handle QMARKs with nonRELOP op1s */
- op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
+ noway_assert(op1);
- // Request that the codegen for op1 sets the condition flags
- // when it generates the code for op1.
- //
- // Codegen for op1 must set the condition flags if
- // this method returns true.
- //
- op1->gtRequestSetFlags();
- }
- else
- {
- GenTreePtr effOp1 = op1->gtEffectiveVal();
- noway_assert((effOp1->gtOper == GT_CNS_INT) &&
- (effOp1->IsIntegralConst(0) || effOp1->IsIntegralConst(1)));
- }
- break;
+ if (op1->OperKind() & GTK_RELOP)
+ {
+ noway_assert((oper == GT_JTRUE) || (op1->gtFlags & GTF_RELOP_QMARK));
+ /* Mark the comparison node with GTF_RELOP_JMP_USED so it knows that it does
+ not need to materialize the result as a 0 or 1. */
+
+ /* We also mark it as DONT_CSE, as we don't handle QMARKs with nonRELOP op1s */
+ op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_DONT_CSE);
+
+ // Request that the codegen for op1 sets the condition flags
+ // when it generates the code for op1.
+ //
+ // Codegen for op1 must set the condition flags if
+ // this method returns true.
+ //
+ op1->gtRequestSetFlags();
+ }
+ else
+ {
+ GenTreePtr effOp1 = op1->gtEffectiveVal();
+ noway_assert((effOp1->gtOper == GT_CNS_INT) &&
+ (effOp1->IsIntegralConst(0) || effOp1->IsIntegralConst(1)));
+ }
+ break;
- case GT_COLON:
+ case GT_COLON:
#if LOCAL_ASSERTION_PROP
- if (optLocalAssertionProp)
+ if (optLocalAssertionProp)
#endif
- {
- isQmarkColon = true;
- }
- break;
+ {
+ isQmarkColon = true;
+ }
+ break;
- case GT_INDEX:
- return fgMorphArrayIndex(tree);
+ case GT_INDEX:
+ return fgMorphArrayIndex(tree);
- case GT_CAST:
- return fgMorphCast(tree);
+ case GT_CAST:
+ return fgMorphCast(tree);
- case GT_MUL:
+ case GT_MUL:
#ifndef _TARGET_64BIT_
- if (typ == TYP_LONG)
- {
- /* For (long)int1 * (long)int2, we dont actually do the
- casts, and just multiply the 32 bit values, which will
- give us the 64 bit result in edx:eax */
+ if (typ == TYP_LONG)
+ {
+ /* For (long)int1 * (long)int2, we dont actually do the
+ casts, and just multiply the 32 bit values, which will
+ give us the 64 bit result in edx:eax */
- noway_assert(op2);
- if ((op1->gtOper == GT_CAST && op2->gtOper == GT_CAST &&
- genActualType(op1->CastFromType()) == TYP_INT &&
- genActualType(op2->CastFromType()) == TYP_INT) &&
- !op1->gtOverflow() && !op2->gtOverflow())
+ noway_assert(op2);
+ if ((op1->gtOper == GT_CAST && op2->gtOper == GT_CAST &&
+ genActualType(op1->CastFromType()) == TYP_INT && genActualType(op2->CastFromType()) == TYP_INT) &&
+ !op1->gtOverflow() && !op2->gtOverflow())
+ {
+ // The casts have to be of the same signedness.
+ if ((op1->gtFlags & GTF_UNSIGNED) != (op2->gtFlags & GTF_UNSIGNED))
{
- // The casts have to be of the same signedness.
- if ((op1->gtFlags & GTF_UNSIGNED) != (op2->gtFlags & GTF_UNSIGNED))
- {
- // We see if we can force an int constant to change its signedness
- GenTreePtr constOp;
- if (op1->gtCast.CastOp()->gtOper == GT_CNS_INT)
- constOp = op1;
- else if (op2->gtCast.CastOp()->gtOper == GT_CNS_INT)
- constOp = op2;
- else
- goto NO_MUL_64RSLT;
-
- if (((unsigned)(constOp->gtCast.CastOp()->gtIntCon.gtIconVal) < (unsigned)(0x80000000)))
- constOp->gtFlags ^= GTF_UNSIGNED;
- else
- goto NO_MUL_64RSLT;
- }
+ // We see if we can force an int constant to change its signedness
+ GenTreePtr constOp;
+ if (op1->gtCast.CastOp()->gtOper == GT_CNS_INT)
+ constOp = op1;
+ else if (op2->gtCast.CastOp()->gtOper == GT_CNS_INT)
+ constOp = op2;
+ else
+ goto NO_MUL_64RSLT;
- // The only combination that can overflow
- if (tree->gtOverflow() && (tree->gtFlags & GTF_UNSIGNED) && !(op1->gtFlags & GTF_UNSIGNED))
+ if (((unsigned)(constOp->gtCast.CastOp()->gtIntCon.gtIconVal) < (unsigned)(0x80000000)))
+ constOp->gtFlags ^= GTF_UNSIGNED;
+ else
goto NO_MUL_64RSLT;
+ }
- /* Remaining combinations can never overflow during long mul. */
+ // The only combination that can overflow
+ if (tree->gtOverflow() && (tree->gtFlags & GTF_UNSIGNED) && !(op1->gtFlags & GTF_UNSIGNED))
+ goto NO_MUL_64RSLT;
- tree->gtFlags &= ~GTF_OVERFLOW;
+ /* Remaining combinations can never overflow during long mul. */
- /* Do unsigned mul only if the casts were unsigned */
+ tree->gtFlags &= ~GTF_OVERFLOW;
- tree->gtFlags &= ~GTF_UNSIGNED;
- tree->gtFlags |= op1->gtFlags & GTF_UNSIGNED;
+ /* Do unsigned mul only if the casts were unsigned */
- /* Since we are committing to GTF_MUL_64RSLT, we don't want
- the casts to be folded away. So morph the castees directly */
+ tree->gtFlags &= ~GTF_UNSIGNED;
+ tree->gtFlags |= op1->gtFlags & GTF_UNSIGNED;
- op1->gtOp.gtOp1 = fgMorphTree(op1->gtOp.gtOp1);
- op2->gtOp.gtOp1 = fgMorphTree(op2->gtOp.gtOp1);
+ /* Since we are committing to GTF_MUL_64RSLT, we don't want
+ the casts to be folded away. So morph the castees directly */
- // Propagate side effect flags up the tree
- op1->gtFlags &= ~GTF_ALL_EFFECT;
- op1->gtFlags |= (op1->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
- op2->gtFlags &= ~GTF_ALL_EFFECT;
- op2->gtFlags |= (op2->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
+ op1->gtOp.gtOp1 = fgMorphTree(op1->gtOp.gtOp1);
+ op2->gtOp.gtOp1 = fgMorphTree(op2->gtOp.gtOp1);
- // If the GT_MUL can be altogether folded away, we should do that.
+ // Propagate side effect flags up the tree
+ op1->gtFlags &= ~GTF_ALL_EFFECT;
+ op1->gtFlags |= (op1->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
+ op2->gtFlags &= ~GTF_ALL_EFFECT;
+ op2->gtFlags |= (op2->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
- if ((op1->gtCast.CastOp()->OperKind() & op2->gtCast.CastOp()->OperKind() & GTK_CONST) &&
- opts.OptEnabled(CLFLG_CONSTANTFOLD))
- {
- tree->gtOp.gtOp1 = op1 = gtFoldExprConst(op1);
- tree->gtOp.gtOp2 = op2 = gtFoldExprConst(op2);
- noway_assert(op1->OperKind() & op2->OperKind() & GTK_CONST);
- tree = gtFoldExprConst(tree);
- noway_assert(tree->OperIsConst());
- return tree;
- }
+ // If the GT_MUL can be altogether folded away, we should do that.
- tree->gtFlags |= GTF_MUL_64RSLT;
+ if ((op1->gtCast.CastOp()->OperKind() & op2->gtCast.CastOp()->OperKind() & GTK_CONST) &&
+ opts.OptEnabled(CLFLG_CONSTANTFOLD))
+ {
+ tree->gtOp.gtOp1 = op1 = gtFoldExprConst(op1);
+ tree->gtOp.gtOp2 = op2 = gtFoldExprConst(op2);
+ noway_assert(op1->OperKind() & op2->OperKind() & GTK_CONST);
+ tree = gtFoldExprConst(tree);
+ noway_assert(tree->OperIsConst());
+ return tree;
+ }
- // If op1 and op2 are unsigned casts, we need to do an unsigned mult
- tree->gtFlags |= (op1->gtFlags & GTF_UNSIGNED);
+ tree->gtFlags |= GTF_MUL_64RSLT;
- // Insert GT_NOP nodes for the cast operands so that they do not get folded
- // And propagate the new flags. We don't want to CSE the casts because
- // codegen expects GTF_MUL_64RSLT muls to have a certain layout.
+ // If op1 and op2 are unsigned casts, we need to do an unsigned mult
+ tree->gtFlags |= (op1->gtFlags & GTF_UNSIGNED);
- if (op1->gtCast.CastOp()->OperGet() != GT_NOP)
- {
- op1->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op1->gtCast.CastOp());
- op1->gtFlags &= ~GTF_ALL_EFFECT;
- op1->gtFlags |= (op1->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
- }
+ // Insert GT_NOP nodes for the cast operands so that they do not get folded
+ // And propagate the new flags. We don't want to CSE the casts because
+ // codegen expects GTF_MUL_64RSLT muls to have a certain layout.
- if (op2->gtCast.CastOp()->OperGet() != GT_NOP)
- {
- op2->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op2->gtCast.CastOp());
- op2->gtFlags &= ~GTF_ALL_EFFECT;
- op2->gtFlags |= (op2->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
- }
+ if (op1->gtCast.CastOp()->OperGet() != GT_NOP)
+ {
+ op1->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op1->gtCast.CastOp());
+ op1->gtFlags &= ~GTF_ALL_EFFECT;
+ op1->gtFlags |= (op1->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
+ }
- op1->gtFlags |= GTF_DONT_CSE;
- op2->gtFlags |= GTF_DONT_CSE;
+ if (op2->gtCast.CastOp()->OperGet() != GT_NOP)
+ {
+ op2->gtOp.gtOp1 = gtNewOperNode(GT_NOP, TYP_INT, op2->gtCast.CastOp());
+ op2->gtFlags &= ~GTF_ALL_EFFECT;
+ op2->gtFlags |= (op2->gtCast.CastOp()->gtFlags & GTF_ALL_EFFECT);
+ }
- tree->gtFlags &= ~GTF_ALL_EFFECT;
- tree->gtFlags |= ((op1->gtFlags | op2->gtFlags) & GTF_ALL_EFFECT);
+ op1->gtFlags |= GTF_DONT_CSE;
+ op2->gtFlags |= GTF_DONT_CSE;
- goto DONE_MORPHING_CHILDREN;
- }
- else if ((tree->gtFlags & GTF_MUL_64RSLT) == 0)
- {
- NO_MUL_64RSLT:
- if (tree->gtOverflow())
- helper = (tree->gtFlags & GTF_UNSIGNED) ? CORINFO_HELP_ULMUL_OVF : CORINFO_HELP_LMUL_OVF;
- else
- helper = CORINFO_HELP_LMUL;
+ tree->gtFlags &= ~GTF_ALL_EFFECT;
+ tree->gtFlags |= ((op1->gtFlags | op2->gtFlags) & GTF_ALL_EFFECT);
- goto USE_HELPER_FOR_ARITH;
- }
+ goto DONE_MORPHING_CHILDREN;
+ }
+ else if ((tree->gtFlags & GTF_MUL_64RSLT) == 0)
+ {
+ NO_MUL_64RSLT:
+ if (tree->gtOverflow())
+ helper = (tree->gtFlags & GTF_UNSIGNED) ? CORINFO_HELP_ULMUL_OVF : CORINFO_HELP_LMUL_OVF;
else
- {
- /* We are seeing this node again. We have decided to use
- GTF_MUL_64RSLT, so leave it alone. */
+ helper = CORINFO_HELP_LMUL;
- assert(tree->gtIsValid64RsltMul());
- }
+ goto USE_HELPER_FOR_ARITH;
+ }
+ else
+ {
+ /* We are seeing this node again. We have decided to use
+ GTF_MUL_64RSLT, so leave it alone. */
+
+ assert(tree->gtIsValid64RsltMul());
}
+ }
#endif // !_TARGET_64BIT_
- break;
+ break;
- case GT_DIV:
+ case GT_DIV:
#ifndef _TARGET_64BIT_
- if (typ == TYP_LONG)
- {
- helper = CORINFO_HELP_LDIV;
- goto USE_HELPER_FOR_ARITH;
- }
+ if (typ == TYP_LONG)
+ {
+ helper = CORINFO_HELP_LDIV;
+ goto USE_HELPER_FOR_ARITH;
+ }
#if USE_HELPERS_FOR_INT_DIV
- if (typ == TYP_INT && !fgIsSignedDivOptimizable(op2))
- {
- helper = CORINFO_HELP_DIV;
- goto USE_HELPER_FOR_ARITH;
- }
+ if (typ == TYP_INT && !fgIsSignedDivOptimizable(op2))
+ {
+ helper = CORINFO_HELP_DIV;
+ goto USE_HELPER_FOR_ARITH;
+ }
#endif
#endif // !_TARGET_64BIT_
#ifndef LEGACY_BACKEND
- if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
- {
- op2 = gtFoldExprConst(op2);
- }
+ if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
+ {
+ op2 = gtFoldExprConst(op2);
+ }
#endif // !LEGACY_BACKEND
- break;
+ break;
- case GT_UDIV:
+ case GT_UDIV:
#ifndef _TARGET_64BIT_
- if (typ == TYP_LONG)
- {
- helper = CORINFO_HELP_ULDIV;
- goto USE_HELPER_FOR_ARITH;
- }
+ if (typ == TYP_LONG)
+ {
+ helper = CORINFO_HELP_ULDIV;
+ goto USE_HELPER_FOR_ARITH;
+ }
#if USE_HELPERS_FOR_INT_DIV
- if (typ == TYP_INT && !fgIsUnsignedDivOptimizable(op2))
- {
- helper = CORINFO_HELP_UDIV;
- goto USE_HELPER_FOR_ARITH;
- }
+ if (typ == TYP_INT && !fgIsUnsignedDivOptimizable(op2))
+ {
+ helper = CORINFO_HELP_UDIV;
+ goto USE_HELPER_FOR_ARITH;
+ }
#endif
#endif // _TARGET_64BIT_
- break;
+ break;
- case GT_MOD:
+ case GT_MOD:
- if (varTypeIsFloating(typ))
+ if (varTypeIsFloating(typ))
+ {
+ helper = CORINFO_HELP_DBLREM;
+ noway_assert(op2);
+ if (op1->TypeGet() == TYP_FLOAT)
{
- helper = CORINFO_HELP_DBLREM;
- noway_assert(op2);
- if (op1->TypeGet() == TYP_FLOAT)
+ if (op2->TypeGet() == TYP_FLOAT)
{
- if (op2->TypeGet() == TYP_FLOAT)
- {
- helper = CORINFO_HELP_FLTREM;
- }
- else
- {
- tree->gtOp.gtOp1 = op1 = gtNewCastNode(TYP_DOUBLE, op1, TYP_DOUBLE);
- }
+ helper = CORINFO_HELP_FLTREM;
}
- else if (op2->TypeGet() == TYP_FLOAT)
+ else
{
- tree->gtOp.gtOp2 = op2 = gtNewCastNode(TYP_DOUBLE, op2, TYP_DOUBLE);
+ tree->gtOp.gtOp1 = op1 = gtNewCastNode(TYP_DOUBLE, op1, TYP_DOUBLE);
}
- goto USE_HELPER_FOR_ARITH;
}
+ else if (op2->TypeGet() == TYP_FLOAT)
+ {
+ tree->gtOp.gtOp2 = op2 = gtNewCastNode(TYP_DOUBLE, op2, TYP_DOUBLE);
+ }
+ goto USE_HELPER_FOR_ARITH;
+ }
- // Do not use optimizations (unlike UMOD's idiv optimizing during codegen) for signed mod.
- // A similar optimization for signed mod will not work for a negative perfectly divisible
- // HI-word. To make it correct, we would need to divide without the sign and then flip the
- // result sign after mod. This requires 18 opcodes + flow making it not worthy to inline.
- goto ASSIGN_HELPER_FOR_MOD;
+ // Do not use optimizations (unlike UMOD's idiv optimizing during codegen) for signed mod.
+ // A similar optimization for signed mod will not work for a negative perfectly divisible
+ // HI-word. To make it correct, we would need to divide without the sign and then flip the
+ // result sign after mod. This requires 18 opcodes + flow making it not worthy to inline.
+ goto ASSIGN_HELPER_FOR_MOD;
- case GT_UMOD:
+ case GT_UMOD:
#ifdef _TARGET_ARMARCH_
//
// Note for _TARGET_ARMARCH_ we don't have a remainder instruction, so we don't do this optimization
//
#else // _TARGET_XARCH
- /* If this is an unsigned long mod with op2 which is a cast to long from a
- constant int, then don't morph to a call to the helper. This can be done
- faster inline using idiv.
- */
+ /* If this is an unsigned long mod with op2 which is a cast to long from a
+ constant int, then don't morph to a call to the helper. This can be done
+ faster inline using idiv.
+ */
- noway_assert(op2);
- if ((typ == TYP_LONG) && opts.OptEnabled(CLFLG_CONSTANTFOLD) &&
- ((tree->gtFlags & GTF_UNSIGNED) == (op1->gtFlags & GTF_UNSIGNED)) &&
- ((tree->gtFlags & GTF_UNSIGNED) == (op2->gtFlags & GTF_UNSIGNED)))
- {
- if (op2->gtOper == GT_CAST && op2->gtCast.CastOp()->gtOper == GT_CNS_INT &&
- op2->gtCast.CastOp()->gtIntCon.gtIconVal >= 2 &&
- op2->gtCast.CastOp()->gtIntCon.gtIconVal <= 0x3fffffff &&
- (tree->gtFlags & GTF_UNSIGNED) == (op2->gtCast.CastOp()->gtFlags & GTF_UNSIGNED))
- {
- tree->gtOp.gtOp2 = op2 = fgMorphCast(op2);
- noway_assert(op2->gtOper == GT_CNS_NATIVELONG);
- }
+ noway_assert(op2);
+ if ((typ == TYP_LONG) && opts.OptEnabled(CLFLG_CONSTANTFOLD) &&
+ ((tree->gtFlags & GTF_UNSIGNED) == (op1->gtFlags & GTF_UNSIGNED)) &&
+ ((tree->gtFlags & GTF_UNSIGNED) == (op2->gtFlags & GTF_UNSIGNED)))
+ {
+ if (op2->gtOper == GT_CAST && op2->gtCast.CastOp()->gtOper == GT_CNS_INT &&
+ op2->gtCast.CastOp()->gtIntCon.gtIconVal >= 2 &&
+ op2->gtCast.CastOp()->gtIntCon.gtIconVal <= 0x3fffffff &&
+ (tree->gtFlags & GTF_UNSIGNED) == (op2->gtCast.CastOp()->gtFlags & GTF_UNSIGNED))
+ {
+ tree->gtOp.gtOp2 = op2 = fgMorphCast(op2);
+ noway_assert(op2->gtOper == GT_CNS_NATIVELONG);
+ }
- if (op2->gtOper == GT_CNS_NATIVELONG && op2->gtIntConCommon.LngValue() >= 2 &&
- op2->gtIntConCommon.LngValue() <= 0x3fffffff)
- {
- tree->gtOp.gtOp1 = op1 = fgMorphTree(op1);
- noway_assert(op1->TypeGet() == TYP_LONG);
+ if (op2->gtOper == GT_CNS_NATIVELONG && op2->gtIntConCommon.LngValue() >= 2 &&
+ op2->gtIntConCommon.LngValue() <= 0x3fffffff)
+ {
+ tree->gtOp.gtOp1 = op1 = fgMorphTree(op1);
+ noway_assert(op1->TypeGet() == TYP_LONG);
- // Update flags for op1 morph
- tree->gtFlags &= ~GTF_ALL_EFFECT;
+ // Update flags for op1 morph
+ tree->gtFlags &= ~GTF_ALL_EFFECT;
- tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT); // Only update with op1 as op2 is a constant
+ tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT); // Only update with op1 as op2 is a constant
- // If op1 is a constant, then do constant folding of the division operator
- if (op1->gtOper == GT_CNS_NATIVELONG)
- {
- tree = gtFoldExpr(tree);
- }
- return tree;
+ // If op1 is a constant, then do constant folding of the division operator
+ if (op1->gtOper == GT_CNS_NATIVELONG)
+ {
+ tree = gtFoldExpr(tree);
}
+ return tree;
}
+ }
#endif // _TARGET_XARCH
- ASSIGN_HELPER_FOR_MOD:
+ ASSIGN_HELPER_FOR_MOD:
- // For "val % 1", return 0 if op1 doesn't have any side effects
- // and we are not in the CSE phase, we cannot discard 'tree'
- // because it may contain CSE expressions that we haven't yet examined.
- //
- if (((op1->gtFlags & GTF_SIDE_EFFECT) == 0) && !optValnumCSE_phase)
+ // For "val % 1", return 0 if op1 doesn't have any side effects
+ // and we are not in the CSE phase, we cannot discard 'tree'
+ // because it may contain CSE expressions that we haven't yet examined.
+ //
+ if (((op1->gtFlags & GTF_SIDE_EFFECT) == 0) && !optValnumCSE_phase)
+ {
+ if (op2->IsIntegralConst(1))
{
- if (op2->IsIntegralConst(1))
- {
- GenTreePtr zeroNode = gtNewZeroConNode(typ);
+ GenTreePtr zeroNode = gtNewZeroConNode(typ);
#ifdef DEBUG
- zeroNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+ zeroNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
#endif
- DEBUG_DESTROY_NODE(tree);
- return zeroNode;
- }
+ DEBUG_DESTROY_NODE(tree);
+ return zeroNode;
}
+ }
#ifndef _TARGET_64BIT_
- if (typ == TYP_LONG)
+ if (typ == TYP_LONG)
+ {
+ helper = (oper == GT_UMOD) ? CORINFO_HELP_ULMOD : CORINFO_HELP_LMOD;
+ goto USE_HELPER_FOR_ARITH;
+ }
+
+#if USE_HELPERS_FOR_INT_DIV
+ if (typ == TYP_INT)
+ {
+ if (oper == GT_UMOD && !fgIsUnsignedModOptimizable(op2))
{
- helper = (oper == GT_UMOD) ? CORINFO_HELP_ULMOD : CORINFO_HELP_LMOD;
+ helper = CORINFO_HELP_UMOD;
goto USE_HELPER_FOR_ARITH;
}
-
-#if USE_HELPERS_FOR_INT_DIV
- if (typ == TYP_INT)
+ else if (oper == GT_MOD && !fgIsSignedModOptimizable(op2))
{
- if (oper == GT_UMOD && !fgIsUnsignedModOptimizable(op2))
- {
- helper = CORINFO_HELP_UMOD;
- goto USE_HELPER_FOR_ARITH;
- }
- else if (oper == GT_MOD && !fgIsSignedModOptimizable(op2))
- {
- helper = CORINFO_HELP_MOD;
- goto USE_HELPER_FOR_ARITH;
- }
+ helper = CORINFO_HELP_MOD;
+ goto USE_HELPER_FOR_ARITH;
}
+ }
#endif
#endif // !_TARGET_64BIT_
#ifndef LEGACY_BACKEND
- if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
- {
- op2 = gtFoldExprConst(op2);
- }
+ if (op2->gtOper == GT_CAST && op2->gtOp.gtOp1->IsCnsIntOrI())
+ {
+ op2 = gtFoldExprConst(op2);
+ }
#ifdef _TARGET_ARM64_
- // For ARM64 we don't have a remainder instruction,
- // The architecture manual suggests the following transformation to
- // generate code for such operator:
- //
- // a % b = a - (a / b) * b;
- //
- // We will use the suggested transform except in the special case
- // when the modulo operation is unsigned and the divisor is a
- // integer constant power of two. In this case, we will rely on lower
- // to make the transform:
- //
- // a % b = a & (b - 1);
- //
- // Note: We must always perform one or the other of these transforms.
- // Therefore we must also detect the special cases where lower does not do the
- // % to & transform. In our case there is only currently one extra condition:
- //
- // * Dividend must not be constant. Lower disables this rare const % const case
- //
- {
- // Do "a % b = a - (a / b) * b" morph if ...........................
- bool doMorphModToSubMulDiv =
- (tree->OperGet() == GT_MOD) || // Modulo operation is signed
- !op2->IsIntegralConst() || // Divisor is not an integer constant
- !isPow2(op2->AsIntCon()->IconValue()) || // Divisor is not a power of two
- op1->IsCnsIntOrI(); // Dividend is constant
-
- if (doMorphModToSubMulDiv)
- {
- assert(!optValnumCSE_phase);
-
- tree = fgMorphModToSubMulDiv(tree->AsOp());
- op1 = tree->gtOp.gtOp1;
- op2 = tree->gtOp.gtOp2;
- }
- }
-#else // !_TARGET_ARM64_
- // If b is not a power of 2 constant then lowering replaces a % b
- // with a - (a / b) * b and applies magic division optimization to
- // a / b. The code may already contain an a / b expression (e.g.
- // x = a / 10; y = a % 10;) and then we end up with redundant code.
- // If we convert % to / here we give CSE the opportunity to eliminate
- // the redundant division. If there's no redundant division then
- // nothing is lost, lowering would have done this transform anyway.
+ // For ARM64 we don't have a remainder instruction,
+ // The architecture manual suggests the following transformation to
+ // generate code for such operator:
+ //
+ // a % b = a - (a / b) * b;
+ //
+ // We will use the suggested transform except in the special case
+ // when the modulo operation is unsigned and the divisor is a
+ // integer constant power of two. In this case, we will rely on lower
+ // to make the transform:
+ //
+ // a % b = a & (b - 1);
+ //
+ // Note: We must always perform one or the other of these transforms.
+ // Therefore we must also detect the special cases where lower does not do the
+ // % to & transform. In our case there is only currently one extra condition:
+ //
+ // * Dividend must not be constant. Lower disables this rare const % const case
+ //
+ {
+ // Do "a % b = a - (a / b) * b" morph if ...........................
+ bool doMorphModToSubMulDiv = (tree->OperGet() == GT_MOD) || // Modulo operation is signed
+ !op2->IsIntegralConst() || // Divisor is not an integer constant
+ !isPow2(op2->AsIntCon()->IconValue()) || // Divisor is not a power of two
+ op1->IsCnsIntOrI(); // Dividend is constant
- if (!optValnumCSE_phase && ((tree->OperGet() == GT_MOD) && op2->IsIntegralConst()))
+ if (doMorphModToSubMulDiv)
{
- ssize_t divisorValue = op2->AsIntCon()->IconValue();
- size_t absDivisorValue = (divisorValue == SSIZE_T_MIN) ? static_cast<size_t>(divisorValue)
- : static_cast<size_t>(abs(divisorValue));
+ assert(!optValnumCSE_phase);
- if (!isPow2(absDivisorValue))
- {
- tree = fgMorphModToSubMulDiv(tree->AsOp());
- op1 = tree->gtOp.gtOp1;
- op2 = tree->gtOp.gtOp2;
- }
+ tree = fgMorphModToSubMulDiv(tree->AsOp());
+ op1 = tree->gtOp.gtOp1;
+ op2 = tree->gtOp.gtOp2;
}
-#endif //_TARGET_ARM64_
-#endif // !LEGACY_BACKEND
- break;
+ }
+#else // !_TARGET_ARM64_
+ // If b is not a power of 2 constant then lowering replaces a % b
+ // with a - (a / b) * b and applies magic division optimization to
+ // a / b. The code may already contain an a / b expression (e.g.
+ // x = a / 10; y = a % 10;) and then we end up with redundant code.
+ // If we convert % to / here we give CSE the opportunity to eliminate
+ // the redundant division. If there's no redundant division then
+ // nothing is lost, lowering would have done this transform anyway.
- USE_HELPER_FOR_ARITH:
+ if (!optValnumCSE_phase && ((tree->OperGet() == GT_MOD) && op2->IsIntegralConst()))
{
- /* We have to morph these arithmetic operations into helper calls
- before morphing the arguments (preorder), else the arguments
- won't get correct values of fgPtrArgCntCur.
- However, try to fold the tree first in case we end up with a
- simple node which won't need a helper call at all */
-
- noway_assert(tree->OperIsBinary());
-
- GenTreePtr oldTree = tree;
+ ssize_t divisorValue = op2->AsIntCon()->IconValue();
+ size_t absDivisorValue = (divisorValue == SSIZE_T_MIN) ? static_cast<size_t>(divisorValue)
+ : static_cast<size_t>(abs(divisorValue));
- tree = gtFoldExpr(tree);
-
- // Were we able to fold it ?
- // Note that gtFoldExpr may return a non-leaf even if successful
- // e.g. for something like "expr / 1" - see also bug #290853
- if (tree->OperIsLeaf() || (oldTree != tree))
- {
- return (oldTree != tree) ? fgMorphTree(tree) : fgMorphLeaf(tree);
- }
-
- // Did we fold it into a comma node with throw?
- if (tree->gtOper == GT_COMMA)
+ if (!isPow2(absDivisorValue))
{
- noway_assert(fgIsCommaThrow(tree));
- return fgMorphTree(tree);
+ tree = fgMorphModToSubMulDiv(tree->AsOp());
+ op1 = tree->gtOp.gtOp1;
+ op2 = tree->gtOp.gtOp2;
}
}
- return fgMorphIntoHelperCall(tree, helper, gtNewArgList(op1, op2));
-
- case GT_RETURN:
- // normalize small integer return values
- if (fgGlobalMorph && varTypeIsSmall(info.compRetType) && (op1 != nullptr) &&
- (op1->TypeGet() != TYP_VOID) && fgCastNeeded(op1, info.compRetType))
- {
- // Small-typed return values are normalized by the callee
- op1 = gtNewCastNode(TYP_INT, op1, info.compRetType);
-
- // Propagate GTF_COLON_COND
- op1->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
-
- tree->gtOp.gtOp1 = fgMorphCast(op1);
-
- // Propagate side effect flags
- tree->gtFlags &= ~GTF_ALL_EFFECT;
- tree->gtFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
-
- return tree;
- }
- break;
-
- case GT_EQ:
- case GT_NE:
-
- // Check for typeof(...) == obj.GetType()
- // Also check for typeof(...) == typeof(...)
- // IMPORTANT NOTE: this optimization relies on a one-to-one mapping between
- // type handles and instances of System.Type
- // If this invariant is ever broken, the optimization will need updating
- CLANG_FORMAT_COMMENT_ANCHOR;
-
-#ifdef LEGACY_BACKEND
- if (op1->gtOper == GT_CALL && op2->gtOper == GT_CALL &&
- ((op1->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) ||
- (op1->gtCall.gtCallType == CT_HELPER)) &&
- ((op2->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) ||
- (op2->gtCall.gtCallType == CT_HELPER)))
-#else
- if ((((op1->gtOper == GT_INTRINSIC) &&
- (op1->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)) ||
- ((op1->gtOper == GT_CALL) && (op1->gtCall.gtCallType == CT_HELPER))) &&
- (((op2->gtOper == GT_INTRINSIC) &&
- (op2->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType)) ||
- ((op2->gtOper == GT_CALL) && (op2->gtCall.gtCallType == CT_HELPER))))
-#endif
- {
- GenTreePtr pGetClassFromHandle;
- GenTreePtr pGetType;
-
-#ifdef LEGACY_BACKEND
- bool bOp1ClassFromHandle = gtIsTypeHandleToRuntimeTypeHelper(op1->AsCall());
- bool bOp2ClassFromHandle = gtIsTypeHandleToRuntimeTypeHelper(op2->AsCall());
-#else
- bool bOp1ClassFromHandle =
- op1->gtOper == GT_CALL ? gtIsTypeHandleToRuntimeTypeHelper(op1->AsCall()) : false;
- bool bOp2ClassFromHandle =
- op2->gtOper == GT_CALL ? gtIsTypeHandleToRuntimeTypeHelper(op2->AsCall()) : false;
-#endif
-
- // Optimize typeof(...) == typeof(...)
- // Typically this occurs in generic code that attempts a type switch
- // e.g. typeof(T) == typeof(int)
-
- if (bOp1ClassFromHandle && bOp2ClassFromHandle)
- {
- JITDUMP("Optimizing compare of types-from-handles to instead compare handles\n");
+#endif //_TARGET_ARM64_
+#endif // !LEGACY_BACKEND
+ break;
- GenTreePtr classFromHandleArg1 = tree->gtOp.gtOp1->gtCall.gtCallArgs->gtOp.gtOp1;
- GenTreePtr classFromHandleArg2 = tree->gtOp.gtOp2->gtCall.gtCallArgs->gtOp.gtOp1;
+ USE_HELPER_FOR_ARITH:
+ {
+ /* We have to morph these arithmetic operations into helper calls
+ before morphing the arguments (preorder), else the arguments
+ won't get correct values of fgPtrArgCntCur.
+ However, try to fold the tree first in case we end up with a
+ simple node which won't need a helper call at all */
- GenTreePtr compare = gtNewOperNode(oper, TYP_INT, classFromHandleArg1, classFromHandleArg2);
+ noway_assert(tree->OperIsBinary());
- compare->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+ GenTreePtr oldTree = tree;
- // Morph and return
- return fgMorphTree(compare);
- }
- else if (bOp1ClassFromHandle || bOp2ClassFromHandle)
- {
- //
- // Now check for GetClassFromHandle(handle) == obj.GetType()
- //
+ tree = gtFoldExpr(tree);
- if (bOp1ClassFromHandle)
- {
- pGetClassFromHandle = tree->gtOp.gtOp1;
- pGetType = op2;
- }
- else
- {
- pGetClassFromHandle = tree->gtOp.gtOp2;
- pGetType = op1;
- }
+ // Were we able to fold it ?
+ // Note that gtFoldExpr may return a non-leaf even if successful
+ // e.g. for something like "expr / 1" - see also bug #290853
+ if (tree->OperIsLeaf() || (oldTree != tree))
+ {
+ return (oldTree != tree) ? fgMorphTree(tree) : fgMorphLeaf(tree);
+ }
- GenTreePtr pGetClassFromHandleArgument = pGetClassFromHandle->gtCall.gtCallArgs->gtOp.gtOp1;
- GenTreePtr pConstLiteral = pGetClassFromHandleArgument;
+ // Did we fold it into a comma node with throw?
+ if (tree->gtOper == GT_COMMA)
+ {
+ noway_assert(fgIsCommaThrow(tree));
+ return fgMorphTree(tree);
+ }
+ }
+ return fgMorphIntoHelperCall(tree, helper, gtNewArgList(op1, op2));
- // Unwrap GT_NOP node used to prevent constant folding
- if (pConstLiteral->gtOper == GT_NOP && pConstLiteral->gtType == TYP_I_IMPL)
- {
- pConstLiteral = pConstLiteral->gtOp.gtOp1;
- }
+ case GT_RETURN:
+ // normalize small integer return values
+ if (fgGlobalMorph && varTypeIsSmall(info.compRetType) && (op1 != nullptr) && (op1->TypeGet() != TYP_VOID) &&
+ fgCastNeeded(op1, info.compRetType))
+ {
+ // Small-typed return values are normalized by the callee
+ op1 = gtNewCastNode(TYP_INT, op1, info.compRetType);
- // In the ngen case, we have to go thru an indirection to get the right handle.
- if (pConstLiteral->gtOper == GT_IND)
- {
- pConstLiteral = pConstLiteral->gtOp.gtOp1;
- }
-#ifdef LEGACY_BACKEND
+ // Propagate GTF_COLON_COND
+ op1->gtFlags |= (tree->gtFlags & GTF_COLON_COND);
- if (pGetType->gtCall.gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC &&
- info.compCompHnd->getIntrinsicID(pGetType->gtCall.gtCallMethHnd) ==
- CORINFO_INTRINSIC_Object_GetType &&
-#else
- if ((pGetType->gtOper == GT_INTRINSIC) &&
- (pGetType->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Object_GetType) &&
-#endif
- pConstLiteral->gtOper == GT_CNS_INT && pConstLiteral->gtType == TYP_I_IMPL)
- {
- CORINFO_CLASS_HANDLE clsHnd =
- CORINFO_CLASS_HANDLE(pConstLiteral->gtIntCon.gtCompileTimeHandle);
+ tree->gtOp.gtOp1 = fgMorphCast(op1);
- if (info.compCompHnd->canInlineTypeCheckWithObjectVTable(clsHnd))
- {
- // Fetch object method table from the object itself
- JITDUMP("Optimizing compare of obj.GetType()"
- " and type-from-handle to compare handles\n");
+ // Propagate side effect flags
+ tree->gtFlags &= ~GTF_ALL_EFFECT;
+ tree->gtFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_ALL_EFFECT);
- // Method table constant
- GenTree* cnsMT = pGetClassFromHandleArgument;
-#ifdef LEGACY_BACKEND
- // Method table from object
- GenTree* objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, pGetType->gtCall.gtCallObjp);
-#else
- // Method table from object
- GenTree* objMT = gtNewOperNode(GT_IND, TYP_I_IMPL, pGetType->gtUnOp.gtOp1);
-#endif
- objMT->gtFlags |= GTF_EXCEPT; // Null ref exception if object is null
- compCurBB->bbFlags |= BBF_HAS_VTABREF;
- optMethodFlags |= OMF_HAS_VTABLEREF;
+ return tree;
+ }
+ break;
- GenTreePtr compare = gtNewOperNode(oper, TYP_INT, objMT, cnsMT);
+ case GT_EQ:
+ case GT_NE:
+ {
+ GenTree* optimizedTree = gtFoldTypeCompare(tree);
- compare->gtFlags |=
- tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+ if (optimizedTree != tree)
+ {
+ return fgMorphTree(optimizedTree);
+ }
+ }
- // Morph and return
- return fgMorphTree(compare);
- }
- }
- }
- }
+ __fallthrough;
- __fallthrough;
+ case GT_GT:
- case GT_GT:
+ // Try to optimize away calls to CORINFO_HELP_BOX_NULLABLE for GT_EQ, GT_NE, and unsigned GT_GT.
+ if ((oper != GT_GT) || tree->IsUnsigned())
+ {
+ fgMorphRecognizeBoxNullable(tree);
+ }
- // Try to optimize away calls to CORINFO_HELP_BOX_NULLABLE for GT_EQ, GT_NE, and unsigned GT_GT.
- if ((oper != GT_GT) || tree->IsUnsigned())
- {
- fgMorphRecognizeBoxNullable(tree);
- }
+ op1 = tree->gtOp.gtOp1;
+ op2 = tree->gtGetOp2IfPresent();
- op1 = tree->gtOp.gtOp1;
- op2 = tree->gtGetOp2IfPresent();
+ break;
- break;
+ case GT_RUNTIMELOOKUP:
+ return fgMorphTree(op1);
#ifdef _TARGET_ARM_
- case GT_INTRINSIC:
- if (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round)
+ case GT_INTRINSIC:
+ if (tree->gtIntrinsic.gtIntrinsicId == CORINFO_INTRINSIC_Round)
+ {
+ switch (tree->TypeGet())
{
- switch (tree->TypeGet())
- {
- case TYP_DOUBLE:
- return fgMorphIntoHelperCall(tree, CORINFO_HELP_DBLROUND, gtNewArgList(op1));
- case TYP_FLOAT:
- return fgMorphIntoHelperCall(tree, CORINFO_HELP_FLTROUND, gtNewArgList(op1));
- default:
- unreached();
- }
+ case TYP_DOUBLE:
+ return fgMorphIntoHelperCall(tree, CORINFO_HELP_DBLROUND, gtNewArgList(op1));
+ case TYP_FLOAT:
+ return fgMorphIntoHelperCall(tree, CORINFO_HELP_FLTROUND, gtNewArgList(op1));
+ default:
+ unreached();
}
- break;
+ }
+ break;
#endif
- default:
- break;
- }
+ default:
+ break;
+ }
#if !CPU_HAS_FP_SUPPORT
- tree = fgMorphToEmulatedFP(tree);
+ tree = fgMorphToEmulatedFP(tree);
#endif
- /*-------------------------------------------------------------------------
- * Process the first operand, if any
- */
+ /*-------------------------------------------------------------------------
+ * Process the first operand, if any
+ */
- if (op1)
- {
+ if (op1)
+ {
#if LOCAL_ASSERTION_PROP
- // If we are entering the "then" part of a Qmark-Colon we must
- // save the state of the current copy assignment table
- // so that we can restore this state when entering the "else" part
- if (isQmarkColon)
+ // If we are entering the "then" part of a Qmark-Colon we must
+ // save the state of the current copy assignment table
+ // so that we can restore this state when entering the "else" part
+ if (isQmarkColon)
+ {
+ noway_assert(optLocalAssertionProp);
+ if (optAssertionCount)
{
- noway_assert(optLocalAssertionProp);
- if (optAssertionCount)
- {
- noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
- unsigned tabSize = optAssertionCount * sizeof(AssertionDsc);
- origAssertionTab = (AssertionDsc*)ALLOCA(tabSize);
- origAssertionCount = optAssertionCount;
- memcpy(origAssertionTab, optAssertionTabPrivate, tabSize);
- }
- else
- {
- origAssertionCount = 0;
- origAssertionTab = nullptr;
- }
+ noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
+ unsigned tabSize = optAssertionCount * sizeof(AssertionDsc);
+ origAssertionTab = (AssertionDsc*)ALLOCA(tabSize);
+ origAssertionCount = optAssertionCount;
+ memcpy(origAssertionTab, optAssertionTabPrivate, tabSize);
}
+ else
+ {
+ origAssertionCount = 0;
+ origAssertionTab = nullptr;
+ }
+ }
#endif // LOCAL_ASSERTION_PROP
- // We might need a new MorphAddressContext context. (These are used to convey
- // parent context about how addresses being calculated will be used; see the
- // specification comment for MorphAddrContext for full details.)
- // Assume it's an Ind context to start.
- MorphAddrContext subIndMac1(MACK_Ind);
- MorphAddrContext* subMac1 = mac;
- if (subMac1 == nullptr || subMac1->m_kind == MACK_Ind)
+ // We might need a new MorphAddressContext context. (These are used to convey
+ // parent context about how addresses being calculated will be used; see the
+ // specification comment for MorphAddrContext for full details.)
+ // Assume it's an Ind context to start.
+ MorphAddrContext subIndMac1(MACK_Ind);
+ MorphAddrContext* subMac1 = mac;
+ if (subMac1 == nullptr || subMac1->m_kind == MACK_Ind)
+ {
+ switch (tree->gtOper)
{
- switch (tree->gtOper)
- {
- case GT_ADDR:
- if (subMac1 == nullptr)
- {
- subMac1 = &subIndMac1;
- subMac1->m_kind = MACK_Addr;
- }
- break;
- case GT_COMMA:
- // In a comma, the incoming context only applies to the rightmost arg of the
- // comma list. The left arg (op1) gets a fresh context.
- subMac1 = nullptr;
- break;
- case GT_OBJ:
- case GT_BLK:
- case GT_DYN_BLK:
- case GT_IND:
- subMac1 = &subIndMac1;
- break;
- default:
- break;
- }
+ case GT_ADDR:
+ if (subMac1 == nullptr)
+ {
+ subMac1 = &subIndMac1;
+ subMac1->m_kind = MACK_Addr;
+ }
+ break;
+ case GT_COMMA:
+ // In a comma, the incoming context only applies to the rightmost arg of the
+ // comma list. The left arg (op1) gets a fresh context.
+ subMac1 = nullptr;
+ break;
+ case GT_OBJ:
+ case GT_BLK:
+ case GT_DYN_BLK:
+ case GT_IND:
+ subMac1 = &subIndMac1;
+ break;
+ default:
+ break;
}
+ }
- // For additions, if we're in an IND context keep track of whether
- // all offsets added to the address are constant, and their sum.
- if (tree->gtOper == GT_ADD && subMac1 != nullptr)
+ // For additions, if we're in an IND context keep track of whether
+ // all offsets added to the address are constant, and their sum.
+ if (tree->gtOper == GT_ADD && subMac1 != nullptr)
+ {
+ assert(subMac1->m_kind == MACK_Ind || subMac1->m_kind == MACK_Addr); // Can't be a CopyBlock.
+ GenTreePtr otherOp = tree->gtOp.gtOp2;
+ // Is the other operator a constant?
+ if (otherOp->IsCnsIntOrI())
{
- assert(subMac1->m_kind == MACK_Ind || subMac1->m_kind == MACK_Addr); // Can't be a CopyBlock.
- GenTreePtr otherOp = tree->gtOp.gtOp2;
- // Is the other operator a constant?
- if (otherOp->IsCnsIntOrI())
+ ClrSafeInt<size_t> totalOffset(subMac1->m_totalOffset);
+ totalOffset += otherOp->gtIntConCommon.IconValue();
+ if (totalOffset.IsOverflow())
{
- ClrSafeInt<size_t> totalOffset(subMac1->m_totalOffset);
- totalOffset += otherOp->gtIntConCommon.IconValue();
- if (totalOffset.IsOverflow())
- {
- // We will consider an offset so large as to overflow as "not a constant" --
- // we will do a null check.
- subMac1->m_allConstantOffsets = false;
- }
- else
- {
- subMac1->m_totalOffset += otherOp->gtIntConCommon.IconValue();
- }
+ // We will consider an offset so large as to overflow as "not a constant" --
+ // we will do a null check.
+ subMac1->m_allConstantOffsets = false;
}
else
{
- subMac1->m_allConstantOffsets = false;
+ subMac1->m_totalOffset += otherOp->gtIntConCommon.IconValue();
}
}
-
- // If gtOp1 is a GT_FIELD, we need to pass down the mac if
- // its parent is GT_ADDR, since the address of the field
- // is part of an ongoing address computation. Otherwise
- // op1 represents the value of the field and so any address
- // calculations it does are in a new context.
- if ((op1->gtOper == GT_FIELD) && (tree->gtOper != GT_ADDR))
+ else
{
- subMac1 = nullptr;
-
- // The impact of this field's value to any ongoing
- // address computation is handled below when looking
- // at op2.
+ subMac1->m_allConstantOffsets = false;
}
+ }
+
+ // If gtOp1 is a GT_FIELD, we need to pass down the mac if
+ // its parent is GT_ADDR, since the address of the field
+ // is part of an ongoing address computation. Otherwise
+ // op1 represents the value of the field and so any address
+ // calculations it does are in a new context.
+ if ((op1->gtOper == GT_FIELD) && (tree->gtOper != GT_ADDR))
+ {
+ subMac1 = nullptr;
+
+ // The impact of this field's value to any ongoing
+ // address computation is handled below when looking
+ // at op2.
+ }
- tree->gtOp.gtOp1 = op1 = fgMorphTree(op1, subMac1);
+ tree->gtOp.gtOp1 = op1 = fgMorphTree(op1, subMac1);
#if LOCAL_ASSERTION_PROP
- // If we are exiting the "then" part of a Qmark-Colon we must
- // save the state of the current copy assignment table
- // so that we can merge this state with the "else" part exit
- if (isQmarkColon)
+ // If we are exiting the "then" part of a Qmark-Colon we must
+ // save the state of the current copy assignment table
+ // so that we can merge this state with the "else" part exit
+ if (isQmarkColon)
+ {
+ noway_assert(optLocalAssertionProp);
+ if (optAssertionCount)
{
- noway_assert(optLocalAssertionProp);
- if (optAssertionCount)
- {
- noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
- unsigned tabSize = optAssertionCount * sizeof(AssertionDsc);
- thenAssertionTab = (AssertionDsc*)ALLOCA(tabSize);
- thenAssertionCount = optAssertionCount;
- memcpy(thenAssertionTab, optAssertionTabPrivate, tabSize);
- }
- else
- {
- thenAssertionCount = 0;
- thenAssertionTab = nullptr;
- }
+ noway_assert(optAssertionCount <= optMaxAssertionCount); // else ALLOCA() is a bad idea
+ unsigned tabSize = optAssertionCount * sizeof(AssertionDsc);
+ thenAssertionTab = (AssertionDsc*)ALLOCA(tabSize);
+ thenAssertionCount = optAssertionCount;
+ memcpy(thenAssertionTab, optAssertionTabPrivate, tabSize);
+ }
+ else
+ {
+ thenAssertionCount = 0;
+ thenAssertionTab = nullptr;
}
+ }
#endif // LOCAL_ASSERTION_PROP
- /* Morphing along with folding and inlining may have changed the
- * side effect flags, so we have to reset them
- *
- * NOTE: Don't reset the exception flags on nodes that may throw */
+ /* Morphing along with folding and inlining may have changed the
+ * side effect flags, so we have to reset them
+ *
+ * NOTE: Don't reset the exception flags on nodes that may throw */
- assert(tree->gtOper != GT_CALL);
+ assert(tree->gtOper != GT_CALL);
- if ((tree->gtOper != GT_INTRINSIC) || !IsIntrinsicImplementedByUserCall(tree->gtIntrinsic.gtIntrinsicId))
- {
- tree->gtFlags &= ~GTF_CALL;
- }
+ if ((tree->gtOper != GT_INTRINSIC) || !IsIntrinsicImplementedByUserCall(tree->gtIntrinsic.gtIntrinsicId))
+ {
+ tree->gtFlags &= ~GTF_CALL;
+ }
- /* Propagate the new flags */
- tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
+ /* Propagate the new flags */
+ tree->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
- // &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does
- // Similarly for clsVar
- if (oper == GT_ADDR && (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_CLS_VAR))
- {
- tree->gtFlags &= ~GTF_GLOB_REF;
- }
- } // if (op1)
+ // &aliasedVar doesn't need GTF_GLOB_REF, though alisasedVar does
+ // Similarly for clsVar
+ if (oper == GT_ADDR && (op1->gtOper == GT_LCL_VAR || op1->gtOper == GT_CLS_VAR))
+ {
+ tree->gtFlags &= ~GTF_GLOB_REF;
+ }
+ } // if (op1)
- /*-------------------------------------------------------------------------
- * Process the second operand, if any
- */
+ /*-------------------------------------------------------------------------
+ * Process the second operand, if any
+ */
- if (op2)
- {
+ if (op2)
+ {
#if LOCAL_ASSERTION_PROP
- // If we are entering the "else" part of a Qmark-Colon we must
- // reset the state of the current copy assignment table
- if (isQmarkColon)
+ // If we are entering the "else" part of a Qmark-Colon we must
+ // reset the state of the current copy assignment table
+ if (isQmarkColon)
+ {
+ noway_assert(optLocalAssertionProp);
+ optAssertionReset(0);
+ if (origAssertionCount)
{
- noway_assert(optLocalAssertionProp);
- optAssertionReset(0);
- if (origAssertionCount)
- {
- size_t tabSize = origAssertionCount * sizeof(AssertionDsc);
- memcpy(optAssertionTabPrivate, origAssertionTab, tabSize);
- optAssertionReset(origAssertionCount);
- }
+ size_t tabSize = origAssertionCount * sizeof(AssertionDsc);
+ memcpy(optAssertionTabPrivate, origAssertionTab, tabSize);
+ optAssertionReset(origAssertionCount);
}
+ }
#endif // LOCAL_ASSERTION_PROP
- // We might need a new MorphAddressContext context to use in evaluating op2.
- // (These are used to convey parent context about how addresses being calculated
- // will be used; see the specification comment for MorphAddrContext for full details.)
- // Assume it's an Ind context to start.
- switch (tree->gtOper)
- {
- case GT_ADD:
- if (mac != nullptr && mac->m_kind == MACK_Ind)
+ // We might need a new MorphAddressContext context to use in evaluating op2.
+ // (These are used to convey parent context about how addresses being calculated
+ // will be used; see the specification comment for MorphAddrContext for full details.)
+ // Assume it's an Ind context to start.
+ switch (tree->gtOper)
+ {
+ case GT_ADD:
+ if (mac != nullptr && mac->m_kind == MACK_Ind)
+ {
+ GenTreePtr otherOp = tree->gtOp.gtOp1;
+ // Is the other operator a constant?
+ if (otherOp->IsCnsIntOrI())
{
- GenTreePtr otherOp = tree->gtOp.gtOp1;
- // Is the other operator a constant?
- if (otherOp->IsCnsIntOrI())
- {
- mac->m_totalOffset += otherOp->gtIntConCommon.IconValue();
- }
- else
- {
- mac->m_allConstantOffsets = false;
- }
+ mac->m_totalOffset += otherOp->gtIntConCommon.IconValue();
}
- break;
- default:
- break;
- }
+ else
+ {
+ mac->m_allConstantOffsets = false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
- // If gtOp2 is a GT_FIELD, we must be taking its value,
- // so it should evaluate its address in a new context.
- if (op2->gtOper == GT_FIELD)
- {
- // The impact of this field's value to any ongoing
- // address computation is handled above when looking
- // at op1.
- mac = nullptr;
- }
+ // If gtOp2 is a GT_FIELD, we must be taking its value,
+ // so it should evaluate its address in a new context.
+ if (op2->gtOper == GT_FIELD)
+ {
+ // The impact of this field's value to any ongoing
+ // address computation is handled above when looking
+ // at op1.
+ mac = nullptr;
+ }
- tree->gtOp.gtOp2 = op2 = fgMorphTree(op2, mac);
+ tree->gtOp.gtOp2 = op2 = fgMorphTree(op2, mac);
- /* Propagate the side effect flags from op2 */
+ /* Propagate the side effect flags from op2 */
- tree->gtFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
+ tree->gtFlags |= (op2->gtFlags & GTF_ALL_EFFECT);
#if LOCAL_ASSERTION_PROP
- // If we are exiting the "else" part of a Qmark-Colon we must
- // merge the state of the current copy assignment table with
- // that of the exit of the "then" part.
- if (isQmarkColon)
+ // If we are exiting the "else" part of a Qmark-Colon we must
+ // merge the state of the current copy assignment table with
+ // that of the exit of the "then" part.
+ if (isQmarkColon)
+ {
+ noway_assert(optLocalAssertionProp);
+ // If either exit table has zero entries then
+ // the merged table also has zero entries
+ if (optAssertionCount == 0 || thenAssertionCount == 0)
{
- noway_assert(optLocalAssertionProp);
- // If either exit table has zero entries then
- // the merged table also has zero entries
- if (optAssertionCount == 0 || thenAssertionCount == 0)
- {
- optAssertionReset(0);
- }
- else
+ optAssertionReset(0);
+ }
+ else
+ {
+ size_t tabSize = optAssertionCount * sizeof(AssertionDsc);
+ if ((optAssertionCount != thenAssertionCount) ||
+ (memcmp(thenAssertionTab, optAssertionTabPrivate, tabSize) != 0))
{
- size_t tabSize = optAssertionCount * sizeof(AssertionDsc);
- if ((optAssertionCount != thenAssertionCount) ||
- (memcmp(thenAssertionTab, optAssertionTabPrivate, tabSize) != 0))
+ // Yes they are different so we have to find the merged set
+ // Iterate over the copy asgn table removing any entries
+ // that do not have an exact match in the thenAssertionTab
+ AssertionIndex index = 1;
+ while (index <= optAssertionCount)
{
- // Yes they are different so we have to find the merged set
- // Iterate over the copy asgn table removing any entries
- // that do not have an exact match in the thenAssertionTab
- AssertionIndex index = 1;
- while (index <= optAssertionCount)
+ AssertionDsc* curAssertion = optGetAssertion(index);
+
+ for (unsigned j = 0; j < thenAssertionCount; j++)
{
- AssertionDsc* curAssertion = optGetAssertion(index);
+ AssertionDsc* thenAssertion = &thenAssertionTab[j];
- for (unsigned j = 0; j < thenAssertionCount; j++)
+ // Do the left sides match?
+ if ((curAssertion->op1.lcl.lclNum == thenAssertion->op1.lcl.lclNum) &&
+ (curAssertion->assertionKind == thenAssertion->assertionKind))
{
- AssertionDsc* thenAssertion = &thenAssertionTab[j];
-
- // Do the left sides match?
- if ((curAssertion->op1.lcl.lclNum == thenAssertion->op1.lcl.lclNum) &&
- (curAssertion->assertionKind == thenAssertion->assertionKind))
+ // Do the right sides match?
+ if ((curAssertion->op2.kind == thenAssertion->op2.kind) &&
+ (curAssertion->op2.lconVal == thenAssertion->op2.lconVal))
{
- // Do the right sides match?
- if ((curAssertion->op2.kind == thenAssertion->op2.kind) &&
- (curAssertion->op2.lconVal == thenAssertion->op2.lconVal))
- {
- goto KEEP;
- }
- else
- {
- goto REMOVE;
- }
+ goto KEEP;
+ }
+ else
+ {
+ goto REMOVE;
}
}
- //
- // If we fall out of the loop above then we didn't find
- // any matching entry in the thenAssertionTab so it must
- // have been killed on that path so we remove it here
- //
- REMOVE:
- // The data at optAssertionTabPrivate[i] is to be removed
- CLANG_FORMAT_COMMENT_ANCHOR;
+ }
+ //
+ // If we fall out of the loop above then we didn't find
+ // any matching entry in the thenAssertionTab so it must
+ // have been killed on that path so we remove it here
+ //
+ REMOVE:
+ // The data at optAssertionTabPrivate[i] is to be removed
+ CLANG_FORMAT_COMMENT_ANCHOR;
#ifdef DEBUG
- if (verbose)
- {
- printf("The QMARK-COLON ");
- printTreeID(tree);
- printf(" removes assertion candidate #%d\n", index);
- }
-#endif
- optAssertionRemove(index);
- continue;
- KEEP:
- // The data at optAssertionTabPrivate[i] is to be kept
- index++;
+ if (verbose)
+ {
+ printf("The QMARK-COLON ");
+ printTreeID(tree);
+ printf(" removes assertion candidate #%d\n", index);
}
+#endif
+ optAssertionRemove(index);
+ continue;
+ KEEP:
+ // The data at optAssertionTabPrivate[i] is to be kept
+ index++;
}
}
}
-#endif // LOCAL_ASSERTION_PROP
- } // if (op2)
+ }
+#endif // LOCAL_ASSERTION_PROP
+ } // if (op2)
- DONE_MORPHING_CHILDREN:
+DONE_MORPHING_CHILDREN:
- if (tree->OperMayThrow(this))
+ if (tree->OperMayThrow(this))
+ {
+ // Mark the tree node as potentially throwing an exception
+ tree->gtFlags |= GTF_EXCEPT;
+ }
+ else
+ {
+ if (tree->OperIsIndirOrArrLength())
{
- // Mark the tree node as potentially throwing an exception
- tree->gtFlags |= GTF_EXCEPT;
+ tree->gtFlags |= GTF_IND_NONFAULTING;
}
- else
+ if (((op1 == nullptr) || ((op1->gtFlags & GTF_EXCEPT) == 0)) &&
+ ((op2 == nullptr) || ((op2->gtFlags & GTF_EXCEPT) == 0)))
{
- if (tree->OperIsIndirOrArrLength())
- {
- tree->gtFlags |= GTF_IND_NONFAULTING;
- }
- if (((op1 == nullptr) || ((op1->gtFlags & GTF_EXCEPT) == 0)) &&
- ((op2 == nullptr) || ((op2->gtFlags & GTF_EXCEPT) == 0)))
- {
- tree->gtFlags &= ~GTF_EXCEPT;
- }
+ tree->gtFlags &= ~GTF_EXCEPT;
}
+ }
- if (tree->OperRequiresAsgFlag())
- {
- tree->gtFlags |= GTF_ASG;
- }
- else
+ if (tree->OperRequiresAsgFlag())
+ {
+ tree->gtFlags |= GTF_ASG;
+ }
+ else
+ {
+ if (((op1 == nullptr) || ((op1->gtFlags & GTF_ASG) == 0)) &&
+ ((op2 == nullptr) || ((op2->gtFlags & GTF_ASG) == 0)))
{
- if (((op1 == nullptr) || ((op1->gtFlags & GTF_ASG) == 0)) &&
- ((op2 == nullptr) || ((op2->gtFlags & GTF_ASG) == 0)))
- {
- tree->gtFlags &= ~GTF_ASG;
- }
+ tree->gtFlags &= ~GTF_ASG;
}
+ }
/*-------------------------------------------------------------------------
* Now do POST-ORDER processing
*/
#if FEATURE_FIXED_OUT_ARGS && !defined(_TARGET_64BIT_)
- // Variable shifts of a long end up being helper calls, so mark the tree as such. This
- // is potentially too conservative, since they'll get treated as having side effects.
- // It is important to mark them as calls so if they are part of an argument list,
- // they will get sorted and processed properly (for example, it is important to handle
- // all nested calls before putting struct arguments in the argument registers). We
- // could mark the trees just before argument processing, but it would require a full
- // tree walk of the argument tree, so we just do it here, instead, even though we'll
- // mark non-argument trees (that will still get converted to calls, anyway).
- if (GenTree::OperIsShift(oper) && (tree->TypeGet() == TYP_LONG) && (op2->OperGet() != GT_CNS_INT))
- {
- tree->gtFlags |= GTF_CALL;
- }
+ // Variable shifts of a long end up being helper calls, so mark the tree as such. This
+ // is potentially too conservative, since they'll get treated as having side effects.
+ // It is important to mark them as calls so if they are part of an argument list,
+ // they will get sorted and processed properly (for example, it is important to handle
+ // all nested calls before putting struct arguments in the argument registers). We
+ // could mark the trees just before argument processing, but it would require a full
+ // tree walk of the argument tree, so we just do it here, instead, even though we'll
+ // mark non-argument trees (that will still get converted to calls, anyway).
+ if (GenTree::OperIsShift(oper) && (tree->TypeGet() == TYP_LONG) && (op2->OperGet() != GT_CNS_INT))
+ {
+ tree->gtFlags |= GTF_CALL;
+ }
#endif // FEATURE_FIXED_OUT_ARGS && !_TARGET_64BIT_
- if (varTypeIsGC(tree->TypeGet()) && (op1 && !varTypeIsGC(op1->TypeGet())) &&
- (op2 && !varTypeIsGC(op2->TypeGet())))
- {
- // The tree is really not GC but was marked as such. Now that the
- // children have been unmarked, unmark the tree too.
+ if (varTypeIsGC(tree->TypeGet()) && (op1 && !varTypeIsGC(op1->TypeGet())) && (op2 && !varTypeIsGC(op2->TypeGet())))
+ {
+ // The tree is really not GC but was marked as such. Now that the
+ // children have been unmarked, unmark the tree too.
- // Remember that GT_COMMA inherits it's type only from op2
- if (tree->gtOper == GT_COMMA)
- {
- tree->gtType = genActualType(op2->TypeGet());
- }
- else
- {
- tree->gtType = genActualType(op1->TypeGet());
- }
+ // Remember that GT_COMMA inherits it's type only from op2
+ if (tree->gtOper == GT_COMMA)
+ {
+ tree->gtType = genActualType(op2->TypeGet());
}
-
- GenTreePtr oldTree = tree;
-
- GenTreePtr qmarkOp1 = nullptr;
- GenTreePtr qmarkOp2 = nullptr;
-
- if ((tree->OperGet() == GT_QMARK) && (tree->gtOp.gtOp2->OperGet() == GT_COLON))
+ else
{
- qmarkOp1 = oldTree->gtOp.gtOp2->gtOp.gtOp1;
- qmarkOp2 = oldTree->gtOp.gtOp2->gtOp.gtOp2;
+ tree->gtType = genActualType(op1->TypeGet());
}
+ }
- // Try to fold it, maybe we get lucky,
- tree = gtFoldExpr(tree);
+ GenTreePtr oldTree = tree;
- if (oldTree != tree)
- {
- /* if gtFoldExpr returned op1 or op2 then we are done */
- if ((tree == op1) || (tree == op2) || (tree == qmarkOp1) || (tree == qmarkOp2))
- {
- return tree;
- }
+ GenTreePtr qmarkOp1 = nullptr;
+ GenTreePtr qmarkOp2 = nullptr;
- /* If we created a comma-throw tree then we need to morph op1 */
- if (fgIsCommaThrow(tree))
- {
- tree->gtOp.gtOp1 = fgMorphTree(tree->gtOp.gtOp1);
- fgMorphTreeDone(tree);
- return tree;
- }
+ if ((tree->OperGet() == GT_QMARK) && (tree->gtOp.gtOp2->OperGet() == GT_COLON))
+ {
+ qmarkOp1 = oldTree->gtOp.gtOp2->gtOp.gtOp1;
+ qmarkOp2 = oldTree->gtOp.gtOp2->gtOp.gtOp2;
+ }
+
+ // Try to fold it, maybe we get lucky,
+ tree = gtFoldExpr(tree);
+ if (oldTree != tree)
+ {
+ /* if gtFoldExpr returned op1 or op2 then we are done */
+ if ((tree == op1) || (tree == op2) || (tree == qmarkOp1) || (tree == qmarkOp2))
+ {
return tree;
}
- else if (tree->OperKind() & GTK_CONST)
+
+ /* If we created a comma-throw tree then we need to morph op1 */
+ if (fgIsCommaThrow(tree))
{
+ tree->gtOp.gtOp1 = fgMorphTree(tree->gtOp.gtOp1);
+ fgMorphTreeDone(tree);
return tree;
}
- /* gtFoldExpr could have used setOper to change the oper */
- oper = tree->OperGet();
- typ = tree->TypeGet();
+ return tree;
+ }
+ else if (tree->OperKind() & GTK_CONST)
+ {
+ return tree;
+ }
+
+ /* gtFoldExpr could have used setOper to change the oper */
+ oper = tree->OperGet();
+ typ = tree->TypeGet();
- /* gtFoldExpr could have changed op1 and op2 */
- op1 = tree->gtOp.gtOp1;
- op2 = tree->gtGetOp2IfPresent();
+ /* gtFoldExpr could have changed op1 and op2 */
+ op1 = tree->gtOp.gtOp1;
+ op2 = tree->gtGetOp2IfPresent();
- // Do we have an integer compare operation?
+ // Do we have an integer compare operation?
+ //
+ if (tree->OperIsCompare() && varTypeIsIntegralOrI(tree->TypeGet()))
+ {
+ // Are we comparing against zero?
//
- if (tree->OperIsCompare() && varTypeIsIntegralOrI(tree->TypeGet()))
+ if (op2->IsIntegralConst(0))
{
- // Are we comparing against zero?
+ // Request that the codegen for op1 sets the condition flags
+ // when it generates the code for op1.
//
- if (op2->IsIntegralConst(0))
- {
- // Request that the codegen for op1 sets the condition flags
- // when it generates the code for op1.
- //
- // Codegen for op1 must set the condition flags if
- // this method returns true.
- //
- op1->gtRequestSetFlags();
- }
+ // Codegen for op1 must set the condition flags if
+ // this method returns true.
+ //
+ op1->gtRequestSetFlags();
}
- /*-------------------------------------------------------------------------
- * Perform the required oper-specific postorder morphing
- */
+ }
+ /*-------------------------------------------------------------------------
+ * Perform the required oper-specific postorder morphing
+ */
- GenTreePtr temp;
- GenTreePtr cns1, cns2;
- GenTreePtr thenNode;
- GenTreePtr elseNode;
- size_t ival1, ival2;
- GenTreePtr lclVarTree;
- GenTreeLclVarCommon* lclVarCmnTree;
- FieldSeqNode* fieldSeq = nullptr;
+ GenTreePtr temp;
+ GenTreePtr cns1, cns2;
+ size_t ival1, ival2;
+ GenTreePtr lclVarTree;
+ FieldSeqNode* fieldSeq = nullptr;
- switch (oper)
- {
- case GT_ASG:
+ switch (oper)
+ {
+ case GT_ASG:
- lclVarTree = fgIsIndirOfAddrOfLocal(op1);
- if (lclVarTree != nullptr)
- {
- lclVarTree->gtFlags |= GTF_VAR_DEF;
- }
+ lclVarTree = fgIsIndirOfAddrOfLocal(op1);
+ if (lclVarTree != nullptr)
+ {
+ lclVarTree->gtFlags |= GTF_VAR_DEF;
+ }
- if (op1->gtEffectiveVal()->OperIsConst())
- {
- op1 = gtNewOperNode(GT_IND, tree->TypeGet(), op1);
- tree->gtOp.gtOp1 = op1;
- }
+ if (op1->gtEffectiveVal()->OperIsConst())
+ {
+ op1 = gtNewOperNode(GT_IND, tree->TypeGet(), op1);
+ tree->gtOp.gtOp1 = op1;
+ }
- /* If we are storing a small type, we might be able to omit a cast */
- if ((op1->gtOper == GT_IND) && varTypeIsSmall(op1->TypeGet()))
+ /* If we are storing a small type, we might be able to omit a cast */
+ if ((op1->gtOper == GT_IND) && varTypeIsSmall(op1->TypeGet()))
+ {
+ if (!gtIsActiveCSE_Candidate(op2) && (op2->gtOper == GT_CAST) && !op2->gtOverflow())
{
- if (!gtIsActiveCSE_Candidate(op2) && (op2->gtOper == GT_CAST) && !op2->gtOverflow())
- {
- var_types castType = op2->CastToType();
+ var_types castType = op2->CastToType();
- // If we are performing a narrowing cast and
- // castType is larger or the same as op1's type
- // then we can discard the cast.
+ // If we are performing a narrowing cast and
+ // castType is larger or the same as op1's type
+ // then we can discard the cast.
- if (varTypeIsSmall(castType) && (castType >= op1->TypeGet()))
- {
- tree->gtOp.gtOp2 = op2 = op2->gtCast.CastOp();
- }
- }
- else if (op2->OperIsCompare() && varTypeIsByte(op1->TypeGet()))
+ if (varTypeIsSmall(castType) && (castType >= op1->TypeGet()))
{
- /* We don't need to zero extend the setcc instruction */
- op2->gtType = TYP_BYTE;
+ tree->gtOp.gtOp2 = op2 = op2->gtCast.CastOp();
}
}
- // If we introduced a CSE we may need to undo the optimization above
- // (i.e. " op2->gtType = TYP_BYTE;" which depends upon op1 being a GT_IND of a byte type)
- // When we introduce the CSE we remove the GT_IND and subsitute a GT_LCL_VAR in it place.
- else if (op2->OperIsCompare() && (op2->gtType == TYP_BYTE) && (op1->gtOper == GT_LCL_VAR))
+ else if (op2->OperIsCompare() && varTypeIsByte(op1->TypeGet()))
{
- unsigned varNum = op1->gtLclVarCommon.gtLclNum;
- LclVarDsc* varDsc = &lvaTable[varNum];
-
- /* We again need to zero extend the setcc instruction */
- op2->gtType = varDsc->TypeGet();
+ /* We don't need to zero extend the setcc instruction */
+ op2->gtType = TYP_BYTE;
}
- fgAssignSetVarDef(tree);
+ }
+ // If we introduced a CSE we may need to undo the optimization above
+ // (i.e. " op2->gtType = TYP_BYTE;" which depends upon op1 being a GT_IND of a byte type)
+ // When we introduce the CSE we remove the GT_IND and subsitute a GT_LCL_VAR in it place.
+ else if (op2->OperIsCompare() && (op2->gtType == TYP_BYTE) && (op1->gtOper == GT_LCL_VAR))
+ {
+ unsigned varNum = op1->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &lvaTable[varNum];
- __fallthrough;
+ /* We again need to zero extend the setcc instruction */
+ op2->gtType = varDsc->TypeGet();
+ }
+ fgAssignSetVarDef(tree);
- case GT_ASG_ADD:
- case GT_ASG_SUB:
- case GT_ASG_MUL:
- case GT_ASG_DIV:
- case GT_ASG_MOD:
- case GT_ASG_UDIV:
- case GT_ASG_UMOD:
- case GT_ASG_OR:
- case GT_ASG_XOR:
- case GT_ASG_AND:
- case GT_ASG_LSH:
- case GT_ASG_RSH:
- case GT_ASG_RSZ:
-
- /* We can't CSE the LHS of an assignment */
- /* We also must set in the pre-morphing phase, otherwise assertionProp doesn't see it */
- if (op1->IsLocal() || (op1->TypeGet() != TYP_STRUCT))
- {
- op1->gtFlags |= GTF_DONT_CSE;
- }
- break;
+#ifdef LEGACY_BACKEND
+ __fallthrough;
- case GT_EQ:
- case GT_NE:
+ case GT_ASG_ADD:
+ case GT_ASG_SUB:
+ case GT_ASG_MUL:
+ case GT_ASG_DIV:
+ case GT_ASG_MOD:
+ case GT_ASG_UDIV:
+ case GT_ASG_UMOD:
+ case GT_ASG_OR:
+ case GT_ASG_XOR:
+ case GT_ASG_AND:
+ case GT_ASG_LSH:
+ case GT_ASG_RSH:
+ case GT_ASG_RSZ:
+#endif
- /* Make sure we're allowed to do this */
+ /* We can't CSE the LHS of an assignment */
+ /* We also must set in the pre-morphing phase, otherwise assertionProp doesn't see it */
+ if (op1->IsLocal() || (op1->TypeGet() != TYP_STRUCT))
+ {
+ op1->gtFlags |= GTF_DONT_CSE;
+ }
+ break;
- if (optValnumCSE_phase)
- {
- // It is not safe to reorder/delete CSE's
- break;
- }
+ case GT_EQ:
+ case GT_NE:
- cns2 = op2;
+ /* Make sure we're allowed to do this */
- /* Check for "(expr +/- icon1) ==/!= (non-zero-icon2)" */
+ if (optValnumCSE_phase)
+ {
+ // It is not safe to reorder/delete CSE's
+ break;
+ }
- if (cns2->gtOper == GT_CNS_INT && cns2->gtIntCon.gtIconVal != 0)
- {
- op1 = tree->gtOp.gtOp1;
+ cns2 = op2;
- /* Since this can occur repeatedly we use a while loop */
+ /* Check for "(expr +/- icon1) ==/!= (non-zero-icon2)" */
- while ((op1->gtOper == GT_ADD || op1->gtOper == GT_SUB) &&
- (op1->gtOp.gtOp2->gtOper == GT_CNS_INT) && (op1->gtType == TYP_INT) &&
- (op1->gtOverflow() == false))
- {
- /* Got it; change "x+icon1==icon2" to "x==icon2-icon1" */
+ if (cns2->gtOper == GT_CNS_INT && cns2->gtIntCon.gtIconVal != 0)
+ {
+ op1 = tree->gtOp.gtOp1;
- ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
- ival2 = cns2->gtIntCon.gtIconVal;
+ /* Since this can occur repeatedly we use a while loop */
- if (op1->gtOper == GT_ADD)
- {
- ival2 -= ival1;
- }
- else
- {
- ival2 += ival1;
- }
- cns2->gtIntCon.gtIconVal = ival2;
+ while ((op1->gtOper == GT_ADD || op1->gtOper == GT_SUB) && (op1->gtOp.gtOp2->gtOper == GT_CNS_INT) &&
+ (op1->gtType == TYP_INT) && (op1->gtOverflow() == false))
+ {
+ /* Got it; change "x+icon1==icon2" to "x==icon2-icon1" */
+
+ ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
+ ival2 = cns2->gtIntCon.gtIconVal;
+
+ if (op1->gtOper == GT_ADD)
+ {
+ ival2 -= ival1;
+ }
+ else
+ {
+ ival2 += ival1;
+ }
+ cns2->gtIntCon.gtIconVal = ival2;
#ifdef _TARGET_64BIT_
- // we need to properly re-sign-extend or truncate as needed.
- cns2->AsIntCon()->TruncateOrSignExtend32();
+ // we need to properly re-sign-extend or truncate as needed.
+ cns2->AsIntCon()->TruncateOrSignExtend32();
#endif // _TARGET_64BIT_
- op1 = tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
- }
+ op1 = tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
}
+ }
- //
- // Here we look for the following tree
- //
- // EQ/NE
- // / \
+ //
+ // Here we look for the following tree
+ //
+ // EQ/NE
+ // / \
// op1 CNS 0/1
- //
- ival2 = INT_MAX; // The value of INT_MAX for ival2 just means that the constant value is not 0 or 1
+ //
+ ival2 = INT_MAX; // The value of INT_MAX for ival2 just means that the constant value is not 0 or 1
- // cast to unsigned allows test for both 0 and 1
- if ((cns2->gtOper == GT_CNS_INT) && (((size_t)cns2->gtIntConCommon.IconValue()) <= 1U))
- {
- ival2 = (size_t)cns2->gtIntConCommon.IconValue();
- }
- else // cast to UINT64 allows test for both 0 and 1
- if ((cns2->gtOper == GT_CNS_LNG) && (((UINT64)cns2->gtIntConCommon.LngValue()) <= 1ULL))
- {
- ival2 = (size_t)cns2->gtIntConCommon.LngValue();
- }
+ // cast to unsigned allows test for both 0 and 1
+ if ((cns2->gtOper == GT_CNS_INT) && (((size_t)cns2->gtIntConCommon.IconValue()) <= 1U))
+ {
+ ival2 = (size_t)cns2->gtIntConCommon.IconValue();
+ }
+ else // cast to UINT64 allows test for both 0 and 1
+ if ((cns2->gtOper == GT_CNS_LNG) && (((UINT64)cns2->gtIntConCommon.LngValue()) <= 1ULL))
+ {
+ ival2 = (size_t)cns2->gtIntConCommon.LngValue();
+ }
- if (ival2 != INT_MAX)
+ if (ival2 != INT_MAX)
+ {
+ // If we don't have a comma and relop, we can't do this optimization
+ //
+ if ((op1->gtOper == GT_COMMA) && (op1->gtOp.gtOp2->OperIsCompare()))
{
- // If we don't have a comma and relop, we can't do this optimization
+ // Here we look for the following transformation
//
- if ((op1->gtOper == GT_COMMA) && (op1->gtOp.gtOp2->OperIsCompare()))
- {
- // Here we look for the following transformation
- //
- // EQ/NE Possible REVERSE(RELOP)
- // / \ / \
+ // EQ/NE Possible REVERSE(RELOP)
+ // / \ / \
// COMMA CNS 0/1 -> COMMA relop_op2
- // / \ / \
+ // / \ / \
// x RELOP x relop_op1
- // / \
+ // / \
// relop_op1 relop_op2
- //
- //
- //
- GenTreePtr comma = op1;
- GenTreePtr relop = comma->gtOp.gtOp2;
+ //
+ //
+ //
+ GenTreePtr comma = op1;
+ GenTreePtr relop = comma->gtOp.gtOp2;
- GenTreePtr relop_op1 = relop->gtOp.gtOp1;
+ GenTreePtr relop_op1 = relop->gtOp.gtOp1;
- bool reverse = ((ival2 == 0) == (oper == GT_EQ));
+ bool reverse = ((ival2 == 0) == (oper == GT_EQ));
- if (reverse)
- {
- gtReverseCond(relop);
- }
+ if (reverse)
+ {
+ gtReverseCond(relop);
+ }
- relop->gtOp.gtOp1 = comma;
- comma->gtOp.gtOp2 = relop_op1;
+ relop->gtOp.gtOp1 = comma;
+ comma->gtOp.gtOp2 = relop_op1;
- // Comma now has fewer nodes underneath it, so we need to regenerate its flags
- comma->gtFlags &= ~GTF_ALL_EFFECT;
- comma->gtFlags |= (comma->gtOp.gtOp1->gtFlags) & GTF_ALL_EFFECT;
- comma->gtFlags |= (comma->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
+ // Comma now has fewer nodes underneath it, so we need to regenerate its flags
+ comma->gtFlags &= ~GTF_ALL_EFFECT;
+ comma->gtFlags |= (comma->gtOp.gtOp1->gtFlags) & GTF_ALL_EFFECT;
+ comma->gtFlags |= (comma->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
- noway_assert((relop->gtFlags & GTF_RELOP_JMP_USED) == 0);
- noway_assert((relop->gtFlags & GTF_REVERSE_OPS) == 0);
- relop->gtFlags |=
- tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE | GTF_ALL_EFFECT);
+ noway_assert((relop->gtFlags & GTF_RELOP_JMP_USED) == 0);
+ noway_assert((relop->gtFlags & GTF_REVERSE_OPS) == 0);
+ relop->gtFlags |=
+ tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE | GTF_ALL_EFFECT);
- return relop;
- }
+ return relop;
+ }
- if (op1->gtOper == GT_COMMA)
- {
- // Here we look for the following tree
- // and when the LCL_VAR is a temp we can fold the tree:
- //
- // EQ/NE EQ/NE
- // / \ / \
+ if (op1->gtOper == GT_COMMA)
+ {
+ // Here we look for the following tree
+ // and when the LCL_VAR is a temp we can fold the tree:
+ //
+ // EQ/NE EQ/NE
+ // / \ / \
// COMMA CNS 0/1 -> RELOP CNS 0/1
- // / \ / \
+ // / \ / \
// ASG LCL_VAR
- // / \
+ // / \
// LCL_VAR RELOP
- // / \
+ // / \
//
- GenTreePtr asg = op1->gtOp.gtOp1;
- GenTreePtr lcl = op1->gtOp.gtOp2;
+ GenTreePtr asg = op1->gtOp.gtOp1;
+ GenTreePtr lcl = op1->gtOp.gtOp2;
- /* Make sure that the left side of the comma is the assignment of the LCL_VAR */
- if (asg->gtOper != GT_ASG)
- {
- goto SKIP;
- }
+ /* Make sure that the left side of the comma is the assignment of the LCL_VAR */
+ if (asg->gtOper != GT_ASG)
+ {
+ goto SKIP;
+ }
- /* The right side of the comma must be a LCL_VAR temp */
- if (lcl->gtOper != GT_LCL_VAR)
- {
- goto SKIP;
- }
+ /* The right side of the comma must be a LCL_VAR temp */
+ if (lcl->gtOper != GT_LCL_VAR)
+ {
+ goto SKIP;
+ }
- unsigned lclNum = lcl->gtLclVarCommon.gtLclNum;
- noway_assert(lclNum < lvaCount);
+ unsigned lclNum = lcl->gtLclVarCommon.gtLclNum;
+ noway_assert(lclNum < lvaCount);
- /* If the LCL_VAR is not a temp then bail, a temp has a single def */
- if (!lvaTable[lclNum].lvIsTemp)
- {
- goto SKIP;
- }
+ /* If the LCL_VAR is not a temp then bail, a temp has a single def */
+ if (!lvaTable[lclNum].lvIsTemp)
+ {
+ goto SKIP;
+ }
#if FEATURE_ANYCSE
- /* If the LCL_VAR is a CSE temp then bail, it could have multiple defs/uses */
- // Fix 383856 X86/ARM ILGEN
- if (lclNumIsCSE(lclNum))
- {
- goto SKIP;
- }
+ /* If the LCL_VAR is a CSE temp then bail, it could have multiple defs/uses */
+ // Fix 383856 X86/ARM ILGEN
+ if (lclNumIsCSE(lclNum))
+ {
+ goto SKIP;
+ }
#endif
- /* We also must be assigning the result of a RELOP */
- if (asg->gtOp.gtOp1->gtOper != GT_LCL_VAR)
- {
- goto SKIP;
- }
-
- /* Both of the LCL_VAR must match */
- if (asg->gtOp.gtOp1->gtLclVarCommon.gtLclNum != lclNum)
- {
- goto SKIP;
- }
-
- /* If right side of asg is not a RELOP then skip */
- if (!asg->gtOp.gtOp2->OperIsCompare())
- {
- goto SKIP;
- }
+ /* We also must be assigning the result of a RELOP */
+ if (asg->gtOp.gtOp1->gtOper != GT_LCL_VAR)
+ {
+ goto SKIP;
+ }
- LclVarDsc* varDsc = lvaTable + lclNum;
-
- /* Set op1 to the right side of asg, (i.e. the RELOP) */
- op1 = asg->gtOp.gtOp2;
-
- DEBUG_DESTROY_NODE(asg->gtOp.gtOp1);
- DEBUG_DESTROY_NODE(lcl);
-
- /* This local variable should never be used again */
- // <BUGNUM>
- // VSW 184221: Make RefCnt to zero to indicate that this local var
- // is not used any more. (Keey the lvType as is.)
- // Otherwise lvOnFrame will be set to true in Compiler::raMarkStkVars
- // And then emitter::emitEndCodeGen will assert in the following line:
- // noway_assert( dsc->lvTracked);
- // </BUGNUM>
- noway_assert(varDsc->lvRefCnt == 0 || // lvRefCnt may not have been set yet.
- varDsc->lvRefCnt == 2 // Or, we assume this tmp should only be used here,
- // and it only shows up twice.
- );
- lvaTable[lclNum].lvRefCnt = 0;
- lvaTable[lclNum].lvaResetSortAgainFlag(this);
+ /* Both of the LCL_VAR must match */
+ if (asg->gtOp.gtOp1->gtLclVarCommon.gtLclNum != lclNum)
+ {
+ goto SKIP;
}
- if (op1->OperIsCompare())
+ /* If right side of asg is not a RELOP then skip */
+ if (!asg->gtOp.gtOp2->OperIsCompare())
{
- // Here we look for the following tree
- //
- // EQ/NE -> RELOP/!RELOP
- // / \ / \
+ goto SKIP;
+ }
+
+ LclVarDsc* varDsc = lvaTable + lclNum;
+
+ /* Set op1 to the right side of asg, (i.e. the RELOP) */
+ op1 = asg->gtOp.gtOp2;
+
+ DEBUG_DESTROY_NODE(asg->gtOp.gtOp1);
+ DEBUG_DESTROY_NODE(lcl);
+
+ /* This local variable should never be used again */
+ // <BUGNUM>
+ // VSW 184221: Make RefCnt to zero to indicate that this local var
+ // is not used any more. (Keey the lvType as is.)
+ // Otherwise lvOnFrame will be set to true in Compiler::raMarkStkVars
+ // And then emitter::emitEndCodeGen will assert in the following line:
+ // noway_assert( dsc->lvTracked);
+ // </BUGNUM>
+ noway_assert(varDsc->lvRefCnt == 0 || // lvRefCnt may not have been set yet.
+ varDsc->lvRefCnt == 2 // Or, we assume this tmp should only be used here,
+ // and it only shows up twice.
+ );
+ lvaTable[lclNum].lvRefCnt = 0;
+ lvaTable[lclNum].lvaResetSortAgainFlag(this);
+ }
+
+ if (op1->OperIsCompare())
+ {
+ // Here we look for the following tree
+ //
+ // EQ/NE -> RELOP/!RELOP
+ // / \ / \
// RELOP CNS 0/1
- // / \
+ // / \
//
- // Note that we will remove/destroy the EQ/NE node and move
- // the RELOP up into it's location.
+ // Note that we will remove/destroy the EQ/NE node and move
+ // the RELOP up into it's location.
- /* Here we reverse the RELOP if necessary */
+ /* Here we reverse the RELOP if necessary */
- bool reverse = ((ival2 == 0) == (oper == GT_EQ));
+ bool reverse = ((ival2 == 0) == (oper == GT_EQ));
- if (reverse)
- {
- gtReverseCond(op1);
- }
+ if (reverse)
+ {
+ gtReverseCond(op1);
+ }
- /* Propagate gtType of tree into op1 in case it is TYP_BYTE for setcc optimization */
- op1->gtType = tree->gtType;
+ /* Propagate gtType of tree into op1 in case it is TYP_BYTE for setcc optimization */
+ op1->gtType = tree->gtType;
- noway_assert((op1->gtFlags & GTF_RELOP_JMP_USED) == 0);
- op1->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+ noway_assert((op1->gtFlags & GTF_RELOP_JMP_USED) == 0);
+ op1->gtFlags |= tree->gtFlags & (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
- DEBUG_DESTROY_NODE(tree);
- return op1;
- }
+ DEBUG_DESTROY_NODE(tree);
+ return op1;
+ }
- //
- // Now we check for a compare with the result of an '&' operator
- //
- // Here we look for the following transformation:
- //
- // EQ/NE EQ/NE
- // / \ / \
+ //
+ // Now we check for a compare with the result of an '&' operator
+ //
+ // Here we look for the following transformation:
+ //
+ // EQ/NE EQ/NE
+ // / \ / \
// AND CNS 0/1 -> AND CNS 0
- // / \ / \
+ // / \ / \
// RSZ/RSH CNS 1 x CNS (1 << y)
- // / \
+ // / \
// x CNS_INT +y
- if (op1->gtOper == GT_AND)
+ if (op1->gtOper == GT_AND)
+ {
+ GenTreePtr andOp = op1;
+ GenTreePtr rshiftOp = andOp->gtOp.gtOp1;
+
+ if ((rshiftOp->gtOper != GT_RSZ) && (rshiftOp->gtOper != GT_RSH))
{
- GenTreePtr andOp = op1;
- GenTreePtr rshiftOp = andOp->gtOp.gtOp1;
+ goto SKIP;
+ }
- if ((rshiftOp->gtOper != GT_RSZ) && (rshiftOp->gtOper != GT_RSH))
- {
- goto SKIP;
- }
+ if (!rshiftOp->gtOp.gtOp2->IsCnsIntOrI())
+ {
+ goto SKIP;
+ }
- if (!rshiftOp->gtOp.gtOp2->IsCnsIntOrI())
- {
- goto SKIP;
- }
+ ssize_t shiftAmount = rshiftOp->gtOp.gtOp2->gtIntCon.gtIconVal;
- ssize_t shiftAmount = rshiftOp->gtOp.gtOp2->gtIntCon.gtIconVal;
+ if (shiftAmount < 0)
+ {
+ goto SKIP;
+ }
- if (shiftAmount < 0)
- {
- goto SKIP;
- }
+ if (!andOp->gtOp.gtOp2->IsIntegralConst(1))
+ {
+ goto SKIP;
+ }
- if (!andOp->gtOp.gtOp2->IsIntegralConst(1))
+ if (andOp->gtType == TYP_INT)
+ {
+ if (shiftAmount > 31)
{
goto SKIP;
}
- if (andOp->gtType == TYP_INT)
- {
- if (shiftAmount > 31)
- {
- goto SKIP;
- }
-
- UINT32 newAndOperand = ((UINT32)1) << shiftAmount;
+ UINT32 newAndOperand = ((UINT32)1) << shiftAmount;
- andOp->gtOp.gtOp2->gtIntCon.gtIconVal = newAndOperand;
+ andOp->gtOp.gtOp2->gtIntCon.gtIconVal = newAndOperand;
- // Reverse the cond if necessary
- if (ival2 == 1)
- {
- gtReverseCond(tree);
- cns2->gtIntCon.gtIconVal = 0;
- oper = tree->gtOper;
- }
+ // Reverse the cond if necessary
+ if (ival2 == 1)
+ {
+ gtReverseCond(tree);
+ cns2->gtIntCon.gtIconVal = 0;
+ oper = tree->gtOper;
}
- else if (andOp->gtType == TYP_LONG)
+ }
+ else if (andOp->gtType == TYP_LONG)
+ {
+ if (shiftAmount > 63)
{
- if (shiftAmount > 63)
- {
- goto SKIP;
- }
+ goto SKIP;
+ }
- UINT64 newAndOperand = ((UINT64)1) << shiftAmount;
+ UINT64 newAndOperand = ((UINT64)1) << shiftAmount;
- andOp->gtOp.gtOp2->gtIntConCommon.SetLngValue(newAndOperand);
+ andOp->gtOp.gtOp2->gtIntConCommon.SetLngValue(newAndOperand);
- // Reverse the cond if necessary
- if (ival2 == 1)
- {
- gtReverseCond(tree);
- cns2->gtIntConCommon.SetLngValue(0);
- oper = tree->gtOper;
- }
+ // Reverse the cond if necessary
+ if (ival2 == 1)
+ {
+ gtReverseCond(tree);
+ cns2->gtIntConCommon.SetLngValue(0);
+ oper = tree->gtOper;
}
-
- andOp->gtOp.gtOp1 = rshiftOp->gtOp.gtOp1;
-
- DEBUG_DESTROY_NODE(rshiftOp->gtOp.gtOp2);
- DEBUG_DESTROY_NODE(rshiftOp);
}
- } // END if (ival2 != INT_MAX)
- SKIP:
- /* Now check for compares with small constant longs that can be cast to int */
+ andOp->gtOp.gtOp1 = rshiftOp->gtOp.gtOp1;
- if (!cns2->OperIsConst())
- {
- goto COMPARE;
+ DEBUG_DESTROY_NODE(rshiftOp->gtOp.gtOp2);
+ DEBUG_DESTROY_NODE(rshiftOp);
}
+ } // END if (ival2 != INT_MAX)
- if (cns2->TypeGet() != TYP_LONG)
- {
- goto COMPARE;
- }
+ SKIP:
+ /* Now check for compares with small constant longs that can be cast to int */
- /* Is the constant 31 bits or smaller? */
+ if (!cns2->OperIsConst())
+ {
+ goto COMPARE;
+ }
- if ((cns2->gtIntConCommon.LngValue() >> 31) != 0)
- {
- goto COMPARE;
- }
+ if (cns2->TypeGet() != TYP_LONG)
+ {
+ goto COMPARE;
+ }
- /* Is the first comparand mask operation of type long ? */
+ /* Is the constant 31 bits or smaller? */
- if (op1->gtOper != GT_AND)
- {
- /* Another interesting case: cast from int */
+ if ((cns2->gtIntConCommon.LngValue() >> 31) != 0)
+ {
+ goto COMPARE;
+ }
- if (op1->gtOper == GT_CAST && op1->CastFromType() == TYP_INT &&
- !gtIsActiveCSE_Candidate(op1) && // op1 cannot be a CSE candidate
- !op1->gtOverflow()) // cannot be an overflow checking cast
- {
- /* Simply make this into an integer comparison */
+ /* Is the first comparand mask operation of type long ? */
- tree->gtOp.gtOp1 = op1->gtCast.CastOp();
- tree->gtOp.gtOp2 = gtNewIconNode((int)cns2->gtIntConCommon.LngValue(), TYP_INT);
- }
+ if (op1->gtOper != GT_AND)
+ {
+ /* Another interesting case: cast from int */
+
+ if (op1->gtOper == GT_CAST && op1->CastFromType() == TYP_INT &&
+ !gtIsActiveCSE_Candidate(op1) && // op1 cannot be a CSE candidate
+ !op1->gtOverflow()) // cannot be an overflow checking cast
+ {
+ /* Simply make this into an integer comparison */
- goto COMPARE;
+ tree->gtOp.gtOp1 = op1->gtCast.CastOp();
+ tree->gtOp.gtOp2 = gtNewIconNode((int)cns2->gtIntConCommon.LngValue(), TYP_INT);
}
- noway_assert(op1->TypeGet() == TYP_LONG && op1->OperGet() == GT_AND);
+ goto COMPARE;
+ }
- /* Is the result of the mask effectively an INT ? */
+ noway_assert(op1->TypeGet() == TYP_LONG && op1->OperGet() == GT_AND);
- GenTreePtr andMask;
- andMask = op1->gtOp.gtOp2;
- if (andMask->gtOper != GT_CNS_NATIVELONG)
- {
- goto COMPARE;
- }
- if ((andMask->gtIntConCommon.LngValue() >> 32) != 0)
- {
- goto COMPARE;
- }
+ /* Is the result of the mask effectively an INT ? */
+
+ GenTreePtr andMask;
+ andMask = op1->gtOp.gtOp2;
+ if (andMask->gtOper != GT_CNS_NATIVELONG)
+ {
+ goto COMPARE;
+ }
+ if ((andMask->gtIntConCommon.LngValue() >> 32) != 0)
+ {
+ goto COMPARE;
+ }
- /* Now we know that we can cast gtOp.gtOp1 of AND to int */
+ /* Now we know that we can cast gtOp.gtOp1 of AND to int */
- op1->gtOp.gtOp1 = gtNewCastNode(TYP_INT, op1->gtOp.gtOp1, TYP_INT);
+ op1->gtOp.gtOp1 = gtNewCastNode(TYP_INT, op1->gtOp.gtOp1, TYP_INT);
- /* now replace the mask node (gtOp.gtOp2 of AND node) */
+ /* now replace the mask node (gtOp.gtOp2 of AND node) */
- noway_assert(andMask == op1->gtOp.gtOp2);
+ noway_assert(andMask == op1->gtOp.gtOp2);
- ival1 = (int)andMask->gtIntConCommon.LngValue();
- andMask->SetOper(GT_CNS_INT);
- andMask->gtType = TYP_INT;
- andMask->gtIntCon.gtIconVal = ival1;
+ ival1 = (int)andMask->gtIntConCommon.LngValue();
+ andMask->SetOper(GT_CNS_INT);
+ andMask->gtType = TYP_INT;
+ andMask->gtIntCon.gtIconVal = ival1;
- /* now change the type of the AND node */
+ /* now change the type of the AND node */
- op1->gtType = TYP_INT;
+ op1->gtType = TYP_INT;
- /* finally we replace the comparand */
+ /* finally we replace the comparand */
- ival2 = (int)cns2->gtIntConCommon.LngValue();
- cns2->SetOper(GT_CNS_INT);
- cns2->gtType = TYP_INT;
+ ival2 = (int)cns2->gtIntConCommon.LngValue();
+ cns2->SetOper(GT_CNS_INT);
+ cns2->gtType = TYP_INT;
- noway_assert(cns2 == op2);
- cns2->gtIntCon.gtIconVal = ival2;
+ noway_assert(cns2 == op2);
+ cns2->gtIntCon.gtIconVal = ival2;
- goto COMPARE;
+ goto COMPARE;
- case GT_LT:
- case GT_LE:
- case GT_GE:
- case GT_GT:
+ case GT_LT:
+ case GT_LE:
+ case GT_GE:
+ case GT_GT:
- if ((tree->gtFlags & GTF_UNSIGNED) == 0)
+ if ((tree->gtFlags & GTF_UNSIGNED) == 0)
+ {
+ if (op2->gtOper == GT_CNS_INT)
{
- if (op2->gtOper == GT_CNS_INT)
+ cns2 = op2;
+ /* Check for "expr relop 1" */
+ if (cns2->IsIntegralConst(1))
{
- cns2 = op2;
- /* Check for "expr relop 1" */
- if (cns2->IsIntegralConst(1))
+ /* Check for "expr >= 1" */
+ if (oper == GT_GE)
{
- /* Check for "expr >= 1" */
- if (oper == GT_GE)
- {
- /* Change to "expr > 0" */
- oper = GT_GT;
- goto SET_OPER;
- }
- /* Check for "expr < 1" */
- else if (oper == GT_LT)
- {
- /* Change to "expr <= 0" */
- oper = GT_LE;
- goto SET_OPER;
- }
+ /* Change to "expr > 0" */
+ oper = GT_GT;
+ goto SET_OPER;
}
- /* Check for "expr relop -1" */
- else if (cns2->IsIntegralConst(-1) && ((oper == GT_LE) || (oper == GT_GT)))
+ /* Check for "expr < 1" */
+ else if (oper == GT_LT)
{
- /* Check for "expr <= -1" */
- if (oper == GT_LE)
- {
- /* Change to "expr < 0" */
- oper = GT_LT;
- goto SET_OPER;
- }
- /* Check for "expr > -1" */
- else if (oper == GT_GT)
- {
- /* Change to "expr >= 0" */
- oper = GT_GE;
-
- SET_OPER:
- // IF we get here we should be changing 'oper'
- assert(tree->OperGet() != oper);
+ /* Change to "expr <= 0" */
+ oper = GT_LE;
+ goto SET_OPER;
+ }
+ }
+ /* Check for "expr relop -1" */
+ else if (cns2->IsIntegralConst(-1) && ((oper == GT_LE) || (oper == GT_GT)))
+ {
+ /* Check for "expr <= -1" */
+ if (oper == GT_LE)
+ {
+ /* Change to "expr < 0" */
+ oper = GT_LT;
+ goto SET_OPER;
+ }
+ /* Check for "expr > -1" */
+ else if (oper == GT_GT)
+ {
+ /* Change to "expr >= 0" */
+ oper = GT_GE;
- // Keep the old ValueNumber for 'tree' as the new expr
- // will still compute the same value as before
- tree->SetOper(oper, GenTree::PRESERVE_VN);
- cns2->gtIntCon.gtIconVal = 0;
+ SET_OPER:
+ // IF we get here we should be changing 'oper'
+ assert(tree->OperGet() != oper);
- // vnStore is null before the ValueNumber phase has run
- if (vnStore != nullptr)
- {
- // Update the ValueNumber for 'cns2', as we just changed it to 0
- fgValueNumberTreeConst(cns2);
- }
+ // Keep the old ValueNumber for 'tree' as the new expr
+ // will still compute the same value as before
+ tree->SetOper(oper, GenTree::PRESERVE_VN);
+ cns2->gtIntCon.gtIconVal = 0;
- op2 = tree->gtOp.gtOp2 = gtFoldExpr(op2);
+ // vnStore is null before the ValueNumber phase has run
+ if (vnStore != nullptr)
+ {
+ // Update the ValueNumber for 'cns2', as we just changed it to 0
+ fgValueNumberTreeConst(cns2);
}
+
+ op2 = tree->gtOp.gtOp2 = gtFoldExpr(op2);
}
}
}
- else // we have an unsigned comparison
+ }
+ else // we have an unsigned comparison
+ {
+ if (op2->IsIntegralConst(0))
{
- if (op2->IsIntegralConst(0))
+ if ((oper == GT_GT) || (oper == GT_LE))
{
- if ((oper == GT_GT) || (oper == GT_LE))
- {
- // IL doesn't have a cne instruction so compilers use cgt.un instead. The JIT
- // recognizes certain patterns that involve GT_NE (e.g (x & 4) != 0) and fails
- // if GT_GT is used instead. Transform (x GT_GT.unsigned 0) into (x GT_NE 0)
- // and (x GT_LE.unsigned 0) into (x GT_EQ 0). The later case is rare, it sometimes
- // occurs as a result of branch inversion.
- oper = (oper == GT_LE) ? GT_EQ : GT_NE;
- tree->SetOper(oper, GenTree::PRESERVE_VN);
- tree->gtFlags &= ~GTF_UNSIGNED;
- }
+ // IL doesn't have a cne instruction so compilers use cgt.un instead. The JIT
+ // recognizes certain patterns that involve GT_NE (e.g (x & 4) != 0) and fails
+ // if GT_GT is used instead. Transform (x GT_GT.unsigned 0) into (x GT_NE 0)
+ // and (x GT_LE.unsigned 0) into (x GT_EQ 0). The later case is rare, it sometimes
+ // occurs as a result of branch inversion.
+ oper = (oper == GT_LE) ? GT_EQ : GT_NE;
+ tree->SetOper(oper, GenTree::PRESERVE_VN);
+ tree->gtFlags &= ~GTF_UNSIGNED;
}
}
+ }
- COMPARE:
+ COMPARE:
- noway_assert(tree->OperKind() & GTK_RELOP);
+ noway_assert(tree->OperKind() & GTK_RELOP);
#ifdef LEGACY_BACKEND
- /* Check if the result of the comparison is used for a jump.
- * If not then only the int (i.e. 32 bit) case is handled in
- * the code generator through the (x86) "set" instructions.
- * For the rest of the cases, the simplest way is to
- * "simulate" the comparison with ?:
- *
- * On ARM, we previously used the IT instruction, but the IT instructions
- * have mostly been declared obsolete and off-limits, so all cases on ARM
- * get converted to ?: */
+ /* Check if the result of the comparison is used for a jump.
+ * If not then only the int (i.e. 32 bit) case is handled in
+ * the code generator through the (x86) "set" instructions.
+ * For the rest of the cases, the simplest way is to
+ * "simulate" the comparison with ?:
+ *
+ * On ARM, we previously used the IT instruction, but the IT instructions
+ * have mostly been declared obsolete and off-limits, so all cases on ARM
+ * get converted to ?: */
- if (!(tree->gtFlags & GTF_RELOP_JMP_USED) && fgMorphRelopToQmark(op1))
- {
- /* We convert it to "(CMP_TRUE) ? (1):(0)" */
+ if (!(tree->gtFlags & GTF_RELOP_JMP_USED) && fgMorphRelopToQmark(op1))
+ {
+ /* We convert it to "(CMP_TRUE) ? (1):(0)" */
- op1 = tree;
- op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
- op1->gtRequestSetFlags();
+ op1 = tree;
+ op1->gtFlags |= (GTF_RELOP_JMP_USED | GTF_RELOP_QMARK | GTF_DONT_CSE);
+ op1->gtRequestSetFlags();
- op2 = new (this, GT_COLON) GenTreeColon(TYP_INT, gtNewIconNode(1), gtNewIconNode(0));
- op2 = fgMorphTree(op2);
+ op2 = new (this, GT_COLON) GenTreeColon(TYP_INT, gtNewIconNode(1), gtNewIconNode(0));
+ op2 = fgMorphTree(op2);
- tree = gtNewQmarkNode(TYP_INT, op1, op2);
+ tree = gtNewQmarkNode(TYP_INT, op1, op2);
- fgMorphTreeDone(tree);
+ fgMorphTreeDone(tree);
- return tree;
- }
+ return tree;
+ }
#endif // LEGACY_BACKEND
- break;
+ break;
#ifdef LEGACY_BACKEND
- case GT_QMARK:
+ case GT_QMARK:
+ {
+ /* If op1 is a comma throw node then we won't be keeping op2 */
+ if (fgIsCommaThrow(op1))
+ {
+ break;
+ }
- /* If op1 is a comma throw node then we won't be keeping op2 */
- if (fgIsCommaThrow(op1))
- {
- break;
- }
+ /* Get hold of the two branches */
- /* Get hold of the two branches */
+ noway_assert(op2->OperGet() == GT_COLON);
+ GenTreePtr thenNode = op2->AsColon()->ThenNode();
+ GenTreePtr elseNode = op2->AsColon()->ElseNode();
- noway_assert(op2->OperGet() == GT_COLON);
- elseNode = op2->AsColon()->ElseNode();
- thenNode = op2->AsColon()->ThenNode();
+ /* Try to hoist assignments out of qmark colon constructs.
+ ie. replace (cond?(x=a):(x=b)) with (x=(cond?a:b)). */
- /* Try to hoist assignments out of qmark colon constructs.
- ie. replace (cond?(x=a):(x=b)) with (x=(cond?a:b)). */
+ if (tree->TypeGet() == TYP_VOID && thenNode->OperGet() == GT_ASG && elseNode->OperGet() == GT_ASG &&
+ thenNode->TypeGet() != TYP_LONG && GenTree::Compare(thenNode->gtOp.gtOp1, elseNode->gtOp.gtOp1) &&
+ thenNode->gtOp.gtOp2->TypeGet() == elseNode->gtOp.gtOp2->TypeGet())
+ {
+ noway_assert(thenNode->TypeGet() == elseNode->TypeGet());
- if (tree->TypeGet() == TYP_VOID && thenNode->OperGet() == GT_ASG && elseNode->OperGet() == GT_ASG &&
- thenNode->TypeGet() != TYP_LONG && GenTree::Compare(thenNode->gtOp.gtOp1, elseNode->gtOp.gtOp1) &&
- thenNode->gtOp.gtOp2->TypeGet() == elseNode->gtOp.gtOp2->TypeGet())
- {
- noway_assert(thenNode->TypeGet() == elseNode->TypeGet());
+ GenTreePtr asg = thenNode;
+ GenTreePtr colon = op2;
+ colon->gtOp.gtOp1 = thenNode->gtOp.gtOp2;
+ colon->gtOp.gtOp2 = elseNode->gtOp.gtOp2;
+ tree->gtType = colon->gtType = asg->gtOp.gtOp2->gtType;
+ asg->gtOp.gtOp2 = tree;
- GenTreePtr asg = thenNode;
- GenTreePtr colon = op2;
- colon->gtOp.gtOp1 = thenNode->gtOp.gtOp2;
- colon->gtOp.gtOp2 = elseNode->gtOp.gtOp2;
- tree->gtType = colon->gtType = asg->gtOp.gtOp2->gtType;
- asg->gtOp.gtOp2 = tree;
+ // Asg will have all the flags that the QMARK had
+ asg->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
- // Asg will have all the flags that the QMARK had
- asg->gtFlags |= (tree->gtFlags & GTF_ALL_EFFECT);
+ // Colon flag won't have the flags that x had.
+ colon->gtFlags &= ~GTF_ALL_EFFECT;
+ colon->gtFlags |= (colon->gtOp.gtOp1->gtFlags | colon->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
- // Colon flag won't have the flags that x had.
- colon->gtFlags &= ~GTF_ALL_EFFECT;
- colon->gtFlags |= (colon->gtOp.gtOp1->gtFlags | colon->gtOp.gtOp2->gtFlags) & GTF_ALL_EFFECT;
+ DEBUG_DESTROY_NODE(elseNode->gtOp.gtOp1);
+ DEBUG_DESTROY_NODE(elseNode);
- DEBUG_DESTROY_NODE(elseNode->gtOp.gtOp1);
- DEBUG_DESTROY_NODE(elseNode);
+ return asg;
+ }
- return asg;
- }
+ /* If the 'else' branch is empty swap the two branches and reverse the condition */
- /* If the 'else' branch is empty swap the two branches and reverse the condition */
+ if (elseNode->IsNothingNode())
+ {
+ /* This can only happen for VOID ?: */
+ noway_assert(op2->gtType == TYP_VOID);
- if (elseNode->IsNothingNode())
+ /* If the thenNode and elseNode are both nop nodes then optimize away the QMARK */
+ if (thenNode->IsNothingNode())
{
- /* This can only happen for VOID ?: */
- noway_assert(op2->gtType == TYP_VOID);
+ // We may be able to throw away op1 (unless it has side-effects)
- /* If the thenNode and elseNode are both nop nodes then optimize away the QMARK */
- if (thenNode->IsNothingNode())
+ if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
{
- // We may be able to throw away op1 (unless it has side-effects)
-
- if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
- {
- /* Just return a a Nop Node */
- return thenNode;
- }
- else
- {
- /* Just return the relop, but clear the special flags. Note
- that we can't do that for longs and floats (see code under
- COMPARE label above) */
-
- if (!fgMorphRelopToQmark(op1->gtOp.gtOp1))
- {
- op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
- return op1;
- }
- }
+ /* Just return a a Nop Node */
+ return thenNode;
}
else
{
- GenTreePtr tmp = elseNode;
+ /* Just return the relop, but clear the special flags. Note
+ that we can't do that for longs and floats (see code under
+ COMPARE label above) */
- op2->AsColon()->ElseNode() = elseNode = thenNode;
- op2->AsColon()->ThenNode() = thenNode = tmp;
- gtReverseCond(op1);
+ if (!fgMorphRelopToQmark(op1->gtOp.gtOp1))
+ {
+ op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
+ return op1;
+ }
}
}
+ else
+ {
+ GenTreePtr tmp = elseNode;
+
+ op2->AsColon()->ElseNode() = elseNode = thenNode;
+ op2->AsColon()->ThenNode() = thenNode = tmp;
+ gtReverseCond(op1);
+ }
+ }
#if !defined(_TARGET_ARM_)
- // If we have (cond)?0:1, then we just return "cond" for TYP_INTs
- //
- // Don't do this optimization for ARM: we always require assignment
- // to boolean to remain ?:, since we don't have any way to generate
- // this with straight-line code, like x86 does using setcc (at least
- // after the IT instruction is deprecated).
+ // If we have (cond)?0:1, then we just return "cond" for TYP_INTs
+ //
+ // Don't do this optimization for ARM: we always require assignment
+ // to boolean to remain ?:, since we don't have any way to generate
+ // this with straight-line code, like x86 does using setcc (at least
+ // after the IT instruction is deprecated).
- if (genActualType(op1->gtOp.gtOp1->gtType) == TYP_INT && genActualType(typ) == TYP_INT &&
- thenNode->gtOper == GT_CNS_INT && elseNode->gtOper == GT_CNS_INT)
- {
- ival1 = thenNode->gtIntCon.gtIconVal;
- ival2 = elseNode->gtIntCon.gtIconVal;
+ if (genActualType(op1->gtOp.gtOp1->gtType) == TYP_INT && genActualType(typ) == TYP_INT &&
+ thenNode->gtOper == GT_CNS_INT && elseNode->gtOper == GT_CNS_INT)
+ {
+ ival1 = thenNode->gtIntCon.gtIconVal;
+ ival2 = elseNode->gtIntCon.gtIconVal;
- // Is one constant 0 and the other 1?
- if ((ival1 | ival2) == 1 && (ival1 & ival2) == 0)
+ // Is one constant 0 and the other 1?
+ if ((ival1 | ival2) == 1 && (ival1 & ival2) == 0)
+ {
+ // If the constants are {1, 0}, reverse the condition
+ if (ival1 == 1)
{
- // If the constants are {1, 0}, reverse the condition
- if (ival1 == 1)
- {
- gtReverseCond(op1);
- }
+ gtReverseCond(op1);
+ }
- // Unmark GTF_RELOP_JMP_USED on the condition node so it knows that it
- // needs to materialize the result as a 0 or 1.
- noway_assert(op1->gtFlags & (GTF_RELOP_QMARK | GTF_RELOP_JMP_USED));
- op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
+ // Unmark GTF_RELOP_JMP_USED on the condition node so it knows that it
+ // needs to materialize the result as a 0 or 1.
+ noway_assert(op1->gtFlags & (GTF_RELOP_QMARK | GTF_RELOP_JMP_USED));
+ op1->gtFlags &= ~(GTF_RELOP_QMARK | GTF_RELOP_JMP_USED);
- DEBUG_DESTROY_NODE(tree);
- DEBUG_DESTROY_NODE(op2);
+ DEBUG_DESTROY_NODE(tree);
+ DEBUG_DESTROY_NODE(op2);
- return op1;
- }
+ return op1;
}
+ }
#endif // !_TARGET_ARM_
+ }
+ break; // end case GT_QMARK
+#endif // LEGACY_BACKEND
- break; // end case GT_QMARK
-#endif // LEGACY_BACKEND
-
- case GT_MUL:
+ case GT_MUL:
#ifndef _TARGET_64BIT_
- if (typ == TYP_LONG)
- {
- // This must be GTF_MUL_64RSLT
- assert(tree->gtIsValid64RsltMul());
- return tree;
- }
+ if (typ == TYP_LONG)
+ {
+ // This must be GTF_MUL_64RSLT
+ assert(tree->gtIsValid64RsltMul());
+ return tree;
+ }
#endif // _TARGET_64BIT_
+ goto CM_OVF_OP;
+
+ case GT_SUB:
+
+ if (tree->gtOverflow())
+ {
goto CM_OVF_OP;
+ }
- case GT_SUB:
+ // TODO #4104: there are a lot of other places where
+ // this condition is not checked before transformations.
+ if (fgGlobalMorph)
+ {
+ /* Check for "op1 - cns2" , we change it to "op1 + (-cns2)" */
- if (tree->gtOverflow())
+ noway_assert(op2);
+ if (op2->IsCnsIntOrI())
{
- goto CM_OVF_OP;
+ /* Negate the constant and change the node to be "+" */
+
+ op2->gtIntConCommon.SetIconValue(-op2->gtIntConCommon.IconValue());
+ oper = GT_ADD;
+ tree->ChangeOper(oper);
+ goto CM_ADD_OP;
}
- // TODO #4104: there are a lot of other places where
- // this condition is not checked before transformations.
- if (fgGlobalMorph)
+ /* Check for "cns1 - op2" , we change it to "(cns1 + (-op2))" */
+
+ noway_assert(op1);
+ if (op1->IsCnsIntOrI())
{
- /* Check for "op1 - cns2" , we change it to "op1 + (-cns2)" */
+ noway_assert(varTypeIsIntOrI(tree));
- noway_assert(op2);
- if (op2->IsCnsIntOrI())
- {
- /* Negate the constant and change the node to be "+" */
+ tree->gtOp.gtOp2 = op2 = gtNewOperNode(GT_NEG, tree->gtType, op2); // The type of the new GT_NEG
+ // node should be the same
+ // as the type of the tree, i.e. tree->gtType.
+ fgMorphTreeDone(op2);
- op2->gtIntConCommon.SetIconValue(-op2->gtIntConCommon.IconValue());
- oper = GT_ADD;
- tree->ChangeOper(oper);
- goto CM_ADD_OP;
- }
+ oper = GT_ADD;
+ tree->ChangeOper(oper);
+ goto CM_ADD_OP;
+ }
- /* Check for "cns1 - op2" , we change it to "(cns1 + (-op2))" */
+ /* No match - exit */
+ }
+ break;
- noway_assert(op1);
- if (op1->IsCnsIntOrI())
- {
- noway_assert(varTypeIsIntOrI(tree));
+#ifdef _TARGET_ARM64_
+ case GT_DIV:
+ if (!varTypeIsFloating(tree->gtType))
+ {
+ // Codegen for this instruction needs to be able to throw two exceptions:
+ fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
+ fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
+ }
+ break;
+ case GT_UDIV:
+ // Codegen for this instruction needs to be able to throw one exception:
+ fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
+ break;
+#endif
- tree->gtOp.gtOp2 = op2 = gtNewOperNode(GT_NEG, tree->gtType, op2); // The type of the new GT_NEG
- // node should be the same
- // as the type of the tree, i.e. tree->gtType.
- fgMorphTreeDone(op2);
+ case GT_ADD:
- oper = GT_ADD;
- tree->ChangeOper(oper);
- goto CM_ADD_OP;
- }
+ CM_OVF_OP:
+ if (tree->gtOverflow())
+ {
+ tree->gtRequestSetFlags();
- /* No match - exit */
- }
- break;
+ // Add the excptn-throwing basic block to jump to on overflow
-#ifdef _TARGET_ARM64_
- case GT_DIV:
- if (!varTypeIsFloating(tree->gtType))
- {
- // Codegen for this instruction needs to be able to throw two exceptions:
- fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
- fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
- }
- break;
- case GT_UDIV:
- // Codegen for this instruction needs to be able to throw one exception:
- fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
- break;
-#endif
+ fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
- case GT_ADD:
+ // We can't do any commutative morphing for overflow instructions
- CM_OVF_OP:
- if (tree->gtOverflow())
- {
- tree->gtRequestSetFlags();
+ break;
+ }
- // Add the excptn-throwing basic block to jump to on overflow
+ CM_ADD_OP:
- fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
+ case GT_OR:
+ case GT_XOR:
+ case GT_AND:
- // We can't do any commutative morphing for overflow instructions
+ /* Commute any non-REF constants to the right */
- break;
- }
+ noway_assert(op1);
+ if (op1->OperIsConst() && (op1->gtType != TYP_REF))
+ {
+ // TODO-Review: We used to assert here that
+ // noway_assert(!op2->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD));
+ // With modifications to AddrTaken==>AddrExposed, we did more assertion propagation,
+ // and would sometimes hit this assertion. This may indicate a missed "remorph".
+ // Task is to re-enable this assertion and investigate.
- CM_ADD_OP:
+ /* Swap the operands */
+ tree->gtOp.gtOp1 = op2;
+ tree->gtOp.gtOp2 = op1;
- case GT_OR:
- case GT_XOR:
- case GT_AND:
+ op1 = op2;
+ op2 = tree->gtOp.gtOp2;
+ }
- /* Commute any non-REF constants to the right */
+ /* See if we can fold GT_ADD nodes. */
- noway_assert(op1);
- if (op1->OperIsConst() && (op1->gtType != TYP_REF))
+ if (oper == GT_ADD)
+ {
+ /* Fold "((x+icon1)+(y+icon2)) to ((x+y)+(icon1+icon2))" */
+
+ if (op1->gtOper == GT_ADD && op2->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op2) &&
+ op1->gtOp.gtOp2->gtOper == GT_CNS_INT && op2->gtOp.gtOp2->gtOper == GT_CNS_INT &&
+ !op1->gtOverflow() && !op2->gtOverflow())
{
- // TODO-Review: We used to assert here that
- // noway_assert(!op2->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD));
- // With modifications to AddrTaken==>AddrExposed, we did more assertion propagation,
- // and would sometimes hit this assertion. This may indicate a missed "remorph".
- // Task is to re-enable this assertion and investigate.
+ cns1 = op1->gtOp.gtOp2;
+ cns2 = op2->gtOp.gtOp2;
+ cns1->gtIntCon.gtIconVal += cns2->gtIntCon.gtIconVal;
+#ifdef _TARGET_64BIT_
+ if (cns1->TypeGet() == TYP_INT)
+ {
+ // we need to properly re-sign-extend or truncate after adding two int constants above
+ cns1->AsIntCon()->TruncateOrSignExtend32();
+ }
+#endif //_TARGET_64BIT_
- /* Swap the operands */
- tree->gtOp.gtOp1 = op2;
- tree->gtOp.gtOp2 = op1;
+ tree->gtOp.gtOp2 = cns1;
+ DEBUG_DESTROY_NODE(cns2);
- op1 = op2;
+ op1->gtOp.gtOp2 = op2->gtOp.gtOp1;
+ op1->gtFlags |= (op1->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT);
+ DEBUG_DESTROY_NODE(op2);
op2 = tree->gtOp.gtOp2;
}
- /* See if we can fold GT_ADD nodes. */
-
- if (oper == GT_ADD)
+ if (op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ))
{
- /* Fold "((x+icon1)+(y+icon2)) to ((x+y)+(icon1+icon2))" */
+ /* Fold "((x+icon1)+icon2) to (x+(icon1+icon2))" */
- if (op1->gtOper == GT_ADD && op2->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op2) &&
- op1->gtOp.gtOp2->gtOper == GT_CNS_INT && op2->gtOp.gtOp2->gtOper == GT_CNS_INT &&
- !op1->gtOverflow() && !op2->gtOverflow())
+ if (op1->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op1) && op1->gtOp.gtOp2->IsCnsIntOrI() &&
+ !op1->gtOverflow() && op1->gtOp.gtOp2->OperGet() == op2->OperGet())
{
cns1 = op1->gtOp.gtOp2;
- cns2 = op2->gtOp.gtOp2;
- cns1->gtIntCon.gtIconVal += cns2->gtIntCon.gtIconVal;
+ op2->gtIntConCommon.SetIconValue(cns1->gtIntConCommon.IconValue() +
+ op2->gtIntConCommon.IconValue());
#ifdef _TARGET_64BIT_
- if (cns1->TypeGet() == TYP_INT)
+ if (op2->TypeGet() == TYP_INT)
{
// we need to properly re-sign-extend or truncate after adding two int constants above
- cns1->AsIntCon()->TruncateOrSignExtend32();
+ op2->AsIntCon()->TruncateOrSignExtend32();
}
#endif //_TARGET_64BIT_
- tree->gtOp.gtOp2 = cns1;
- DEBUG_DESTROY_NODE(cns2);
+ if (cns1->OperGet() == GT_CNS_INT)
+ {
+ op2->gtIntCon.gtFieldSeq =
+ GetFieldSeqStore()->Append(cns1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
+ }
+ DEBUG_DESTROY_NODE(cns1);
- op1->gtOp.gtOp2 = op2->gtOp.gtOp1;
- op1->gtFlags |= (op1->gtOp.gtOp2->gtFlags & GTF_ALL_EFFECT);
- DEBUG_DESTROY_NODE(op2);
- op2 = tree->gtOp.gtOp2;
+ tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
+ DEBUG_DESTROY_NODE(op1);
+ op1 = tree->gtOp.gtOp1;
}
- if (op2->IsCnsIntOrI() && varTypeIsIntegralOrI(typ))
- {
- /* Fold "((x+icon1)+icon2) to (x+(icon1+icon2))" */
+ // Fold (x + 0).
- if (op1->gtOper == GT_ADD && !gtIsActiveCSE_Candidate(op1) && op1->gtOp.gtOp2->IsCnsIntOrI() &&
- !op1->gtOverflow() && op1->gtOp.gtOp2->OperGet() == op2->OperGet())
- {
- cns1 = op1->gtOp.gtOp2;
- op2->gtIntConCommon.SetIconValue(cns1->gtIntConCommon.IconValue() +
- op2->gtIntConCommon.IconValue());
-#ifdef _TARGET_64BIT_
- if (op2->TypeGet() == TYP_INT)
- {
- // we need to properly re-sign-extend or truncate after adding two int constants above
- op2->AsIntCon()->TruncateOrSignExtend32();
- }
-#endif //_TARGET_64BIT_
+ if ((op2->gtIntConCommon.IconValue() == 0) && !gtIsActiveCSE_Candidate(tree))
+ {
- if (cns1->OperGet() == GT_CNS_INT)
- {
- op2->gtIntCon.gtFieldSeq =
- GetFieldSeqStore()->Append(cns1->gtIntCon.gtFieldSeq, op2->gtIntCon.gtFieldSeq);
- }
- DEBUG_DESTROY_NODE(cns1);
+ // If this addition is adding an offset to a null pointer,
+ // avoid the work and yield the null pointer immediately.
+ // Dereferencing the pointer in either case will have the
+ // same effect.
- tree->gtOp.gtOp1 = op1->gtOp.gtOp1;
+ if (!optValnumCSE_phase && varTypeIsGC(op2->TypeGet()) &&
+ ((op1->gtFlags & GTF_ALL_EFFECT) == 0))
+ {
+ op2->gtType = tree->gtType;
DEBUG_DESTROY_NODE(op1);
- op1 = tree->gtOp.gtOp1;
+ DEBUG_DESTROY_NODE(tree);
+ return op2;
}
- // Fold (x + 0).
+ // Remove the addition iff it won't change the tree type
+ // to TYP_REF.
- if ((op2->gtIntConCommon.IconValue() == 0) && !gtIsActiveCSE_Candidate(tree))
+ if (!gtIsActiveCSE_Candidate(op2) &&
+ ((op1->TypeGet() == tree->TypeGet()) || (op1->TypeGet() != TYP_REF)))
{
-
- // If this addition is adding an offset to a null pointer,
- // avoid the work and yield the null pointer immediately.
- // Dereferencing the pointer in either case will have the
- // same effect.
-
- if (!optValnumCSE_phase && varTypeIsGC(op2->TypeGet()) &&
- ((op1->gtFlags & GTF_ALL_EFFECT) == 0))
+ if (fgGlobalMorph && (op2->OperGet() == GT_CNS_INT) &&
+ (op2->gtIntCon.gtFieldSeq != nullptr) &&
+ (op2->gtIntCon.gtFieldSeq != FieldSeqStore::NotAField()))
{
- op2->gtType = tree->gtType;
- DEBUG_DESTROY_NODE(op1);
- DEBUG_DESTROY_NODE(tree);
- return op2;
+ fgAddFieldSeqForZeroOffset(op1, op2->gtIntCon.gtFieldSeq);
}
- // Remove the addition iff it won't change the tree type
- // to TYP_REF.
-
- if (!gtIsActiveCSE_Candidate(op2) &&
- ((op1->TypeGet() == tree->TypeGet()) || (op1->TypeGet() != TYP_REF)))
- {
- if (fgGlobalMorph && (op2->OperGet() == GT_CNS_INT) &&
- (op2->gtIntCon.gtFieldSeq != nullptr) &&
- (op2->gtIntCon.gtFieldSeq != FieldSeqStore::NotAField()))
- {
- fgAddFieldSeqForZeroOffset(op1, op2->gtIntCon.gtFieldSeq);
- }
-
- DEBUG_DESTROY_NODE(op2);
- DEBUG_DESTROY_NODE(tree);
+ DEBUG_DESTROY_NODE(op2);
+ DEBUG_DESTROY_NODE(tree);
- return op1;
- }
+ return op1;
}
}
}
- /* See if we can fold GT_MUL by const nodes */
- else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
- {
+ }
+ /* See if we can fold GT_MUL by const nodes */
+ else if (oper == GT_MUL && op2->IsCnsIntOrI() && !optValnumCSE_phase)
+ {
#ifndef _TARGET_64BIT_
- noway_assert(typ <= TYP_UINT);
+ noway_assert(typ <= TYP_UINT);
#endif // _TARGET_64BIT_
- noway_assert(!tree->gtOverflow());
+ noway_assert(!tree->gtOverflow());
+
+ ssize_t mult = op2->gtIntConCommon.IconValue();
+ bool op2IsConstIndex = op2->OperGet() == GT_CNS_INT && op2->gtIntCon.gtFieldSeq != nullptr &&
+ op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq();
+
+ assert(!op2IsConstIndex || op2->AsIntCon()->gtFieldSeq->m_next == nullptr);
+
+ if (mult == 0)
+ {
+ // We may be able to throw away op1 (unless it has side-effects)
+
+ if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
+ {
+ DEBUG_DESTROY_NODE(op1);
+ DEBUG_DESTROY_NODE(tree);
+ return op2; // Just return the "0" node
+ }
+
+ // We need to keep op1 for the side-effects. Hang it off
+ // a GT_COMMA node
- ssize_t mult = op2->gtIntConCommon.IconValue();
- bool op2IsConstIndex = op2->OperGet() == GT_CNS_INT && op2->gtIntCon.gtFieldSeq != nullptr &&
- op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq();
+ tree->ChangeOper(GT_COMMA);
+ return tree;
+ }
- assert(!op2IsConstIndex || op2->AsIntCon()->gtFieldSeq->m_next == nullptr);
+ size_t abs_mult = (mult >= 0) ? mult : -mult;
+ size_t lowestBit = genFindLowestBit(abs_mult);
+ bool changeToShift = false;
- if (mult == 0)
+ // is it a power of two? (positive or negative)
+ if (abs_mult == lowestBit)
+ {
+ // if negative negate (min-int does not need negation)
+ if (mult < 0 && mult != SSIZE_T_MIN)
{
- // We may be able to throw away op1 (unless it has side-effects)
+ tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_NEG, op1->gtType, op1);
+ fgMorphTreeDone(op1);
+ }
- if ((op1->gtFlags & GTF_SIDE_EFFECT) == 0)
+ // If "op2" is a constant array index, the other multiplicand must be a constant.
+ // Transfer the annotation to the other one.
+ if (op2->OperGet() == GT_CNS_INT && op2->gtIntCon.gtFieldSeq != nullptr &&
+ op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
+ {
+ assert(op2->gtIntCon.gtFieldSeq->m_next == nullptr);
+ GenTreePtr otherOp = op1;
+ if (otherOp->OperGet() == GT_NEG)
{
- DEBUG_DESTROY_NODE(op1);
- DEBUG_DESTROY_NODE(tree);
- return op2; // Just return the "0" node
+ otherOp = otherOp->gtOp.gtOp1;
}
+ assert(otherOp->OperGet() == GT_CNS_INT);
+ assert(otherOp->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
+ otherOp->gtIntCon.gtFieldSeq = op2->gtIntCon.gtFieldSeq;
+ }
- // We need to keep op1 for the side-effects. Hang it off
- // a GT_COMMA node
-
- tree->ChangeOper(GT_COMMA);
- return tree;
+ if (abs_mult == 1)
+ {
+ DEBUG_DESTROY_NODE(op2);
+ DEBUG_DESTROY_NODE(tree);
+ return op1;
}
- size_t abs_mult = (mult >= 0) ? mult : -mult;
- size_t lowestBit = genFindLowestBit(abs_mult);
- bool changeToShift = false;
+ /* Change the multiplication into a shift by log2(val) bits */
+ op2->gtIntConCommon.SetIconValue(genLog2(abs_mult));
+ changeToShift = true;
+ }
+#if LEA_AVAILABLE
+ else if ((lowestBit > 1) && jitIsScaleIndexMul(lowestBit) && optAvoidIntMult())
+ {
+ int shift = genLog2(lowestBit);
+ ssize_t factor = abs_mult >> shift;
- // is it a power of two? (positive or negative)
- if (abs_mult == lowestBit)
+ if (factor == 3 || factor == 5 || factor == 9)
{
// if negative negate (min-int does not need negation)
if (mult < 0 && mult != SSIZE_T_MIN)
@@ -13604,471 +13498,411 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
fgMorphTreeDone(op1);
}
- // If "op2" is a constant array index, the other multiplicand must be a constant.
- // Transfer the annotation to the other one.
- if (op2->OperGet() == GT_CNS_INT && op2->gtIntCon.gtFieldSeq != nullptr &&
- op2->gtIntCon.gtFieldSeq->IsConstantIndexFieldSeq())
+ GenTreePtr factorIcon = gtNewIconNode(factor, TYP_I_IMPL);
+ if (op2IsConstIndex)
{
- assert(op2->gtIntCon.gtFieldSeq->m_next == nullptr);
- GenTreePtr otherOp = op1;
- if (otherOp->OperGet() == GT_NEG)
- {
- otherOp = otherOp->gtOp.gtOp1;
- }
- assert(otherOp->OperGet() == GT_CNS_INT);
- assert(otherOp->gtIntCon.gtFieldSeq == FieldSeqStore::NotAField());
- otherOp->gtIntCon.gtFieldSeq = op2->gtIntCon.gtFieldSeq;
+ factorIcon->AsIntCon()->gtFieldSeq =
+ GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
}
- if (abs_mult == 1)
- {
- DEBUG_DESTROY_NODE(op2);
- DEBUG_DESTROY_NODE(tree);
- return op1;
- }
+ // change the multiplication into a smaller multiplication (by 3, 5 or 9) and a shift
+ tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_MUL, tree->gtType, op1, factorIcon);
+ fgMorphTreeDone(op1);
- /* Change the multiplication into a shift by log2(val) bits */
- op2->gtIntConCommon.SetIconValue(genLog2(abs_mult));
+ op2->gtIntConCommon.SetIconValue(shift);
changeToShift = true;
}
-#if LEA_AVAILABLE
- else if ((lowestBit > 1) && jitIsScaleIndexMul(lowestBit) && optAvoidIntMult())
- {
- int shift = genLog2(lowestBit);
- ssize_t factor = abs_mult >> shift;
-
- if (factor == 3 || factor == 5 || factor == 9)
- {
- // if negative negate (min-int does not need negation)
- if (mult < 0 && mult != SSIZE_T_MIN)
- {
- tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_NEG, op1->gtType, op1);
- fgMorphTreeDone(op1);
- }
-
- GenTreePtr factorIcon = gtNewIconNode(factor, TYP_I_IMPL);
- if (op2IsConstIndex)
- {
- factorIcon->AsIntCon()->gtFieldSeq =
- GetFieldSeqStore()->CreateSingleton(FieldSeqStore::ConstantIndexPseudoField);
- }
-
- // change the multiplication into a smaller multiplication (by 3, 5 or 9) and a shift
- tree->gtOp.gtOp1 = op1 = gtNewOperNode(GT_MUL, tree->gtType, op1, factorIcon);
- fgMorphTreeDone(op1);
-
- op2->gtIntConCommon.SetIconValue(shift);
- changeToShift = true;
- }
- }
+ }
#endif // LEA_AVAILABLE
- if (changeToShift)
+ if (changeToShift)
+ {
+ // vnStore is null before the ValueNumber phase has run
+ if (vnStore != nullptr)
{
- // vnStore is null before the ValueNumber phase has run
- if (vnStore != nullptr)
- {
- // Update the ValueNumber for 'op2', as we just changed the constant
- fgValueNumberTreeConst(op2);
- }
- oper = GT_LSH;
- // Keep the old ValueNumber for 'tree' as the new expr
- // will still compute the same value as before
- tree->ChangeOper(oper, GenTree::PRESERVE_VN);
-
- goto DONE_MORPHING_CHILDREN;
+ // Update the ValueNumber for 'op2', as we just changed the constant
+ fgValueNumberTreeConst(op2);
}
- }
- else if (fgOperIsBitwiseRotationRoot(oper))
- {
- tree = fgRecognizeAndMorphBitwiseRotation(tree);
+ oper = GT_LSH;
+ // Keep the old ValueNumber for 'tree' as the new expr
+ // will still compute the same value as before
+ tree->ChangeOper(oper, GenTree::PRESERVE_VN);
- // fgRecognizeAndMorphBitwiseRotation may return a new tree
- oper = tree->OperGet();
- typ = tree->TypeGet();
- op1 = tree->gtOp.gtOp1;
- op2 = tree->gtOp.gtOp2;
+ goto DONE_MORPHING_CHILDREN;
}
+ }
+ else if (fgOperIsBitwiseRotationRoot(oper))
+ {
+ tree = fgRecognizeAndMorphBitwiseRotation(tree);
- break;
+ // fgRecognizeAndMorphBitwiseRotation may return a new tree
+ oper = tree->OperGet();
+ typ = tree->TypeGet();
+ op1 = tree->gtOp.gtOp1;
+ op2 = tree->gtOp.gtOp2;
+ }
- case GT_CHS:
- case GT_NOT:
- case GT_NEG:
+ break;
- /* Any constant cases should have been folded earlier */
- noway_assert(!op1->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD) || optValnumCSE_phase);
- break;
+#ifdef LEGACY_BACKEND
+ case GT_CHS:
+#endif
+ case GT_NOT:
+ case GT_NEG:
- case GT_CKFINITE:
+ /* Any constant cases should have been folded earlier */
+ noway_assert(!op1->OperIsConst() || !opts.OptEnabled(CLFLG_CONSTANTFOLD) || optValnumCSE_phase);
+ break;
- noway_assert(varTypeIsFloating(op1->TypeGet()));
+ case GT_CKFINITE:
- fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_ARITH_EXCPN, fgPtrArgCntCur);
- break;
+ noway_assert(varTypeIsFloating(op1->TypeGet()));
- case GT_OBJ:
- // If we have GT_OBJ(GT_ADDR(X)) and X has GTF_GLOB_REF, we must set GTF_GLOB_REF on
- // the GT_OBJ. Note that the GTF_GLOB_REF will have been cleared on ADDR(X) where X
- // is a local or clsVar, even if it has been address-exposed.
- if (op1->OperGet() == GT_ADDR)
- {
- tree->gtFlags |= (op1->gtGetOp1()->gtFlags & GTF_GLOB_REF);
- }
+ fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_ARITH_EXCPN, fgPtrArgCntCur);
+ break;
+
+ case GT_OBJ:
+ // If we have GT_OBJ(GT_ADDR(X)) and X has GTF_GLOB_REF, we must set GTF_GLOB_REF on
+ // the GT_OBJ. Note that the GTF_GLOB_REF will have been cleared on ADDR(X) where X
+ // is a local or clsVar, even if it has been address-exposed.
+ if (op1->OperGet() == GT_ADDR)
+ {
+ tree->gtFlags |= (op1->gtGetOp1()->gtFlags & GTF_GLOB_REF);
+ }
+ break;
+
+ case GT_IND:
+
+ // Can not remove a GT_IND if it is currently a CSE candidate.
+ if (gtIsActiveCSE_Candidate(tree))
+ {
break;
+ }
- case GT_IND:
+ bool foldAndReturnTemp;
+ foldAndReturnTemp = false;
+ temp = nullptr;
+ ival1 = 0;
- // Can not remove a GT_IND if it is currently a CSE candidate.
- if (gtIsActiveCSE_Candidate(tree))
+ /* Try to Fold *(&X) into X */
+ if (op1->gtOper == GT_ADDR)
+ {
+ // Can not remove a GT_ADDR if it is currently a CSE candidate.
+ if (gtIsActiveCSE_Candidate(op1))
{
break;
}
- bool foldAndReturnTemp;
- foldAndReturnTemp = false;
- temp = nullptr;
- ival1 = 0;
+ temp = op1->gtOp.gtOp1; // X
- /* Try to Fold *(&X) into X */
- if (op1->gtOper == GT_ADDR)
+ // In the test below, if they're both TYP_STRUCT, this of course does *not* mean that
+ // they are the *same* struct type. In fact, they almost certainly aren't. If the
+ // address has an associated field sequence, that identifies this case; go through
+ // the "lcl_fld" path rather than this one.
+ FieldSeqNode* addrFieldSeq = nullptr; // This is an unused out parameter below.
+ if (typ == temp->TypeGet() && !GetZeroOffsetFieldMap()->Lookup(op1, &addrFieldSeq))
{
- // Can not remove a GT_ADDR if it is currently a CSE candidate.
- if (gtIsActiveCSE_Candidate(op1))
- {
- break;
- }
-
- temp = op1->gtOp.gtOp1; // X
+ foldAndReturnTemp = true;
+ }
+ else if (temp->OperIsLocal())
+ {
+ unsigned lclNum = temp->gtLclVarCommon.gtLclNum;
+ LclVarDsc* varDsc = &lvaTable[lclNum];
- // In the test below, if they're both TYP_STRUCT, this of course does *not* mean that
- // they are the *same* struct type. In fact, they almost certainly aren't. If the
- // address has an associated field sequence, that identifies this case; go through
- // the "lcl_fld" path rather than this one.
- FieldSeqNode* addrFieldSeq = nullptr; // This is an unused out parameter below.
- if (typ == temp->TypeGet() && !GetZeroOffsetFieldMap()->Lookup(op1, &addrFieldSeq))
+ // We will try to optimize when we have a promoted struct promoted with a zero lvFldOffset
+ if (varDsc->lvPromoted && (varDsc->lvFldOffset == 0))
{
- foldAndReturnTemp = true;
- }
- else if (temp->OperIsLocal())
- {
- unsigned lclNum = temp->gtLclVarCommon.gtLclNum;
- LclVarDsc* varDsc = &lvaTable[lclNum];
+ noway_assert(varTypeIsStruct(varDsc));
- // We will try to optimize when we have a promoted struct promoted with a zero lvFldOffset
- if (varDsc->lvPromoted && (varDsc->lvFldOffset == 0))
+ // We will try to optimize when we have a single field struct that is being struct promoted
+ if (varDsc->lvFieldCnt == 1)
{
- noway_assert(varTypeIsStruct(varDsc));
+ unsigned lclNumFld = varDsc->lvFieldLclStart;
+ // just grab the promoted field
+ LclVarDsc* fieldVarDsc = &lvaTable[lclNumFld];
- // We will try to optimize when we have a single field struct that is being struct promoted
- if (varDsc->lvFieldCnt == 1)
+ // Also make sure that the tree type matches the fieldVarType and that it's lvFldOffset
+ // is zero
+ if (fieldVarDsc->TypeGet() == typ && (fieldVarDsc->lvFldOffset == 0))
{
- unsigned lclNumFld = varDsc->lvFieldLclStart;
- // just grab the promoted field
- LclVarDsc* fieldVarDsc = &lvaTable[lclNumFld];
+ // We can just use the existing promoted field LclNum
+ temp->gtLclVarCommon.SetLclNum(lclNumFld);
+ temp->gtType = fieldVarDsc->TypeGet();
- // Also make sure that the tree type matches the fieldVarType and that it's lvFldOffset
- // is zero
- if (fieldVarDsc->TypeGet() == typ && (fieldVarDsc->lvFldOffset == 0))
- {
- // We can just use the existing promoted field LclNum
- temp->gtLclVarCommon.SetLclNum(lclNumFld);
- temp->gtType = fieldVarDsc->TypeGet();
-
- foldAndReturnTemp = true;
- }
+ foldAndReturnTemp = true;
}
}
- // If the type of the IND (typ) is a "small int", and the type of the local has the
- // same width, then we can reduce to just the local variable -- it will be
- // correctly normalized, and signed/unsigned differences won't matter.
- //
- // The below transformation cannot be applied if the local var needs to be normalized on load.
- else if (varTypeIsSmall(typ) && (genTypeSize(lvaTable[lclNum].lvType) == genTypeSize(typ)) &&
- !lvaTable[lclNum].lvNormalizeOnLoad())
- {
- tree->gtType = typ = temp->TypeGet();
- foldAndReturnTemp = true;
- }
- else
- {
- // Assumes that when Lookup returns "false" it will leave "fieldSeq" unmodified (i.e.
- // nullptr)
- assert(fieldSeq == nullptr);
- bool b = GetZeroOffsetFieldMap()->Lookup(op1, &fieldSeq);
- assert(b || fieldSeq == nullptr);
+ }
+ // If the type of the IND (typ) is a "small int", and the type of the local has the
+ // same width, then we can reduce to just the local variable -- it will be
+ // correctly normalized, and signed/unsigned differences won't matter.
+ //
+ // The below transformation cannot be applied if the local var needs to be normalized on load.
+ else if (varTypeIsSmall(typ) && (genTypeSize(lvaTable[lclNum].lvType) == genTypeSize(typ)) &&
+ !lvaTable[lclNum].lvNormalizeOnLoad())
+ {
+ tree->gtType = typ = temp->TypeGet();
+ foldAndReturnTemp = true;
+ }
+ else
+ {
+ // Assumes that when Lookup returns "false" it will leave "fieldSeq" unmodified (i.e.
+ // nullptr)
+ assert(fieldSeq == nullptr);
+ bool b = GetZeroOffsetFieldMap()->Lookup(op1, &fieldSeq);
+ assert(b || fieldSeq == nullptr);
- if ((fieldSeq != nullptr) && (temp->OperGet() == GT_LCL_FLD))
- {
- // Append the field sequence, change the type.
- temp->AsLclFld()->gtFieldSeq =
- GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
- temp->gtType = typ;
+ if ((fieldSeq != nullptr) && (temp->OperGet() == GT_LCL_FLD))
+ {
+ // Append the field sequence, change the type.
+ temp->AsLclFld()->gtFieldSeq =
+ GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
+ temp->gtType = typ;
- foldAndReturnTemp = true;
- }
+ foldAndReturnTemp = true;
}
- // Otherwise will will fold this into a GT_LCL_FLD below
- // where we check (temp != nullptr)
}
- else // !temp->OperIsLocal()
+ // Otherwise will will fold this into a GT_LCL_FLD below
+ // where we check (temp != nullptr)
+ }
+ else // !temp->OperIsLocal()
+ {
+ // We don't try to fold away the GT_IND/GT_ADDR for this case
+ temp = nullptr;
+ }
+ }
+ else if (op1->OperGet() == GT_ADD)
+ {
+ /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */
+
+ if (op1->gtOp.gtOp1->OperGet() == GT_ADDR && op1->gtOp.gtOp2->OperGet() == GT_CNS_INT &&
+ (!(opts.MinOpts() || opts.compDbgCode)))
+ {
+ // No overflow arithmetic with pointers
+ noway_assert(!op1->gtOverflow());
+
+ temp = op1->gtOp.gtOp1->gtOp.gtOp1;
+ if (!temp->OperIsLocal())
{
- // We don't try to fold away the GT_IND/GT_ADDR for this case
temp = nullptr;
+ break;
}
- }
- else if (op1->OperGet() == GT_ADD)
- {
- /* Try to change *(&lcl + cns) into lcl[cns] to prevent materialization of &lcl */
- if (op1->gtOp.gtOp1->OperGet() == GT_ADDR && op1->gtOp.gtOp2->OperGet() == GT_CNS_INT &&
- (!(opts.MinOpts() || opts.compDbgCode)))
+ // Can not remove the GT_ADDR if it is currently a CSE candidate.
+ if (gtIsActiveCSE_Candidate(op1->gtOp.gtOp1))
{
- // No overflow arithmetic with pointers
- noway_assert(!op1->gtOverflow());
+ break;
+ }
- temp = op1->gtOp.gtOp1->gtOp.gtOp1;
- if (!temp->OperIsLocal())
- {
- temp = nullptr;
- break;
- }
+ ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
+ fieldSeq = op1->gtOp.gtOp2->gtIntCon.gtFieldSeq;
+
+ // Does the address have an associated zero-offset field sequence?
+ FieldSeqNode* addrFieldSeq = nullptr;
+ if (GetZeroOffsetFieldMap()->Lookup(op1->gtOp.gtOp1, &addrFieldSeq))
+ {
+ fieldSeq = GetFieldSeqStore()->Append(addrFieldSeq, fieldSeq);
+ }
- // Can not remove the GT_ADDR if it is currently a CSE candidate.
- if (gtIsActiveCSE_Candidate(op1->gtOp.gtOp1))
+ if (ival1 == 0 && typ == temp->TypeGet() && temp->TypeGet() != TYP_STRUCT)
+ {
+ noway_assert(!varTypeIsGC(temp->TypeGet()));
+ foldAndReturnTemp = true;
+ }
+ else
+ {
+ // The emitter can't handle large offsets
+ if (ival1 != (unsigned short)ival1)
{
break;
}
- ival1 = op1->gtOp.gtOp2->gtIntCon.gtIconVal;
- fieldSeq = op1->gtOp.gtOp2->gtIntCon.gtFieldSeq;
-
- // Does the address have an associated zero-offset field sequence?
- FieldSeqNode* addrFieldSeq = nullptr;
- if (GetZeroOffsetFieldMap()->Lookup(op1->gtOp.gtOp1, &addrFieldSeq))
+ // The emitter can get confused by invalid offsets
+ if (ival1 >= Compiler::lvaLclSize(temp->gtLclVarCommon.gtLclNum))
{
- fieldSeq = GetFieldSeqStore()->Append(addrFieldSeq, fieldSeq);
+ break;
}
- if (ival1 == 0 && typ == temp->TypeGet() && temp->TypeGet() != TYP_STRUCT)
- {
- noway_assert(!varTypeIsGC(temp->TypeGet()));
- foldAndReturnTemp = true;
- }
- else
+#ifdef _TARGET_ARM_
+ // Check for a LclVar TYP_STRUCT with misalignment on a Floating Point field
+ //
+ if (varTypeIsFloating(typ))
{
- // The emitter can't handle large offsets
- if (ival1 != (unsigned short)ival1)
- {
- break;
- }
-
- // The emitter can get confused by invalid offsets
- if (ival1 >= Compiler::lvaLclSize(temp->gtLclVarCommon.gtLclNum))
+ if ((ival1 % emitTypeSize(typ)) != 0)
{
+ tree->gtFlags |= GTF_IND_UNALIGNED;
break;
}
-
-#ifdef _TARGET_ARM_
- // Check for a LclVar TYP_STRUCT with misalignment on a Floating Point field
- //
- if (varTypeIsFloating(typ))
- {
- if ((ival1 % emitTypeSize(typ)) != 0)
- {
- tree->gtFlags |= GTF_IND_UNALIGNED;
- break;
- }
- }
-#endif
}
- // Now we can fold this into a GT_LCL_FLD below
- // where we check (temp != nullptr)
+#endif
}
+ // Now we can fold this into a GT_LCL_FLD below
+ // where we check (temp != nullptr)
}
+ }
- // At this point we may have a lclVar or lclFld that might be foldable with a bit of extra massaging:
- // - We may have a load of a local where the load has a different type than the local
- // - We may have a load of a local plus an offset
- //
- // In these cases, we will change the lclVar or lclFld into a lclFld of the appropriate type and
- // offset if doing so is legal. The only cases in which this transformation is illegal are if the load
- // begins before the local or if the load extends beyond the end of the local (i.e. if the load is
- // out-of-bounds w.r.t. the local).
- if ((temp != nullptr) && !foldAndReturnTemp)
- {
- assert(temp->OperIsLocal());
+ // At this point we may have a lclVar or lclFld that might be foldable with a bit of extra massaging:
+ // - We may have a load of a local where the load has a different type than the local
+ // - We may have a load of a local plus an offset
+ //
+ // In these cases, we will change the lclVar or lclFld into a lclFld of the appropriate type and
+ // offset if doing so is legal. The only cases in which this transformation is illegal are if the load
+ // begins before the local or if the load extends beyond the end of the local (i.e. if the load is
+ // out-of-bounds w.r.t. the local).
+ if ((temp != nullptr) && !foldAndReturnTemp)
+ {
+ assert(temp->OperIsLocal());
- const unsigned lclNum = temp->AsLclVarCommon()->gtLclNum;
- LclVarDsc* const varDsc = &lvaTable[lclNum];
+ const unsigned lclNum = temp->AsLclVarCommon()->gtLclNum;
+ LclVarDsc* const varDsc = &lvaTable[lclNum];
- const var_types tempTyp = temp->TypeGet();
- const bool useExactSize =
- varTypeIsStruct(tempTyp) || (tempTyp == TYP_BLK) || (tempTyp == TYP_LCLBLK);
- const unsigned varSize = useExactSize ? varDsc->lvExactSize : genTypeSize(temp);
+ const var_types tempTyp = temp->TypeGet();
+ const bool useExactSize = varTypeIsStruct(tempTyp) || (tempTyp == TYP_BLK) || (tempTyp == TYP_LCLBLK);
+ const unsigned varSize = useExactSize ? varDsc->lvExactSize : genTypeSize(temp);
- // Make sure we do not enregister this lclVar.
- lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
+ // Make sure we do not enregister this lclVar.
+ lvaSetVarDoNotEnregister(lclNum DEBUGARG(DNER_LocalField));
- // If the size of the load is greater than the size of the lclVar, we cannot fold this access into
- // a lclFld: the access represented by an lclFld node must begin at or after the start of the
- // lclVar and must not extend beyond the end of the lclVar.
- if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= varSize))
+ // If the size of the load is greater than the size of the lclVar, we cannot fold this access into
+ // a lclFld: the access represented by an lclFld node must begin at or after the start of the
+ // lclVar and must not extend beyond the end of the lclVar.
+ if ((ival1 >= 0) && ((ival1 + genTypeSize(typ)) <= varSize))
+ {
+ // We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
+ // or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
+ // Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
+ //
+ if (temp->OperGet() == GT_LCL_FLD)
{
- // We will turn a GT_LCL_VAR into a GT_LCL_FLD with an gtLclOffs of 'ival'
- // or if we already have a GT_LCL_FLD we will adjust the gtLclOffs by adding 'ival'
- // Then we change the type of the GT_LCL_FLD to match the orginal GT_IND type.
- //
- if (temp->OperGet() == GT_LCL_FLD)
- {
- temp->AsLclFld()->gtLclOffs += (unsigned short)ival1;
- temp->AsLclFld()->gtFieldSeq =
- GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
- }
- else
- {
- temp->ChangeOper(GT_LCL_FLD); // Note that this makes the gtFieldSeq "NotAField"...
- temp->AsLclFld()->gtLclOffs = (unsigned short)ival1;
- if (fieldSeq != nullptr)
- { // If it does represent a field, note that.
- temp->AsLclFld()->gtFieldSeq = fieldSeq;
- }
+ temp->AsLclFld()->gtLclOffs += (unsigned short)ival1;
+ temp->AsLclFld()->gtFieldSeq =
+ GetFieldSeqStore()->Append(temp->AsLclFld()->gtFieldSeq, fieldSeq);
+ }
+ else
+ {
+ temp->ChangeOper(GT_LCL_FLD); // Note that this makes the gtFieldSeq "NotAField"...
+ temp->AsLclFld()->gtLclOffs = (unsigned short)ival1;
+ if (fieldSeq != nullptr)
+ { // If it does represent a field, note that.
+ temp->AsLclFld()->gtFieldSeq = fieldSeq;
}
- temp->gtType = tree->gtType;
- foldAndReturnTemp = true;
}
+ temp->gtType = tree->gtType;
+ foldAndReturnTemp = true;
}
+ }
- if (foldAndReturnTemp)
- {
- assert(temp != nullptr);
- assert(temp->TypeGet() == typ);
- assert((op1->OperGet() == GT_ADD) || (op1->OperGet() == GT_ADDR));
+ if (foldAndReturnTemp)
+ {
+ assert(temp != nullptr);
+ assert(temp->TypeGet() == typ);
+ assert((op1->OperGet() == GT_ADD) || (op1->OperGet() == GT_ADDR));
- // Copy the value of GTF_DONT_CSE from the original tree to `temp`: it can be set for
- // 'temp' because a GT_ADDR always marks it for its operand.
- temp->gtFlags &= ~GTF_DONT_CSE;
- temp->gtFlags |= (tree->gtFlags & GTF_DONT_CSE);
+ // Copy the value of GTF_DONT_CSE from the original tree to `temp`: it can be set for
+ // 'temp' because a GT_ADDR always marks it for its operand.
+ temp->gtFlags &= ~GTF_DONT_CSE;
+ temp->gtFlags |= (tree->gtFlags & GTF_DONT_CSE);
- if (op1->OperGet() == GT_ADD)
- {
- DEBUG_DESTROY_NODE(op1->gtOp.gtOp1); // GT_ADDR
- DEBUG_DESTROY_NODE(op1->gtOp.gtOp2); // GT_CNS_INT
- }
- DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR
- DEBUG_DESTROY_NODE(tree); // GT_IND
+ if (op1->OperGet() == GT_ADD)
+ {
+ DEBUG_DESTROY_NODE(op1->gtOp.gtOp1); // GT_ADDR
+ DEBUG_DESTROY_NODE(op1->gtOp.gtOp2); // GT_CNS_INT
+ }
+ DEBUG_DESTROY_NODE(op1); // GT_ADD or GT_ADDR
+ DEBUG_DESTROY_NODE(tree); // GT_IND
- // If the result of the fold is a local var, we may need to perform further adjustments e.g. for
- // normalization.
- if (temp->OperIs(GT_LCL_VAR))
- {
+ // If the result of the fold is a local var, we may need to perform further adjustments e.g. for
+ // normalization.
+ if (temp->OperIs(GT_LCL_VAR))
+ {
#ifdef DEBUG
- // We clear this flag on `temp` because `fgMorphLocalVar` may assert that this bit is clear
- // and the node in question must have this bit set (as it has already been morphed).
- temp->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
+ // We clear this flag on `temp` because `fgMorphLocalVar` may assert that this bit is clear
+ // and the node in question must have this bit set (as it has already been morphed).
+ temp->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
#endif // DEBUG
- const bool forceRemorph = true;
- temp = fgMorphLocalVar(temp, forceRemorph);
+ const bool forceRemorph = true;
+ temp = fgMorphLocalVar(temp, forceRemorph);
#ifdef DEBUG
- // We then set this flag on `temp` because `fgMorhpLocalVar` may not set it itself, and the
- // caller of `fgMorphSmpOp` may assert that this flag is set on `temp` once this function
- // returns.
- temp->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+ // We then set this flag on `temp` because `fgMorhpLocalVar` may not set it itself, and the
+ // caller of `fgMorphSmpOp` may assert that this flag is set on `temp` once this function
+ // returns.
+ temp->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
#endif // DEBUG
- }
-
- return temp;
}
- // Only do this optimization when we are in the global optimizer. Doing this after value numbering
- // could result in an invalid value number for the newly generated GT_IND node.
- if ((op1->OperGet() == GT_COMMA) && fgGlobalMorph)
- {
- // Perform the transform IND(COMMA(x, ..., z)) == COMMA(x, ..., IND(z)).
- // TBD: this transformation is currently necessary for correctness -- it might
- // be good to analyze the failures that result if we don't do this, and fix them
- // in other ways. Ideally, this should be optional.
- GenTreePtr commaNode = op1;
- unsigned treeFlags = tree->gtFlags;
- commaNode->gtType = typ;
- commaNode->gtFlags = (treeFlags & ~GTF_REVERSE_OPS); // Bashing the GT_COMMA flags here is
- // dangerous, clear the GTF_REVERSE_OPS at
- // least.
-#ifdef DEBUG
- commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
-#endif
- while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
- {
- commaNode = commaNode->gtOp.gtOp2;
- commaNode->gtType = typ;
- commaNode->gtFlags =
- (treeFlags & ~GTF_REVERSE_OPS & ~GTF_ASG); // Bashing the GT_COMMA flags here is
+ return temp;
+ }
+
+ // Only do this optimization when we are in the global optimizer. Doing this after value numbering
+ // could result in an invalid value number for the newly generated GT_IND node.
+ if ((op1->OperGet() == GT_COMMA) && fgGlobalMorph)
+ {
+ // Perform the transform IND(COMMA(x, ..., z)) == COMMA(x, ..., IND(z)).
+ // TBD: this transformation is currently necessary for correctness -- it might
+ // be good to analyze the failures that result if we don't do this, and fix them
+ // in other ways. Ideally, this should be optional.
+ GenTreePtr commaNode = op1;
+ unsigned treeFlags = tree->gtFlags;
+ commaNode->gtType = typ;
+ commaNode->gtFlags = (treeFlags & ~GTF_REVERSE_OPS); // Bashing the GT_COMMA flags here is
// dangerous, clear the GTF_REVERSE_OPS at
// least.
- commaNode->gtFlags |=
- ((commaNode->gtOp.gtOp1->gtFlags & GTF_ASG) | (commaNode->gtOp.gtOp2->gtFlags & GTF_ASG));
#ifdef DEBUG
- commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+ commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
#endif
- }
- bool wasArrIndex = (tree->gtFlags & GTF_IND_ARR_INDEX) != 0;
- ArrayInfo arrInfo;
- if (wasArrIndex)
- {
- bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
- assert(b);
- GetArrayInfoMap()->Remove(tree);
- }
- tree = op1;
- GenTree* addr = commaNode->gtOp.gtOp2;
- op1 = gtNewIndir(typ, addr);
- // This is very conservative
- op1->gtFlags |= treeFlags & ~GTF_ALL_EFFECT & ~GTF_IND_NONFAULTING;
- op1->gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT);
-
- if (wasArrIndex)
- {
- GetArrayInfoMap()->Set(op1, arrInfo);
- }
+ while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
+ {
+ commaNode = commaNode->gtOp.gtOp2;
+ commaNode->gtType = typ;
+ commaNode->gtFlags =
+ (treeFlags & ~GTF_REVERSE_OPS & ~GTF_ASG); // Bashing the GT_COMMA flags here is
+ // dangerous, clear the GTF_REVERSE_OPS at
+ // least.
+ commaNode->gtFlags |=
+ ((commaNode->gtOp.gtOp1->gtFlags & GTF_ASG) | (commaNode->gtOp.gtOp2->gtFlags & GTF_ASG));
#ifdef DEBUG
- op1->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+ commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
#endif
- commaNode->gtOp.gtOp2 = op1;
- commaNode->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
- return tree;
}
-
- break;
-
- case GT_ADDR:
-
- // Can not remove op1 if it is currently a CSE candidate.
- if (gtIsActiveCSE_Candidate(op1))
+ bool wasArrIndex = (tree->gtFlags & GTF_IND_ARR_INDEX) != 0;
+ ArrayInfo arrInfo;
+ if (wasArrIndex)
{
- break;
+ bool b = GetArrayInfoMap()->Lookup(tree, &arrInfo);
+ assert(b);
+ GetArrayInfoMap()->Remove(tree);
}
+ tree = op1;
+ GenTree* addr = commaNode->gtOp.gtOp2;
+ op1 = gtNewIndir(typ, addr);
+ // This is very conservative
+ op1->gtFlags |= treeFlags & ~GTF_ALL_EFFECT & ~GTF_IND_NONFAULTING;
+ op1->gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT);
- if (op1->OperGet() == GT_IND)
+ if (wasArrIndex)
{
- if ((op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
- {
- // Can not remove a GT_ADDR if it is currently a CSE candidate.
- if (gtIsActiveCSE_Candidate(tree))
- {
- break;
- }
+ GetArrayInfoMap()->Set(op1, arrInfo);
+ }
+#ifdef DEBUG
+ op1->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+#endif
+ commaNode->gtOp.gtOp2 = op1;
+ commaNode->gtFlags |= (op1->gtFlags & GTF_ALL_EFFECT);
+ return tree;
+ }
- // Perform the transform ADDR(IND(...)) == (...).
- GenTreePtr addr = op1->gtOp.gtOp1;
+ break;
- noway_assert(varTypeIsGC(addr->gtType) || addr->gtType == TYP_I_IMPL);
+ case GT_ADDR:
- DEBUG_DESTROY_NODE(op1);
- DEBUG_DESTROY_NODE(tree);
+ // Can not remove op1 if it is currently a CSE candidate.
+ if (gtIsActiveCSE_Candidate(op1))
+ {
+ break;
+ }
- return addr;
- }
- }
- else if (op1->OperGet() == GT_OBJ)
+ if (op1->OperGet() == GT_IND)
+ {
+ if ((op1->gtFlags & GTF_IND_ARR_INDEX) == 0)
{
// Can not remove a GT_ADDR if it is currently a CSE candidate.
if (gtIsActiveCSE_Candidate(tree))
@@ -14076,8 +13910,8 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
break;
}
- // Perform the transform ADDR(OBJ(...)) == (...).
- GenTreePtr addr = op1->AsObj()->Addr();
+ // Perform the transform ADDR(IND(...)) == (...).
+ GenTreePtr addr = op1->gtOp.gtOp1;
noway_assert(varTypeIsGC(addr->gtType) || addr->gtType == TYP_I_IMPL);
@@ -14086,355 +13920,372 @@ GenTreePtr Compiler::fgMorphSmpOp(GenTreePtr tree, MorphAddrContext* mac)
return addr;
}
- else if (op1->gtOper == GT_CAST)
+ }
+ else if (op1->OperGet() == GT_OBJ)
+ {
+ // Can not remove a GT_ADDR if it is currently a CSE candidate.
+ if (gtIsActiveCSE_Candidate(tree))
{
- GenTreePtr casting = op1->gtCast.CastOp();
- if (casting->gtOper == GT_LCL_VAR || casting->gtOper == GT_CLS_VAR)
- {
- DEBUG_DESTROY_NODE(op1);
- tree->gtOp.gtOp1 = op1 = casting;
- }
+ break;
}
- else if ((op1->gtOper == GT_COMMA) && !optValnumCSE_phase)
- {
- // Perform the transform ADDR(COMMA(x, ..., z)) == COMMA(x, ..., ADDR(z)).
- // (Be sure to mark "z" as an l-value...)
- GenTreePtr commaNode = op1;
- while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
- {
- commaNode = commaNode->gtOp.gtOp2;
- }
- // The top-level addr might be annotated with a zeroOffset field.
- FieldSeqNode* zeroFieldSeq = nullptr;
- bool isZeroOffset = GetZeroOffsetFieldMap()->Lookup(tree, &zeroFieldSeq);
- tree = op1;
- commaNode->gtOp.gtOp2->gtFlags |= GTF_DONT_CSE;
-
- // If the node we're about to put under a GT_ADDR is an indirection, it
- // doesn't need to be materialized, since we only want the addressing mode. Because
- // of this, this GT_IND is not a faulting indirection and we don't have to extract it
- // as a side effect.
- GenTree* commaOp2 = commaNode->gtOp.gtOp2;
- if (commaOp2->OperIsBlk())
- {
- commaOp2 = fgMorphBlkToInd(commaOp2->AsBlk(), commaOp2->TypeGet());
- }
- if (commaOp2->gtOper == GT_IND)
- {
- commaOp2->gtFlags |= GTF_IND_NONFAULTING;
- commaOp2->gtFlags &= ~GTF_EXCEPT;
- commaOp2->gtFlags |= (commaOp2->gtOp.gtOp1->gtFlags & GTF_EXCEPT);
- }
- op1 = gtNewOperNode(GT_ADDR, TYP_BYREF, commaOp2);
+ // Perform the transform ADDR(OBJ(...)) == (...).
+ GenTreePtr addr = op1->AsObj()->Addr();
- if (isZeroOffset)
- {
- // Transfer the annotation to the new GT_ADDR node.
- GetZeroOffsetFieldMap()->Set(op1, zeroFieldSeq);
- }
- commaNode->gtOp.gtOp2 = op1;
- // Originally, I gave all the comma nodes type "byref". But the ADDR(IND(x)) == x transform
- // might give op1 a type different from byref (like, say, native int). So now go back and give
- // all the comma nodes the type of op1.
- // TODO: the comma flag update below is conservative and can be improved.
- // For example, if we made the ADDR(IND(x)) == x transformation, we may be able to
- // get rid of some of the the IND flags on the COMMA nodes (e.g., GTF_GLOB_REF).
- commaNode = tree;
- while (commaNode->gtOper == GT_COMMA)
- {
- commaNode->gtType = op1->gtType;
- commaNode->gtFlags |= op1->gtFlags;
-#ifdef DEBUG
- commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
-#endif
- commaNode = commaNode->gtOp.gtOp2;
- }
+ noway_assert(varTypeIsGC(addr->gtType) || addr->gtType == TYP_I_IMPL);
- tree->gtFlags &= ~GTF_EXCEPT;
+ DEBUG_DESTROY_NODE(op1);
+ DEBUG_DESTROY_NODE(tree);
- // Propagate the new flags
- tree->gtFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_EXCEPT);
- tree->gtFlags |= (tree->gtOp.gtOp2->gtFlags & GTF_EXCEPT);
+ return addr;
+ }
+ else if (op1->gtOper == GT_CAST)
+ {
+ GenTreePtr casting = op1->gtCast.CastOp();
+ if (casting->gtOper == GT_LCL_VAR || casting->gtOper == GT_CLS_VAR)
+ {
+ DEBUG_DESTROY_NODE(op1);
+ tree->gtOp.gtOp1 = op1 = casting;
+ }
+ }
+ else if ((op1->gtOper == GT_COMMA) && !optValnumCSE_phase)
+ {
+ // Perform the transform ADDR(COMMA(x, ..., z)) == COMMA(x, ..., ADDR(z)).
+ // (Be sure to mark "z" as an l-value...)
+ GenTreePtr commaNode = op1;
+ while (commaNode->gtOp.gtOp2->gtOper == GT_COMMA)
+ {
+ commaNode = commaNode->gtOp.gtOp2;
+ }
+ // The top-level addr might be annotated with a zeroOffset field.
+ FieldSeqNode* zeroFieldSeq = nullptr;
+ bool isZeroOffset = GetZeroOffsetFieldMap()->Lookup(tree, &zeroFieldSeq);
+ tree = op1;
+ commaNode->gtOp.gtOp2->gtFlags |= GTF_DONT_CSE;
- return tree;
+ // If the node we're about to put under a GT_ADDR is an indirection, it
+ // doesn't need to be materialized, since we only want the addressing mode. Because
+ // of this, this GT_IND is not a faulting indirection and we don't have to extract it
+ // as a side effect.
+ GenTree* commaOp2 = commaNode->gtOp.gtOp2;
+ if (commaOp2->OperIsBlk())
+ {
+ commaOp2 = fgMorphBlkToInd(commaOp2->AsBlk(), commaOp2->TypeGet());
+ }
+ if (commaOp2->gtOper == GT_IND)
+ {
+ commaOp2->gtFlags |= GTF_IND_NONFAULTING;
+ commaOp2->gtFlags &= ~GTF_EXCEPT;
+ commaOp2->gtFlags |= (commaOp2->gtOp.gtOp1->gtFlags & GTF_EXCEPT);
}
- /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
- op1->gtFlags |= GTF_DONT_CSE;
- break;
+ op1 = gtNewOperNode(GT_ADDR, TYP_BYREF, commaOp2);
- case GT_COLON:
- if (fgGlobalMorph)
+ if (isZeroOffset)
{
- /* Mark the nodes that are conditionally executed */
- fgWalkTreePre(&tree, gtMarkColonCond);
+ // Transfer the annotation to the new GT_ADDR node.
+ GetZeroOffsetFieldMap()->Set(op1, zeroFieldSeq);
+ }
+ commaNode->gtOp.gtOp2 = op1;
+ // Originally, I gave all the comma nodes type "byref". But the ADDR(IND(x)) == x transform
+ // might give op1 a type different from byref (like, say, native int). So now go back and give
+ // all the comma nodes the type of op1.
+ // TODO: the comma flag update below is conservative and can be improved.
+ // For example, if we made the ADDR(IND(x)) == x transformation, we may be able to
+ // get rid of some of the the IND flags on the COMMA nodes (e.g., GTF_GLOB_REF).
+ commaNode = tree;
+ while (commaNode->gtOper == GT_COMMA)
+ {
+ commaNode->gtType = op1->gtType;
+ commaNode->gtFlags |= op1->gtFlags;
+#ifdef DEBUG
+ commaNode->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
+#endif
+ commaNode = commaNode->gtOp.gtOp2;
}
- /* Since we're doing this postorder we clear this if it got set by a child */
- fgRemoveRestOfBlock = false;
- break;
- case GT_COMMA:
+ tree->gtFlags &= ~GTF_EXCEPT;
+
+ // Propagate the new flags
+ tree->gtFlags |= (tree->gtOp.gtOp1->gtFlags & GTF_EXCEPT);
+ tree->gtFlags |= (tree->gtOp.gtOp2->gtFlags & GTF_EXCEPT);
+
+ return tree;
+ }
+
+ /* op1 of a GT_ADDR is an l-value. Only r-values can be CSEed */
+ op1->gtFlags |= GTF_DONT_CSE;
+ break;
- /* Special case: trees that don't produce a value */
- if ((op2->OperKind() & GTK_ASGOP) || (op2->OperGet() == GT_COMMA && op2->TypeGet() == TYP_VOID) ||
- fgIsThrow(op2))
+ case GT_COLON:
+ if (fgGlobalMorph)
+ {
+ /* Mark the nodes that are conditionally executed */
+ fgWalkTreePre(&tree, gtMarkColonCond);
+ }
+ /* Since we're doing this postorder we clear this if it got set by a child */
+ fgRemoveRestOfBlock = false;
+ break;
+
+ case GT_COMMA:
+
+ /* Special case: trees that don't produce a value */
+ if (op2->OperIsAssignment() || (op2->OperGet() == GT_COMMA && op2->TypeGet() == TYP_VOID) || fgIsThrow(op2))
+ {
+ typ = tree->gtType = TYP_VOID;
+ }
+
+ // If we are in the Valuenum CSE phase then don't morph away anything as these
+ // nodes may have CSE defs/uses in them.
+ //
+ if (!optValnumCSE_phase)
+ {
+ // Extract the side effects from the left side of the comma. Since they don't "go" anywhere, this
+ // is all we need.
+
+ GenTreePtr op1SideEffects = nullptr;
+ // The addition of "GTF_MAKE_CSE" below prevents us from throwing away (for example)
+ // hoisted expressions in loops.
+ gtExtractSideEffList(op1, &op1SideEffects, (GTF_SIDE_EFFECT | GTF_MAKE_CSE));
+ if (op1SideEffects)
{
- typ = tree->gtType = TYP_VOID;
+ // Replace the left hand side with the side effect list.
+ tree->gtOp.gtOp1 = op1SideEffects;
+ tree->gtFlags |= (op1SideEffects->gtFlags & GTF_ALL_EFFECT);
}
-
- // If we are in the Valuenum CSE phase then don't morph away anything as these
- // nodes may have CSE defs/uses in them.
- //
- if (!optValnumCSE_phase)
+ else
{
- // Extract the side effects from the left side of the comma. Since they don't "go" anywhere, this
- // is all we need.
-
- GenTreePtr op1SideEffects = nullptr;
- // The addition of "GTF_MAKE_CSE" below prevents us from throwing away (for example)
- // hoisted expressions in loops.
- gtExtractSideEffList(op1, &op1SideEffects, (GTF_SIDE_EFFECT | GTF_MAKE_CSE));
- if (op1SideEffects)
- {
- // Replace the left hand side with the side effect list.
- tree->gtOp.gtOp1 = op1SideEffects;
- tree->gtFlags |= (op1SideEffects->gtFlags & GTF_ALL_EFFECT);
- }
- else
+ /* The left operand is worthless, throw it away */
+ if (lvaLocalVarRefCounted)
{
- /* The left operand is worthless, throw it away */
- if (lvaLocalVarRefCounted)
- {
- lvaRecursiveDecRefCounts(op1);
- }
- op2->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
- DEBUG_DESTROY_NODE(tree);
- DEBUG_DESTROY_NODE(op1);
- return op2;
+ lvaRecursiveDecRefCounts(op1);
}
+ op2->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
+ DEBUG_DESTROY_NODE(tree);
+ DEBUG_DESTROY_NODE(op1);
+ return op2;
+ }
- /* If the right operand is just a void nop node, throw it away */
- if (op2->IsNothingNode() && op1->gtType == TYP_VOID)
- {
- op1->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
- DEBUG_DESTROY_NODE(tree);
- DEBUG_DESTROY_NODE(op2);
- return op1;
- }
+ /* If the right operand is just a void nop node, throw it away */
+ if (op2->IsNothingNode() && op1->gtType == TYP_VOID)
+ {
+ op1->gtFlags |= (tree->gtFlags & (GTF_DONT_CSE | GTF_LATE_ARG));
+ DEBUG_DESTROY_NODE(tree);
+ DEBUG_DESTROY_NODE(op2);
+ return op1;
}
+ }
- break;
+ break;
- case GT_JTRUE:
+ case GT_JTRUE:
- /* Special case if fgRemoveRestOfBlock is set to true */
- if (fgRemoveRestOfBlock)
+ /* Special case if fgRemoveRestOfBlock is set to true */
+ if (fgRemoveRestOfBlock)
+ {
+ if (fgIsCommaThrow(op1, true))
{
- if (fgIsCommaThrow(op1, true))
- {
- GenTreePtr throwNode = op1->gtOp.gtOp1;
- noway_assert(throwNode->gtType == TYP_VOID);
+ GenTreePtr throwNode = op1->gtOp.gtOp1;
+ noway_assert(throwNode->gtType == TYP_VOID);
- return throwNode;
- }
+ return throwNode;
+ }
- noway_assert(op1->OperKind() & GTK_RELOP);
- noway_assert(op1->gtFlags & GTF_EXCEPT);
+ noway_assert(op1->OperKind() & GTK_RELOP);
+ noway_assert(op1->gtFlags & GTF_EXCEPT);
- // We need to keep op1 for the side-effects. Hang it off
- // a GT_COMMA node
+ // We need to keep op1 for the side-effects. Hang it off
+ // a GT_COMMA node
- tree->ChangeOper(GT_COMMA);
- tree->gtOp.gtOp2 = op2 = gtNewNothingNode();
+ tree->ChangeOper(GT_COMMA);
+ tree->gtOp.gtOp2 = op2 = gtNewNothingNode();
- // Additionally since we're eliminating the JTRUE
- // codegen won't like it if op1 is a RELOP of longs, floats or doubles.
- // So we change it into a GT_COMMA as well.
- op1->ChangeOper(GT_COMMA);
- op1->gtType = op1->gtOp.gtOp1->gtType;
+ // Additionally since we're eliminating the JTRUE
+ // codegen won't like it if op1 is a RELOP of longs, floats or doubles.
+ // So we change it into a GT_COMMA as well.
+ op1->ChangeOper(GT_COMMA);
+ op1->gtType = op1->gtOp.gtOp1->gtType;
- return tree;
- }
+ return tree;
+ }
- default:
- break;
- }
+ default:
+ break;
+ }
- assert(oper == tree->gtOper);
+ assert(oper == tree->gtOper);
- // If we are in the Valuenum CSE phase then don't morph away anything as these
- // nodes may have CSE defs/uses in them.
- //
- if (!optValnumCSE_phase && (oper != GT_ASG) && (oper != GT_COLON) && !tree->OperIsAnyList())
+ // If we are in the Valuenum CSE phase then don't morph away anything as these
+ // nodes may have CSE defs/uses in them.
+ //
+ if (!optValnumCSE_phase && (oper != GT_ASG) && (oper != GT_COLON) && !tree->OperIsAnyList())
+ {
+ /* Check for op1 as a GT_COMMA with a unconditional throw node */
+ if (op1 && fgIsCommaThrow(op1, true))
{
- /* Check for op1 as a GT_COMMA with a unconditional throw node */
- if (op1 && fgIsCommaThrow(op1, true))
+ if ((op1->gtFlags & GTF_COLON_COND) == 0)
{
- if ((op1->gtFlags & GTF_COLON_COND) == 0)
- {
- /* We can safely throw out the rest of the statements */
- fgRemoveRestOfBlock = true;
- }
+ /* We can safely throw out the rest of the statements */
+ fgRemoveRestOfBlock = true;
+ }
- GenTreePtr throwNode = op1->gtOp.gtOp1;
- noway_assert(throwNode->gtType == TYP_VOID);
+ GenTreePtr throwNode = op1->gtOp.gtOp1;
+ noway_assert(throwNode->gtType == TYP_VOID);
- if (oper == GT_COMMA)
- {
- /* Both tree and op1 are GT_COMMA nodes */
- /* Change the tree's op1 to the throw node: op1->gtOp.gtOp1 */
- tree->gtOp.gtOp1 = throwNode;
+ if (oper == GT_COMMA)
+ {
+ /* Both tree and op1 are GT_COMMA nodes */
+ /* Change the tree's op1 to the throw node: op1->gtOp.gtOp1 */
+ tree->gtOp.gtOp1 = throwNode;
- // Possibly reset the assignment flag
- if (((throwNode->gtFlags & GTF_ASG) == 0) && ((op2 == nullptr) || ((op2->gtFlags & GTF_ASG) == 0)))
- {
- tree->gtFlags &= ~GTF_ASG;
- }
+ // Possibly reset the assignment flag
+ if (((throwNode->gtFlags & GTF_ASG) == 0) && ((op2 == nullptr) || ((op2->gtFlags & GTF_ASG) == 0)))
+ {
+ tree->gtFlags &= ~GTF_ASG;
+ }
- return tree;
+ return tree;
+ }
+ else if (oper != GT_NOP)
+ {
+ if (genActualType(typ) == genActualType(op1->gtType))
+ {
+ /* The types match so, return the comma throw node as the new tree */
+ return op1;
}
- else if (oper != GT_NOP)
+ else
{
- if (genActualType(typ) == genActualType(op1->gtType))
+ if (typ == TYP_VOID)
{
- /* The types match so, return the comma throw node as the new tree */
- return op1;
+ // Return the throw node
+ return throwNode;
}
else
{
- if (typ == TYP_VOID)
+ GenTreePtr commaOp2 = op1->gtOp.gtOp2;
+
+ // need type of oper to be same as tree
+ if (typ == TYP_LONG)
+ {
+ commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
+ commaOp2->gtIntConCommon.SetLngValue(0);
+ /* Change the types of oper and commaOp2 to TYP_LONG */
+ op1->gtType = commaOp2->gtType = TYP_LONG;
+ }
+ else if (varTypeIsFloating(typ))
{
- // Return the throw node
- return throwNode;
+ commaOp2->ChangeOperConst(GT_CNS_DBL);
+ commaOp2->gtDblCon.gtDconVal = 0.0;
+ /* Change the types of oper and commaOp2 to TYP_DOUBLE */
+ op1->gtType = commaOp2->gtType = TYP_DOUBLE;
}
else
{
- GenTreePtr commaOp2 = op1->gtOp.gtOp2;
-
- // need type of oper to be same as tree
- if (typ == TYP_LONG)
- {
- commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
- commaOp2->gtIntConCommon.SetLngValue(0);
- /* Change the types of oper and commaOp2 to TYP_LONG */
- op1->gtType = commaOp2->gtType = TYP_LONG;
- }
- else if (varTypeIsFloating(typ))
- {
- commaOp2->ChangeOperConst(GT_CNS_DBL);
- commaOp2->gtDblCon.gtDconVal = 0.0;
- /* Change the types of oper and commaOp2 to TYP_DOUBLE */
- op1->gtType = commaOp2->gtType = TYP_DOUBLE;
- }
- else
- {
- commaOp2->ChangeOperConst(GT_CNS_INT);
- commaOp2->gtIntConCommon.SetIconValue(0);
- /* Change the types of oper and commaOp2 to TYP_INT */
- op1->gtType = commaOp2->gtType = TYP_INT;
- }
-
- /* Return the GT_COMMA node as the new tree */
- return op1;
+ commaOp2->ChangeOperConst(GT_CNS_INT);
+ commaOp2->gtIntConCommon.SetIconValue(0);
+ /* Change the types of oper and commaOp2 to TYP_INT */
+ op1->gtType = commaOp2->gtType = TYP_INT;
}
+
+ /* Return the GT_COMMA node as the new tree */
+ return op1;
}
}
}
+ }
+
+ /* Check for op2 as a GT_COMMA with a unconditional throw */
- /* Check for op2 as a GT_COMMA with a unconditional throw */
+ if (op2 && fgIsCommaThrow(op2, true))
+ {
+ if ((op2->gtFlags & GTF_COLON_COND) == 0)
+ {
+ /* We can safely throw out the rest of the statements */
+ fgRemoveRestOfBlock = true;
+ }
- if (op2 && fgIsCommaThrow(op2, true))
+ // If op1 has no side-effects
+ if ((op1->gtFlags & GTF_ALL_EFFECT) == 0)
{
- if ((op2->gtFlags & GTF_COLON_COND) == 0)
+ // If tree is an asg node
+ if (tree->OperIsAssignment())
{
- /* We can safely throw out the rest of the statements */
- fgRemoveRestOfBlock = true;
+ /* Return the throw node as the new tree */
+ return op2->gtOp.gtOp1;
}
- // If op1 has no side-effects
- if ((op1->gtFlags & GTF_ALL_EFFECT) == 0)
+ if (tree->OperGet() == GT_ARR_BOUNDS_CHECK)
{
- // If tree is an asg node
- if (tree->OperIsAssignment())
- {
- /* Return the throw node as the new tree */
- return op2->gtOp.gtOp1;
- }
-
- if (tree->OperGet() == GT_ARR_BOUNDS_CHECK)
- {
- /* Return the throw node as the new tree */
- return op2->gtOp.gtOp1;
- }
+ /* Return the throw node as the new tree */
+ return op2->gtOp.gtOp1;
+ }
- // If tree is a comma node
- if (tree->OperGet() == GT_COMMA)
- {
- /* Return the throw node as the new tree */
- return op2->gtOp.gtOp1;
- }
+ // If tree is a comma node
+ if (tree->OperGet() == GT_COMMA)
+ {
+ /* Return the throw node as the new tree */
+ return op2->gtOp.gtOp1;
+ }
- /* for the shift nodes the type of op2 can differ from the tree type */
- if ((typ == TYP_LONG) && (genActualType(op2->gtType) == TYP_INT))
- {
- noway_assert(GenTree::OperIsShiftOrRotate(oper));
+ /* for the shift nodes the type of op2 can differ from the tree type */
+ if ((typ == TYP_LONG) && (genActualType(op2->gtType) == TYP_INT))
+ {
+ noway_assert(GenTree::OperIsShiftOrRotate(oper));
- GenTreePtr commaOp2 = op2->gtOp.gtOp2;
+ GenTreePtr commaOp2 = op2->gtOp.gtOp2;
- commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
- commaOp2->gtIntConCommon.SetLngValue(0);
+ commaOp2->ChangeOperConst(GT_CNS_NATIVELONG);
+ commaOp2->gtIntConCommon.SetLngValue(0);
- /* Change the types of oper and commaOp2 to TYP_LONG */
- op2->gtType = commaOp2->gtType = TYP_LONG;
- }
+ /* Change the types of oper and commaOp2 to TYP_LONG */
+ op2->gtType = commaOp2->gtType = TYP_LONG;
+ }
- if ((genActualType(typ) == TYP_INT) &&
- (genActualType(op2->gtType) == TYP_LONG || varTypeIsFloating(op2->TypeGet())))
- {
- // An example case is comparison (say GT_GT) of two longs or floating point values.
+ if ((genActualType(typ) == TYP_INT) &&
+ (genActualType(op2->gtType) == TYP_LONG || varTypeIsFloating(op2->TypeGet())))
+ {
+ // An example case is comparison (say GT_GT) of two longs or floating point values.
- GenTreePtr commaOp2 = op2->gtOp.gtOp2;
+ GenTreePtr commaOp2 = op2->gtOp.gtOp2;
- commaOp2->ChangeOperConst(GT_CNS_INT);
- commaOp2->gtIntCon.gtIconVal = 0;
- /* Change the types of oper and commaOp2 to TYP_INT */
- op2->gtType = commaOp2->gtType = TYP_INT;
- }
+ commaOp2->ChangeOperConst(GT_CNS_INT);
+ commaOp2->gtIntCon.gtIconVal = 0;
+ /* Change the types of oper and commaOp2 to TYP_INT */
+ op2->gtType = commaOp2->gtType = TYP_INT;
+ }
- if ((typ == TYP_BYREF) && (genActualType(op2->gtType) == TYP_I_IMPL))
- {
- noway_assert(tree->OperGet() == GT_ADD);
+ if ((typ == TYP_BYREF) && (genActualType(op2->gtType) == TYP_I_IMPL))
+ {
+ noway_assert(tree->OperGet() == GT_ADD);
- GenTreePtr commaOp2 = op2->gtOp.gtOp2;
+ GenTreePtr commaOp2 = op2->gtOp.gtOp2;
- commaOp2->ChangeOperConst(GT_CNS_INT);
- commaOp2->gtIntCon.gtIconVal = 0;
- /* Change the types of oper and commaOp2 to TYP_BYREF */
- op2->gtType = commaOp2->gtType = TYP_BYREF;
- }
+ commaOp2->ChangeOperConst(GT_CNS_INT);
+ commaOp2->gtIntCon.gtIconVal = 0;
+ /* Change the types of oper and commaOp2 to TYP_BYREF */
+ op2->gtType = commaOp2->gtType = TYP_BYREF;
+ }
- /* types should now match */
- noway_assert((genActualType(typ) == genActualType(op2->gtType)));
+ /* types should now match */
+ noway_assert((genActualType(typ) == genActualType(op2->gtType)));
- /* Return the GT_COMMA node as the new tree */
- return op2;
- }
+ /* Return the GT_COMMA node as the new tree */
+ return op2;
}
}
+ }
- /*-------------------------------------------------------------------------
- * Optional morphing is done if tree transformations is permitted
- */
+ /*-------------------------------------------------------------------------
+ * Optional morphing is done if tree transformations is permitted
+ */
- if ((opts.compFlags & CLFLG_TREETRANS) == 0)
- {
- return tree;
- }
+ if ((opts.compFlags & CLFLG_TREETRANS) == 0)
+ {
+ return tree;
+ }
- tree = fgMorphSmpOpOptional(tree->AsOp());
+ tree = fgMorphSmpOpOptional(tree->AsOp());
- } // extra scope for gcc workaround
return tree;
}
#ifdef _PREFAST_
@@ -14533,19 +14384,12 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
switch (oper)
{
+#ifdef LEGACY_BACKEND
genTreeOps cmop;
bool dstIsSafeLclVar;
+#endif
case GT_ASG:
- /* We'll convert "a = a <op> x" into "a <op>= x" */
- /* and also "a = x <op> a" into "a <op>= x" for communative ops */
- CLANG_FORMAT_COMMENT_ANCHOR;
-
- if (typ == TYP_LONG)
- {
- break;
- }
-
if (varTypeIsStruct(typ) && !tree->IsPhiDefn())
{
if (tree->OperIsCopyBlkOp())
@@ -14558,6 +14402,11 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
}
}
+ if (typ == TYP_LONG)
+ {
+ break;
+ }
+
/* Make sure we're allowed to do this */
if (optValnumCSE_phase)
@@ -14566,6 +14415,10 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
break;
}
+#ifdef LEGACY_BACKEND
+ /* We'll convert "a = a <op> x" into "a <op>= x" */
+ /* and also "a = x <op> a" into "a <op>= x" for communative ops */
+
/* Are we assigning to a GT_LCL_VAR ? */
dstIsSafeLclVar = (op1->gtOper == GT_LCL_VAR);
@@ -14590,6 +14443,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
}
if (!dstIsSafeLclVar)
+#endif // LEGACY_BACKEND
{
if (op2->gtFlags & GTF_ASG)
{
@@ -14604,6 +14458,11 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
/* Special case: a cast that can be thrown away */
+ // TODO-Cleanup: fgMorphSmp does a similar optimization. However, it removes only
+ // one cast and sometimes there is another one after it that gets removed by this
+ // code. fgMorphSmp should be improved to remove all redundant casts so this code
+ // can be removed.
+
if (op1->gtOper == GT_IND && op2->gtOper == GT_CAST && !op2->gtOverflow())
{
var_types srct;
@@ -14622,6 +14481,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
}
}
+#ifdef LEGACY_BACKEND
/* Make sure we have the operator range right */
static_assert(GT_SUB == GT_ADD + 1, "bad oper value");
@@ -14878,7 +14738,7 @@ GenTree* Compiler::fgMorphSmpOpOptional(GenTreeOp* tree)
default:
break;
}
-
+#endif // LEGACY_BACKEND
break;
case GT_MUL:
@@ -15632,14 +15492,13 @@ GenTreePtr Compiler::fgMorphTree(GenTreePtr tree, MorphAddrContext* mac)
copy = new (this, GT_CALL) GenTreeCall(TYP_INT);
}
- copy->CopyFrom(tree, this);
+ copy->ReplaceWith(tree, this);
#if defined(LATE_DISASM)
- // GT_CNS_INT is considered small, so CopyFrom() won't copy all fields
+ // GT_CNS_INT is considered small, so ReplaceWith() won't copy all fields
if ((tree->gtOper == GT_CNS_INT) && tree->IsIconHandle())
{
- copy->gtIntCon.gtIconHdl.gtIconHdl1 = tree->gtIntCon.gtIconHdl.gtIconHdl1;
- copy->gtIntCon.gtIconHdl.gtIconHdl2 = tree->gtIntCon.gtIconHdl.gtIconHdl2;
+ copy->gtIntCon.gtCompileTimeHandle = tree->gtIntCon.gtCompileTimeHandle;
}
#endif
@@ -16499,7 +16358,11 @@ bool Compiler::fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(co
* for reentrant calls.
*/
+#ifdef LEGACY_BACKEND
void Compiler::fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loadw)
+#else
+void Compiler::fgMorphStmts(BasicBlock* block, bool* lnot, bool* loadw)
+#endif
{
fgRemoveRestOfBlock = false;
@@ -16507,7 +16370,10 @@ void Compiler::fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loa
compCurBB = block;
- *mult = *lnot = *loadw = false;
+ *lnot = *loadw = false;
+#ifdef LEGACY_BACKEND
+ *mult = false;
+#endif
fgCurrentlyInUseArgTemps = hashBv::Create(this);
@@ -16676,8 +16542,7 @@ void Compiler::fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loa
continue;
}
-#if OPT_MULT_ADDSUB
-
+#ifdef LEGACY_BACKEND
/* Note whether we have two or more +=/-= operators in a row */
if (tree->gtOper == GT_ASG_ADD || tree->gtOper == GT_ASG_SUB)
@@ -16688,14 +16553,13 @@ void Compiler::fgMorphStmts(BasicBlock* block, bool* mult, bool* lnot, bool* loa
}
}
-#endif
-
/* Note "x = a[i] & icon" followed by "x |= a[i] << 8" */
if (tree->gtOper == GT_ASG_OR && prev && prev->gtOper == GT_ASG)
{
*loadw = true;
}
+#endif // LEGACY_BACKEND
}
if (fgRemoveRestOfBlock)
@@ -16801,7 +16665,7 @@ void Compiler::fgMorphBlocks()
do
{
-#if OPT_MULT_ADDSUB
+#ifdef LEGACY_BACKEND
bool mult = false;
#endif
@@ -16830,17 +16694,16 @@ void Compiler::fgMorphBlocks()
}
#endif
- /* Process all statement trees in the basic block */
-
- GenTreePtr tree;
+/* Process all statement trees in the basic block */
+#ifndef LEGACY_BACKEND
+ fgMorphStmts(block, &lnot, &loadw);
+#else
fgMorphStmts(block, &mult, &lnot, &loadw);
-#if OPT_MULT_ADDSUB
-
if (mult && (opts.compFlags & CLFLG_TREETRANS) && !opts.compDbgCode && !opts.MinOpts())
{
- for (tree = block->bbTreeList; tree; tree = tree->gtNext)
+ for (GenTreePtr tree = block->bbTreeList; tree; tree = tree->gtNext)
{
assert(tree->gtOper == GT_STMT);
GenTreePtr last = tree->gtStmt.gtStmtExpr;
@@ -16996,7 +16859,7 @@ void Compiler::fgMorphBlocks()
}
}
-#endif
+#endif // LEGACY_BACKEND
/* Are we using a single return block? */
@@ -17997,6 +17860,8 @@ void Compiler::fgMorph()
#ifdef DEBUG
/* Inliner could add basic blocks. Check that the flowgraph data is up-to-date */
fgDebugCheckBBlist(false, false);
+ /* Inliner could clone some trees. */
+ fgDebugCheckNodesUniqueness();
#endif // DEBUG
fgRemoveEmptyTry();
@@ -18905,7 +18770,7 @@ GenTreePtr Compiler::fgMorphImplicitByRefArgs(GenTreePtr tree, bool isAddr)
if (fieldHnd == nullptr)
{
// change &X into just plain X
- tree->CopyFrom(lclVarTree, this);
+ tree->ReplaceWith(lclVarTree, this);
tree->gtType = TYP_BYREF;
}
else
@@ -19515,6 +19380,7 @@ bool Compiler::fgNodesMayInterfere(GenTree* write, GenTree* read)
}
}
+#ifdef LEGACY_BACKEND
/** This predicate decides whether we will fold a tree with the structure:
* x = x <op> y where x could be any arbitrary expression into
* x <op>= y.
@@ -19533,10 +19399,7 @@ bool Compiler::fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse)
#if CPU_LOAD_STORE_ARCH
/* In the case of a load/store architecture, there's no gain by doing any of this, we bail. */
return false;
-#elif !defined(LEGACY_BACKEND)
- return false;
-#else // defined(LEGACY_BACKEND)
-
+#else
GenTreePtr op1 = tree->gtOp.gtOp1;
GenTreePtr op2 = tree->gtGetOp2();
genTreeOps cmop = op2->OperGet();
@@ -19601,8 +19464,9 @@ bool Compiler::fgShouldCreateAssignOp(GenTreePtr tree, bool* bReverse)
}
}
return false;
-#endif // defined(LEGACY_BACKEND)
+#endif // !CPU_LOAD_STORE_ARCH
}
+#endif // LEGACY_BACKEND
#ifdef FEATURE_SIMD
@@ -19711,7 +19575,6 @@ bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, GenTreePtr
setLclRelatedToSIMDIntrinsic(localDst);
}
- GenTree* simdStructAddr;
if (simdStructNode->TypeGet() == TYP_BYREF)
{
assert(simdStructNode->OperIsLocal());
diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h
index 42786a0c9e..1144df6ad2 100644
--- a/src/jit/namedintrinsiclist.h
+++ b/src/jit/namedintrinsiclist.h
@@ -14,7 +14,7 @@ enum NamedIntrinsic : unsigned int
NI_MathF_Round = 2,
NI_Math_Round = 3,
NI_System_Collections_Generic_EqualityComparer_get_Default = 4,
-#ifdef _TARGET_XARCH_
+#if FEATURE_HW_INTRINSICS
NI_HW_INTRINSIC_START,
#define HARDWARE_INTRINSIC(id, name, isa) NI_##id,
#include "hwintrinsiclistxarch.h"
diff --git a/src/jit/nodeinfo.h b/src/jit/nodeinfo.h
index 3f8532bd37..5f03da2776 100644
--- a/src/jit/nodeinfo.h
+++ b/src/jit/nodeinfo.h
@@ -32,7 +32,6 @@ public:
regOptional = false;
definesAnyRegisters = false;
isInternalRegDelayFree = false;
- isNoRegCompare = false;
#ifdef DEBUG
isInitialized = false;
#endif
@@ -145,9 +144,6 @@ public:
// in which result is produced.
unsigned char isInternalRegDelayFree : 1;
- // True if this is a compare feeding a JTRUE that doesn't need to be generated into a register.
- unsigned char isNoRegCompare : 1;
-
#ifdef DEBUG
// isInitialized is set when the tree node is handled.
unsigned char isInitialized : 1;
diff --git a/src/jit/optcse.cpp b/src/jit/optcse.cpp
index bcb5a4c2a8..7c42852cec 100644
--- a/src/jit/optcse.cpp
+++ b/src/jit/optcse.cpp
@@ -871,9 +871,6 @@ void Compiler::optValnumCSE_InitDataFlow()
{
for (BasicBlock* block = fgFirstBB; block; block = block->bbNext)
{
- GenTreePtr stmt;
- GenTreePtr tree;
-
/* Initialize the blocks's bbCseIn set */
bool init_to_zero = false;
diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp
index 4aae376079..04285916ff 100644
--- a/src/jit/optimizer.cpp
+++ b/src/jit/optimizer.cpp
@@ -3173,12 +3173,16 @@ bool Compiler::optComputeLoopRep(int constInit,
switch (iterOper)
{
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
case GT_SUB:
iterInc = -iterInc;
__fallthrough;
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
case GT_ADD:
if (constInitX != constLimitX)
{
@@ -3207,15 +3211,17 @@ bool Compiler::optComputeLoopRep(int constInit,
*iterCount = loopCount;
return true;
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
- case GT_MUL:
case GT_ASG_DIV:
- case GT_DIV:
case GT_ASG_RSH:
- case GT_RSH:
case GT_ASG_LSH:
- case GT_LSH:
case GT_ASG_UDIV:
+#endif
+ case GT_MUL:
+ case GT_DIV:
+ case GT_RSH:
+ case GT_LSH:
case GT_UDIV:
return false;
@@ -3227,12 +3233,16 @@ bool Compiler::optComputeLoopRep(int constInit,
case GT_LT:
switch (iterOper)
{
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
case GT_SUB:
iterInc = -iterInc;
__fallthrough;
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
case GT_ADD:
if (constInitX < constLimitX)
{
@@ -3261,15 +3271,17 @@ bool Compiler::optComputeLoopRep(int constInit,
*iterCount = loopCount;
return true;
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
- case GT_MUL:
case GT_ASG_DIV:
- case GT_DIV:
case GT_ASG_RSH:
- case GT_RSH:
case GT_ASG_LSH:
- case GT_LSH:
case GT_ASG_UDIV:
+#endif
+ case GT_MUL:
+ case GT_DIV:
+ case GT_RSH:
+ case GT_LSH:
case GT_UDIV:
return false;
@@ -3281,12 +3293,16 @@ bool Compiler::optComputeLoopRep(int constInit,
case GT_LE:
switch (iterOper)
{
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
case GT_SUB:
iterInc = -iterInc;
__fallthrough;
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
case GT_ADD:
if (constInitX <= constLimitX)
{
@@ -3315,15 +3331,17 @@ bool Compiler::optComputeLoopRep(int constInit,
*iterCount = loopCount;
return true;
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
- case GT_MUL:
case GT_ASG_DIV:
- case GT_DIV:
case GT_ASG_RSH:
- case GT_RSH:
case GT_ASG_LSH:
- case GT_LSH:
case GT_ASG_UDIV:
+#endif
+ case GT_MUL:
+ case GT_DIV:
+ case GT_RSH:
+ case GT_LSH:
case GT_UDIV:
return false;
@@ -3335,12 +3353,16 @@ bool Compiler::optComputeLoopRep(int constInit,
case GT_GT:
switch (iterOper)
{
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
case GT_SUB:
iterInc = -iterInc;
__fallthrough;
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
case GT_ADD:
if (constInitX > constLimitX)
{
@@ -3369,15 +3391,17 @@ bool Compiler::optComputeLoopRep(int constInit,
*iterCount = loopCount;
return true;
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
- case GT_MUL:
case GT_ASG_DIV:
- case GT_DIV:
case GT_ASG_RSH:
- case GT_RSH:
case GT_ASG_LSH:
- case GT_LSH:
case GT_ASG_UDIV:
+#endif
+ case GT_MUL:
+ case GT_DIV:
+ case GT_RSH:
+ case GT_LSH:
case GT_UDIV:
return false;
@@ -3389,12 +3413,16 @@ bool Compiler::optComputeLoopRep(int constInit,
case GT_GE:
switch (iterOper)
{
+#ifdef LEGACY_BACKEND
case GT_ASG_SUB:
+#endif
case GT_SUB:
iterInc = -iterInc;
__fallthrough;
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
+#endif
case GT_ADD:
if (constInitX >= constLimitX)
{
@@ -3423,15 +3451,17 @@ bool Compiler::optComputeLoopRep(int constInit,
*iterCount = loopCount;
return true;
+#ifdef LEGACY_BACKEND
case GT_ASG_MUL:
- case GT_MUL:
case GT_ASG_DIV:
- case GT_DIV:
case GT_ASG_RSH:
- case GT_RSH:
case GT_ASG_LSH:
- case GT_LSH:
case GT_ASG_UDIV:
+#endif
+ case GT_MUL:
+ case GT_DIV:
+ case GT_RSH:
+ case GT_LSH:
case GT_UDIV:
return false;
@@ -5566,7 +5596,7 @@ bool Compiler::optNarrowTree(GenTreePtr tree, var_types srct, var_types dstt, Va
oper = tree->OperGet();
kind = tree->OperKind();
- if (kind & GTK_ASGOP)
+ if (GenTree::OperIsAssignment(oper))
{
noway_assert(doit == false);
return false;
@@ -5906,7 +5936,7 @@ Compiler::fgWalkResult Compiler::optIsVarAssgCB(GenTreePtr* pTree, fgWalkData* d
{
GenTreePtr tree = *pTree;
- if (tree->OperKind() & GTK_ASGOP)
+ if (tree->OperIsAssignment())
{
GenTreePtr dest = tree->gtOp.gtOp1;
genTreeOps destOper = dest->OperGet();
@@ -6473,7 +6503,6 @@ void Compiler::optHoistThisLoop(unsigned lnum, LoopHoistContext* hoistCtxt)
BasicBlock* head = pLoopDsc->lpHead;
BasicBlock* tail = pLoopDsc->lpBottom;
BasicBlock* lbeg = pLoopDsc->lpEntry;
- BasicBlock* block;
// We must have a do-while loop
if ((pLoopDsc->lpFlags & LPFLG_DO_WHILE) == 0)
@@ -8082,7 +8111,7 @@ GenTreePtr Compiler::optFindLocalInit(BasicBlock* block,
GenTreePtr tree = stmt->gtStmt.gtStmtExpr;
// If we encounter an assignment to a local variable,
- if ((tree->OperKind() & GTK_ASGOP) && tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)
+ if (tree->OperIsAssignment() && tree->gtOp.gtOp1->gtOper == GT_LCL_VAR)
{
// And the assigned variable equals the input local,
if (tree->gtOp.gtOp1->gtLclVarCommon.gtLclNum == LclNum)
@@ -8213,7 +8242,12 @@ bool Compiler::optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* contex
}
// TODO-CQ: CLONE: Mark increasing or decreasing loops.
- if ((pLoop->lpIterOper() != GT_ASG_ADD && pLoop->lpIterOper() != GT_ADD) || (pLoop->lpIterConst() != 1))
+ if ((
+#ifdef LEGACY_BACKEND
+ pLoop->lpIterOper() != GT_ASG_ADD &&
+#endif
+ pLoop->lpIterOper() != GT_ADD) ||
+ (pLoop->lpIterConst() != 1))
{
JITDUMP("> Loop iteration operator not matching\n");
return false;
@@ -8226,10 +8260,16 @@ bool Compiler::optIdentifyLoopOptInfo(unsigned loopNum, LoopCloneContext* contex
return false;
}
- if (!(((pLoop->lpTestOper() == GT_LT || pLoop->lpTestOper() == GT_LE) &&
- (pLoop->lpIterOper() == GT_ADD || pLoop->lpIterOper() == GT_ASG_ADD)) ||
- ((pLoop->lpTestOper() == GT_GT || pLoop->lpTestOper() == GT_GE) &&
- (pLoop->lpIterOper() == GT_SUB || pLoop->lpIterOper() == GT_ASG_SUB))))
+ if (!(((pLoop->lpTestOper() == GT_LT || pLoop->lpTestOper() == GT_LE) && (pLoop->lpIterOper() == GT_ADD
+#ifdef LEGACY_BACKEND
+ || pLoop->lpIterOper() == GT_ASG_ADD
+#endif
+ )) ||
+ ((pLoop->lpTestOper() == GT_GT || pLoop->lpTestOper() == GT_GE) && (pLoop->lpIterOper() == GT_SUB
+#ifdef LEGACY_BACKEND
+ || pLoop->lpIterOper() == GT_ASG_SUB
+#endif
+ ))))
{
JITDUMP("> Loop test (%s) doesn't agree with the direction (%s) of the pLoop->\n",
GenTree::OpName(pLoop->lpTestOper()), GenTree::OpName(pLoop->lpIterOper()));
diff --git a/src/jit/protojit/protojit.nativeproj b/src/jit/protojit/protojit.nativeproj
index 3de0f0aeed..bea7344893 100644
--- a/src/jit/protojit/protojit.nativeproj
+++ b/src/jit/protojit/protojit.nativeproj
@@ -39,7 +39,7 @@
<LinkModuleDefinitionFile>$(OutputName).def</LinkModuleDefinitionFile>
<ClDefines>$(ClDefines);ALT_JIT</ClDefines>
- <ClDefines Condition="'$(BuildArchitecture)' == 'amd64'">$(ClDefines);FEATURE_SIMD;FEATURE_AVX_SUPPORT</ClDefines>
+ <ClDefines Condition="'$(BuildArchitecture)' == 'amd64'">$(ClDefines);FEATURE_SIMD</ClDefines>
<Win32DllLibs>$(SdkLibPath)\kernel32.lib;$(SdkLibPath)\user32.lib;$(SdkLibPath)\advapi32.lib;$(SdkLibPath)\oleaut32.lib;$(SdkLibPath)\uuid.lib</Win32DllLibs>
<Win32DllLibs>$(Win32DllLibs);$(ClrLibPath)\utilcode.lib</Win32DllLibs>
diff --git a/src/jit/protononjit/CMakeLists.txt b/src/jit/protononjit/CMakeLists.txt
index f8d99381c5..33916c3cae 100644
--- a/src/jit/protononjit/CMakeLists.txt
+++ b/src/jit/protononjit/CMakeLists.txt
@@ -6,7 +6,8 @@ add_definitions(-DSELF_NO_HOST)
remove_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE)
remove_definitions(-DFEATURE_SIMD)
-remove_definitions(-DFEATURE_AVX_SUPPORT)
+
+remove_definitions(-DFEATURE_HW_INTRINSICS)
if(FEATURE_READYTORUN)
add_definitions(-DFEATURE_READYTORUN_COMPILER)
diff --git a/src/jit/rangecheck.cpp b/src/jit/rangecheck.cpp
index 803758095d..6dd2956811 100644
--- a/src/jit/rangecheck.cpp
+++ b/src/jit/rangecheck.cpp
@@ -384,16 +384,21 @@ bool RangeCheck::IsMonotonicallyIncreasing(GenTreePtr expr, SearchPath* path)
return false;
}
GenTreePtr asg = loc->parent;
- assert(asg->OperKind() & GTK_ASGOP);
+ assert(asg->OperIsAssignment());
switch (asg->OperGet())
{
case GT_ASG:
return IsMonotonicallyIncreasing(asg->gtGetOp2(), path);
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
return IsBinOpMonotonicallyIncreasing(asg->gtGetOp1(), asg->gtGetOp2(), GT_ADD, path);
+#endif
default:
+#ifndef LEGACY_BACKEND
+ noway_assert(false);
+#endif
// All other 'asg->OperGet()' kinds, return false
break;
}
@@ -857,7 +862,7 @@ Range RangeCheck::ComputeRangeForLocalDef(
}
#endif
GenTreePtr asg = loc->parent;
- assert(asg->OperKind() & GTK_ASGOP);
+ assert(asg->OperIsAssignment());
switch (asg->OperGet())
{
// If the operator of the definition is assignment, then compute the range of the rhs.
@@ -875,14 +880,19 @@ Range RangeCheck::ComputeRangeForLocalDef(
return range;
}
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
// If the operator of the definition is +=, then compute the range of the operands of +.
// Note that gtGetOp1 will return op1 to be the lhs; in the formulation of ssa, we have
// a side table for defs and the lhs of a += is considered to be a use for SSA numbering.
return ComputeRangeForBinOp(loc->block, loc->stmt, asg->gtGetOp1(), asg->gtGetOp2(), GT_ADD, path,
monotonic DEBUGARG(indent));
+#endif
default:
+#ifndef LEGACY_BACKEND
+ noway_assert(false);
+#endif
// All other 'asg->OperGet()' kinds, return Limit::keUnknown
break;
}
@@ -1034,17 +1044,22 @@ bool RangeCheck::DoesVarDefOverflow(BasicBlock* block, GenTreePtr stmt, GenTreeP
}
// Get the parent node which is an asg.
GenTreePtr asg = loc->parent;
- assert(asg->OperKind() & GTK_ASGOP);
+ assert(asg->OperIsAssignment());
switch (asg->OperGet())
{
case GT_ASG:
return DoesOverflow(loc->block, loc->stmt, asg->gtGetOp2(), path);
+#ifdef LEGACY_BACKEND
case GT_ASG_ADD:
// For GT_ASG_ADD, op2 is use, op1 is also use since we side table for defs in useasg case.
return DoesBinOpOverflow(loc->block, loc->stmt, asg->gtGetOp1(), asg->gtGetOp2(), path);
+#endif
default:
+#ifndef LEGACY_BACKEND
+ noway_assert(false);
+#endif
// All other 'asg->OperGet()' kinds, conservatively return true
break;
}
@@ -1283,7 +1298,7 @@ void RangeCheck::MapStmtDefs(const Location& loc)
if (ssaNum != SsaConfig::RESERVED_SSA_NUM)
{
// To avoid ind(addr) use asgs
- if (loc.parent->OperKind() & GTK_ASGOP)
+ if (loc.parent->OperIsAssignment())
{
SetDef(HashCode(lclNum, ssaNum), new (m_pCompiler->getAllocator()) Location(loc));
}
diff --git a/src/jit/regset.cpp b/src/jit/regset.cpp
index 44312dab42..a42a6cede3 100644
--- a/src/jit/regset.cpp
+++ b/src/jit/regset.cpp
@@ -407,6 +407,7 @@ void RegSet::rsUnlockReg(regMaskTP regMask, regMaskTP usedMask)
}
#endif // LEGACY_BACKEND
+#ifdef LEGACY_BACKEND
/*****************************************************************************
*
* Assume all registers contain garbage (called at start of codegen and when
@@ -419,6 +420,7 @@ void RegTracker::rsTrackRegClr()
assert(RV_TRASH == 0);
memset(rsRegValues, 0, sizeof(rsRegValues));
}
+#endif // LEGACY_BACKEND
/*****************************************************************************
*
@@ -432,11 +434,14 @@ void RegTracker::rsTrackRegTrash(regNumber reg)
regSet->rsSetRegsModified(genRegMask(reg));
+#ifdef LEGACY_BACKEND
/* Record the new value for the register */
rsRegValues[reg].rvdKind = RV_TRASH;
+#endif // LEGACY_BACKEND
}
+#ifdef LEGACY_BACKEND
/*****************************************************************************
*
* calls rsTrackRegTrash on the set of registers in regmask
@@ -460,6 +465,7 @@ void RegTracker::rsTrackRegMaskTrash(regMaskTP regMask)
}
}
}
+#endif // LEGACY_BACKEND
/*****************************************************************************/
@@ -472,12 +478,15 @@ void RegTracker::rsTrackRegIntCns(regNumber reg, ssize_t val)
regSet->rsSetRegsModified(genRegMask(reg));
+#ifdef LEGACY_BACKEND
/* Record the new value for the register */
rsRegValues[reg].rvdKind = RV_INT_CNS;
rsRegValues[reg].rvdIntCnsVal = val;
+#endif
}
+#ifdef LEGACY_BACKEND
/*****************************************************************************/
// inline
@@ -557,8 +566,6 @@ void RegTracker::rsTrackRegAssign(GenTree* op1, GenTree* op2)
}
}
-#ifdef LEGACY_BACKEND
-
/*****************************************************************************
*
* Given a regmask, find the best regPairNo that can be formed
@@ -1371,9 +1378,11 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var)
#if CPU_HAS_FP_SUPPORT
assert(varTypeIsFloating(varDsc->TypeGet()) == false);
#endif
+#ifdef LEGACY_BACKEND
// Kill the register before doing anything in case we take a
// shortcut out of here
rsRegValues[reg].rvdKind = RV_TRASH;
+#endif
if (compiler->lvaTable[var].lvAddrExposed)
{
@@ -1384,7 +1393,7 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var)
regSet->rsSetRegsModified(genRegMask(reg));
-#if REDUNDANT_LOAD
+#ifdef LEGACY_BACKEND
/* Is the variable a pointer? */
@@ -1409,8 +1418,6 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var)
return;
}
-#endif
-
#ifdef DEBUG
if (compiler->verbose)
{
@@ -1431,10 +1438,12 @@ void RegTracker::rsTrackRegLclVar(regNumber reg, unsigned var)
}
rsRegValues[reg].rvdLclVarNum = var;
+#endif // LEGACY_BACKEND
}
/*****************************************************************************/
+#ifdef LEGACY_BACKEND
void RegTracker::rsTrackRegSwap(regNumber reg1, regNumber reg2)
{
RegValDsc tmp;
@@ -1443,6 +1452,7 @@ void RegTracker::rsTrackRegSwap(regNumber reg1, regNumber reg2)
rsRegValues[reg1] = rsRegValues[reg2];
rsRegValues[reg2] = tmp;
}
+#endif // LEGACY_BACKEND
void RegTracker::rsTrackRegCopy(regNumber reg1, regNumber reg2)
{
@@ -1453,7 +1463,9 @@ void RegTracker::rsTrackRegCopy(regNumber reg1, regNumber reg2)
regSet->rsSetRegsModified(genRegMask(reg1));
+#ifdef LEGACY_BACKEND
rsRegValues[reg1] = rsRegValues[reg2];
+#endif // LEGACY_BACKEND
}
#ifdef LEGACY_BACKEND
@@ -2904,10 +2916,7 @@ var_types RegSet::rsRmvMultiReg(regNumber reg)
SpillDsc::freeDsc(this, dsc);
return type;
}
-#endif // LEGACY_BACKEND
-
/*****************************************************************************/
-#if REDUNDANT_LOAD
/*****************************************************************************
*
* Search for a register which contains the given constant value.
@@ -3173,6 +3182,7 @@ void RegTracker::rsTrashLcl(unsigned var)
}
}
}
+#endif // LEGACY_BACKEND
/*****************************************************************************
*
@@ -3197,6 +3207,7 @@ void RegTracker::rsTrashRegSet(regMaskTP regMask)
}
}
+#ifdef LEGACY_BACKEND
/*****************************************************************************
*
* Return a mask of registers that hold no useful value.
@@ -3222,7 +3233,7 @@ regMaskTP RegTracker::rsUselessRegs()
}
/*****************************************************************************/
-#endif // REDUNDANT_LOAD
+#endif // LEGACY_BACKEND
/*****************************************************************************/
/*
@@ -3845,7 +3856,7 @@ void RegSet::rsSpillChk()
#endif
/*****************************************************************************/
-#if REDUNDANT_LOAD
+#ifdef LEGACY_BACKEND
// inline
bool RegTracker::rsIconIsInReg(ssize_t val, regNumber reg)
@@ -3862,5 +3873,5 @@ bool RegTracker::rsIconIsInReg(ssize_t val, regNumber reg)
return false;
}
-#endif // REDUNDANT_LOAD
+#endif // LEGACY_BACKEND
/*****************************************************************************/
diff --git a/src/jit/regset.h b/src/jit/regset.h
index 9af5200290..d16cd95502 100644
--- a/src/jit/regset.h
+++ b/src/jit/regset.h
@@ -30,6 +30,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*/
+#ifdef LEGACY_BACKEND
/*****************************************************************************
*
* Keep track of the current state of each register. This is intended to be
@@ -45,6 +46,7 @@ enum regValKind
RV_LCL_VAR_LNG_LO, // lower half of long local variable
RV_LCL_VAR_LNG_HI,
};
+#endif // LEGACY_BACKEND
/*****************************************************************************/
@@ -403,6 +405,7 @@ private:
// Only integer registers are tracked.
//
+#ifdef LEGACY_BACKEND
struct RegValDsc
{
regValKind rvdKind;
@@ -411,32 +414,44 @@ struct RegValDsc
unsigned rvdLclVarNum; // for rvdKind == RV_LCL_VAR, RV_LCL_VAR_LNG_LO, RV_LCL_VAR_LNG_HI
};
};
+#endif // LEGACY_BACKEND
class RegTracker
{
Compiler* compiler;
RegSet* regSet;
+#ifdef LEGACY_BACKEND
RegValDsc rsRegValues[REG_COUNT];
+#endif
public:
void rsTrackInit(Compiler* comp, RegSet* rs)
{
compiler = comp;
regSet = rs;
+#ifdef LEGACY_BACKEND
rsTrackRegClr();
+#endif
}
+#ifdef LEGACY_BACKEND
void rsTrackRegClr();
void rsTrackRegClrPtr();
+#endif // LEGACY_BACKEND
void rsTrackRegTrash(regNumber reg);
+#ifdef LEGACY_BACKEND
void rsTrackRegMaskTrash(regMaskTP regMask);
regMaskTP rsTrashRegsForGCInterruptability();
+#endif // LEGACY_BACKEND
void rsTrackRegIntCns(regNumber reg, ssize_t val);
void rsTrackRegLclVar(regNumber reg, unsigned var);
+#ifdef LEGACY_BACKEND
void rsTrackRegLclVarLng(regNumber reg, unsigned var, bool low);
bool rsTrackIsLclVarLng(regValKind rvKind);
void rsTrackRegClsVar(regNumber reg, GenTreePtr clsVar);
+#endif // LEGACY_BACKEND
void rsTrackRegCopy(regNumber reg1, regNumber reg2);
+#ifdef LEGACY_BACKEND
void rsTrackRegSwap(regNumber reg1, regNumber reg2);
void rsTrackRegAssign(GenTree* op1, GenTree* op2);
@@ -445,16 +460,14 @@ public:
regNumber rsLclIsInReg(unsigned var);
regPairNo rsLclIsInRegPair(unsigned var);
-//---------------------- Load suppression ---------------------------------
-
-#if REDUNDANT_LOAD
+ //---------------------- Load suppression ---------------------------------
void rsTrashLclLong(unsigned var);
void rsTrashLcl(unsigned var);
+#endif // LEGACY_BACKEND
void rsTrashRegSet(regMaskTP regMask);
-
+#ifdef LEGACY_BACKEND
regMaskTP rsUselessRegs();
-
-#endif // REDUNDANT_LOAD
+#endif // LEGACY_BACKEND
};
#endif // _REGSET_H
diff --git a/src/jit/sideeffects.cpp b/src/jit/sideeffects.cpp
index e87abd3086..931ee6f8f4 100644
--- a/src/jit/sideeffects.cpp
+++ b/src/jit/sideeffects.cpp
@@ -263,6 +263,10 @@ void AliasSet::AddNode(Compiler* compiler, GenTree* node)
m_lclVarReads.Add(compiler, lclNum);
}
+ if (!operand->IsArgPlaceHolderNode() && operand->isContained())
+ {
+ AddNode(compiler, operand);
+ }
return GenTree::VisitResult::Continue;
});
diff --git a/src/jit/simd.cpp b/src/jit/simd.cpp
index 329a1d281f..490d1369f8 100644
--- a/src/jit/simd.cpp
+++ b/src/jit/simd.cpp
@@ -98,6 +98,8 @@ int Compiler::getSIMDTypeAlignment(var_types simdType)
assert(size == 32);
return 32;
}
+#elif defined(_TARGET_ARM64_)
+ return 16;
#else
assert(!"getSIMDTypeAlignment() unimplemented on target arch");
unreached();
@@ -691,8 +693,8 @@ GenTreePtr Compiler::impSIMDPopStack(var_types type, bool expectAddr)
}
else if (tree->gtType == TYP_BYREF)
{
- assert(tree->IsLocal() || (tree->OperGet() == GT_RET_EXPR) ||
- (tree->gtOper == GT_ADDR) && varTypeIsSIMD(tree->gtGetOp1()));
+ assert(tree->IsLocal() || (tree->OperGet() == GT_RET_EXPR) || (tree->OperGet() == GT_CALL) ||
+ ((tree->gtOper == GT_ADDR) && varTypeIsSIMD(tree->gtGetOp1())));
}
return tree;
@@ -938,7 +940,7 @@ SIMDIntrinsicID Compiler::impSIMDIntegralRelOpGreaterThanOrEqual(
// This routine should be used only for integer base type vectors
assert(varTypeIsIntegral(baseType));
- if ((getSIMDInstructionSet() == InstructionSet_SSE2) && ((baseType == TYP_LONG) || baseType == TYP_UBYTE))
+ if ((getSIMDSupportLevel() == SIMD_SSE2_Supported) && ((baseType == TYP_LONG) || baseType == TYP_UBYTE))
{
return impSIMDLongRelOpGreaterThanOrEqual(typeHnd, size, pOp1, pOp2);
}
@@ -1004,9 +1006,9 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
assert(isRelOpSIMDIntrinsic(relOpIntrinsicId));
-#ifdef _TARGET_XARCH_
SIMDIntrinsicID intrinsicID = relOpIntrinsicId;
- var_types baseType = *inOutBaseType;
+#ifdef _TARGET_XARCH_
+ var_types baseType = *inOutBaseType;
if (varTypeIsFloating(baseType))
{
@@ -1036,7 +1038,7 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
: SIMDIntrinsicGreaterThanOrEqual;
}
- if ((getSIMDInstructionSet() == InstructionSet_SSE2) && baseType == TYP_LONG)
+ if ((getSIMDSupportLevel() == SIMD_SSE2_Supported) && baseType == TYP_LONG)
{
// There is no direct SSE2 support for comparing TYP_LONG vectors.
// These have to be implemented interms of TYP_INT vector comparison operations.
@@ -1140,12 +1142,26 @@ SIMDIntrinsicID Compiler::impSIMDRelOp(SIMDIntrinsicID relOpIntrinsicId,
return impSIMDRelOp(intrinsicID, typeHnd, size, inOutBaseType, pOp1, pOp2);
}
}
+#elif defined(_TARGET_ARM64_)
+ // TODO-ARM64-CQ handle comparisons against zero
- return intrinsicID;
+ // _TARGET_ARM64_ doesn't support < and <= on register register comparisons
+ // Therefore, we need to use > and >= with swapped operands.
+ if (intrinsicID == SIMDIntrinsicLessThan || intrinsicID == SIMDIntrinsicLessThanOrEqual)
+ {
+ GenTree* tmp = *pOp1;
+ *pOp1 = *pOp2;
+ *pOp2 = tmp;
+
+ intrinsicID =
+ (intrinsicID == SIMDIntrinsicLessThan) ? SIMDIntrinsicGreaterThan : SIMDIntrinsicGreaterThanOrEqual;
+ }
#else // !_TARGET_XARCH_
assert(!"impSIMDRelOp() unimplemented on target arch");
unreached();
#endif // !_TARGET_XARCH_
+
+ return intrinsicID;
}
//-------------------------------------------------------------------------
@@ -1171,7 +1187,7 @@ GenTreePtr Compiler::impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType
// result = ConditionalSelect(BitVector, vector.Zero - v, v)
bool useConditionalSelect = false;
- if (getSIMDInstructionSet() == InstructionSet_SSE2)
+ if (getSIMDSupportLevel() == SIMD_SSE2_Supported)
{
// SSE2 doesn't support abs on signed integer type vectors.
if (baseType == TYP_LONG || baseType == TYP_INT || baseType == TYP_SHORT || baseType == TYP_BYTE)
@@ -1181,10 +1197,10 @@ GenTreePtr Compiler::impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType
}
else
{
- assert(getSIMDInstructionSet() >= InstructionSet_SSE3_4);
+ assert(getSIMDSupportLevel() >= SIMD_SSE4_Supported);
if (baseType == TYP_LONG)
{
- // SSE3_4/AVX2 don't support abs on long type vector.
+ // SSE4/AVX2 don't support abs on long type vector.
useConditionalSelect = true;
}
}
@@ -1284,12 +1300,22 @@ GenTreePtr Compiler::impSIMDAbs(CORINFO_CLASS_HANDLE typeHnd, var_types baseType
}
else
{
- assert(getSIMDInstructionSet() >= InstructionSet_SSE3_4);
+ assert(getSIMDSupportLevel() >= SIMD_SSE4_Supported);
assert(baseType != TYP_LONG);
retVal = gtNewSIMDNode(simdType, op1, SIMDIntrinsicAbs, baseType, size);
}
-#else // !_TARGET_XARCH_
+#elif defined(_TARGET_ARM64_)
+ if (varTypeIsUnsigned(baseType))
+ {
+ // Abs is a no-op on unsigned integer type vectors
+ retVal = op1;
+ }
+ else
+ {
+ retVal = gtNewSIMDNode(simdType, op1, SIMDIntrinsicAbs, baseType, size);
+ }
+#else // !defined(_TARGET_XARCH)_ && !defined(_TARGET_ARM64_)
assert(!"Abs intrinsic on non-xarch target not implemented");
#endif // !_TARGET_XARCH_
@@ -1317,6 +1343,8 @@ GenTreePtr Compiler::impSIMDSelect(
assert(op2->TypeGet() == simdType);
assert(op3->TypeGet() == simdType);
+ // TODO-ARM64-CQ Support generating select instruction for SIMD
+
// Select(BitVector vc, va, vb) = (va & vc) | (vb & !vc)
// Select(op1, op2, op3) = (op2 & op1) | (op3 & !op1)
// = SIMDIntrinsicBitwiseOr(SIMDIntrinsicBitwiseAnd(op2, op1),
@@ -1336,8 +1364,14 @@ GenTreePtr Compiler::impSIMDSelect(
GenTree* andExpr = gtNewSIMDNode(simdType, op2, tmp, SIMDIntrinsicBitwiseAnd, baseType, size);
GenTree* dupOp1 = gtCloneExpr(tmp);
assert(dupOp1 != nullptr);
+#ifdef _TARGET_ARM64_
+ // ARM64 implements SIMDIntrinsicBitwiseAndNot as Left & ~Right
+ GenTree* andNotExpr = gtNewSIMDNode(simdType, op3, dupOp1, SIMDIntrinsicBitwiseAndNot, baseType, size);
+#else
+ // XARCH implements SIMDIntrinsicBitwiseAndNot as ~Left & Right
GenTree* andNotExpr = gtNewSIMDNode(simdType, dupOp1, op3, SIMDIntrinsicBitwiseAndNot, baseType, size);
- GenTree* simdTree = gtNewSIMDNode(simdType, andExpr, andNotExpr, SIMDIntrinsicBitwiseOr, baseType, size);
+#endif
+ GenTree* simdTree = gtNewSIMDNode(simdType, andExpr, andNotExpr, SIMDIntrinsicBitwiseOr, baseType, size);
// If asg not null, create a GT_COMMA tree.
if (asg != nullptr)
@@ -1373,13 +1407,16 @@ GenTreePtr Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId,
var_types simdType = op1->TypeGet();
assert(op2->TypeGet() == simdType);
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
+ GenTree* simdTree = nullptr;
+
#ifdef _TARGET_XARCH_
// SSE2 has direct support for float/double/signed word/unsigned byte.
// SSE4.1 has direct support for int32/uint32/signed byte/unsigned word.
// For other integer types we compute min/max as follows
//
// int32/uint32 (SSE2)
- // int64/uint64 (SSE2&SSE3_4):
+ // int64/uint64 (SSE2&SSE4):
// compResult = (op1 < op2) in case of Min
// (op1 > op2) in case of Max
// Min/Max(op1, op2) = Select(compResult, op1, op2)
@@ -1396,10 +1433,8 @@ GenTreePtr Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId,
// result = SSE2 unsigned byte Min/Max(op1, op2)
// result = result - 2^15 ; readjust it back
- GenTree* simdTree = nullptr;
-
if (varTypeIsFloating(baseType) || baseType == TYP_SHORT || baseType == TYP_UBYTE ||
- (getSIMDInstructionSet() >= InstructionSet_SSE3_4 &&
+ (getSIMDSupportLevel() >= SIMD_SSE4_Supported &&
(baseType == TYP_BYTE || baseType == TYP_INT || baseType == TYP_UINT || baseType == TYP_CHAR)))
{
// SSE2 or SSE4.1 has direct support
@@ -1407,7 +1442,7 @@ GenTreePtr Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId,
}
else if (baseType == TYP_CHAR || baseType == TYP_BYTE)
{
- assert(getSIMDInstructionSet() == InstructionSet_SSE2);
+ assert(getSIMDSupportLevel() == SIMD_SSE2_Supported);
int constVal;
SIMDIntrinsicID operIntrinsic;
SIMDIntrinsicID adjustIntrinsic;
@@ -1449,6 +1484,19 @@ GenTreePtr Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId,
tmp = gtNewLclvNode(tmp->AsLclVarCommon()->GetLclNum(), tmp->TypeGet());
simdTree = gtNewSIMDNode(simdType, simdTree, tmp, adjustIntrinsic, baseType, size);
}
+#elif defined(_TARGET_ARM64_)
+ // Arm64 has direct support for all types except int64/uint64
+ // For which we compute min/max as follows
+ //
+ // int64/uint64
+ // compResult = (op1 < op2) in case of Min
+ // (op1 > op2) in case of Max
+ // Min/Max(op1, op2) = Select(compResult, op1, op2)
+ if (baseType != TYP_ULONG && baseType != TYP_LONG)
+ {
+ simdTree = gtNewSIMDNode(simdType, op1, op2, intrinsicId, baseType, size);
+ }
+#endif
else
{
GenTree* dupOp1 = nullptr;
@@ -1515,10 +1563,10 @@ GenTreePtr Compiler::impSIMDMinMax(SIMDIntrinsicID intrinsicId,
assert(simdTree != nullptr);
return simdTree;
-#else // !_TARGET_XARCH_
+#else // !(defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_))
assert(!"impSIMDMinMax() unimplemented on target arch");
unreached();
-#endif // !_TARGET_XARCH_
+#endif // !(defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_))
}
//------------------------------------------------------------------------
@@ -2407,7 +2455,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
case SIMDIntrinsicBitwiseOr:
case SIMDIntrinsicBitwiseXor:
{
-#if defined(_TARGET_XARCH_) && defined(DEBUG)
+#if defined(DEBUG)
// check for the cases where we don't support intrinsics.
// This check should be done before we make modifications to type stack.
// Note that this is more of a double safety check for robustness since
@@ -2418,6 +2466,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
{
if (simdIntrinsicID == SIMDIntrinsicMul)
{
+#if defined(_TARGET_XARCH_)
if ((baseType != TYP_INT) && (baseType != TYP_SHORT))
{
// TODO-CQ: implement mul on these integer vectors.
@@ -2425,8 +2474,18 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
assert(!"Mul not supported on long/ulong/uint/small int vectors\n");
return nullptr;
}
+#endif // _TARGET_XARCH_
+#if defined(_TARGET_ARM64_)
+ if ((baseType == TYP_ULONG) && (baseType == TYP_LONG))
+ {
+ // TODO-CQ: implement mul on these integer vectors.
+ // Note that ARM64 has no direct support for these vectors.
+ assert(!"Mul not supported on long/ulong vectors\n");
+ return nullptr;
+ }
+#endif // _TARGET_ARM64_
}
-
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
// common to all integer type vectors
if (simdIntrinsicID == SIMDIntrinsicDiv)
{
@@ -2434,8 +2493,9 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
assert(!"Div not supported on integer type vectors\n");
return nullptr;
}
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
}
-#endif // _TARGET_XARCH_ && DEBUG
+#endif // DEBUG
// op1 is the first operand; if instance method, op1 is "this" arg
// op2 is the second operand
@@ -2479,7 +2539,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
op2 = impSIMDPopStack(TYP_INT);
op1 = impSIMDPopStack(simdType, instMethod);
int vectorLength = getSIMDVectorLength(size, baseType);
- if (!op2->IsCnsIntOrI() || op2->AsIntCon()->gtIconVal >= vectorLength)
+ if (!op2->IsCnsIntOrI() || op2->AsIntCon()->gtIconVal >= vectorLength || op2->AsIntCon()->gtIconVal < 0)
{
// We need to bounds-check the length of the vector.
// For that purpose, we need to clone the index expression.
@@ -2514,8 +2574,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
#if defined(_TARGET_XARCH_)
// Right now dot product is supported only for float/double vectors and
// int vectors on SSE4/AVX.
- if (!varTypeIsFloating(baseType) &&
- !(baseType == TYP_INT && getSIMDInstructionSet() >= InstructionSet_SSE3_4))
+ if (!varTypeIsFloating(baseType) && !(baseType == TYP_INT && getSIMDSupportLevel() >= SIMD_SSE4_Supported))
{
return nullptr;
}
@@ -2537,8 +2596,8 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
case SIMDIntrinsicSqrt:
{
-#if defined(_TARGET_XARCH_) && defined(DEBUG)
- // SSE/AVX doesn't support sqrt on integer type vectors and hence
+#if (defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)) && defined(DEBUG)
+ // SSE/AVX/ARM64 doesn't support sqrt on integer type vectors and hence
// should never be seen as an intrinsic here. See SIMDIntrinsicList.h
// for supported base types for this intrinsic.
if (!varTypeIsFloating(baseType))
@@ -2546,7 +2605,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
assert(!"Sqrt not supported on integer vectors\n");
return nullptr;
}
-#endif // _TARGET_XARCH_ && DEBUG
+#endif // (defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)) && defined(DEBUG)
op1 = impSIMDPopStack(simdType);
@@ -2623,7 +2682,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
case SIMDIntrinsicConvertToInt64:
case SIMDIntrinsicConvertToUInt64:
{
-#ifdef _TARGET_AMD64_
+#ifdef _TARGET_64BIT_
op1 = impSIMDPopStack(simdType, instMethod);
simdTree = gtNewSIMDNode(simdType, op1, nullptr, simdIntrinsicID, baseType, size);
@@ -2687,15 +2746,15 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE opcode,
return nullptr;
}
-#ifdef _TARGET_XARCH_
- // XArch: also indicate that we use floating point registers.
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
+ // XArch/Arm64: also indicate that we use floating point registers.
// The need for setting this here is that a method may not have SIMD
// type lclvars, but might be exercising SIMD intrinsics on fields of
// SIMD type.
//
// e.g. public Vector<float> ComplexVecFloat::sqabs() { return this.r * this.r + this.i * this.i; }
compFloatingPointUsed = true;
-#endif // _TARGET_XARCH_
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
// At this point, we have a tree that we are going to store into a destination.
// TODO-1stClassStructs: This should be a simple store or assignment, and should not require
diff --git a/src/jit/simd.h b/src/jit/simd.h
index ff522fd52f..c1650482a5 100644
--- a/src/jit/simd.h
+++ b/src/jit/simd.h
@@ -5,6 +5,43 @@
#ifndef _SIMD_H_
#define _SIMD_H_
+// Underlying hardware information
+// This type is used to control
+// 1. The length of System.Numerics.Vector<T>.
+// 2. Codegen of System.Numerics.Vectors.
+// 3. Codegen of floating-point arithmetics (VEX-encoding or not).
+//
+// Note
+// - Hardware SIMD support is classified to the levels. Do not directly use
+// InstructionSet (instr.h) for System.Numerics.Vectors.
+// - Values of SIMDLevel have strictly increasing order that each SIMD level
+// is a superset of the previous levels.
+enum SIMDLevel
+{
+ SIMD_Not_Supported = 0,
+#ifdef _TARGET_XARCH_
+ // SSE2 - The min bar of SIMD ISA on x86/x64.
+ // Vector<T> length is 128-bit.
+ // Floating-point instructions are legacy SSE encoded.
+ SIMD_SSE2_Supported = 1,
+
+ // SSE4 - RyuJIT may generate SSE3, SSSE3, SSE4.1 and SSE4.2 instructions for certain intrinsics.
+ // Vector<T> length is 128-bit.
+ // Floating-point instructions are legacy SSE encoded.
+ SIMD_SSE4_Supported = 2,
+
+ // TODO - AVX - Hardware supports AVX instruction set.
+ // TODO - Vector<T> length is 128-bit and SIMD instructions are VEX-128 encoded.
+ // TODO - Floating-point instructions are VEX-128 encoded.
+ SIMD_AVX_Supported = 3,
+
+ // AVX2 - Hardware has AVX and AVX2 instruction set.
+ // Vector<T> length is 256-bit and SIMD instructions are VEX-256 encoded.
+ // Floating-point instructions are VEX-128 encoded.
+ SIMD_AVX2_Supported = 4,
+#endif
+};
+
#ifdef FEATURE_SIMD
#ifdef DEBUG
diff --git a/src/jit/simdcodegenxarch.cpp b/src/jit/simdcodegenxarch.cpp
index b7c9b29088..4db83b6f8d 100644
--- a/src/jit/simdcodegenxarch.cpp
+++ b/src/jit/simdcodegenxarch.cpp
@@ -205,7 +205,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
{
result = INS_pmullw;
}
- else if ((baseType == TYP_INT) && (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4))
+ else if ((baseType == TYP_INT) && (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported))
{
result = INS_pmulld;
}
@@ -243,7 +243,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
{
result = INS_pminsw;
}
- else if (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4)
+ else if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)
{
if (baseType == TYP_BYTE)
{
@@ -285,7 +285,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
{
result = INS_pmaxsw;
}
- else if (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4)
+ else if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)
{
if (baseType == TYP_BYTE)
{
@@ -311,7 +311,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
break;
case SIMDIntrinsicAbs:
- if (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4)
+ if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)
{
if (baseType == TYP_INT)
{
@@ -354,7 +354,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
result = INS_pcmpeqb;
}
else if ((baseType == TYP_ULONG || baseType == TYP_LONG) &&
- (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4))
+ (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported))
{
result = INS_pcmpeqq;
}
@@ -413,7 +413,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
{
result = INS_pcmpgtb;
}
- else if ((baseType == TYP_LONG) && (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4))
+ else if ((baseType == TYP_LONG) && (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported))
{
result = INS_pcmpgtq;
}
@@ -515,7 +515,7 @@ instruction CodeGen::getOpForSIMDIntrinsic(SIMDIntrinsicID intrinsicId, var_type
{
case TYP_INT:
case TYP_UINT:
- if (compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4)
+ if (compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported)
{
result = INS_packusdw;
}
@@ -671,8 +671,7 @@ void CodeGen::genSIMDScalarMove(
var_types targetType, var_types baseType, regNumber targetReg, regNumber srcReg, SIMDScalarMoveType moveType)
{
assert(varTypeIsFloating(baseType));
-#ifdef FEATURE_AVX_SUPPORT
- if (compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
switch (moveType)
{
@@ -719,7 +718,6 @@ void CodeGen::genSIMDScalarMove(
}
}
else
-#endif // FEATURE_AVX_SUPPORT
{
// SSE
@@ -786,9 +784,9 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->gtRegNum;
assert(targetReg != REG_NA);
- var_types targetType = simdNode->TypeGet();
- InstructionSet iset = compiler->getSIMDInstructionSet();
- unsigned size = simdNode->gtSIMDSize;
+ var_types targetType = simdNode->TypeGet();
+ SIMDLevel level = compiler->getSIMDSupportLevel();
+ unsigned size = simdNode->gtSIMDSize;
// Should never see small int base type vectors except for zero initialization.
noway_assert(!varTypeIsSmallInt(baseType) || op1->IsIntegralConst(0));
@@ -843,13 +841,11 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
ins = getOpForSIMDIntrinsic(SIMDIntrinsicBitwiseOr, baseType);
inst_RV_RV(ins, targetReg, tmpReg, targetType, emitActualTypeSize(targetType));
-#ifdef FEATURE_AVX_SUPPORT
if (compiler->canUseAVX())
{
inst_RV_RV(INS_vpbroadcastq, targetReg, targetReg, TYP_SIMD32, emitTypeSize(TYP_SIMD32));
}
else
-#endif // FEATURE_AVX_SUPPORT
{
ins = getOpForSIMDIntrinsic(SIMDIntrinsicShuffleSSE2, baseType);
getEmitter()->emitIns_R_R_I(ins, emitActualTypeSize(targetType), targetReg, targetReg, 0);
@@ -871,10 +867,9 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
ins = getOpForSIMDIntrinsic(SIMDIntrinsicEqual, TYP_INT);
inst_RV_RV(ins, targetReg, targetReg, targetType, emitActualTypeSize(targetType));
}
-#ifdef FEATURE_AVX_SUPPORT
else
{
- assert(iset == InstructionSet_AVX);
+ assert(level == SIMD_AVX2_Supported);
ins = getOpForSIMDIntrinsic(SIMDIntrinsicInit, baseType);
if (op1->IsCnsFltOrDbl())
{
@@ -891,9 +886,8 @@ void CodeGen::genSIMDIntrinsicInit(GenTreeSIMD* simdNode)
unreached();
}
}
-#endif // FEATURE_AVX_SUPPORT
}
- else if (iset == InstructionSet_AVX && ((size == 32) || (size == 16)))
+ else if (level == SIMD_AVX2_Supported && ((size == 32) || (size == 16)))
{
regNumber srcReg = genConsumeReg(op1);
if (baseType == TYP_INT || baseType == TYP_UINT || baseType == TYP_LONG || baseType == TYP_ULONG)
@@ -1145,7 +1139,7 @@ void CodeGen::genSIMDIntrinsic32BitConvert(GenTreeSIMD* simdNode)
getEmitter()->emitIns_R_I(INS_mov, EA_8BYTE, tmpIntReg, (ssize_t)0X5300000053000000);
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_ULONG);
#else
- if (compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
getEmitter()->emitIns_R_I(INS_mov, EA_4BYTE, tmpIntReg, (ssize_t)0X53000000);
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_UINT);
@@ -1158,7 +1152,7 @@ void CodeGen::genSIMDIntrinsic32BitConvert(GenTreeSIMD* simdNode)
getEmitter()->emitIns_R_R_I(INS_pinsrw, emitTypeSize(TYP_INT), tmpReg, tmpIntReg, 3);
}
#endif
- if (compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
inst_RV_RV(INS_vpbroadcastd, tmpReg, tmpReg, targetType, emitActualTypeSize(targetType));
}
@@ -1239,13 +1233,13 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->gtRegNum;
assert(targetReg != REG_NA);
- var_types simdType = simdNode->TypeGet();
- regNumber op1Reg = genConsumeReg(op1);
- regNumber tmpIntReg = simdNode->GetSingleTempReg(RBM_ALLINT);
- regNumber tmpReg;
- regNumber tmpReg2;
- regNumber tmpReg3;
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ var_types simdType = simdNode->TypeGet();
+ regNumber op1Reg = genConsumeReg(op1);
+ regNumber tmpIntReg = simdNode->GetSingleTempReg(RBM_ALLINT);
+ regNumber tmpReg;
+ regNumber tmpReg2;
+ regNumber tmpReg3;
+ SIMDLevel level = compiler->getSIMDSupportLevel();
#ifdef _TARGET_X86_
if (baseType == TYP_LONG)
@@ -1257,7 +1251,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
}
else
#endif
- if (iset == InstructionSet_AVX || (baseType == TYP_ULONG))
+ if (level == SIMD_AVX2_Supported || (baseType == TYP_ULONG))
{
tmpReg = simdNode->ExtractTempReg(RBM_ALLFLOAT);
tmpReg2 = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
@@ -1313,7 +1307,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_UINT);
getEmitter()->emitIns_R_I(INS_pslldq, EA_16BYTE, tmpReg, 4);
#endif
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
inst_RV_RV(INS_vpbroadcastq, tmpReg, tmpReg, simdType, emitActualTypeSize(simdType));
}
@@ -1335,7 +1329,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_UINT);
getEmitter()->emitIns_R_I(INS_pslldq, EA_16BYTE, tmpReg, 4);
#endif
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
inst_RV_RV(INS_vpbroadcastq, tmpReg, tmpReg, simdType, emitActualTypeSize(simdType));
}
@@ -1357,7 +1351,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
instruction rightShiftIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftRightInternal, TYP_SIMD16);
instruction leftShiftIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftLeftInternal, TYP_SIMD16);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
// Extract the high 16-bits
getEmitter()->emitIns_R_R_I(INS_vextracti128, EA_32BYTE, tmpReg, op1Reg, 0x01);
@@ -1395,7 +1389,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
inst_RV_RV(INS_movaps, targetReg, tmpReg, simdType, emitActualTypeSize(simdType));
}
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
getEmitter()->emitIns_R_R_I(INS_vinsertf128, EA_32BYTE, targetReg, tmpReg2, 0x01);
}
@@ -1425,7 +1419,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_UINT);
getEmitter()->emitIns_R_I(INS_pslldq, EA_16BYTE, tmpReg, 4);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
inst_RV_RV(INS_vpbroadcastq, tmpReg, tmpReg, simdType, emitActualTypeSize(simdType));
}
@@ -1443,7 +1437,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
inst_RV_RV(INS_mov_i2xmm, tmpReg, tmpIntReg, TYP_UINT);
getEmitter()->emitIns_R_I(INS_pslldq, EA_16BYTE, tmpReg, 4);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
inst_RV_RV(INS_vpbroadcastq, tmpReg, tmpReg, simdType, emitActualTypeSize(simdType));
}
@@ -1468,7 +1462,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
instruction rightShiftIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftRightInternal, TYP_SIMD16);
instruction leftShiftIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftLeftInternal, TYP_SIMD16);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
// Extract the high 16-bits
getEmitter()->emitIns_R_R_I(INS_vextractf128, EA_32BYTE, tmpReg, op1Reg, 0x01);
@@ -1504,7 +1498,7 @@ void CodeGen::genSIMDIntrinsic64BitConvert(GenTreeSIMD* simdNode)
// Merge or copy the results (only at this point are we done with op1Reg).
assert(tmpReg != targetReg);
inst_RV_RV(INS_por, targetReg, tmpReg, simdType, emitActualTypeSize(simdType));
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
getEmitter()->emitIns_R_R_I(INS_vinserti128, EA_32BYTE, targetReg, tmpReg2, 0x01);
}
@@ -1526,7 +1520,7 @@ void CodeGen::genSIMDExtractUpperHalf(GenTreeSIMD* simdNode, regNumber srcReg, r
{
var_types simdType = simdNode->TypeGet();
emitAttr emitSize = emitActualTypeSize(simdType);
- if (compiler->getSIMDInstructionSet() == InstructionSet_AVX)
+ if (compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported)
{
instruction extractIns = varTypeIsFloating(simdNode->gtSIMDBaseType) ? INS_vextractf128 : INS_vextracti128;
getEmitter()->emitIns_R_R_I(extractIns, EA_32BYTE, tgtReg, srcReg, 0x01);
@@ -1560,8 +1554,8 @@ void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode)
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->gtRegNum;
assert(targetReg != REG_NA);
- var_types simdType = simdNode->TypeGet();
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ var_types simdType = simdNode->TypeGet();
+ SIMDLevel level = compiler->getSIMDSupportLevel();
genConsumeOperands(simdNode);
regNumber op1Reg = op1->gtRegNum;
@@ -1588,7 +1582,7 @@ void CodeGen::genSIMDIntrinsicWiden(GenTreeSIMD* simdNode)
regNumber tmpReg = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
assert(tmpReg != op1Reg);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
// permute op1Reg and put it into targetReg
unsigned ival = 0xd4;
@@ -1633,9 +1627,9 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->gtRegNum;
assert(targetReg != REG_NA);
- var_types simdType = simdNode->TypeGet();
- emitAttr emitSize = emitTypeSize(simdType);
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ var_types simdType = simdNode->TypeGet();
+ emitAttr emitSize = emitTypeSize(simdType);
+ SIMDLevel level = compiler->getSIMDSupportLevel();
genConsumeOperands(simdNode);
regNumber op1Reg = op1->gtRegNum;
@@ -1658,7 +1652,7 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
}
else if (varTypeIsLong(baseType))
{
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
// We have 8 long elements, 0-3 in op1Reg, 4-7 in op2Reg.
// We will generate the following:
@@ -1720,7 +1714,7 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
instruction shiftLeftIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftLeftInternal, baseType);
instruction shiftRightIns = getOpForSIMDIntrinsic(SIMDIntrinsicShiftRightInternal, baseType);
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
regNumber tmpReg = simdNode->ExtractTempReg(RBM_ALLFLOAT);
regNumber tmpReg2 = simdNode->GetSingleTempReg(RBM_ALLFLOAT);
@@ -1744,7 +1738,7 @@ void CodeGen::genSIMDIntrinsicNarrow(GenTreeSIMD* simdNode)
inst_RV_RV(ins_Copy(simdType), tmpReg, op2Reg, simdType, emitSize);
instruction tmpShiftRight = shiftRightIns;
- if ((baseType == TYP_INT || baseType == TYP_UINT) && iset == InstructionSet_SSE2)
+ if ((baseType == TYP_INT || baseType == TYP_UINT) && level == SIMD_SSE2_Supported)
{
tmpShiftRight = INS_psrad;
}
@@ -1784,8 +1778,8 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
var_types baseType = simdNode->gtSIMDBaseType;
regNumber targetReg = simdNode->gtRegNum;
assert(targetReg != REG_NA);
- var_types targetType = simdNode->TypeGet();
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ var_types targetType = simdNode->TypeGet();
+ SIMDLevel level = compiler->getSIMDSupportLevel();
genConsumeOperands(simdNode);
regNumber op1Reg = op1->gtRegNum;
@@ -1796,7 +1790,7 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
// SSE2 doesn't have an instruction to perform this operation directly
// whereas SSE4.1 does (pmulld). This is special cased and computed
// as follows.
- if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul && baseType == TYP_INT && iset == InstructionSet_SSE2)
+ if (simdNode->gtSIMDIntrinsicID == SIMDIntrinsicMul && baseType == TYP_INT && level == SIMD_SSE2_Supported)
{
// We need a temporary register that is NOT the same as the target,
// and we MAY need another.
@@ -1958,12 +1952,12 @@ void CodeGen::genSIMDIntrinsicBinOp(GenTreeSIMD* simdNode)
//
void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
{
- GenTree* op1 = simdNode->gtGetOp1();
- GenTree* op2 = simdNode->gtGetOp2();
- var_types baseType = simdNode->gtSIMDBaseType;
- regNumber targetReg = simdNode->gtRegNum;
- var_types targetType = simdNode->TypeGet();
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ GenTree* op1 = simdNode->gtGetOp1();
+ GenTree* op2 = simdNode->gtGetOp2();
+ var_types baseType = simdNode->gtSIMDBaseType;
+ regNumber targetReg = simdNode->gtRegNum;
+ var_types targetType = simdNode->TypeGet();
+ SIMDLevel level = compiler->getSIMDSupportLevel();
genConsumeOperands(simdNode);
regNumber op1Reg = op1->gtRegNum;
@@ -1982,7 +1976,7 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
// TYP_INT comparison operations
if (baseType == TYP_LONG || baseType == TYP_ULONG)
{
- assert(iset >= InstructionSet_SSE3_4);
+ assert(level >= SIMD_SSE4_Supported);
}
#endif
@@ -2049,6 +2043,9 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
case SIMDIntrinsicOpEquality:
case SIMDIntrinsicOpInEquality:
{
+ // We're only setting condition flags, if a 0/1 value is desired then Lowering should have inserted a SETCC.
+ assert(targetReg == REG_NA);
+
var_types simdType = op1->TypeGet();
// TODO-1stClassStructs: Temporary to minimize asmDiffs
if (simdType == TYP_DOUBLE)
@@ -2064,9 +2061,9 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
}
// On SSE4/AVX, we can generate optimal code for (in)equality against zero using ptest.
- if ((compiler->getSIMDInstructionSet() >= InstructionSet_SSE3_4) && op2->IsIntegralConstVector(0))
+ if (op2->isContained())
{
- assert(op2->isContained());
+ assert((compiler->getSIMDSupportLevel() >= SIMD_SSE4_Supported) && op2->IsIntegralConstVector(0));
inst_RV_RV(INS_ptest, op1->gtRegNum, op1->gtRegNum, simdType, emitActualTypeSize(simdType));
}
else
@@ -2103,22 +2100,7 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
inst_RV_RV(ins, tmpReg1, otherReg, simdType, emitActualTypeSize(simdType));
}
- regNumber intReg;
- if (targetReg == REG_NA)
- {
- // If we are not materializing result into a register,
- // we would have reserved an int type internal register.
- intReg = simdNode->GetSingleTempReg(RBM_ALLINT);
- }
- else
- {
- // We can use targetReg for setting flags.
- intReg = targetReg;
-
- // Must have not reserved any int type internal registers.
- assert(simdNode->AvailableTempRegCount(RBM_ALLINT) == 0);
- }
-
+ regNumber intReg = simdNode->GetSingleTempReg(RBM_ALLINT);
inst_RV_RV(INS_pmovmskb, intReg, tmpReg1, simdType, emitActualTypeSize(simdType));
// There's no pmovmskw/pmovmskd/pmovmskq but they're not needed anyway. Vector compare
// instructions produce "all ones"/"all zeroes" components and pmovmskb extracts a
@@ -2147,27 +2129,6 @@ void CodeGen::genSIMDIntrinsicRelOp(GenTreeSIMD* simdNode)
}
getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, intReg, mask);
}
-
- if (targetReg != REG_NA)
- {
- // If we need to materialize result into a register, targetReg needs to
- // be set to 1 on true and zero on false.
- // Equality:
- // cmp targetReg, 0xFFFFFFFF or 0xFFFF
- // sete targetReg
- // movzx targetReg, targetReg
- //
- // InEquality:
- // cmp targetReg, 0xFFFFFFFF or 0xFFFF
- // setne targetReg
- // movzx targetReg, targetReg
- //
- assert(simdNode->TypeGet() == TYP_INT);
- inst_RV((simdNode->gtSIMDIntrinsicID == SIMDIntrinsicOpEquality) ? INS_sete : INS_setne, targetReg,
- TYP_INT, EA_1BYTE);
- // Set the higher bytes to 0
- inst_RV_RV(ins_Move_Extend(TYP_UBYTE, true), targetReg, targetReg, TYP_UBYTE, emitTypeSize(TYP_UBYTE));
- }
}
break;
@@ -2214,7 +2175,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
regNumber tmpReg1 = REG_NA;
regNumber tmpReg2 = REG_NA;
- InstructionSet iset = compiler->getSIMDInstructionSet();
+ SIMDLevel level = compiler->getSIMDSupportLevel();
// Dot product intrinsic is supported only on float/double vectors
// and 32-byte int vectors on AVX.
@@ -2231,7 +2192,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
// different from targetReg as scratch.
if (varTypeIsFloating(baseType))
{
- if ((compiler->getSIMDInstructionSet() == InstructionSet_SSE2) || (simdEvalType == TYP_SIMD32))
+ if ((compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported) || (simdEvalType == TYP_SIMD32))
{
tmpReg1 = simdNode->GetSingleTempReg();
assert(tmpReg1 != targetReg);
@@ -2244,9 +2205,9 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
else
{
assert(baseType == TYP_INT);
- assert(iset >= InstructionSet_SSE3_4);
+ assert(level >= SIMD_SSE4_Supported);
- if (iset == InstructionSet_SSE3_4)
+ if (level == SIMD_SSE4_Supported)
{
tmpReg1 = simdNode->GetSingleTempReg();
}
@@ -2257,7 +2218,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
}
}
- if (iset == InstructionSet_SSE2)
+ if (level == SIMD_SSE2_Supported)
{
// We avoid reg move if either op1Reg == targetReg or op2Reg == targetReg
if (op1Reg == targetReg)
@@ -2333,7 +2294,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
}
else
{
- assert(iset >= InstructionSet_SSE3_4);
+ assert(level >= SIMD_SSE4_Supported);
if (varTypeIsFloating(baseType))
{
@@ -2388,7 +2349,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
{
// On AVX, we have no 16-byte vectors of double. Note that, if we did, we could use
// dppd directly.
- assert(iset == InstructionSet_SSE3_4);
+ assert(level == SIMD_SSE4_Supported);
inst_RV_RV_IV(INS_dppd, emitSize, targetReg, op2Reg, 0x31);
}
}
@@ -2414,7 +2375,7 @@ void CodeGen::genSIMDIntrinsicDotProduct(GenTreeSIMD* simdNode)
#endif
// tmpReg1 = op1 * op2
- if (iset == InstructionSet_AVX)
+ if (level == SIMD_AVX2_Supported)
{
// On AVX take advantage 3 operand form of pmulld
inst_RV_RV_RV(INS_pmulld, tmpReg1, op1Reg, op2Reg, emitTypeSize(simdEvalType));
@@ -2611,7 +2572,7 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
if (byteShiftCnt >= 16)
{
- assert(compiler->getSIMDInstructionSet() == InstructionSet_AVX);
+ assert(compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported);
byteShiftCnt -= 16;
regNumber newSrcReg;
if (varTypeIsFloating(baseType))
@@ -2671,7 +2632,7 @@ void CodeGen::genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode)
// low 3 bits of index, but it's better to use the right value.
if (index > 8)
{
- assert(compiler->getSIMDInstructionSet() == InstructionSet_AVX);
+ assert(compiler->getSIMDSupportLevel() == SIMD_AVX2_Supported);
index -= 8;
}
@@ -2803,7 +2764,7 @@ void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
// logic needs modification.
noway_assert(baseType == TYP_FLOAT);
- if (compiler->getSIMDInstructionSet() == InstructionSet_SSE2)
+ if (compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported)
{
// We need one additional int register as scratch
regNumber tmpReg = simdNode->GetSingleTempReg();
@@ -2843,7 +2804,7 @@ void CodeGen::genSIMDIntrinsicSetItem(GenTreeSIMD* simdNode)
void CodeGen::genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode)
{
assert(simdNode->gtSIMDIntrinsicID == SIMDIntrinsicShuffleSSE2);
- noway_assert(compiler->getSIMDInstructionSet() == InstructionSet_SSE2);
+ noway_assert(compiler->getSIMDSupportLevel() == SIMD_SSE2_Supported);
GenTree* op1 = simdNode->gtGetOp1();
GenTree* op2 = simdNode->gtGetOp2();
diff --git a/src/jit/simdintrinsiclist.h b/src/jit/simdintrinsiclist.h
index 2eb4df38ca..2b59ec9058 100644
--- a/src/jit/simdintrinsiclist.h
+++ b/src/jit/simdintrinsiclist.h
@@ -20,7 +20,7 @@
e) TODO-Cleanup: when we plumb TYP_SIMD through front-end, replace TYP_STRUCT with TYP_SIMD.
*/
-#ifdef _TARGET_XARCH_
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM64_)
// Max number of parameters that we model in the table for SIMD intrinsic methods.
#define SIMD_INTRINSIC_MAX_MODELED_PARAM_COUNT 3
@@ -34,8 +34,8 @@
#define SIMD_INTRINSIC_MAX_BASETYPE_COUNT 10
/***************************************************************************************************************************************************************************************************************************
- Method Name, Is Instance Intrinsic Id, Display Name, return type, Arg count, Individual argument types SSE2 supported
- Method (including implicit "this") base types
+ Method Name, Is Instance Intrinsic Id, Display Name, return type, Arg count, Individual argument types Supported base types
+ Method (including implicit "this")
***************************************************************************************************************************************************************************************************************************/
SIMD_INTRINSIC(nullptr, false, None, "None", TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
@@ -86,7 +86,14 @@ SIMD_INTRINSIC("op_Inequality", false, OpInEquality,
// Arithmetic Operations
SIMD_INTRINSIC("op_Addition", false, Add, "+", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG})
SIMD_INTRINSIC("op_Subtraction", false, Sub, "-", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG})
+
+#if defined(_TARGET_XARCH_)
SIMD_INTRINSIC("op_Multiply", false, Mul, "*", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_SHORT,TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
+#elif defined(_TARGET_ARM64_)
+// TODO-ARM64-CQ Investigate code sequence to accelerate LONG/ULONG vector multiply
+SIMD_INTRINSIC("op_Multiply", false, Mul, "*", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF})
+#endif
+
SIMD_INTRINSIC("op_Division", false, Div, "/", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
// SquareRoot is recognized as an intrinsic only for float or double vectors
@@ -110,8 +117,13 @@ SIMD_INTRINSIC("op_BitwiseOr", false, BitwiseOr,
SIMD_INTRINSIC("op_ExclusiveOr", false, BitwiseXor, "^", TYP_STRUCT, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG})
// Dot Product
+#if defined(_TARGET_XARCH_)
// Is supported only on Vector<int> on AVX.
SIMD_INTRINSIC("Dot", false, DotProduct, "Dot", TYP_UNKNOWN, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
+#elif defined(_TARGET_ARM64_)
+// Dot Product does not support LONG/ULONG due to lack of multiply support (see TODO-ARM64-CQ above)
+SIMD_INTRINSIC("Dot", false, DotProduct, "Dot", TYP_UNKNOWN, 2, {TYP_STRUCT, TYP_STRUCT, TYP_UNDEF}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_UNDEF, TYP_UNDEF})
+#endif
// Select
SIMD_INTRINSIC("ConditionalSelect", false, Select, "Select", TYP_STRUCT, 3, {TYP_STRUCT, TYP_STRUCT, TYP_STRUCT}, {TYP_INT, TYP_FLOAT, TYP_DOUBLE, TYP_LONG, TYP_CHAR, TYP_UBYTE, TYP_BYTE, TYP_SHORT, TYP_UINT, TYP_ULONG})
@@ -139,6 +151,7 @@ SIMD_INTRINSIC("Widen", false, Widen,
// Miscellaneous
SIMD_INTRINSIC("get_IsHardwareAccelerated", false, HWAccel, "HWAccel", TYP_BOOL, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
+#ifdef _TARGET_XARCH_
// Shuffle and Shift operations - these are internal intrinsics as there is no corresponding managed method.
// To prevent this being accidentally recognized as an intrinsic, all of the arg types and supported base types is made TYP_UNDEF
SIMD_INTRINSIC("ShuffleSSE2", false, ShuffleSSE2, "ShuffleSSE2", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
@@ -146,6 +159,7 @@ SIMD_INTRINSIC("ShuffleSSE2", false, ShuffleSSE2,
// Internal, logical shift operations that shift the entire vector register instead of individual elements of the vector.
SIMD_INTRINSIC("ShiftLeftInternal", false, ShiftLeftInternal, "<< Internal", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
SIMD_INTRINSIC("ShiftRightInternal", false, ShiftRightInternal, ">> Internal", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
+#endif // _TARGET_XARCH_
// Internal intrinsics for saving & restoring the upper half of a vector register
SIMD_INTRINSIC("UpperSave", false, UpperSave, "UpperSave Internal", TYP_STRUCT, 2, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
@@ -157,10 +171,10 @@ SIMD_INTRINSIC("WidenLo", false, WidenLo,
SIMD_INTRINSIC(nullptr, false, Invalid, "Invalid", TYP_UNDEF, 0, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF}, {TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF, TYP_UNDEF})
#undef SIMD_INTRINSIC
-
-#else //_TARGET_XARCH_
+#else // !defined(_TARGET_XARCH_) && !defined(_TARGET_ARM64_)
#error SIMD intrinsics not defined for target arch
-#endif //!_TARGET_XARCH_
+#endif // !defined(_TARGET_XARCH_) && !defined(_TARGET_ARM64_)
+
#endif //FEATURE_SIMD
// clang-format on
diff --git a/src/jit/stackfp.cpp b/src/jit/stackfp.cpp
index 594c73e588..afdec7ec0b 100644
--- a/src/jit/stackfp.cpp
+++ b/src/jit/stackfp.cpp
@@ -3281,7 +3281,7 @@ GenTreePtr CodeGen::genMakeAddressableStackFP(GenTreePtr tree,
printf(" with value %lf\n", tree->gtDblCon.gtDconVal);
}
#endif // DEBUG
- tree->CopyFrom(addr, compiler);
+ tree->ReplaceWith(addr, compiler);
return tree;
}
break;
diff --git a/src/jit/target.h b/src/jit/target.h
index fd28796bd2..ad36689346 100644
--- a/src/jit/target.h
+++ b/src/jit/target.h
@@ -737,9 +737,9 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#ifdef FEATURE_SIMD
#define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
-#if defined(UNIX_AMD64_ABI) || !defined(FEATURE_AVX_SUPPORT)
+#if defined(UNIX_AMD64_ABI)
#define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 0 // Whether SIMD registers are partially saved at calls
-#else // !UNIX_AMD64_ABI && !FEATURE_AVX_SUPPORT
+#else // !UNIX_AMD64_ABI
#define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
#endif // !UNIX_AMD64_ABI
#endif
@@ -1248,6 +1248,8 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define RBM_CALLEE_TRASH_NOGC RBM_CALLEE_TRASH
#endif
#define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
+ #define REG_FASTTAILCALL_TARGET REG_R12 // Target register for fast tail call
+ #define RBM_FASTTAILCALL_TARGET RBM_R12
#define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
#define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
@@ -1527,6 +1529,11 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define CPBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll CpBlk.
#define INITBLK_UNROLL_LIMIT 64 // Upper bound to let the code generator to loop unroll InitBlk.
+#ifdef FEATURE_SIMD
+ #define ALIGN_SIMD_TYPES 1 // whether SIMD type locals are to be aligned
+ #define FEATURE_PARTIAL_SIMD_CALLEE_SAVE 1 // Whether SIMD registers are partially saved at calls
+#endif // FEATURE_SIMD
+
#define FEATURE_WRITE_BARRIER 1 // Generate the proper WriteBarrier calls for GC
#define FEATURE_FIXED_OUT_ARGS 1 // Preallocate the outgoing arg area in the prolog
#define FEATURE_STRUCTPROMOTE 1 // JIT Optimization to promote fields of structs into registers
@@ -1587,6 +1594,8 @@ typedef unsigned short regPairNoSmall; // arm: need 12 bits
#define RBM_CALLEE_TRASH (RBM_INT_CALLEE_TRASH | RBM_FLT_CALLEE_TRASH)
#define RBM_CALLEE_TRASH_NOGC (RBM_R12|RBM_R13|RBM_R14|RBM_R15|RBM_IP1)
#define REG_DEFAULT_HELPER_CALL_TARGET REG_R12
+ #define REG_FASTTAILCALL_TARGET REG_IP0 // Target register for fast tail call
+ #define RBM_FASTTAILCALL_TARGET RBM_IP0
#define RBM_ALLINT (RBM_INT_CALLEE_SAVED | RBM_INT_CALLEE_TRASH)
#define RBM_ALLFLOAT (RBM_FLT_CALLEE_SAVED | RBM_FLT_CALLEE_TRASH)
diff --git a/src/jit/unwind.cpp b/src/jit/unwind.cpp
index b354504bb7..643f15a39f 100644
--- a/src/jit/unwind.cpp
+++ b/src/jit/unwind.cpp
@@ -118,6 +118,299 @@ void Compiler::unwindGetFuncLocations(FuncInfoDsc* func,
#endif // FEATURE_EH_FUNCLETS
+#if defined(_TARGET_UNIX_)
+
+void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
+{
+ CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
+ func->cfiCodes->push_back(cfiEntry);
+}
+
+void Compiler::unwindPushCFI(regNumber reg)
+{
+ assert(compGeneratingProlog);
+
+ FuncInfoDsc* func = funCurrentFunc();
+
+ unsigned int cbProlog = unwindGetCurrentOffset(func);
+ noway_assert((BYTE)cbProlog == cbProlog);
+
+ createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, REGSIZE_BYTES == 8 ? 8 : 4);
+ if ((RBM_CALLEE_SAVED & genRegMask(reg))
+#if defined(UNIX_AMD64_ABI)
+#if ETW_EBP_FRAMED
+ // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
+ // is excluded from the callee-save register list.
+ // Make sure the register gets PUSH unwind info in this case,
+ // since it is pushed as a frame register.
+ || (reg == REG_FPBASE)
+#endif // ETW_EBP_FRAMED
+#endif
+ )
+ {
+ createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
+ }
+}
+
+template <typename T>
+inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
+{
+ return jitstd::allocator<T>(alloc).allocate(count);
+}
+
+typedef jitstd::vector<CFI_CODE> CFICodeVector;
+
+void Compiler::unwindBegPrologCFI()
+{
+ assert(compGeneratingProlog);
+
+#if FEATURE_EH_FUNCLETS
+ FuncInfoDsc* func = funCurrentFunc();
+
+ // There is only one prolog for a function/funclet, and it comes first. So now is
+ // a good time to initialize all the unwind data structures.
+
+ unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
+
+ if (fgFirstColdBlock != nullptr)
+ {
+ unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
+ }
+
+ jitstd::allocator<void> allocator(getAllocator());
+
+ func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
+#endif // FEATURE_EH_FUNCLETS
+}
+
+void Compiler::unwindPushMaskCFI(regMaskTP regMask, bool isFloat)
+{
+ regMaskTP regBit = isFloat ? genRegMask(REG_FP_FIRST) : 1;
+
+ for (regNumber regNum = isFloat ? REG_FP_FIRST : REG_FIRST; regNum < REG_COUNT;
+ regNum = REG_NEXT(regNum), regBit <<= 1)
+ {
+ if (regBit > regMask)
+ {
+ break;
+ }
+
+ if (regBit & regMask)
+ {
+ unwindPushCFI(regNum);
+ }
+ }
+}
+
+void Compiler::unwindAllocStackCFI(unsigned size)
+{
+ assert(compGeneratingProlog);
+
+ FuncInfoDsc* func = funCurrentFunc();
+
+ unsigned int cbProlog = unwindGetCurrentOffset(func);
+ noway_assert((BYTE)cbProlog == cbProlog);
+ createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
+}
+
+//------------------------------------------------------------------------
+// Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
+//
+// Arguments:
+// reg - The register being set as the frame register.
+// offset - The offset from the current stack pointer that the frame pointer will point at.
+//
+void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
+{
+ assert(compGeneratingProlog);
+ FuncInfoDsc* func = funCurrentFunc();
+
+ unsigned int cbProlog = unwindGetCurrentOffset(func);
+ noway_assert((BYTE)cbProlog == cbProlog);
+
+ createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
+ if (offset != 0)
+ {
+ // before: cfa = rsp + old_cfa_offset;
+ // rbp = rsp + offset;
+ // after: cfa should be based on rbp, but points to the old address:
+ // rsp + old_cfa_offset == rbp + old_cfa_offset + adjust;
+ // adjust = -offset;
+ int adjust = -(int)offset;
+ createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
+ }
+}
+
+void Compiler::unwindEmitFuncCFI(FuncInfoDsc* func, void* pHotCode, void* pColdCode)
+{
+ UNATIVE_OFFSET startOffset;
+ UNATIVE_OFFSET endOffset;
+ DWORD unwindCodeBytes = 0;
+ BYTE* pUnwindBlock = nullptr;
+
+ if (func->startLoc == nullptr)
+ {
+ startOffset = 0;
+ }
+ else
+ {
+ startOffset = func->startLoc->CodeOffset(genEmitter);
+ }
+
+ if (func->endLoc == nullptr)
+ {
+ endOffset = info.compNativeCodeSize;
+ }
+ else
+ {
+ endOffset = func->endLoc->CodeOffset(genEmitter);
+ }
+
+ DWORD size = (DWORD)func->cfiCodes->size();
+ if (size > 0)
+ {
+ unwindCodeBytes = size * sizeof(CFI_CODE);
+ pUnwindBlock = (BYTE*)&(*func->cfiCodes)[0];
+ }
+
+#ifdef DEBUG
+ if (opts.dspUnwind)
+ {
+ DumpCfiInfo(true /*isHotCode*/, startOffset, endOffset, unwindCodeBytes, (const CFI_CODE* const)pUnwindBlock);
+ }
+#endif // DEBUG
+
+ assert(endOffset <= info.compTotalHotCodeSize);
+
+ eeAllocUnwindInfo((BYTE*)pHotCode, nullptr /* pColdCode */, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
+ (CorJitFuncKind)func->funKind);
+
+ if (pColdCode != nullptr)
+ {
+ assert(fgFirstColdBlock != nullptr);
+ assert(func->funKind == FUNC_ROOT); // No splitting of funclets.
+
+ unwindCodeBytes = 0;
+ pUnwindBlock = nullptr;
+
+ if (func->coldStartLoc == nullptr)
+ {
+ startOffset = 0;
+ }
+ else
+ {
+ startOffset = func->coldStartLoc->CodeOffset(genEmitter);
+ }
+
+ if (func->coldEndLoc == nullptr)
+ {
+ endOffset = info.compNativeCodeSize;
+ }
+ else
+ {
+ endOffset = func->coldEndLoc->CodeOffset(genEmitter);
+ }
+
+#ifdef DEBUG
+ if (opts.dspUnwind)
+ {
+ DumpCfiInfo(false /*isHotCode*/, startOffset, endOffset, unwindCodeBytes,
+ (const CFI_CODE* const)pUnwindBlock);
+ }
+#endif // DEBUG
+
+ assert(startOffset >= info.compTotalHotCodeSize);
+ startOffset -= info.compTotalHotCodeSize;
+ endOffset -= info.compTotalHotCodeSize;
+
+ eeAllocUnwindInfo((BYTE*)pHotCode, (BYTE*)pColdCode, startOffset, endOffset, unwindCodeBytes, pUnwindBlock,
+ (CorJitFuncKind)func->funKind);
+ }
+}
+
+#ifdef DEBUG
+//------------------------------------------------------------------------
+// DumpCfiInfo: Dump the Cfi data.
+//
+// Arguments:
+// isHotCode - true if this cfi data is for the hot section, false otherwise.
+// startOffset - byte offset of the code start that this cfi data represents.
+// endOffset - byte offset of the code end that this cfi data represents.
+// pcFiCode - pointer to the cfi data blob.
+//
+void Compiler::DumpCfiInfo(bool isHotCode,
+ UNATIVE_OFFSET startOffset,
+ UNATIVE_OFFSET endOffset,
+ DWORD cfiCodeBytes,
+ const CFI_CODE* const pCfiCode)
+{
+ printf("Cfi Info%s:\n", isHotCode ? "" : " COLD");
+ printf(" >> Start offset : 0x%06x \n", dspOffset(startOffset));
+ printf(" >> End offset : 0x%06x \n", dspOffset(endOffset));
+
+ for (int i = 0; i < (int)(cfiCodeBytes / sizeof(CFI_CODE)); i++)
+ {
+ const CFI_CODE* const pCode = &(pCfiCode[i]);
+
+ UCHAR codeOffset = pCode->CodeOffset;
+ SHORT dwarfReg = pCode->DwarfReg;
+ INT offset = pCode->Offset;
+
+ switch (pCode->CfiOpCode)
+ {
+ case CFI_REL_OFFSET:
+ printf(" CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
+ offset);
+ break;
+ case CFI_DEF_CFA_REGISTER:
+ assert(offset == 0);
+ printf(" CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
+ break;
+ case CFI_ADJUST_CFA_OFFSET:
+ assert(dwarfReg == DWARF_REG_ILLEGAL);
+ printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
+ break;
+ default:
+ printf(" Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
+ break;
+ }
+ }
+}
+#endif // DEBUG
+
+#endif // _TARGET_UNIX_
+
+//------------------------------------------------------------------------
+// Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
+// prolog being generated.
+//
+// Arguments:
+// func - The main function or funclet of interest.
+//
+// Return Value:
+// The byte offset of the prolog currently being generated.
+//
+UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
+{
+ assert(compGeneratingProlog);
+ UNATIVE_OFFSET offset;
+ if (func->funKind == FUNC_ROOT)
+ {
+ offset = genEmitter->emitGetPrologOffsetEstimate();
+ }
+ else
+ {
+#if defined(_TARGET_AMD64_)
+ assert(func->startLoc != nullptr);
+ offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
+#else
+ offset = 0; // TODO ???
+#endif
+ }
+
+ return offset;
+}
+
#if defined(_TARGET_AMD64_)
// See unwindAmd64.cpp
diff --git a/src/jit/unwindamd64.cpp b/src/jit/unwindamd64.cpp
index 1b2baf6584..d4c077e4ec 100644
--- a/src/jit/unwindamd64.cpp
+++ b/src/jit/unwindamd64.cpp
@@ -127,41 +127,9 @@ int Compiler::mapRegNumToDwarfReg(regNumber reg)
return dwarfReg;
}
-void Compiler::createCfiCode(FuncInfoDsc* func, UCHAR codeOffset, UCHAR cfiOpcode, USHORT dwarfReg, INT offset)
-{
- CFI_CODE cfiEntry(codeOffset, cfiOpcode, dwarfReg, offset);
- func->cfiCodes->push_back(cfiEntry);
-}
#endif // UNIX_AMD64_ABI
//------------------------------------------------------------------------
-// Compiler::unwindGetCurrentOffset: Calculate the current byte offset of the
-// prolog being generated.
-//
-// Arguments:
-// func - The main function or funclet of interest.
-//
-// Return Value:
-// The byte offset of the prolog currently being generated.
-//
-UNATIVE_OFFSET Compiler::unwindGetCurrentOffset(FuncInfoDsc* func)
-{
- assert(compGeneratingProlog);
- UNATIVE_OFFSET offset;
- if (func->funKind == FUNC_ROOT)
- {
- offset = genEmitter->emitGetPrologOffsetEstimate();
- }
- else
- {
- assert(func->startLoc != nullptr);
- offset = func->startLoc->GetFuncletPrologOffset(genEmitter);
- }
-
- return offset;
-}
-
-//------------------------------------------------------------------------
// Compiler::unwindBegProlog: Initialize the unwind info data structures.
// Called at the beginning of main function or funclet prolog generation.
//
@@ -203,36 +171,6 @@ void Compiler::unwindBegPrologWindows()
func->unwindHeader.FrameOffset = 0;
}
-#ifdef UNIX_AMD64_ABI
-template <typename T>
-inline static T* allocate_any(jitstd::allocator<void>& alloc, size_t count = 5)
-{
- return jitstd::allocator<T>(alloc).allocate(count);
-}
-typedef jitstd::vector<CFI_CODE> CFICodeVector;
-
-void Compiler::unwindBegPrologCFI()
-{
- assert(compGeneratingProlog);
-
- FuncInfoDsc* func = funCurrentFunc();
-
- // There is only one prolog for a function/funclet, and it comes first. So now is
- // a good time to initialize all the unwind data structures.
-
- unwindGetFuncLocations(func, true, &func->startLoc, &func->endLoc);
-
- if (fgFirstColdBlock != nullptr)
- {
- unwindGetFuncLocations(func, false, &func->coldStartLoc, &func->coldEndLoc);
- }
-
- jitstd::allocator<void> allocator(getAllocator());
-
- func->cfiCodes = new (allocate_any<CFICodeVector>(allocator), jitstd::placement_t()) CFICodeVector(allocator);
-}
-#endif // UNIX_AMD64_ABI
-
//------------------------------------------------------------------------
// Compiler::unwindEndProlog: Called at the end of main function or funclet
// prolog generation to indicate there is no more unwind information for this prolog.
@@ -316,29 +254,6 @@ void Compiler::unwindPushWindows(regNumber reg)
}
#ifdef UNIX_AMD64_ABI
-void Compiler::unwindPushCFI(regNumber reg)
-{
- assert(compGeneratingProlog);
-
- FuncInfoDsc* func = funCurrentFunc();
-
- unsigned int cbProlog = unwindGetCurrentOffset(func);
- noway_assert((BYTE)cbProlog == cbProlog);
-
- createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, 8);
- if ((RBM_CALLEE_SAVED & genRegMask(reg))
-#if ETW_EBP_FRAMED
- // In case of ETW_EBP_FRAMED defined the REG_FPBASE (RBP)
- // is excluded from the callee-save register list.
- // Make sure the register gets PUSH unwind info in this case,
- // since it is pushed as a frame register.
- || (reg == REG_FPBASE)
-#endif // ETW_EBP_FRAMED
- )
- {
- createCfiCode(func, cbProlog, CFI_REL_OFFSET, mapRegNumToDwarfReg(reg));
- }
-}
#endif // UNIX_AMD64_ABI
//------------------------------------------------------------------------
@@ -401,19 +316,6 @@ void Compiler::unwindAllocStackWindows(unsigned size)
code->CodeOffset = (BYTE)cbProlog;
}
-#ifdef UNIX_AMD64_ABI
-void Compiler::unwindAllocStackCFI(unsigned size)
-{
- assert(compGeneratingProlog);
-
- FuncInfoDsc* func = funCurrentFunc();
-
- unsigned int cbProlog = unwindGetCurrentOffset(func);
- noway_assert((BYTE)cbProlog == cbProlog);
- createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, size);
-}
-#endif // UNIX_AMD64_ABI
-
//------------------------------------------------------------------------
// Compiler::unwindSetFrameReg: Record a frame register.
//
@@ -480,36 +382,6 @@ void Compiler::unwindSetFrameRegWindows(regNumber reg, unsigned offset)
}
}
-#ifdef UNIX_AMD64_ABI
-//------------------------------------------------------------------------
-// Compiler::unwindSetFrameRegCFI: Record a cfi info for a frame register set.
-//
-// Arguments:
-// reg - The register being set as the frame register.
-// offset - The offset from the current stack pointer that the frame pointer will point at.
-//
-void Compiler::unwindSetFrameRegCFI(regNumber reg, unsigned offset)
-{
- assert(compGeneratingProlog);
- FuncInfoDsc* func = funCurrentFunc();
-
- unsigned int cbProlog = unwindGetCurrentOffset(func);
- noway_assert((BYTE)cbProlog == cbProlog);
-
- createCfiCode(func, cbProlog, CFI_DEF_CFA_REGISTER, mapRegNumToDwarfReg(reg));
- if (offset != 0)
- {
- // before: cfa = rsp + old_cfa_offset;
- // rbp = rsp + offset;
- // after: cfa should be based on rbp, but points to the old address:
- // rsp + old_cfa_offset == rbp + old_cfa_offset + adjust;
- // adjust = -offset;
- int adjust = -(int)offset;
- createCfiCode(func, cbProlog, CFI_ADJUST_CFA_OFFSET, DWARF_REG_ILLEGAL, adjust);
- }
-}
-#endif // UNIX_AMD64_ABI
-
//------------------------------------------------------------------------
// Compiler::unwindSaveReg: Record a register save.
//
@@ -756,55 +628,6 @@ void DumpUnwindInfo(bool isHotCode,
}
}
-#ifdef UNIX_AMD64_ABI
-//------------------------------------------------------------------------
-// DumpCfiInfo: Dump the Cfi data.
-//
-// Arguments:
-// isHotCode - true if this cfi data is for the hot section, false otherwise.
-// startOffset - byte offset of the code start that this cfi data represents.
-// endOffset - byte offset of the code end that this cfi data represents.
-// pcFiCode - pointer to the cfi data blob.
-//
-void DumpCfiInfo(bool isHotCode,
- UNATIVE_OFFSET startOffset,
- UNATIVE_OFFSET endOffset,
- DWORD cfiCodeBytes,
- const CFI_CODE* const pCfiCode)
-{
- printf("Cfi Info%s:\n", isHotCode ? "" : " COLD");
- printf(" >> Start offset : 0x%06x \n", dspOffset(startOffset));
- printf(" >> End offset : 0x%06x \n", dspOffset(endOffset));
-
- for (int i = 0; i < cfiCodeBytes / sizeof(CFI_CODE); i++)
- {
- const CFI_CODE* const pCode = &(pCfiCode[i]);
-
- UCHAR codeOffset = pCode->CodeOffset;
- SHORT dwarfReg = pCode->DwarfReg;
- INT offset = pCode->Offset;
-
- switch (pCode->CfiOpCode)
- {
- case CFI_REL_OFFSET:
- printf(" CodeOffset: 0x%02X Op: RelOffset DwarfReg:0x%x Offset:0x%X\n", codeOffset, dwarfReg,
- offset);
- break;
- case CFI_DEF_CFA_REGISTER:
- assert(offset == 0);
- printf(" CodeOffset: 0x%02X Op: DefCfaRegister DwarfReg:0x%X\n", codeOffset, dwarfReg);
- break;
- case CFI_ADJUST_CFA_OFFSET:
- assert(dwarfReg == DWARF_REG_ILLEGAL);
- printf(" CodeOffset: 0x%02X Op: AdjustCfaOffset Offset:0x%X\n", codeOffset, offset);
- break;
- default:
- printf(" Unrecognized CFI_CODE: 0x%IX\n", *(UINT64*)pCode);
- break;
- }
- }
-}
-#endif // UNIX_AMD64_ABI
#endif // DEBUG
//------------------------------------------------------------------------
diff --git a/src/jit/unwindarm.cpp b/src/jit/unwindarm.cpp
index b537bef4a3..a3cb7a7277 100644
--- a/src/jit/unwindarm.cpp
+++ b/src/jit/unwindarm.cpp
@@ -16,6 +16,165 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#pragma hdrstop
#endif
+#if defined(_TARGET_ARM_) && defined(_TARGET_UNIX_)
+int Compiler::mapRegNumToDwarfReg(regNumber reg)
+{
+ int dwarfReg = DWARF_REG_ILLEGAL;
+
+ switch (reg)
+ {
+ case REG_R0:
+ dwarfReg = 0;
+ break;
+ case REG_R1:
+ dwarfReg = 1;
+ break;
+ case REG_R2:
+ dwarfReg = 2;
+ break;
+ case REG_R3:
+ dwarfReg = 3;
+ break;
+ case REG_R4:
+ dwarfReg = 4;
+ break;
+ case REG_R5:
+ dwarfReg = 5;
+ break;
+ case REG_R6:
+ dwarfReg = 6;
+ break;
+ case REG_R7:
+ dwarfReg = 7;
+ break;
+ case REG_R8:
+ dwarfReg = 8;
+ break;
+ case REG_R9:
+ dwarfReg = 9;
+ break;
+ case REG_R10:
+ dwarfReg = 10;
+ break;
+ case REG_R11:
+ dwarfReg = 11;
+ break;
+ case REG_R12:
+ dwarfReg = 12;
+ break;
+ case REG_R13:
+ dwarfReg = 13;
+ break;
+ case REG_R14:
+ dwarfReg = 14;
+ break;
+ case REG_R15:
+ dwarfReg = 15;
+ break;
+ case REG_F0:
+ dwarfReg = 64;
+ break;
+ case REG_F1:
+ dwarfReg = 65;
+ break;
+ case REG_F2:
+ dwarfReg = 66;
+ break;
+ case REG_F3:
+ dwarfReg = 67;
+ break;
+ case REG_F4:
+ dwarfReg = 68;
+ break;
+ case REG_F5:
+ dwarfReg = 69;
+ break;
+ case REG_F6:
+ dwarfReg = 70;
+ break;
+ case REG_F7:
+ dwarfReg = 71;
+ break;
+ case REG_F8:
+ dwarfReg = 72;
+ break;
+ case REG_F9:
+ dwarfReg = 73;
+ break;
+ case REG_F10:
+ dwarfReg = 74;
+ break;
+ case REG_F11:
+ dwarfReg = 75;
+ break;
+ case REG_F12:
+ dwarfReg = 76;
+ break;
+ case REG_F13:
+ dwarfReg = 77;
+ break;
+ case REG_F14:
+ dwarfReg = 78;
+ break;
+ case REG_F15:
+ dwarfReg = 79;
+ break;
+ case REG_F16:
+ dwarfReg = 80;
+ break;
+ case REG_F17:
+ dwarfReg = 81;
+ break;
+ case REG_F18:
+ dwarfReg = 82;
+ break;
+ case REG_F19:
+ dwarfReg = 83;
+ break;
+ case REG_F20:
+ dwarfReg = 84;
+ break;
+ case REG_F21:
+ dwarfReg = 85;
+ break;
+ case REG_F22:
+ dwarfReg = 86;
+ break;
+ case REG_F23:
+ dwarfReg = 87;
+ break;
+ case REG_F24:
+ dwarfReg = 88;
+ break;
+ case REG_F25:
+ dwarfReg = 89;
+ break;
+ case REG_F26:
+ dwarfReg = 90;
+ break;
+ case REG_F27:
+ dwarfReg = 91;
+ break;
+ case REG_F28:
+ dwarfReg = 92;
+ break;
+ case REG_F29:
+ dwarfReg = 93;
+ break;
+ case REG_F30:
+ dwarfReg = 94;
+ break;
+ case REG_F31:
+ dwarfReg = 95;
+ break;
+ default:
+ noway_assert(!"unexpected REG_NUM");
+ }
+
+ return dwarfReg;
+}
+#endif // _TARGET_ARM_ && _TARGET_UNIX_
+
#ifdef _TARGET_ARMARCH_
/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -31,6 +190,14 @@ void Compiler::unwindBegProlog()
{
assert(compGeneratingProlog);
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ unwindBegPrologCFI();
+ return;
+ }
+#endif // _TARGET_UNIX_
+
FuncInfoDsc* func = funCurrentFunc();
// There is only one prolog for a function/funclet, and it comes first. So now is
@@ -54,6 +221,14 @@ void Compiler::unwindEndProlog()
void Compiler::unwindBegEpilog()
{
assert(compGeneratingEpilog);
+
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
funCurrentFunc()->uwi.AddEpilog();
}
@@ -193,6 +368,14 @@ void Compiler::unwindPushMaskInt(regMaskTP maskInt)
~(RBM_R0 | RBM_R1 | RBM_R2 | RBM_R3 | RBM_R4 | RBM_R5 | RBM_R6 | RBM_R7 | RBM_R8 | RBM_R9 | RBM_R10 |
RBM_R11 | RBM_R12 | RBM_LR)) == 0);
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ unwindPushMaskCFI(maskInt, false);
+ return;
+ }
+#endif // _TARGET_UNIX_
+
bool useOpsize16 = ((maskInt & (RBM_LOW_REGS | RBM_LR)) == maskInt); // Can PUSH use the 16-bit encoding?
unwindPushPopMaskInt(maskInt, useOpsize16);
}
@@ -201,11 +384,27 @@ void Compiler::unwindPushMaskFloat(regMaskTP maskFloat)
{
// Only floating point registers should be in maskFloat
assert((maskFloat & RBM_ALLFLOAT) == maskFloat);
+
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ unwindPushMaskCFI(maskFloat, true);
+ return;
+ }
+#endif // _TARGET_UNIX_
+
unwindPushPopMaskFloat(maskFloat);
}
void Compiler::unwindPopMaskInt(regMaskTP maskInt)
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
// Only r0-r12 and lr and pc are supported (pc is mapped to lr when encoding)
assert((maskInt &
~(RBM_R0 | RBM_R1 | RBM_R2 | RBM_R3 | RBM_R4 | RBM_R5 | RBM_R6 | RBM_R7 | RBM_R8 | RBM_R9 | RBM_R10 |
@@ -227,6 +426,13 @@ void Compiler::unwindPopMaskInt(regMaskTP maskInt)
void Compiler::unwindPopMaskFloat(regMaskTP maskFloat)
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
// Only floating point registers should be in maskFloat
assert((maskFloat & RBM_ALLFLOAT) == maskFloat);
unwindPushPopMaskFloat(maskFloat);
@@ -234,6 +440,17 @@ void Compiler::unwindPopMaskFloat(regMaskTP maskFloat)
void Compiler::unwindAllocStack(unsigned size)
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ if (compGeneratingProlog)
+ {
+ unwindAllocStackCFI(size);
+ }
+ return;
+ }
+#endif // _TARGET_UNIX_
+
UnwindInfo* pu = &funCurrentFunc()->uwi;
assert(size % 4 == 0);
@@ -277,6 +494,17 @@ void Compiler::unwindAllocStack(unsigned size)
void Compiler::unwindSetFrameReg(regNumber reg, unsigned offset)
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ if (compGeneratingProlog)
+ {
+ unwindSetFrameRegCFI(reg, offset);
+ }
+ return;
+ }
+#endif // _TARGET_UNIX_
+
UnwindInfo* pu = &funCurrentFunc()->uwi;
// Arm unwind info does not allow offset
@@ -294,6 +522,13 @@ void Compiler::unwindSaveReg(regNumber reg, unsigned offset)
void Compiler::unwindBranch16()
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
UnwindInfo* pu = &funCurrentFunc()->uwi;
// TODO-CQ: need to handle changing the exit code from 0xFF to 0xFD. Currently, this will waste an extra 0xFF at the
@@ -303,6 +538,13 @@ void Compiler::unwindBranch16()
void Compiler::unwindNop(unsigned codeSizeInBytes) // codeSizeInBytes is 2 or 4 bytes for Thumb2 instruction
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
UnwindInfo* pu = &funCurrentFunc()->uwi;
#ifdef DEBUG
@@ -337,6 +579,13 @@ void Compiler::unwindNop(unsigned codeSizeInBytes) // codeSizeInBytes is 2 or 4
// for them.
void Compiler::unwindPadding()
{
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ return;
+ }
+#endif // _TARGET_UNIX_
+
UnwindInfo* pu = &funCurrentFunc()->uwi;
genEmitter->emitUnwindNopPadding(pu->GetCurrentEmitterLocation(), this);
}
@@ -345,6 +594,9 @@ void Compiler::unwindPadding()
// all its funclets.
void Compiler::unwindReserve()
{
+ assert(!compGeneratingProlog);
+ assert(!compGeneratingEpilog);
+
assert(compFuncInfoCount > 0);
for (unsigned funcIdx = 0; funcIdx < compFuncInfoCount; funcIdx++)
{
@@ -357,6 +609,21 @@ void Compiler::unwindReserveFunc(FuncInfoDsc* func)
BOOL isFunclet = (func->funKind == FUNC_ROOT) ? FALSE : TRUE;
bool funcHasColdSection = false;
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ DWORD unwindCodeBytes = 0;
+ if (fgFirstColdBlock != nullptr)
+ {
+ eeReserveUnwindInfo(isFunclet, true /*isColdCode*/, unwindCodeBytes);
+ }
+ unwindCodeBytes = (DWORD)(func->cfiCodes->size() * sizeof(CFI_CODE));
+ eeReserveUnwindInfo(isFunclet, false /*isColdCode*/, unwindCodeBytes);
+
+ return;
+ }
+#endif // _TARGET_UNIX_
+
// If there is cold code, split the unwind data between the hot section and the
// cold section. This needs to be done before we split into fragments, as each
// of the hot and cold sections can have multiple fragments.
@@ -415,6 +682,14 @@ void Compiler::unwindEmitFunc(FuncInfoDsc* func, void* pHotCode, void* pColdCode
static_assert_no_msg(FUNC_HANDLER == (FuncKind)CORJIT_FUNC_HANDLER);
static_assert_no_msg(FUNC_FILTER == (FuncKind)CORJIT_FUNC_FILTER);
+#if defined(_TARGET_UNIX_)
+ if (generateCFIUnwindCodes())
+ {
+ unwindEmitFuncCFI(func, pHotCode, pColdCode);
+ return;
+ }
+#endif // _TARGET_UNIX_
+
func->uwi.Allocate((CorJitFuncKind)func->funKind, pHotCode, pColdCode, true);
if (func->uwiCold != NULL)
diff --git a/src/jit/unwindarm64.cpp b/src/jit/unwindarm64.cpp
index 21e2a36b2a..0c4dc51740 100644
--- a/src/jit/unwindarm64.cpp
+++ b/src/jit/unwindarm64.cpp
@@ -18,6 +18,17 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#if defined(_TARGET_ARM64_)
+#if defined(_TARGET_UNIX_)
+int Compiler::mapRegNumToDwarfReg(regNumber reg)
+{
+ int dwarfReg = DWARF_REG_ILLEGAL;
+
+ NYI("CFI codes");
+
+ return dwarfReg;
+}
+#endif // _TARGET_ARM_
+
void Compiler::unwindPush(regNumber reg)
{
unreached(); // use one of the unwindSaveReg* functions instead.
diff --git a/src/jit/unwindx86.cpp b/src/jit/unwindx86.cpp
index 516155c6a2..40217fba9c 100644
--- a/src/jit/unwindx86.cpp
+++ b/src/jit/unwindx86.cpp
@@ -20,6 +20,17 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#error "This should be included only for x86"
#endif // _TARGET_X86_
+#if defined(_TARGET_UNIX_)
+int Compiler::mapRegNumToDwarfReg(regNumber reg)
+{
+ int dwarfReg = DWARF_REG_ILLEGAL;
+
+ NYI("CFI codes");
+
+ return dwarfReg;
+}
+#endif // _TARGET_UNIX_
+
void Compiler::unwindBegProlog()
{
}
diff --git a/src/jit/utils.cpp b/src/jit/utils.cpp
index 85aec5464c..ea22912cac 100644
--- a/src/jit/utils.cpp
+++ b/src/jit/utils.cpp
@@ -277,20 +277,20 @@ const char* getRegNameFloat(regNumber reg, var_types type)
#define REGDEF(name, rnum, mask, sname) "x" sname,
#include "register.h"
};
-#ifdef FEATURE_AVX_SUPPORT
+#ifdef FEATURE_SIMD
static const char* regNamesYMM[] = {
#define REGDEF(name, rnum, mask, sname) "y" sname,
#include "register.h"
};
-#endif // FEATURE_AVX_SUPPORT
+#endif // FEATURE_SIMD
assert((unsigned)reg < ArrLen(regNamesFloat));
-#ifdef FEATURE_AVX_SUPPORT
+#ifdef FEATURE_SIMD
if (type == TYP_SIMD32)
{
return regNamesYMM[reg];
}
-#endif // FEATURE_AVX_SUPPORT
+#endif // FEATURE_SIMD
return regNamesFloat[reg];
#endif
@@ -1476,6 +1476,7 @@ void HelperCallProperties::init()
case CORINFO_HELP_RETHROW:
case CORINFO_HELP_THROW_ARGUMENTEXCEPTION:
case CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION:
+ case CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED:
break;
@@ -2113,7 +2114,6 @@ T GetSignedMagic(T denom, int* shift /*out*/)
UT q2;
UT t;
T result_magic;
- int result_shift;
int iters = 0;
absDenom = abs(denom);
diff --git a/src/jit/valuenum.cpp b/src/jit/valuenum.cpp
index 473f0cec8e..105623227c 100644
--- a/src/jit/valuenum.cpp
+++ b/src/jit/valuenum.cpp
@@ -5603,6 +5603,15 @@ void Compiler::fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd)
}
#endif
+#if FEATURE_HW_INTRINSICS
+ if (oper == GT_HWIntrinsic)
+ {
+ // TODO-CQ: For now hardware intrinsics are not handled by value numbering to be amenable for CSE'ing.
+ tree->gtVNPair.SetBoth(vnStore->VNForExpr(compCurBB, TYP_UNKNOWN));
+ return;
+ }
+#endif // FEATURE_HW_INTRINSICS
+
var_types typ = tree->TypeGet();
if (GenTree::OperIsConst(oper))
{
@@ -5908,6 +5917,9 @@ void Compiler::fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd)
}
else // Must be an "op="
{
+#ifndef LEGACY_BACKEND
+ unreached();
+#else
// If the LHS is an IND, we didn't evaluate it when we visited it previously.
// But we didn't know that the parent was an op=. We do now, so go back and evaluate it.
// (We actually check if the effective val is the IND. We will have evaluated any non-last
@@ -5951,6 +5963,7 @@ void Compiler::fgValueNumberTree(GenTreePtr tree, bool evalAsgLhsInd)
lhsNormVNP),
lhsExcVNP);
}
+#endif // !LEGACY_BACKEND
}
if (tree->TypeGet() != TYP_VOID)
{
diff --git a/src/jit/vartype.h b/src/jit/vartype.h
index e75bc2adf1..7ec9d798a3 100644
--- a/src/jit/vartype.h
+++ b/src/jit/vartype.h
@@ -82,9 +82,7 @@ inline bool varTypeIsSIMD(T vt)
case TYP_SIMD8:
case TYP_SIMD12:
case TYP_SIMD16:
-#ifdef FEATURE_AVX_SUPPORT
case TYP_SIMD32:
-#endif // FEATURE_AVX_SUPPORT
return true;
default:
return false;
diff --git a/src/md/compiler/mdvalidator.cpp b/src/md/compiler/mdvalidator.cpp
deleted file mode 100644
index ce6c14e468..0000000000
--- a/src/md/compiler/mdvalidator.cpp
+++ /dev/null
@@ -1,7589 +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.
-//*****************************************************************************
-// MDValidator.cpp
-//
-
-//
-// Implementation for the MetaData validator.
-// Only supported for full mscorwks version.
-//
-//*****************************************************************************
-#include "stdafx.h"
-
-#ifdef FEATURE_METADATA_VALIDATOR
-
-#include "regmeta.h"
-#include "importhelper.h"
-#include "pedecoder.h"
-#include "stgio.h"
-#include "corhost.h"
-#include "sstring.h"
-#include "nsutilpriv.h"
-#include "holder.h"
-#include "vererror.h"
-
-#include "mdsighelper.h"
-
-#ifdef DACCESS_COMPILE
-#error Dac should be using standalone version of metadata, not Wks version.
-#endif
-
-//-----------------------------------------------------------------------------
-// Application specific debug macro.
-#define IfBreakGo(EXPR) \
-do {if ((EXPR) != S_OK) IfFailGo(VLDTR_E_INTERRUPTED); } while (0)
-
-//-----------------------------------------------------------------------------
-
-//#define CACHE_IMPLMAP_VALIDATION_RESULT
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
-// To avoid multiple validation of the same thing:
-struct ValidationResult
-{
- mdToken tok;
- HRESULT hr;
-};
-ValidationResult* g_rValidated=NULL; // allocated in ValidateMetaData
-unsigned g_nValidated=0;
-#endif
-
-//-----------------------------------------------------------------------------
-
-#define BASE_OBJECT_CLASSNAME "Object"
-#define BASE_NAMESPACE "System"
-#define BASE_VTYPE_CLASSNAME "ValueType"
-#define BASE_ENUM_CLASSNAME "Enum"
-#define BASE_VALUE_FIELDNAME "value__"
-#define BASE_CTOR_NAME ".ctor"
-#define BASE_CCTOR_NAME ".cctor"
-#define BASE_MCDELEGATE_CLASSNAME "MulticastDelegate"
-
-#define SYSTEM_OBJECT_TOSTRING_METHODNAME "ToString"
-#define SYSTEM_OBJECT_GETHASHCODE_METHODNAME "GetHashCode"
-#define SYSTEM_OBJECT_EQUALS_METHODNAME "Equals"
-
-// string ToString()
-static const BYTE g_sigSystemObject_ToString[] =
-{
- IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
- 0, // 0x00 ... Param Count
- ELEMENT_TYPE_STRING // 0x0e ... Return Type - string
-};
-
-// int GetHashCode()
-static const BYTE g_sigSystemObject_GetHashCode[] =
-{
- IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
- 0, // 0x00 ... Param Count
- ELEMENT_TYPE_I4 // 0x08 ... Return Type - I4
-};
-
-// bool Equals(object)
-static const BYTE g_sigSystemObject_Equals[] =
-{
- IMAGE_CEE_CS_CALLCONV_HASTHIS, // 0x20
- 1, // 0x01 ... Param Count
- ELEMENT_TYPE_BOOLEAN, // 0x02 ... Return Type - bool
- ELEMENT_TYPE_OBJECT // 0x1c ... Param #1 - object
-};
-
-// as defined in src\vm\vars.hpp
-#define MAX_CLASSNAME_LENGTH 1024
-//-----------------------------------------------------------------------------
-// Class names used in long form signatures (namespace is always "System")
-unsigned g_NumSigLongForms = 19;
-static const LPCSTR g_SigLongFormName[] = {
- "String",
- "______", // "Object", <REVISIT_TODO>// uncomment when EE handles ELEMENT_TYPE_OBJECT</REVISIT_TODO>
- "Boolean",
- "Char",
- "Byte",
- "SByte",
- "UInt16",
- "Int16",
- "UInt32",
- "Int32",
- "UInt64",
- "Int64",
- "Single",
- "Double",
- "SysInt", // Review this.
- "SysUInt", // Review this.
- "SingleResult",
- "Void",
- "IntPtr"
-};
-
-// <REVISIT_TODO>: Why are these global variables?</REVISIT_TODO>
-mdToken g_tkEntryPoint;
-bool g_fValidatingMscorlib;
-bool g_fIsDLL;
-
-//-----------------------------------------------------------------------------
-
-static HRESULT _FindClassLayout(
- CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
- mdTypeDef tkParent, // [IN] the parent that ClassLayout is associated with
- RID *clRid, // [OUT] rid for the ClassLayout.
- RID rid); // [IN] rid to be ignored.
-
-static HRESULT _FindFieldLayout(
- CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
- mdFieldDef tkParent, // [IN] the parent that FieldLayout is associated with
- RID *flRid, // [OUT] rid for the FieldLayout record.
- RID rid); // [IN] rid to be ignored.
-
-static BOOL _IsValidLocale(LPCUTF8 szLocale,
- BOOL fIsV2Assembly);
-
-
-#define REPORT_ERROR0(_VECode) \
- IfFailGo(_ValidateErrorHelper(_VECode, veCtxt))
-#define REPORT_ERROR1(_VECode, _Arg0) \
- IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0))
-#define REPORT_ERROR2(_VECode, _Arg0, _Arg1) \
- IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0, _Arg1))
-#define REPORT_ERROR3(_VECode, _Arg0, _Arg1, _Arg2) \
- IfFailGo(_ValidateErrorHelper(_VECode, veCtxt, _Arg0, _Arg1, _Arg2))
-
-//*****************************************************************************
-// Returns true if ixPtrTbl and ixParTbl are a valid parent-child combination
-// in the pointer table scheme.
-//*****************************************************************************
-static inline bool IsTblPtr(ULONG ixPtrTbl, ULONG ixParTbl)
-{
- if ((ixPtrTbl == TBL_Field && ixParTbl == TBL_TypeDef) ||
- (ixPtrTbl == TBL_Method && ixParTbl == TBL_TypeDef) ||
- (ixPtrTbl == TBL_Param && ixParTbl == TBL_Method) ||
- (ixPtrTbl == TBL_Property && ixParTbl == TBL_PropertyMap) ||
- (ixPtrTbl == TBL_Event && ixParTbl == TBL_EventMap))
- {
- return true;
- }
- return false;
-} // IsTblPtr()
-
-//*****************************************************************************
-// This inline function is used to set the return hr value for the Validate
-// functions to one of VLDTR_S_WRN, VLDTR_S_ERR or VLDTR_S_WRNERR based on
-// the current hr value and the new success code.
-// The general algorithm for error codes from the validation functions is:
-// if (no warnings or errors found)
-// return S_OK or S_FALSE
-// else if (warnings found)
-// return VLDTR_S_WRN
-// else if (errors found)
-// return VLDTR_S_ERR
-// else if (warnings and errors found)
-// return VLDTR_S_WRNERR
-//*****************************************************************************
-static inline void SetVldtrCode(HRESULT *phr, HRESULT successcode)
-{
- _ASSERTE(successcode == S_OK || successcode == S_FALSE ||successcode == VLDTR_S_WRN ||
- successcode == VLDTR_S_ERR || successcode == VLDTR_S_WRNERR);
- _ASSERTE(*phr == S_OK || *phr == VLDTR_S_WRN || *phr == VLDTR_S_ERR ||
- *phr == VLDTR_S_WRNERR);
- if (successcode == S_OK || successcode == S_FALSE ||*phr == VLDTR_S_WRNERR)
- return;
- else if (*phr == S_OK || *phr == S_FALSE)
- *phr = successcode;
- else if (*phr != successcode)
- *phr = VLDTR_S_WRNERR;
-} // SetVldtrCode()
-
-//*****************************************************************************
-// Initialize the Validator related structures in RegMeta.
-//*****************************************************************************
-HRESULT RegMeta::ValidatorInit( // S_OK or error.
- DWORD dwModuleType, // [IN] Specifies whether the module is a PE file or an obj.
- IUnknown *pUnk) // [IN] Validation error handler.
-{
- HRESULT hr = S_OK; // Return value.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- int i = 0; // Index into the function pointer table.
-
- // Initialize the array of function pointers to the validation function on
- // each table.
-#undef MiniMdTable
-#define MiniMdTable(x) m_ValidateRecordFunctionTable[i++] = &RegMeta::Validate##x;
- MiniMdTables()
-
- // Verify that the ModuleType passed in is a valid one.
- if (dwModuleType < ValidatorModuleTypeMin ||
- dwModuleType > ValidatorModuleTypeMax)
- {
- IfFailGo(E_INVALIDARG);
- }
-
- // Verify that the interface passed in supports IID_IVEHandler.
- IfFailGo(pUnk->QueryInterface(IID_IVEHandler, (void **)&m_pVEHandler));
-
- // Set the ModuleType class member. Do this last, this is used in
- // ValidateMetaData to see if the validator is correctly initialized.
- m_ModuleType = (CorValidatorModuleType)dwModuleType;
-ErrExit:
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // HRESULT RegMeta::ValidatorInit()
-
-
-//*****************************************************************************
-// Public implementation for code:IMetaDataValidate::ValidateMetaData
-//
-// Validate the entire MetaData. Here is the basic algorithm.
-// for each table
-// for each record
-// {
-// Do generic validation - validate that the offsets into the blob
-// pool are good, validate that all the rids are within range,
-// validate that token encodings are consistent.
-// }
-// if (problems found in generic validation)
-// return;
-// for each table
-// for each record
-// Do semantic validation.
-//******************************************************************************
-HRESULT RegMeta::ValidateMetaData()
-{
- HRESULT hr = S_OK;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- CMiniMdRW * pMiniMd = &(m_pStgdb->m_MiniMd);
- HRESULT hrSave = S_OK; // Saved hr from generic validation.
- ULONG ulCount; // Count of records in the current table.
- ULONG i; // Index to iterate over the tables.
- ULONG j; // Index to iterate over the records in a given table.
- IHostTaskManager * pHostTaskManager = NULL;
-
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- ULONG rValidatedSize=0; // Size of g_rValidated array
-#endif
-
- // Verify that the validator is initialized correctly
- if (m_ModuleType == ValidatorModuleTypeInvalid)
- {
- _ASSERTE(!"Validator not initialized, initialize with ValidatorInit().");
- IfFailGo(VLDTR_E_NOTINIT);
- }
-
- // First do a validation pass to do some basic structural checks based on
- // the Meta-Meta data. This'll validate all the offsets into the pools,
- // rid value and coded token ranges.
- for (i = 0; i < pMiniMd->GetCountTables(); i++)
- {
- ulCount = pMiniMd->GetCountRecs(i);
-
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- switch(i)
- {
- case TBL_ImplMap:
- rValidatedSize += ulCount;
- default:
- ;
- }
-#endif
- for (j = 1; j <= ulCount; j++)
- {
- IfFailGo(ValidateRecord(i, j));
- SetVldtrCode(&hrSave, hr);
- }
- }
- // Validate that the size of the Ptr tables matches with the corresponding
- // real tables.
-
- // Do not do semantic validation if structural validation failed.
- if (hrSave != S_OK)
- {
- hr = hrSave;
- goto ErrExit;
- }
-
- // Verify the entry point (if any)
- ::g_tkEntryPoint = 0;
- ::g_fIsDLL = false;
- if(m_pStgdb && m_pStgdb->m_pImage)
- {
- NewHolder<PEDecoder> pe;
-
- EX_TRY
- {
- // We need to use different PEDecoder constructors based on the type of data we give it.
- // We use the one with a 'bool' as the second argument when dealing with a mapped file,
- // and we use the one that takes a COUNT_T as the second argument when dealing with a
- // flat file.
-
- if (m_pStgdb->m_pStgIO->GetMemoryMappedType() == MTYPE_IMAGE)
- pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, false);
- else
- pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, (COUNT_T)(m_pStgdb->m_dwImageSize));
-
- hr = S_OK;
- }
- EX_CATCH
- {
- hr = COR_E_BADIMAGEFORMAT;
- }
- EX_END_CATCH(SwallowAllExceptions)
-
- if (SUCCEEDED(hr) && pe == NULL)
- IfFailGo(E_OUTOFMEMORY);
-
- if(FAILED(hr) || !pe->CheckFormat())
- {
- VEContext veCtxt; // Context structure.
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR0(COR_E_BADIMAGEFORMAT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if(!pe->IsILOnly())
- {
- VEContext veCtxt; // Context structure.
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR0(VER_E_BAD_PE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if((pe->GetCorHeader()->Flags & COMIMAGE_FLAGS_NATIVE_ENTRYPOINT) == 0)
- g_tkEntryPoint = pe->GetEntryPointToken();
- g_fIsDLL = pe->IsDll() ? true : false;
-
- if(g_tkEntryPoint)
- {
- RID rid = RidFromToken(g_tkEntryPoint);
- RID maxrid = 0;
- switch(TypeFromToken(g_tkEntryPoint))
- {
- case mdtMethodDef: maxrid = pMiniMd->getCountMethods(); break;
- case mdtFile: maxrid = pMiniMd->getCountFiles(); break;
- default: break;
- }
- if((rid == 0)||(rid > maxrid))
- {
- VEContext veCtxt; // Context structure.
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = g_tkEntryPoint;
- veCtxt.uOffset = 0;
- REPORT_ERROR0(VLDTR_E_EP_BADTOKEN);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if(!g_fIsDLL) // exe must have an entry point
- {
- VEContext veCtxt; // Context structure.
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = g_tkEntryPoint;
- veCtxt.uOffset = 0;
- REPORT_ERROR0(VLDTR_E_EP_BADTOKEN);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- g_fValidatingMscorlib = false;
- if(pMiniMd->GetCountRecs(TBL_Assembly))
- {
- AssemblyRec *pRecord;
- IfFailGo(pMiniMd->GetAssemblyRecord(1, &pRecord));
- LPCSTR szName;
- IfFailGo(pMiniMd->getNameOfAssembly(pRecord, &szName));
- g_fValidatingMscorlib = (0 == SString::_stricmp(szName,"mscorlib"));
- }
- // Verify there are no circular class hierarchies.
-
- // Do per record semantic validation on the MetaData. The function
- // pointers to the per record validation are stored in the table by the
- // ValidatorInit() function.
-
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- g_rValidated = NULL;
- ::g_nValidated = 0;
- if (rValidatedSize)
- {
- g_rValidated = new(nothrow) ValidationResult[rValidatedSize];
- IfNullGo(g_rValidated);
- }
-#endif
- pHostTaskManager = CorHost2::GetHostTaskManager();
-
-#ifdef Sleep
-#undef Sleep
-#endif
- //DWORD cBegin=0,cEnd=0;
- for (i = 0; i < pMiniMd->GetCountTables(); i++)
- {
- ulCount = pMiniMd->GetCountRecs(i);
- //cBegin = GetTickCount();
- for (j = 1; j <= ulCount; j++)
- {
- IfFailGo((this->*m_ValidateRecordFunctionTable[i])(j));
- SetVldtrCode(&hrSave, hr);
- if(pHostTaskManager)
- {
- // SwitchToTask forces the current thread to give up quantum, while a host can decide what
- // to do with Sleep if the current thread has not run out of quantum yet.
- ClrSleepEx(0, FALSE);
- }
- }
- //cEnd = GetTickCount();
- //printf("Table %d, recs: %d, time: %d\n",i,ulCount,(cEnd-cBegin));
- }
- hr = hrSave;
-ErrExit:
-
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- if(g_rValidated) delete [] g_rValidated;
-#endif
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMetaData()
-
-//*****************************************************************************
-// Validate the Module record.
-//*****************************************************************************
-HRESULT RegMeta::ValidateModule(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- ModuleRec *pRecord; // Module record.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- LPCSTR szName;
- GUID GuidOfModule;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the Module record.
- veCtxt.Token = TokenFromRid(rid, mdtModule);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetModuleRecord(rid, &pRecord));
-
- // There can only be one Module record.
- if (rid > 1)
- {
- REPORT_ERROR0(VLDTR_E_MOD_MULTI);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Verify the name
- IfFailGo(pMiniMd->getNameOfModule(pRecord, &szName));
- if(szName && *szName)
- {
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- // Name too long
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(strchr(szName,':') || strchr(szName,'\\'))
- {
- REPORT_ERROR0(VLDTR_E_MOD_NAMEFULLQLFD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- REPORT_ERROR0(VLDTR_E_MOD_NONAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Verify that the MVID is valid.
- IfFailGo(pMiniMd->getMvidOfModule(pRecord, &GuidOfModule));
- if (GuidOfModule == GUID_NULL)
- {
- REPORT_ERROR0(VLDTR_E_MOD_NULLMVID);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateModule()
-
-//*****************************************************************************
-// Validate the given TypeRef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateTypeRef(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- TypeRefRec *pRecord; // TypeRef record.
- mdToken tkRes; // Resolution scope.
- LPCSTR szNamespace; // TypeRef Namespace.
- LPCSTR szName; // TypeRef Name.
- mdTypeRef tkTypeRef; // Duplicate TypeRef.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Get the TypeRef record.
- veCtxt.Token = TokenFromRid(rid, mdtTypeRef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetTypeRefRecord(rid, &pRecord));
-
- // Check name is not NULL.
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pRecord, &szNamespace));
- IfFailGo(pMiniMd->getNameOfTypeRef(pRecord, &szName));
- if (!*szName)
- {
- REPORT_ERROR0(VLDTR_E_TR_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- RID ridScope;
- // Look for a Duplicate, this function reports only one duplicate.
- tkRes = pMiniMd->getResolutionScopeOfTypeRef(pRecord);
- hr = ImportHelper::FindTypeRefByName(pMiniMd, tkRes, szNamespace, szName, &tkTypeRef, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_TR_DUP, tkTypeRef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- ULONG L = (ULONG)(strlen(szName)+strlen(szNamespace));
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- ridScope = RidFromToken(tkRes);
- if(ridScope)
- {
- bool badscope = true;
- //check if valid scope
- switch(TypeFromToken(tkRes))
- {
- case mdtAssemblyRef:
- case mdtModuleRef:
- case mdtModule:
- case mdtTypeRef:
- badscope = !IsValidToken(tkRes);
- break;
- default:
- break;
- }
- if(badscope)
- {
- REPORT_ERROR1(VLDTR_E_TR_BADSCOPE, tkTypeRef);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- else
- {
- // check if there is a ExportedType
- //hr = ImportHelper::FindExportedType(pMiniMd, szNamespace, szName, tkImpl, &tkExportedType, rid);
- }
- // Check if there is TypeDef with the same name
- if(!ridScope)
- {
- if((TypeFromToken(tkRes) != mdtTypeRef) &&
- (S_OK == ImportHelper::FindTypeDefByName(pMiniMd, szNamespace, szName, mdTokenNil,&tkTypeRef, 0)))
- {
- REPORT_ERROR1(VLDTR_E_TR_HASTYPEDEF, tkTypeRef);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- }
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateTypeRef()
-
-//*****************************************************************************
-// Validate the given TypeDef.
-//*****************************************************************************
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
-#endif
-HRESULT RegMeta::ValidateTypeDef(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- TypeDefRec *pRecord; // TypeDef record.
- TypeDefRec *pExtendsRec = 0; // TypeDef record for the parent class.
- mdTypeDef tkTypeDef; // Duplicate TypeDef token.
- DWORD dwFlags; // TypeDef flags.
- DWORD dwExtendsFlags; // TypeDef flags of the parent class.
- LPCSTR szName; // TypeDef Name.
- LPCSTR szNameSpace; // TypeDef NameSpace.
- LPCSTR szExtName = NULL; // Parent Name.
- LPCSTR szExtNameSpace = NULL; // Parent NameSpace.
- CQuickBytes qb; // QuickBytes for flexible allocation.
- mdToken tkExtends; // TypeDef of the parent class.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkEncloser=mdTokenNil; // Encloser, if any
- BOOL bIsEnum,bExtendsEnum,bExtendsVType,bIsVType,bExtendsObject,bIsObject,bExtendsMCDelegate;
- BOOL bHasMethods=FALSE, bHasFields=FALSE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- // Skip validating m_tdModule class.
- if (rid == RidFromToken(m_tdModule))
- goto ErrExit;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the TypeDef record.
- veCtxt.Token = TokenFromRid(rid, mdtTypeDef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetTypeDefRecord(rid, &pRecord));
-
- // Do checks for name validity..
- IfFailGo(pMiniMd->getNameOfTypeDef(pRecord, &szName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pRecord, &szNameSpace));
- if (!*szName)
- {
- // TypeDef Name is null.
- REPORT_ERROR0(VLDTR_E_TD_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (!IsDeletedName(szName))
- {
- RID iRecord;
- IfFailGo(pMiniMd->FindNestedClassHelper(TokenFromRid(rid, mdtTypeDef), &iRecord));
-
- if (InvalidRid(iRecord))
- {
- tkEncloser = mdTokenNil;
- }
- else
- {
- NestedClassRec *pNestedClassRec;
- IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pNestedClassRec));
- tkEncloser = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
- }
-
- // Check for duplicates based on Name/NameSpace. Do not do Dup checks
- // on deleted records.
- hr = ImportHelper::FindTypeDefByName(pMiniMd, szNameSpace, szName, tkEncloser,
- &tkTypeDef, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_TD_DUPNAME, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- ULONG L = (ULONG)(strlen(szName)+strlen(szNameSpace));
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Get the flag value for the TypeDef.
- dwFlags = pMiniMd->getFlagsOfTypeDef(pRecord);
- // Do semantic checks on the flags.
- // RTSpecialName bit must be set on Deleted records.
- if (IsDeletedName(szName))
- {
- if(!IsTdRTSpecialName(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_DLTNORTSPCL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- hr = hrSave;
- goto ErrExit;
- }
-
- // If RTSpecialName bit is set, the record must be a Deleted record.
- if (IsTdRTSpecialName(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_RTSPCLNOTDLT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- if(!IsTdSpecialName(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_RTSPCLNOTSPCL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Check if flag value is valid
- {
- DWORD dwInvalidMask, dwExtraBits;
- dwInvalidMask = (DWORD)~(tdVisibilityMask | tdLayoutMask | tdClassSemanticsMask |
- tdAbstract | tdSealed | tdSpecialName | tdImport | tdSerializable | tdWindowsRuntime |
- tdStringFormatMask | tdBeforeFieldInit | tdReservedMask);
- // check for extra bits
- dwExtraBits = dwFlags & dwInvalidMask;
- if (dwExtraBits == 0)
- {
- // if no extra bits, check layout
- dwExtraBits = dwFlags & tdLayoutMask;
- if (dwExtraBits != tdLayoutMask)
- {
- // layout OK, check string format
- dwExtraBits = dwFlags & tdStringFormatMask;
- if (dwExtraBits != tdStringFormatMask)
- dwExtraBits = 0;
- }
- }
- if (dwExtraBits != 0)
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
-
- // Generic types may be specified to have only AutoLayout or SequentialLayout (never ExplicitLayout).
- if (IsTdExplicitLayout(dwFlags))
- {
- HENUMInternal hEnumTyPars;
- ULONG ulTypeDefArity;
- hr = pMiniMd->FindGenericParamHelper(TokenFromRid(rid, mdtTypeDef), &hEnumTyPars);
- if (SUCCEEDED(hr))
- {
- IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulTypeDefArity));
- HENUMInternal::ClearEnum(&hEnumTyPars);
- if (ulTypeDefArity != 0)
- {
- REPORT_ERROR0(VLDTR_E_TD_GENERICHASEXPLAYOUT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
-
- }
-
- // Get the parent of the TypeDef.
- tkExtends = pMiniMd->getExtendsOfTypeDef(pRecord);
-
- // Check if TypeDef extends itself
- if (tkExtends == veCtxt.Token)
- {
- REPORT_ERROR0(VLDTR_E_TD_EXTENDSITSELF);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check if TypeDef extends one of its children
- if (RidFromToken(tkExtends)&&(TypeFromToken(tkExtends)==mdtTypeDef))
- {
- TypeDefRec *pRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pRec));
- mdToken tkExtends2 = pMiniMd->getExtendsOfTypeDef(pRec);
- if( tkExtends2 == veCtxt.Token)
- {
- REPORT_ERROR0(VLDTR_E_TD_EXTENDSCHILD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
-
-
- if (IsNilToken(tkEncloser) == IsTdNested(dwFlags))
- {
- REPORT_ERROR0(IsNilToken(tkEncloser) ? VLDTR_E_TD_NESTEDNOENCL : VLDTR_E_TD_ENCLNOTNESTED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- bIsObject = bIsEnum = bIsVType = FALSE;
- if(0 == strcmp(szNameSpace,BASE_NAMESPACE))
- {
- bIsObject = (0 == strcmp(szName,BASE_OBJECT_CLASSNAME));
- if(!bIsObject)
- {
- bIsEnum = (0 == strcmp(szName,BASE_ENUM_CLASSNAME));
- if(!bIsEnum)
- {
- bIsVType = (0 == strcmp(szName,BASE_VTYPE_CLASSNAME));
- }
- }
- }
-
- if (IsNilToken(tkExtends))
- {
- // If the parent token is nil, the class must be marked Interface,
- // unless it's the System.Object class.
- if ( !(bIsObject || IsTdInterface(dwFlags)))
- {
- REPORT_ERROR0(VLDTR_E_TD_NOTIFACEOBJEXTNULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- szExtName = "";
- szExtNameSpace = "";
- }
- else
- {
-
- // If tkExtends is a TypeSpec, extract the generic type and continue
- if (TypeFromToken(tkExtends) == mdtTypeSpec)
- {
- //@GENERICSVER: TODO first validate the spec
-
- TypeSpecRec *pRec;
- IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(tkExtends), &pRec));
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
-
- IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, &pSig, &cSig));
-
- switch(CorSigUncompressElementType(pSig))
- {
- default:
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- szExtName = "";
- szExtNameSpace = "";
- break;
- }
- case ELEMENT_TYPE_GENERICINST:
- {
- switch(CorSigUncompressElementType(pSig))
- {
- default:
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- szExtName = "";
- szExtNameSpace = "";
- break;
- }
- case ELEMENT_TYPE_VALUETYPE:
- case ELEMENT_TYPE_CLASS:
- {
- tkExtends = CorSigUncompressToken(pSig);
- break;
- }
- }
- }
- }
- }
-
- // If tkExtends is a TypeRef try to resolve it to a corresponding
- // TypeDef. If it resolves successfully, issue a warning. It means
- // that the Ref to Def optimization didn't happen successfully.
- if (TypeFromToken(tkExtends) == mdtTypeRef)
- {
- TypeRefRec *pTypeRefRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pTypeRefRec));
-
- IfFailGo(pMiniMd->getNameOfTypeRef(pTypeRefRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTypeRefRec, &szExtNameSpace));
-
- BOOL fLookForDef = TRUE;
- mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pTypeRefRec);
- if (TypeFromToken(tkResScope) == mdtAssemblyRef)
- { // We will look for the TypeDef of the same name, only if the AssemblyRef has the same name as AssemblyDef
- fLookForDef = FALSE;
- RID ridResScope = RidFromToken(tkResScope);
- if ((ridResScope > 0) && (ridResScope <= pMiniMd->GetCountRecs(TBL_AssemblyRef)))
- {
- if (pMiniMd->GetCountRecs(TBL_Assembly) > 0)
- {
- AssemblyRefRec * pAsmRefRec;
- IfFailGo(pMiniMd->GetAssemblyRefRecord(ridResScope, &pAsmRefRec));
- AssemblyRec *pAsmRec;
- IfFailGo(pMiniMd->GetAssemblyRecord(1, &pAsmRec));
- if ((pAsmRec != NULL) && (pAsmRefRec != NULL))
- {
- LPCUTF8 szAsmName;
- IfFailGo(pMiniMd->getNameOfAssembly(pAsmRec, &szAsmName));
- LPCUTF8 szAsmRefName;
- IfFailGo(pMiniMd->getNameOfAssemblyRef(pAsmRefRec, &szAsmRefName));
- if ((szAsmName != NULL) && (szAsmRefName != NULL))
- fLookForDef = (strcmp(szAsmName,szAsmRefName) == 0);
- }
- }
- }
- }
-
- if (fLookForDef)
- {
- mdTypeDef tkResTd;
-
- if (ImportHelper::FindTypeDefByName(pMiniMd,
- szExtNameSpace,
- szExtName,
- tkResScope,
- &tkResTd) == S_OK)
- {
- // Ref to Def optimization is not expected to happen for Obj files.
- /*
- if (m_ModuleType != ValidatorModuleTypeObj)
- {
- REPORT_ERROR2(VLDTR_E_TD_EXTTRRES, tkExtends, tkResTd);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- */
-
- // Set tkExtends to the new TypeDef, so we can continue
- // with the validation.
- tkExtends = tkResTd;
- }
- }
- }
-
- // Continue validation, even for the case where TypeRef got resolved
- // to a corresponding TypeDef in the same Module.
- if (TypeFromToken(tkExtends) == mdtTypeDef)
- {
- // Extends must not be sealed.
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtendsRec));
- dwExtendsFlags = pMiniMd->getFlagsOfTypeDef(pExtendsRec);
- IfFailGo(pMiniMd->getNameOfTypeDef(pExtendsRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtendsRec, &szExtNameSpace));
- if (IsTdSealed(dwExtendsFlags))
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTENDSSEALED, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if (IsTdInterface(dwExtendsFlags))
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTENDSIFACE, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if(TypeFromToken(tkExtends) == mdtTypeSpec)
- {
- //If we got here, the instantiated generic type is itself a type spec, which is illegal
- REPORT_ERROR1(VLDTR_E_TD_EXTBADTYPESPEC, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- szExtName = "";
- szExtNameSpace = "";
-
- }
- // If the parent token is non-null, the class must not be System.Object.
- if (bIsObject)
- {
- REPORT_ERROR1(VLDTR_E_TD_OBJEXTENDSNONNULL, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- bExtendsObject = bExtendsEnum = bExtendsVType = bExtendsMCDelegate = FALSE;
- if(0 == strcmp(szExtNameSpace,BASE_NAMESPACE))
- {
- bExtendsObject = (0 == strcmp(szExtName,BASE_OBJECT_CLASSNAME));
- if(!bExtendsObject)
- {
- bExtendsEnum = (0 == strcmp(szExtName,BASE_ENUM_CLASSNAME));
- if(!bExtendsEnum)
- {
- bExtendsVType = (0 == strcmp(szExtName,BASE_VTYPE_CLASSNAME));
- if(!bExtendsVType)
- {
- bExtendsMCDelegate = (0 == strcmp(szExtName,BASE_MCDELEGATE_CLASSNAME));
- }
- }
- }
- }
-
- // System.ValueType must extend System.Object
- if(bIsVType && !bExtendsObject)
- {
- REPORT_ERROR0(VLDTR_E_TD_SYSVTNOTEXTOBJ);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Validate rules for interface. Some of the VOS rules are verified as
- // part of the validation for the corresponding Methods, fields etc.
- if (IsTdInterface(dwFlags))
- {
- // Interface type must be marked abstract.
- if (!IsTdAbstract(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_IFACENOTABS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Interface must not be sealed
- if(IsTdSealed(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_IFACESEALED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Interface must have parent Nil token.
- if (!IsNilToken(tkExtends))
- {
- REPORT_ERROR1(VLDTR_E_TD_IFACEPARNOTNIL, tkExtends);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- //Interface must have only static fields -- checked in ValidateField
- //Interface must have only public fields -- checked in ValidateField
- //Interface must have only abstract or static methods -- checked in ValidateMethod
- //Interface must have only public methods -- checked in ValidateMethod
-
- // Interface must have GUID
- /*
- if (*pGuid == GUID_NULL)
- {
- REPORT_ERROR0(VLDTR_E_TD_IFACEGUIDNULL);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- */
- }
-
-
- // Class must have valid method and field lists
- {
- ULONG ridStart,ridEnd;
- ridStart = pMiniMd->getMethodListOfTypeDef(pRecord);
- ridEnd = pMiniMd->getCountMethods() + 1;
- if(ridStart > ridEnd)
- {
- REPORT_ERROR0(VLDTR_E_TD_BADMETHODLST);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- IfFailGo(pMiniMd->getEndMethodListOfTypeDef(rid, &ridEnd));
- bHasMethods = (ridStart && (ridStart < ridEnd));
- }
-
- ridStart = pMiniMd->getFieldListOfTypeDef(pRecord);
- ridEnd = pMiniMd->getCountFields() + 1;
- if(ridStart > ridEnd)
- {
- REPORT_ERROR0(VLDTR_E_TD_BADFIELDLST);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- IfFailGo(pMiniMd->getEndFieldListOfTypeDef(rid, &ridEnd));
- bHasFields = (ridStart && (ridStart < ridEnd));
- }
- }
-
- // Validate rules for System.Enum
- if(bIsEnum)
- {
- if(!IsTdClass(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_SYSENUMNOTCLASS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!bExtendsVType)
- {
- REPORT_ERROR0(VLDTR_E_TD_SYSENUMNOTEXTVTYPE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- if(bExtendsVType || bExtendsEnum)
- {
- // ValueTypes and Enums must be sealed
- if(!IsTdSealed(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_VTNOTSEAL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Value class must have fields or size
- if(!bHasFields)
- {
- ULONG ulClassSize = 0;
- ClassLayoutRec *pRec;
- RID ridClassLayout;
- IfFailGo(pMiniMd->FindClassLayoutHelper(TokenFromRid(rid, mdtTypeDef), &ridClassLayout));
-
- if (!InvalidRid(ridClassLayout))
- {
- IfFailGo(pMiniMd->GetClassLayoutRecord(RidFromToken(ridClassLayout), &pRec));
- ulClassSize = pMiniMd->getClassSizeOfClassLayout(pRec);
- }
- if(ulClassSize == 0)
- {
- REPORT_ERROR0(VLDTR_E_TD_VTNOSIZE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- else if(bExtendsMCDelegate)
- {
- // Delegates must be sealed
- if(!IsTdSealed(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_TD_VTNOTSEAL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
-
- // Enum-related checks
- if (bExtendsEnum)
- {
- {
- PCCOR_SIGNATURE pValueSig = NULL;
- ULONG cbValueSig = 0;
- mdFieldDef tkValueField=0, tkField, tkValue__Field = 0;
- ULONG ridStart,ridEnd,index;
- FieldRec *pFieldRecord; // Field record.
- DWORD dwRecordFlags, dwTally, dwValueFlags, dwValue__Flags = 0;
- RID ridField,ridValue=0,ridValue__ = 0;
-
- ridStart = pMiniMd->getFieldListOfTypeDef(pRecord);
- IfFailGo(pMiniMd->getEndFieldListOfTypeDef(rid, &ridEnd));
- // check the instance (value__) field(s)
- dwTally = 0;
- for (index = ridStart; index < ridEnd; index++ )
- {
- IfFailGo(pMiniMd->GetFieldRid(index, &ridField));
- IfFailGo(pMiniMd->GetFieldRecord(ridField, &pFieldRecord));
- dwRecordFlags = pFieldRecord->GetFlags();
- if(!IsFdStatic(dwRecordFlags))
- {
- dwTally++;
- if(ridValue == 0)
- {
- ridValue = ridField;
- tkValueField = TokenFromRid(ridField, mdtFieldDef);
- IfFailGo(pMiniMd->getSignatureOfField(pFieldRecord, &pValueSig, &cbValueSig));
- dwValueFlags = dwRecordFlags;
- }
- }
- LPCSTR szFieldName;
- IfFailGo(pMiniMd->getNameOfField(pFieldRecord, &szFieldName));
- if(!strcmp(szFieldName, BASE_VALUE_FIELDNAME))
- {
- ridValue__ = ridField;
- dwValue__Flags = dwRecordFlags;
- tkValue__Field = TokenFromRid(ridField, mdtFieldDef);
- }
- }
- // Enum must have one (and only one) inst.field
- if(dwTally == 0)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMNOINSTFLD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if(dwTally > 1)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMMULINSTFLD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // inst.field name must be "value__" (CLS)
- if(ridValue__ == 0)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMNOVALUE);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- else
- {
- // if "value__" field is present ...
- // ... it must be 1st instance field
- if(ridValue__ != ridValue)
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMVALNOT1ST, tkValue__Field);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ... it must not be static
- if(IsFdStatic(dwValue__Flags))
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMVALSTATIC, tkValue__Field);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ... it must be fdRTSpecialName
- if(!IsFdRTSpecialName(dwValue__Flags))
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMVALNOTSN, tkValueField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ... its type must be integral
- if(cbValueSig && pValueSig)
- {
- //ULONG ulCurByte = CorSigUncompressedDataSize(pValueSig);
- //CorSigUncompressData(pValueSig);
- //ULONG ulElemSize,ulElementType;
- //ulCurByte += (ulElemSize = CorSigUncompressedDataSize(pValueSig));
- //ulElementType = CorSigUncompressData(pValueSig);
- //switch (ulElementType)
- BYTE* pB = (BYTE*)pValueSig;
- pB++; // skip the calling convention
- while((*pB == ELEMENT_TYPE_CMOD_OPT)||
- (*pB == ELEMENT_TYPE_CMOD_REQD))
- {
- mdToken tok;
- pB++; // move from E_T_... to compressed token
- pB += CorSigUncompressToken((PCOR_SIGNATURE)pB,&tok);
- }
- switch(*pB)
- {
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_I:
- case ELEMENT_TYPE_R4:
- case ELEMENT_TYPE_R8:
- break;
- default:
- REPORT_ERROR1(VLDTR_E_TD_ENUMFLDBADTYPE, tkValue__Field);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- // check all the fields
- dwTally = 0;
- for (index = ridStart; index < ridEnd; index++ )
- {
- IfFailGo(pMiniMd->GetFieldRid(index, &ridField));
- if(ridField == ridValue) continue;
- IfFailGo(pMiniMd->GetFieldRecord(ridField, &pFieldRecord));
- LPCSTR szFieldName;
- IfFailGo(pMiniMd->getNameOfField(pFieldRecord, &szFieldName));
- if(IsFdRTSpecialName(pFieldRecord->GetFlags())
- && IsDeletedName(szFieldName)) continue;
- dwTally++;
- tkField = TokenFromRid(ridField, mdtFieldDef);
- if(!IsFdStatic(pFieldRecord->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMFLDNOTST, tkField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!IsFdLiteral(pFieldRecord->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMFLDNOTLIT, tkField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- /*
- IfFailGo(pMiniMd->getSignatureOfField(pFieldRecord, &pvSigTmp, &cbSig));
- if(!(pvSigTmp && (cbSig==cbValueSig) &&(memcmp(pvSigTmp,pValueSig,cbSig)==0)))
- {
- REPORT_ERROR1(VLDTR_E_TD_ENUMFLDSIGMISMATCH, tkField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- */
- }
- if(dwTally == 0)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMNOLITFLDS);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- // Enum must have no methods
- if (bHasMethods)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMHASMETHODS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Enum must implement no interfaces
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountInterfaceImpls() + 1;
- ULONG index;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- InterfaceImplRec *pInterfaceImplRecord;
- IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pInterfaceImplRecord));
- if (veCtxt.Token == pMiniMd->getClassOfInterfaceImpl(pInterfaceImplRecord))
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMIMPLIFACE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- }
- // Enum must have no properties
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountPropertys() + 1;
- ULONG index;
- mdToken tkClass;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- IfFailGo(pMiniMd->FindParentOfPropertyHelper(index | mdtProperty, &tkClass));
- if (veCtxt.Token == tkClass)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMHASPROP);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- }
- // Enum must have no events
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountEvents() + 1;
- ULONG index;
- mdToken tkClass;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- IfFailGo(pMiniMd->FindParentOfEventHelper(index | mdtEvent, &tkClass));
- if (veCtxt.Token == tkClass)
- {
- REPORT_ERROR0(VLDTR_E_TD_ENUMHASEVENT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- }
- } // end if(bExtendsEnum)
- // Class having security must be marked tdHasSecurity and vice versa
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
- ULONG index;
- BOOL bHasSecurity = FALSE;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- DeclSecurityRec *pDeclSecurityRecord;
- IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
- if (veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
- {
- bHasSecurity = TRUE;
- break;
- }
- }
- if (!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
- {
- bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
- "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
- }
- if(bHasSecurity != (IsTdHasSecurity(pRecord->GetFlags())!=0))
- {
- REPORT_ERROR0(bHasSecurity ? VLDTR_E_TD_SECURNOTMARKED : VLDTR_E_TD_MARKEDNOSECUR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateTypeDef()
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
-//*****************************************************************************
-// Validate the given FieldPtr.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFieldPtr(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateFieldPtr()
-
-
-//*****************************************************************************
-// Validate the given Field.
-//*****************************************************************************
-HRESULT RegMeta::ValidateField(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- FieldRec *pRecord; // Field record.
- mdTypeDef tkTypeDef; // Parent TypeDef token.
- mdFieldDef tkFieldDef; // Duplicate FieldDef token.
- LPCSTR szName; // FieldDef name.
- PCCOR_SIGNATURE pbSig; // FieldDef signature.
- ULONG cbSig; // Signature size in bytes.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- BOOL bIsValueField;
- BOOL bIsGlobalField = FALSE;
- BOOL bHasValidRVA = FALSE;
- DWORD dwInvalidFlags;
- DWORD dwFlags;
- RID tempRid;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the FieldDef record.
- veCtxt.Token = TokenFromRid(rid, mdtFieldDef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetFieldRecord(rid, &pRecord));
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getNameOfField(pRecord, &szName));
- if (!*szName)
- {
- // Field name is NULL.
- REPORT_ERROR0(VLDTR_E_FD_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- bIsValueField = (strcmp(szName,BASE_VALUE_FIELDNAME)==0);
- // If field is RTSpecialName, its name must be 'value__' and vice versa
- if((IsFdRTSpecialName(pRecord->GetFlags())!=0) != bIsValueField)
- {
- REPORT_ERROR1(bIsValueField ? VLDTR_E_TD_ENUMVALNOTSN : VLDTR_E_FD_NOTVALUERTSN, veCtxt.Token);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate flags
- dwFlags = pRecord->GetFlags();
- dwInvalidFlags = ~(fdFieldAccessMask | fdStatic | fdInitOnly | fdLiteral | fdNotSerialized | fdSpecialName
- | fdPinvokeImpl | fdReservedMask);
- if(dwFlags & dwInvalidFlags)
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwFlags & dwInvalidFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate access
- if((dwFlags & fdFieldAccessMask) == fdFieldAccessMask)
- {
- REPORT_ERROR0(VLDTR_E_FMD_BADACCESSFLAG);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Literal : Static, !InitOnly
- if(IsFdLiteral(dwFlags))
- {
- if(IsFdInitOnly(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FD_INITONLYANDLITERAL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!IsFdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FD_LITERALNOTSTATIC);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!IsFdHasDefault(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FD_LITERALNODEFAULT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // RTSpecialName => SpecialName
- if(IsFdRTSpecialName(dwFlags) && !IsFdSpecialName(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_RTSNNOTSN);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate Field signature.
- IfFailGo(pMiniMd->getSignatureOfField(pRecord, &pbSig, &cbSig));
- IfFailGo(ValidateFieldSig(TokenFromRid(rid, mdtFieldDef), pbSig, cbSig));
- if (hr != S_OK)
- SetVldtrCode(&hrSave, hr);
-
- // Validate Field RVA
- if(IsFdHasFieldRVA(dwFlags))
- {
- ULONG iFieldRVARid;
- IfFailGo(pMiniMd->FindFieldRVAHelper(TokenFromRid(rid, mdtFieldDef), &iFieldRVARid));
- if((iFieldRVARid==0) || (iFieldRVARid > pMiniMd->getCountFieldRVAs()))
- {
- REPORT_ERROR0(VLDTR_E_FD_RVAHASNORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- /*
- FieldRVARec *pRVARec;
- IfFailGo(pMiniMd->GetFieldRVARecord(iFieldRVARid, &pRVARec));
- if(pRVARec->GetRVA() == 0)
- {
- REPORT_ERROR0(VLDTR_E_FD_RVAHASZERORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- */
- bHasValidRVA = TRUE;
- }
- }
-
- // Get the parent of the Field.
- IfFailGo(pMiniMd->FindParentOfFieldHelper(TokenFromRid(rid, mdtFieldDef), &tkTypeDef));
- // Validate that the parent is not nil.
- if (IsNilToken(tkTypeDef))
- {
- REPORT_ERROR0(VLDTR_E_FD_PARNIL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (RidFromToken(tkTypeDef) != RidFromToken(m_tdModule))
- {
- if(IsValidToken(tkTypeDef) && (TypeFromToken(tkTypeDef) == mdtTypeDef))
- {
- TypeDefRec *pParentRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pParentRec));
- // If the name is "value__" ...
- if(bIsValueField)
- {
- // parent must be Enum
- mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pParentRec);
- RID ridExtends = RidFromToken(tkExtends);
- LPCSTR szExtName="",szExtNameSpace="";
- if(ridExtends)
- {
- if(TypeFromToken(tkExtends) == mdtTypeRef)
- {
- TypeRefRec *pExtRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(ridExtends, &pExtRec));
- IfFailGo(pMiniMd->getNameOfTypeRef(pExtRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtRec, &szExtNameSpace));
- }
- else if(TypeFromToken(tkExtends) == mdtTypeDef)
- {
- TypeDefRec *pExtRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(ridExtends, &pExtRec));
- IfFailGo(pMiniMd->getNameOfTypeDef(pExtRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtRec, &szExtNameSpace));
- }
- }
- if(strcmp(szExtName,BASE_ENUM_CLASSNAME) || strcmp(szExtNameSpace,BASE_NAMESPACE))
- {
- REPORT_ERROR0(VLDTR_E_FD_VALUEPARNOTENUM);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // field must be instance - checked in ValidateTypeDef
- // must be no other instance fields - checked in ValidateTypeDef
- // must be first field - checked in ValidateTypeDef
- // must be RTSpecialName -- checked in ValidateTypeDef
- }
- if(IsTdInterface(pMiniMd->getFlagsOfTypeDef(pParentRec)))
- {
- // Fields in interface are not CLS compliant
- REPORT_ERROR0(VLDTR_E_FD_FLDINIFACE);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
-
- // If field is not static, verify parent is not interface.
- if(!IsFdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FD_INSTINIFACE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- // If field is not public, verify parent is not interface.
- if(!IsFdPublic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FD_NOTPUBINIFACE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- } // end if Valid and TypeDef
- else
- {
- REPORT_ERROR1(VLDTR_E_FD_BADPARENT, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else // i.e. if (RidFromToken(tkTypeDef) == RidFromToken(m_tdModule))
- {
- bIsGlobalField = TRUE;
- // Globals are not CLS-compliant
- REPORT_ERROR0(VLDTR_E_FMD_GLOBALITEM);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- // Validate global field:
- // Must be static
- if(!IsFdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_GLOBALNOTSTATIC);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must have a non-zero RVA
- /*
- if(!bHasValidRVA)
- {
- REPORT_ERROR0(VLDTR_E_FD_GLOBALNORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- */
- }
-
- // Check for duplicates, except global fields with PrivateScope.
- if (*szName && cbSig && !IsFdPrivateScope(dwFlags))
- {
- hr = ImportHelper::FindField(pMiniMd, tkTypeDef, szName, pbSig, cbSig, &tkFieldDef, rid);
- if (hr == S_OK)
- {
- if(!IsFdPrivateScope(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_FD_DUP, tkFieldDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else hr = S_OK;
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- {
- hr = S_OK;
- }
- else
- {
- IfFailGo(hr);
- }
- }
- // Field having security must be marked fdHasSecurity and vice versa
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
- ULONG index;
- BOOL bHasSecurity = FALSE;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- DeclSecurityRec *pDeclSecurityRecord;
- IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
- if ( veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
- {
- bHasSecurity = TRUE;
- break;
- }
- }
- if(!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
- {
- bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
- "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
- }
- if(bHasSecurity)
- {
- REPORT_ERROR0(VLDTR_E_FMD_SECURNOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // Field having marshaling must be marked fdHasFieldMarshal and vice versa
- IfFailGo(pMiniMd->FindFieldMarshalHelper(veCtxt.Token, &tempRid));
- if (InvalidRid(tempRid) == (IsFdHasFieldMarshal(dwFlags) != 0))
- {
- REPORT_ERROR0(IsFdHasFieldMarshal(dwFlags)? VLDTR_E_FD_MARKEDNOMARSHAL : VLDTR_E_FD_MARSHALNOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Field having const value must be marked fdHasDefault and vice versa
- IfFailGo(pMiniMd->FindConstantHelper(veCtxt.Token, &tempRid));
- if(InvalidRid(tempRid) == (IsFdHasDefault(dwFlags) != 0))
- {
- REPORT_ERROR0(IsFdHasDefault(dwFlags)? VLDTR_E_FD_MARKEDNODEFLT : VLDTR_E_FD_DEFLTNOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check the field's impl.map
- {
- ULONG iRecord;
- IfFailGo(pMiniMd->FindImplMapHelper(veCtxt.Token, &iRecord));
- if(IsFdPinvokeImpl(dwFlags))
- {
- // must be static
- if(!IsFdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTSTATIC);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // must have ImplMap
- if (InvalidRid(iRecord))
- {
- REPORT_ERROR0(VLDTR_E_FMD_MARKEDNOPINVOKE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- // must have no ImplMap
- if (!InvalidRid(iRecord))
- {
- REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- if (!InvalidRid(iRecord))
- {
- hr = ValidateImplMap(iRecord);
- if(hr != S_OK)
- {
- REPORT_ERROR0(VLDTR_E_FMD_BADIMPLMAP);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
-
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateField()
-
-//*****************************************************************************
-// Validate the given MethodPtr.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodPtr(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateMethodPtr()
-
-
-//*****************************************************************************
-// Validate the given Method.
-//*****************************************************************************
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
-#endif
-HRESULT RegMeta::ValidateMethod(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- MethodRec *pRecord = NULL; // Method record.
- mdTypeDef tkTypeDef; // Parent TypeDef token.
- mdMethodDef tkMethodDef; // Duplicate MethodDef token.
- LPCSTR szName; // MethodDef name.
- DWORD dwFlags = 0; // Method flags.
- DWORD dwImplFlags = 0; // Method impl.flags.
- PCCOR_SIGNATURE pbSig; // MethodDef signature.
- ULONG cbSig; // Signature size in bytes.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- BOOL bIsCtor=FALSE;
- BOOL bIsCctor=FALSE;
- BOOL bIsGlobal=FALSE;
- BOOL bIsParentImport = FALSE;
- BOOL bIsGeneric = FALSE;
- unsigned retType;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the MethodDef record.
- veCtxt.Token = TokenFromRid(rid, mdtMethodDef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetMethodRecord(rid, &pRecord));
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getNameOfMethod(pRecord, &szName));
- if (!*szName)
- {
- // Method name is NULL.
- REPORT_ERROR0(VLDTR_E_MD_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
- bIsCtor = (0 == strcmp(szName,BASE_CTOR_NAME));
- bIsCctor = (0 == strcmp(szName,BASE_CCTOR_NAME));
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Get the parent, flags and signature of the Method.
- IfFailGo(pMiniMd->FindParentOfMethodHelper(TokenFromRid(rid, mdtMethodDef), &tkTypeDef));
- dwFlags = pMiniMd->getFlagsOfMethod(pRecord);
- dwImplFlags = pMiniMd->getImplFlagsOfMethod(pRecord);
- IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
-
- // Check for duplicates.
- if (*szName && cbSig && !IsNilToken(tkTypeDef) && !IsMdPrivateScope(dwFlags))
- {
- hr = ImportHelper::FindMethod(pMiniMd, tkTypeDef, szName, pbSig, cbSig, &tkMethodDef, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_MD_DUP, tkMethodDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-
- // No further error checking for VtblGap methods.
- if (IsVtblGapName(szName))
- {
- hr = hrSave;
- goto ErrExit;
- }
-
- // Validate Method signature.
- IfFailGo(ValidateMethodSig(TokenFromRid(rid, mdtMethodDef), pbSig, cbSig,
- dwFlags));
- if (hr != S_OK)
- SetVldtrCode(&hrSave, hr);
-
- // Validate that the parent is not nil.
- if (IsNilToken(tkTypeDef))
- {
- REPORT_ERROR0(VLDTR_E_MD_PARNIL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (RidFromToken(tkTypeDef) != RidFromToken(m_tdModule))
- {
- if(TypeFromToken(tkTypeDef) == mdtTypeDef)
- {
- TypeDefRec *pTDRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pTDRec));
- DWORD dwTDFlags = pTDRec->GetFlags();
- LPCSTR szTDName;
- IfFailGo(pMiniMd->getNameOfTypeDef(pTDRec, &szTDName));
- LPCSTR szTDNameSpace;
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTDRec, &szTDNameSpace));
- BOOL fIsTdValue=FALSE, fIsTdEnum=FALSE;
- mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTDRec);
-
- if(0 == strcmp(szTDNameSpace,BASE_NAMESPACE))
- {
- fIsTdEnum = (0 == strcmp(szTDName,BASE_ENUM_CLASSNAME));
- if(!fIsTdEnum)
- {
- fIsTdValue = (0 == strcmp(szTDName,BASE_VTYPE_CLASSNAME));
- }
- }
- if(fIsTdEnum || fIsTdValue)
- {
- fIsTdEnum = fIsTdValue = FALSE; // System.Enum and System.ValueType themselves are classes
- }
- else if(RidFromToken(tkExtends))
- {
- if(TypeFromToken(tkExtends) == mdtTypeDef)
- {
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pTDRec));
- IfFailGo(pMiniMd->getNameOfTypeDef(pTDRec, &szTDName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTDRec, &szTDNameSpace));
- }
- else if(TypeFromToken(tkExtends) == mdtTypeSpec)
- {
- fIsTdEnum = fIsTdValue = FALSE; // a type extending a spec cannot be an enum or value type
- // the assignments are redundant, but clear.
- }
- else
- {
- TypeRefRec *pTRRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pTRRec));
- IfFailGo(pMiniMd->getNameOfTypeRef(pTRRec, &szTDName));
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTRRec, &szTDNameSpace));
- }
-
- if(0 == strcmp(szTDNameSpace,BASE_NAMESPACE))
- {
- fIsTdEnum = (0 == strcmp(szTDName,BASE_ENUM_CLASSNAME));
- if(!fIsTdEnum)
- {
- fIsTdValue = (0 == strcmp(szTDName,BASE_VTYPE_CLASSNAME));
- }
- else fIsTdValue = FALSE;
- }
- }
-
- // If Method is abstract, verify parent is abstract.
- if(IsMdAbstract(dwFlags) && !IsTdAbstract(dwTDFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_ABSTPARNOTABST, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // If parent is import, method must have zero RVA, otherwise it depends...
- if(IsTdImport(dwTDFlags)) bIsParentImport = TRUE;
- if(IsTdInterface(dwTDFlags))
- {
- if(!IsMdStatic(dwFlags))
- {
- // No non-abstract instance methods in interface.
- if(!IsMdAbstract(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_NOTSTATABSTININTF, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // No non-public instance methods in interface.
- if(!IsMdPublic(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_NOTPUBININTF, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // If Method is constructor, verify parent is not interface.
- if(bIsCtor)
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORININTF, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }//end if(interface)
- if((fIsTdValue || fIsTdEnum) && IsMiSynchronized(dwImplFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_SYNCMETHODINVTYPE, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(bIsCtor)
- {
- // .ctor must be instance
- if(IsMdStatic(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORSTATIC, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }//end if .ctor
- else if(bIsCctor)
- {
- // .cctor must be static
- if(!IsMdStatic(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_CCTORNOTSTATIC, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ..cctor must have default callconv
- IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
- if(IMAGE_CEE_CS_CALLCONV_DEFAULT != CorSigUncompressData(pbSig))
- {
- REPORT_ERROR0(VLDTR_E_MD_CCTORCALLCONV);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // .cctor must have no arguments
- if(0 != CorSigUncompressData(pbSig))
- {
- REPORT_ERROR0(VLDTR_E_MD_CCTORHASARGS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
-
- }//end if .cctor
- if(bIsCtor || bIsCctor)
- {
- // .ctor, .cctor must be SpecialName and RTSpecialName
- if(!(IsMdSpecialName(dwFlags) && IsMdRTSpecialName(dwFlags)))
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORNOTSNRTSN, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-#ifdef NO_SUCH_CHECKS_NEEDED_SPEC_TO_BE_UODATED
- // .ctor, .cctor must not be virtual
- if(IsMdVirtual(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORVIRT, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // .ctor, .cctor must not be abstract
- if(IsMdAbstract(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORABST, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // .ctor, .cctor must not be PInvoke
- if(IsMdPinvokeImpl(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_CTORPINVOKE, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // .ctor,.cctor must have RVA!=0
- if(pRecord->GetRVA()==0)
- {
- REPORT_ERROR0(VLDTR_E_MD_CTORZERORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-#endif
- }//end if .ctor or .cctor
- }// end if(parent == TypeDef)
- }// end if not Module
- else // i.e. if (RidFromToken(tkTypeDef) == RidFromToken(m_tdModule))
- {
- bIsGlobal = TRUE;
- // Globals are not CLS-compliant
- REPORT_ERROR0(VLDTR_E_FMD_GLOBALITEM);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- // Validate global method:
- // Must be static
- if(!IsMdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_GLOBALNOTSTATIC);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must not be abstract or virtual
- if(IsMdAbstract(dwFlags) || IsMdVirtual(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_GLOBALABSTORVIRT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must be not .ctor or .cctor
- if(bIsCtor)
- {
- REPORT_ERROR0(VLDTR_E_MD_GLOBALCTORCCTOR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- } //end if Module
-
- // Signature specifics: .ctor, .cctor, entrypoint
- if(bIsCtor || bIsCctor)
- {
- // .ctor, .cctor must return void
- IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
- CorSigUncompressData(pbSig); // get call conv out of the way
- CorSigUncompressData(pbSig); // get num args out of the way
- while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
- || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
- if(retType != ELEMENT_TYPE_VOID)
- {
- REPORT_ERROR0(VLDTR_E_MD_CTORNOTVOID);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- if(g_tkEntryPoint == veCtxt.Token)
- {
- ULONG ulCallConv;
- // EP must be static
- if(!IsMdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_EP_INSTANCE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // EP can't belong to generic class or nested in generic class
- mdToken tkTypeDefCur;
- for(tkTypeDefCur = tkTypeDef; tkTypeDefCur != mdTokenNil;)
- {
- HENUMInternal hEnumTyPars;
- ULONG ulTypeDefArity = 0;
- hr = pMiniMd->FindGenericParamHelper(tkTypeDefCur, &hEnumTyPars);
- if (SUCCEEDED(hr))
- {
- IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulTypeDefArity));
- HENUMInternal::ClearEnum(&hEnumTyPars);
- if (ulTypeDefArity != 0)
- {
- REPORT_ERROR0(VLDTR_E_EP_GENERIC_TYPE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- if(ulTypeDefArity == 0)
- {
- // This class is not generic, how about the encloser?
- RID iRecord;
- IfFailGo(pMiniMd->FindNestedClassHelper(tkTypeDefCur, &iRecord));
-
- if (InvalidRid(iRecord))
- {
- tkTypeDefCur = mdTokenNil;
- }
- else
- {
- NestedClassRec *pNestedClassRec;
- IfFailGo(pMiniMd->GetNestedClassRecord(iRecord, &pNestedClassRec));
- tkTypeDefCur = pMiniMd->getEnclosingClassOfNestedClass(pNestedClassRec);
- }
- }
- else
- tkTypeDefCur = mdTokenNil;
- }
-
- // EP must have a predetermined signature (different for DLL and EXE
- IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &pbSig, &cbSig));
- ulCallConv = CorSigUncompressData(pbSig); // get call conv out of the way
- // EP can't be generic
- if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- // Skip the arity
- CorSigUncompressData(pbSig);
- REPORT_ERROR0(VLDTR_E_EP_GENERIC_METHOD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // EP must have 0 or 1 argument
- unsigned nArgs = CorSigUncompressData(pbSig);
- if(g_fIsDLL)
- {
- if(nArgs != 3)
- {
- REPORT_ERROR1(VLDTR_E_EP_TOOMANYARGS, 3);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- //EP must return I4
- while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
- || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
-
- if(retType != ELEMENT_TYPE_I4)
- {
- REPORT_ERROR0(VLDTR_E_EP_BADRET);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Arguments must be VOID*, U4, VOID*
- if(nArgs)
- {
- unsigned jj;
- bool badarg;
- for(jj=0; jj<nArgs;jj++)
- {
- while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
- || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
-
- switch(jj)
- {
- case 0:
- case 2:
- badarg = (retType != ELEMENT_TYPE_PTR)
- ||(CorSigUncompressData(pbSig) != ELEMENT_TYPE_VOID);
- break;
-
- case 1:
- badarg = (retType != ELEMENT_TYPE_U4);
- break;
-
- default:
- badarg = true;
- }
- if(badarg)
- {
- REPORT_ERROR1(VLDTR_E_EP_BADARG, jj+1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
- else
- {
- if(nArgs > 1)
- {
- REPORT_ERROR1(VLDTR_E_EP_TOOMANYARGS, 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- //EP must return VOID, I4 or U4
- while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
- || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
-
- if((retType != ELEMENT_TYPE_VOID)&&(retType != ELEMENT_TYPE_I4)&&(retType != ELEMENT_TYPE_U4))
- {
- REPORT_ERROR0(VLDTR_E_EP_BADRET);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Argument (if any) must be vector of strings
- if(nArgs)
- {
- while (((retType=CorSigUncompressData(pbSig)) == ELEMENT_TYPE_CMOD_OPT)
- || (retType == ELEMENT_TYPE_CMOD_REQD)) CorSigUncompressToken(pbSig);
-
- if((retType != ELEMENT_TYPE_SZARRAY)||(CorSigUncompressData(pbSig) != ELEMENT_TYPE_STRING))
- {
- REPORT_ERROR1(VLDTR_E_EP_BADARG, 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- } // end if(IsDll)--else
- } // end if (IsEntryPoint)
-
-
- // Check method RVA
- if(pRecord->GetRVA()==0)
- {
- if(!(IsMdPinvokeImpl(dwFlags) || IsMdAbstract(dwFlags)
- || IsMiRuntime(dwImplFlags) || IsMiInternalCall(dwImplFlags)
- || bIsParentImport))
- {
- REPORT_ERROR0(VLDTR_E_MD_ZERORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- if(m_pStgdb && m_pStgdb->m_pImage)
- {
- NewHolder<PEDecoder> pe;
-
- EX_TRY
- {
- // We need to use different PEDecoder constructors based on the type of data we give it.
- // We use the one with a 'bool' as the second argument when dealing with a mapped file,
- // and we use the one that takes a COUNT_T as the second argument when dealing with a
- // flat file.
-
- if (m_pStgdb->m_pStgIO->GetMemoryMappedType() == MTYPE_IMAGE)
- pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, false);
- else
- pe = new (nothrow) PEDecoder(m_pStgdb->m_pImage, (COUNT_T)(m_pStgdb->m_dwImageSize));
-
- }
- EX_CATCH
- {
- hr = COR_E_BADIMAGEFORMAT;
- }
- EX_END_CATCH(SwallowAllExceptions)
-
- IfFailGo(hr);
- IfNullGo(pe);
-
- if (!pe->CheckRva(pRecord->GetRVA()))
- {
- REPORT_ERROR1(VLDTR_E_MD_BADRVA, pRecord->GetRVA());
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(IsMiManaged(dwImplFlags) && (IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags)))
- {
- HRESULT hrTemp = S_OK;
- // validate locals signature token
- EX_TRY
- {
- COR_ILMETHOD_DECODER method((COR_ILMETHOD*) pe->GetRvaData(pRecord->GetRVA()));
- if (method.LocalVarSigTok)
- {
- if((TypeFromToken(method.GetLocalVarSigTok()) != mdtSignature) ||
- (!IsValidToken(method.GetLocalVarSigTok())) || (RidFromToken(method.GetLocalVarSigTok())==0))
- {
- hrTemp = _ValidateErrorHelper(VLDTR_E_MD_BADLOCALSIGTOK, veCtxt, method.GetLocalVarSigTok());
- if (SUCCEEDED(hrTemp))
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- EX_CATCH
- {
- hrTemp = _ValidateErrorHelper(VLDTR_E_MD_BADHEADER, veCtxt);
- if (SUCCEEDED(hrTemp))
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- EX_END_CATCH(SwallowAllExceptions)
-
- IfFailGo(hrTemp);
- }
- }
- }
-
- if(IsMdAbstract(dwFlags) || bIsParentImport
- || IsMiRuntime(dwImplFlags) || IsMiInternalCall(dwImplFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_ZERORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // Check the method flags
- // Validate access
- if((dwFlags & mdMemberAccessMask) == mdMemberAccessMask)
- {
- REPORT_ERROR0(VLDTR_E_FMD_BADACCESSFLAG);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Final/NewSlot must be virtual
- if((IsMdFinal(dwFlags)||IsMdNewSlot(dwFlags)||IsMdCheckAccessOnOverride(dwFlags))
- && !IsMdVirtual(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_FINNOTVIRT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Static can't be final or virtual
- if(IsMdStatic(dwFlags))
- {
- if(IsMdFinal(dwFlags) || IsMdVirtual(dwFlags) || IsMdNewSlot(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_STATANDFINORVIRT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else // non-static can't be an entry point
- {
- if(g_tkEntryPoint == veCtxt.Token)
- {
- REPORT_ERROR0(VLDTR_E_EP_INSTANCE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- if(IsMdAbstract(dwFlags))
- {
- // Can't be both abstract and final
- if(IsMdFinal(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_ABSTANDFINAL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // If abstract, must be not miForwardRef, not Pinvoke, and must be virtual
- if(IsMiForwardRef(dwImplFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_ABSTANDIMPL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(IsMdPinvokeImpl(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_ABSTANDPINVOKE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!IsMdVirtual(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MD_ABSTNOTVIRT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // If PrivateScope, must have RVA!=0
- if(IsMdPrivateScope(dwFlags) && (pRecord->GetRVA() ==0))
- {
- REPORT_ERROR0(VLDTR_E_MD_PRIVSCOPENORVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // RTSpecialName => SpecialName
- if(IsMdRTSpecialName(dwFlags) && !IsMdSpecialName(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_RTSNNOTSN);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Method having security must be marked mdHasSecurity and vice versa
- {
- ULONG ridStart = 1;
- ULONG ridEnd = pMiniMd->getCountDeclSecuritys() + 1;
- ULONG index;
- BOOL bHasSecurity = FALSE;
- for (index = ridStart; index < ridEnd; index ++ )
- {
- DeclSecurityRec *pDeclSecurityRecord;
- IfFailGo(pMiniMd->GetDeclSecurityRecord(index, &pDeclSecurityRecord));
- if ( veCtxt.Token == pMiniMd->getParentOfDeclSecurity(pDeclSecurityRecord))
- {
- bHasSecurity = TRUE;
- break;
- }
- }
- if(!bHasSecurity) // No records, check for CA "SuppressUnmanagedCodeSecurityAttribute"
- {
- bHasSecurity = (S_OK == ImportHelper::GetCustomAttributeByName(pMiniMd, veCtxt.Token,
- "System.Security.SuppressUnmanagedCodeSecurityAttribute", NULL, NULL));
- }
- if(bHasSecurity != (IsMdHasSecurity(dwFlags)!=0))
- {
- REPORT_ERROR0(bHasSecurity ? VLDTR_E_FMD_SECURNOTMARKED : VLDTR_E_FMD_MARKEDNOSECUR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // Validate method semantics
- {
- MethodSemanticsRec *pRec;
- ULONG ridEnd;
- ULONG index;
- unsigned uTally = 0;
- mdToken tkEventProp;
- ULONG iCount;
- DWORD dwSemantic;
- // get the range of method rids given a typedef
- ridEnd = pMiniMd->getCountMethodSemantics();
-
- for (index = 1; index <= ridEnd; index++ )
- {
- IfFailGo(pMiniMd->GetMethodSemanticsRecord(index, &pRec));
- if ( pMiniMd->getMethodOfMethodSemantics(pRec) == veCtxt.Token )
- {
- uTally++;
- if(uTally > 1)
- {
- REPORT_ERROR0(VLDTR_E_MD_MULTIPLESEMANTICS);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- tkEventProp = pMiniMd->getAssociationOfMethodSemantics(pRec);
- if((TypeFromToken(tkEventProp) == mdtEvent)||(TypeFromToken(tkEventProp) == mdtProperty))
- {
- iCount = (TypeFromToken(tkEventProp) == mdtEvent) ? pMiniMd->getCountEvents() :
- pMiniMd->getCountPropertys();
- if(RidFromToken(tkEventProp) > iCount)
- {
- REPORT_ERROR1(VLDTR_E_MD_SEMANTICSNOTEXIST, tkEventProp);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_MD_INVALIDSEMANTICS, tkEventProp);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- // One and only one semantics flag must be set
- iCount = 0;
- dwSemantic = pRec->GetSemantic();
- if(IsMsSetter(dwSemantic)) iCount++;
- if(IsMsGetter(dwSemantic)) iCount++;
- if(IsMsOther(dwSemantic)) iCount++;
- if(IsMsAddOn(dwSemantic)) iCount++;
- if(IsMsRemoveOn(dwSemantic)) iCount++;
- if(IsMsFire(dwSemantic)) iCount++;
- if(iCount != 1)
- {
- REPORT_ERROR1(iCount ? VLDTR_E_MD_MULTSEMANTICFLAGS : VLDTR_E_MD_NOSEMANTICFLAGS, tkEventProp);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- }// end for(index)
- }
- // Check the method's impl.map
- {
- RID iRecord;
- IfFailGo(pMiniMd->FindImplMapHelper(veCtxt.Token, &iRecord));
- if(IsMdPinvokeImpl(dwFlags))
- {
- // must be static
- if(!IsMdStatic(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTSTATIC);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // must have either ImplMap or RVA == 0
- if (InvalidRid(iRecord))
- {
- if(pRecord->GetRVA()==0)
- {
- REPORT_ERROR0(VLDTR_E_FMD_MARKEDNOPINVOKE);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- if(pRecord->GetRVA()!=0)
- {
- // C++ emits ImplMaps for IJW methods,
- // with resolution=ModuleRef with name ""
- ImplMapRec *pIMRecord;
- mdToken tkModuleRef;
- IfFailGo(pMiniMd->GetImplMapRecord(iRecord, &pIMRecord));
- tkModuleRef = pMiniMd->getImportScopeOfImplMap(pIMRecord);
- if((TypeFromToken(tkModuleRef) == mdtModuleRef) && (!IsNilToken(tkModuleRef)))
- {
- ModuleRefRec *pMRRecord; // ModuleRef record.
- LPCUTF8 szMRName; // ModuleRef name.
- // Get the ModuleRef record.
- IfFailGo(pMiniMd->GetModuleRefRecord(RidFromToken(tkModuleRef), &pMRRecord));
- // Check ModuleRef name is "".
- IfFailGo(pMiniMd->getNameOfModuleRef(pMRRecord, &szMRName));
- if (*szMRName)
- {
- REPORT_ERROR0(VLDTR_E_MD_RVAANDIMPLMAP);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- else
- {
- hr = ValidateImplMap(iRecord);
- if(hr != S_OK)
- {
- REPORT_ERROR0(VLDTR_E_FMD_BADIMPLMAP);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- }
-
- }
- else
- {
- // must have no ImplMap
- if (!InvalidRid(iRecord))
- {
- REPORT_ERROR0(VLDTR_E_FMD_PINVOKENOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- // Validate params
- {
- ULONG ridStart = pMiniMd->getParamListOfMethod(pRecord);
- ULONG ridEnd;
- IfFailGo(pMiniMd->getEndParamListOfMethod(rid, &ridEnd));
- ParamRec* pRec;
- ULONG cbSigT;
- PCCOR_SIGNATURE typePtr;
- IfFailGo(pMiniMd->getSignatureOfMethod(pRecord, &typePtr, &cbSigT));
- unsigned callConv = CorSigUncompressData(typePtr); // get the calling convention out of the way
- unsigned numTyArgs = 0;
- if (callConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- bIsGeneric = TRUE;
- numTyArgs = CorSigUncompressData(typePtr);
- }
-
- unsigned numArgs = CorSigUncompressData(typePtr);
- USHORT usPrevSeq = 0;
-
- for(ULONG ridP = ridStart; ridP < ridEnd; ridP++)
- {
- RID tempRid;
- IfFailGo(pMiniMd->GetParamRecord(ridP, &pRec));
- // Sequence order must be ascending
- if(ridP > ridStart)
- {
- if(pRec->GetSequence() <= usPrevSeq)
- {
- REPORT_ERROR2(VLDTR_E_MD_PARAMOUTOFSEQ, ridP-ridStart,pRec->GetSequence());
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
- usPrevSeq = pRec->GetSequence();
- // Sequence value must not exceed num of arguments
- if(usPrevSeq > numArgs)
- {
- REPORT_ERROR2(VLDTR_E_MD_PARASEQTOOBIG, ridP-ridStart,usPrevSeq);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Param having marshaling must be marked pdHasFieldMarshal and vice versa
- IfFailGo(pMiniMd->FindFieldMarshalHelper(TokenFromRid(ridP,mdtParamDef), &tempRid));
- if (InvalidRid(tempRid) == (IsPdHasFieldMarshal(pRec->GetFlags()) != 0))
- {
- REPORT_ERROR1(IsPdHasFieldMarshal(pRec->GetFlags()) ? VLDTR_E_MD_PARMMARKEDNOMARSHAL
- : VLDTR_E_MD_PARMMARSHALNOTMARKED, ridP-ridStart);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Param having const value must be marked pdHasDefault and vice versa
- IfFailGo(pMiniMd->FindConstantHelper(TokenFromRid(ridP,mdtParamDef), &tempRid));
- if (InvalidRid(tempRid) == (IsPdHasDefault(pRec->GetFlags()) != 0))
- {
- REPORT_ERROR1(IsPdHasDefault(pRec->GetFlags()) ? VLDTR_E_MD_PARMMARKEDNODEFLT
- : VLDTR_E_MD_PARMDEFLTNOTMARKED, ridP-ridStart);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
-
- // Generic Method related checks
- if (bIsGeneric)
- {
- if (bIsCctor)
- {
- REPORT_ERROR0(VLDTR_E_MD_GENERIC_CCTOR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (bIsCtor)
- {
- REPORT_ERROR0(VLDTR_E_MD_GENERIC_CTOR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (bIsParentImport)
- {
- REPORT_ERROR0(VLDTR_E_MD_GENERIC_IMPORT);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMethod()
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
-//*****************************************************************************
-// Validate the given ParamPtr.
-//*****************************************************************************
-HRESULT RegMeta::ValidateParamPtr(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateParamPtr()
-
-//*****************************************************************************
-// Validate the given Param.
-//*****************************************************************************
-HRESULT RegMeta::ValidateParam(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- ParamRec *pRecord; // Param record
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- LPCSTR szName; // Param name.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the InterfaceImpl record.
- veCtxt.Token = TokenFromRid(rid, mdtParamDef);
- veCtxt.uOffset = 0;
-
- DWORD dwBadFlags = 0;
- DWORD dwFlags = 0;
- IfFailGo(pMiniMd->GetParamRecord(rid, &pRecord));
- // Name, if any, must not exceed MAX_CLASSNAME_LENGTH
- IfFailGo(pMiniMd->getNameOfParam(pRecord, &szName));
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Flags must be as defined in CorHdr.h
- dwBadFlags = ~(pdIn | pdOut | pdOptional | pdHasDefault | pdHasFieldMarshal);
- dwFlags = pRecord->GetFlags();
- if(dwFlags & dwBadFlags)
- {
- REPORT_ERROR1(VLDTR_E_PD_BADFLAGS, dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateParam()
-
-//*****************************************************************************
-// Helper function for ValidateInterfaceImpl
-//*****************************************************************************
-int IsMethodImplementedByClass(CMiniMdRW *pMiniMd,
- mdToken tkMethod,
- LPCUTF8 szName,
- PCCOR_SIGNATURE pSig,
- ULONG cbSig,
- mdToken tkClass)
-{
- HRESULT hr;
- int numImpl = 0;
- if(TypeFromToken(tkMethod) == mdtMethodDef)
- {
- if(TypeFromToken(tkClass) == mdtTypeSpec)
- {
- // We are trying to find out if an interface method is implemented in the generic class tkClass.
- // Simple signature comparison doesn't work here, because "int Method()" in the interface might
- // be implemented by "T Type.Method()" in the generic type.
- // Therefore we assume it is implemented. Atlernatively we could implement better signature
- // comparison which would match T with any other type, etc.
- numImpl = 1;
- }
- else if(TypeFromToken(tkClass) == mdtTypeDef)
- {
- TypeDefRec *pClass;
- IfFailRet(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pClass));
- RID ridClsStart = pMiniMd->getMethodListOfTypeDef(pClass);
- RID ridClsEnd;
- IfFailRet(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(tkClass), &ridClsEnd));
- mdMethodDef tkFoundMethod = 0;
- DWORD dwFoundMethodFlags = 0;
- // Check among methods
- hr = ImportHelper::FindMethod(pMiniMd, tkClass, szName, pSig, cbSig, &tkFoundMethod, 0);
- if(SUCCEEDED(hr))
- {
- MethodRec * pMethod;
- IfFailRet(pMiniMd->GetMethodRecord(RidFromToken(tkFoundMethod), &pMethod));
- if(pMethod)
- {
- dwFoundMethodFlags = pMiniMd->getFlagsOfMethod(pMethod);
- if(IsMdVirtual(dwFoundMethodFlags)) //&&!IsMdNewSlot(dwFoundMethodFlags))
- numImpl = 1;
- }
- }
- if (numImpl==0) //if(hr == CLDB_E_RECORD_NOTFOUND)
- { // Check among MethodImpls
- RID ridImpl;
- for(RID idxCls = ridClsStart; idxCls < ridClsEnd; idxCls++)
- {
- RID ridCls;
- IfFailRet(pMiniMd->GetMethodRid(idxCls, &ridCls));
-
- hr = ImportHelper::FindMethodImpl(pMiniMd,tkClass,TokenFromRid(ridCls,mdtMethodDef),
- tkMethod,&ridImpl);
- if(hr != CLDB_E_RECORD_NOTFOUND)
- {
- if(SUCCEEDED(hr)) numImpl++;
- break;
- }
- }
- if(numImpl == 0)
- {
- // Check if parent class implements this method
- mdToken tkParent = pMiniMd->getExtendsOfTypeDef(pClass);
- if(RidFromToken(tkParent))
- numImpl = IsMethodImplementedByClass(pMiniMd,tkMethod,szName,pSig,cbSig,tkParent);
- }
- }
- }
- else if (TypeFromToken(tkClass) == mdtTypeRef)
- {
- TypeRefRec *pRecord; // TypeRef record.
- LPCSTR szTRNamespace; // TypeRef Namespace.
- LPCSTR szTRName; // TypeRef Name.
-
- // Get the TypeRef record.
- IfFailRet(pMiniMd->GetTypeRefRecord(RidFromToken(tkClass), &pRecord));
-
- // Check name is not NULL.
- IfFailRet(pMiniMd->getNamespaceOfTypeRef(pRecord, &szTRNamespace));
- IfFailRet(pMiniMd->getNameOfTypeRef(pRecord, &szTRName));
-
- mdToken tkRefScope = pMiniMd->getResolutionScopeOfTypeRef(pRecord);
- if (tkRefScope == TokenFromRid(1, mdtModule))
- {
- // if the typeref is referring to a type in this module then
- // we should check the type definition it is referring to
- mdTypeDef tkTypeDef;
- hr = ImportHelper::FindTypeDefByName(pMiniMd, szTRNamespace, szTRName, tkRefScope, &tkTypeDef);
- if (SUCCEEDED(hr))
- numImpl = IsMethodImplementedByClass(pMiniMd, tkMethod, szName, pSig, cbSig, tkTypeDef);
- }
- else if ((strcmp(szTRNamespace, BASE_NAMESPACE) == 0) &&
- ((strcmp(szTRName, BASE_OBJECT_CLASSNAME) == 0) ||
- (strcmp(szTRName, BASE_VTYPE_CLASSNAME) == 0) ||
- (strcmp(szTRName, BASE_ENUM_CLASSNAME) == 0)))
- {
- if (((strcmp(szName, SYSTEM_OBJECT_TOSTRING_METHODNAME) == 0) &&
- (cbSig == _countof(g_sigSystemObject_ToString)) &&
- (memcmp(pSig, g_sigSystemObject_ToString, cbSig) == 0)) ||
- ((strcmp(szName, SYSTEM_OBJECT_GETHASHCODE_METHODNAME) == 0) &&
- (cbSig == _countof(g_sigSystemObject_GetHashCode)) &&
- (memcmp(pSig, g_sigSystemObject_GetHashCode, cbSig) == 0)) ||
- ((strcmp(szName, SYSTEM_OBJECT_EQUALS_METHODNAME) == 0) &&
- (cbSig == _countof(g_sigSystemObject_Equals)) &&
- (memcmp(pSig, g_sigSystemObject_Equals, cbSig) == 0)))
- {
- numImpl = 1; // Method signature matches one of System.Object's virtual methods
- }
- else
- {
- numImpl = 0; // These classes (System.Object, System.ValueType and System.Enum) don't implement any other virtual methods
- }
- }
- else
- {
- numImpl = -1; // The method is defined in another module, we cannot verify it (no external modules are loaded)
- }
- }
- }
- return numImpl;
-}
-
-//*****************************************************************************
-// Validate the given InterfaceImpl.
-//*****************************************************************************
-//@todo GENERICS: complete logic for type specs
-// - for now, we just allow them, but we should be checking more properties
-HRESULT RegMeta::ValidateInterfaceImpl(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- InterfaceImplRec *pRecord; // InterfaceImpl record.
- mdTypeDef tkClass; // Class implementing the interface.
- mdToken tkInterface; // TypeDef for the interface.
- mdInterfaceImpl tkInterfaceImpl; // Duplicate InterfaceImpl.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- BOOL fCheckTheMethods=TRUE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the InterfaceImpl record.
- veCtxt.Token = TokenFromRid(rid, mdtInterfaceImpl);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetInterfaceImplRecord(rid, &pRecord));
-
- // Get implementing Class and the TypeDef for the interface.
- tkClass = pMiniMd->getClassOfInterfaceImpl(pRecord);
-
- // No validation needs to be done on deleted records.
- if (IsNilToken(tkClass))
- goto ErrExit;
-
- tkInterface = pMiniMd->getInterfaceOfInterfaceImpl(pRecord);
-
- // Validate that the Class is TypeDef.
- if((!IsValidToken(tkClass))||(TypeFromToken(tkClass) != mdtTypeDef)/*&&(TypeFromToken(tkClass) != mdtTypeRef)*/)
- {
- REPORT_ERROR1(VLDTR_E_IFACE_BADIMPL, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- fCheckTheMethods = FALSE;
- }
- // Validate that the Interface is TypeDef or TypeRef or TypeSpec
- if((!IsValidToken(tkInterface))||(TypeFromToken(tkInterface) != mdtTypeDef)&&(TypeFromToken(tkInterface) != mdtTypeRef)
- &&(TypeFromToken(tkInterface) != mdtTypeSpec))
- {
- REPORT_ERROR1(VLDTR_E_IFACE_BADIFACE, tkInterface);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- fCheckTheMethods = FALSE;
- }
- // Validate that Interface is marked tdInterface.
- else if(TypeFromToken(tkInterface) == mdtTypeDef)
- {
- TypeDefRec *pTDRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkInterface), &pTDRec));
- if(!IsTdInterface(pTDRec->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_IFACE_NOTIFACE, tkInterface);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- }
-
- // Look for duplicates.
- hr = ImportHelper::FindInterfaceImpl(pMiniMd, tkClass, tkInterface,
- &tkInterfaceImpl, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_IFACE_DUP, tkInterfaceImpl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
-
- // Validate that the Class (if not interface or abstract) implements all the methods of Interface
- if((TypeFromToken(tkInterface) == mdtTypeDef) && fCheckTheMethods && (tkInterface != tkClass))
- {
- TypeDefRec *pClass;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pClass));
- if(!(IsTdAbstract(pClass->GetFlags())
- ||IsTdImport(pClass->GetFlags())
- ||IsTdInterface(pClass->GetFlags())))
- {
- TypeDefRec *pInterface;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkInterface), &pInterface));
- RID ridIntStart = pMiniMd->getMethodListOfTypeDef(pInterface);
- RID ridIntEnd;
- IfFailGo(pMiniMd->getEndMethodListOfTypeDef(RidFromToken(tkInterface), &ridIntEnd));
- MethodRec* pIntMethod;
- for(RID idxInt = ridIntStart; idxInt < ridIntEnd; idxInt++)
- {
- RID ridInt;
- IfFailGo(pMiniMd->GetMethodRid(idxInt, &ridInt));
- IfFailGo(pMiniMd->GetMethodRecord(ridInt, &pIntMethod));
- const char* szName;
- IfFailGo(pMiniMd->getNameOfMethod(pIntMethod, &szName));
- if(!IsMdStatic(pIntMethod->GetFlags())
- && !IsDeletedName(szName)
- && !IsVtblGapName(szName))
- {
- ULONG cbSig;
- PCCOR_SIGNATURE pSig;
- IfFailGo(pMiniMd->getSignatureOfMethod(pIntMethod, &pSig, &cbSig));
- if(cbSig)
- {
- int num = IsMethodImplementedByClass(pMiniMd,TokenFromRid(ridInt,mdtMethodDef),szName,pSig,cbSig,tkClass);
- if(num == 0)
- { // Error: method not implemented
- REPORT_ERROR3(VLDTR_E_IFACE_METHNOTIMPL, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(num == -1)
- {
- // Traced to a TypeRef, which might implement the method, give warning
- REPORT_ERROR3(VLDTR_E_IFACE_METHNOTIMPLTHISMOD, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- if(num > 1)
- { // Error: multiple method implementation
- REPORT_ERROR3(VLDTR_E_IFACE_METHMULTIMPL, tkClass, tkInterface, TokenFromRid(ridInt,mdtMethodDef));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
- }
- }
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateInterfaceImpl()
-
-//*****************************************************************************
-// Validate the given GenericParam.
-//*****************************************************************************
-HRESULT RegMeta::ValidateGenericParam(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- GenericParamRec *pRecord; // GenericParam record.
- LPCSTR szName; // GenericParam name field.
- mdToken tkOwner; // GenericParam owner field.
- ULONG ulNumber; // GenericParam number field.
- DWORD dwFlags; // GenericParam flags field
-
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the GenericParam record.
- veCtxt.Token = TokenFromRid(rid, mdtGenericParam);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetGenericParamRecord(rid, &pRecord));
-
- // 1. GenericParam may contain zero or more rows.
- // (Nothing to check.)
-
- tkOwner = pMiniMd->getOwnerOfGenericParam(pRecord);
- // 2. Owner must be a valid token and a type def or method def
- // (Already checked by ValidateRecord)
-
- // CLR tolerates Nil owners, ECMA does not
- if(IsNilToken(tkOwner))
- {
- REPORT_ERROR0(VLDTR_E_GP_OWNERNIL);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
-
- //3. Every generic type shall own one row in the Generic Param table for each of its type parameters. [ERROR]
- // (Nothing to check, as the arity of a generic type is, by definition, the number of generic param entries).
-
- //4. Every generic method shall own one row in the Generic Param table for each of its type parameters. [ERROR]
- // (This is checked in ValidateMethodSig, error VLDTR_E_MD_GPMISMATCH).
-
- ulNumber = pMiniMd->getNumberOfGenericParam(pRecord);
-
- // 5. Flags must be valid
- {
- DWORD dwInvalidMask, dwExtraBits;
-
- dwFlags = pMiniMd->getFlagsOfGenericParam(pRecord);
-
-
- // check for extra bits
- dwInvalidMask = (DWORD)~(gpVarianceMask|gpSpecialConstraintMask);
- dwExtraBits = dwFlags & dwInvalidMask;
- if(dwExtraBits)
- {
- //@GENERICS: we could use a custom error,
- // but this is one is already used in more than one context.
- REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- //Check Variance
- {
- DWORD dwVariance = dwFlags & gpVarianceMask;
- switch (dwVariance)
- {
- case gpNonVariant:
- // always ok
- break;
- case gpCovariant:
- case gpContravariant:
- if (TypeFromToken(tkOwner)==mdtTypeDef)
- {
- if (IsNilToken(tkOwner))
- break;
- TypeDefRec *pTypeDefRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkOwner), &pTypeDefRec));
- // co-contra variance only legal on interfaces and delegates
- // If owner is not an interface and does not extend MultiCastDelegate, report an error
- if(!IsTdInterface(pTypeDefRec->GetFlags()))
- {
- // Get the parent of the TypeDef.
- mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTypeDefRec);
- LPCSTR szExtName = NULL; // Parent Name.
- LPCSTR szExtNameSpace = NULL; // Parent NameSpace.
- BOOL bExtendsMCDelegate = FALSE;
-
- // Determine if the parent is MCDelegate
- if (TypeFromToken(tkExtends) != mdtTypeSpec)
- {
- if (TypeFromToken(tkExtends) == mdtTypeRef)
- {
- TypeRefRec *pExtTypeRefRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pExtTypeRefRec));
- mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pExtTypeRefRec);
- if (RidFromToken(tkResScope) && (TypeFromToken(tkResScope) == mdtAssemblyRef))
- {
- AssemblyRefRec * pARRec;
- IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
- LPCSTR szAssemblyRefName;
- IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
- if ((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
- // otherwise don't even bother extracting the name
- {
- IfFailGo(pMiniMd->getNameOfTypeRef(pExtTypeRefRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtTypeRefRec, &szExtNameSpace));
- }
- }
- }
- else if (TypeFromToken(tkExtends) == mdtTypeDef)
- {
- if (g_fValidatingMscorlib) // otherwise don't even bother extracting the name
- {
- TypeDefRec * pExtTypeRefRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtTypeRefRec));
- IfFailGo(pMiniMd->getNameOfTypeDef(pExtTypeRefRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtTypeRefRec, &szExtNameSpace));
- }
- }
-
- bExtendsMCDelegate =
- szExtNameSpace && szExtName &&
- (0 == strcmp(szExtNameSpace,BASE_NAMESPACE)) &&
- (0 == strcmp(szExtName,BASE_MCDELEGATE_CLASSNAME));
- }
-
- // Report any error
- if (!bExtendsMCDelegate)
- {
- REPORT_ERROR1(VLDTR_E_GP_UNEXPECTED_OWNER_FOR_VARIANT_VAR,tkOwner);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- else
- {
- // co-contra variance never legal on MVARs
- REPORT_ERROR0(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
- default:
- REPORT_ERROR1(VLDTR_E_GP_ILLEGAL_VARIANCE_FLAGS,dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
-
- // Check special constraints
- {
- DWORD dwSpecialConstraints = dwFlags & gpSpecialConstraintMask;
- // It is illegal go declare both gpNotNullableValueTypeConstraint
- // and gpReferenceTypeConstraint, but gpDefaultConstructorConstraint
- // is legal with either (or neither).
- if ((dwSpecialConstraints & (gpReferenceTypeConstraint | gpNotNullableValueTypeConstraint)) ==
- (gpReferenceTypeConstraint | gpNotNullableValueTypeConstraint))
- {
- REPORT_ERROR1(VLDTR_E_GP_REFANDVALUETYPE,dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
-
- // 6. Number shall have a value >=0 and < number of type parameters in owner type or method.
- // 7. Successive rows of the GenericParam table that are owned by the same method (sic) (owner?) shall
- // be ordered by increasing Number value; there can be no gaps in the Number sequence.
- {
- if(ulNumber>0)
- { if(rid==1)
- {
- REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_NUMBER);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- GenericParamRec *pPredRecord;
- IfFailGo(pMiniMd->GetGenericParamRecord(rid-1, &pPredRecord));
- mdToken tkPredOwner = pMiniMd->getOwnerOfGenericParam(pPredRecord);
- ULONG ulPredNumber = pMiniMd->getNumberOfGenericParam(pPredRecord);
- if (tkPredOwner != tkOwner)
- {
- REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_OWNER);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if (ulPredNumber != ulNumber-1)
- {
- REPORT_ERROR0(VLDTR_E_GP_NONSEQ_BY_NUMBER);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
-
- // 8. Name must be non-null and not too long
- IfFailGo(pMiniMd->getNameOfGenericParam(pRecord, &szName));
- if (!*szName)
- {
- // name is NULL.
- REPORT_ERROR0(VLDTR_E_GP_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit; //@GENERICS: do we allow parameters to be deleted?
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
-#ifdef THIS_RULE_IS_DISABLED_BECAUSE_CSHARP_EMITS_DUP_NAMES_AND_DOESNT_WANT_TO_STOP
- // 9. There shall be no duplicates based upon Owner and Name
- if (szName)
- {
- mdGenericParam tkDupGenericParam;
- hr = ImportHelper::FindGenericParamByOwner(pMiniMd, tkOwner, szName, NULL, &tkDupGenericParam, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_GP_DUPNAME, tkDupGenericParam);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-#endif
-
- // 10. There shall be no duplicates based upon Owner and Number
- {
- mdGenericParam tkDupGenericParam;
- hr = ImportHelper::FindGenericParamByOwner(pMiniMd, tkOwner, NULL, &ulNumber, &tkDupGenericParam, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_GP_DUPNUMBER, tkDupGenericParam);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-
- hr = hrSave;
-
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateGenericParam()
-
-//*****************************************************************************
-// Validate the given MemberRef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMemberRef(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- MemberRefRec *pRecord; // MemberRef record.
- mdMemberRef tkMemberRef; // Duplicate MemberRef.
- mdToken tkClass; // MemberRef parent.
- LPCSTR szName; // MemberRef name.
- PCCOR_SIGNATURE pbSig; // MemberRef signature.
- PCCOR_SIGNATURE pbSigTmp; // Temp copy of pbSig, so that can be changed.
- ULONG cbSig; // Size of sig in bytes.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the MemberRef record.
- veCtxt.Token = TokenFromRid(rid, mdtMemberRef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetMemberRefRecord(rid, &pRecord));
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getNameOfMemberRef(pRecord, &szName));
- if (!*szName)
- {
- REPORT_ERROR0(VLDTR_E_MR_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if (IsVtblGapName(szName))
- {
- REPORT_ERROR0(VLDTR_E_MR_VTBLNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (IsDeletedName(szName))
- {
- REPORT_ERROR0(VLDTR_E_MR_DELNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- // Name too long
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // MemberRef parent should never be nil in a PE file.
- tkClass = pMiniMd->getClassOfMemberRef(pRecord);
- if (m_ModuleType == ValidatorModuleTypePE && IsNilToken(tkClass))
- {
- REPORT_ERROR0(VLDTR_E_MR_PARNIL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Verify that the signature is a valid signature as per signature spec.
- IfFailGo(pMiniMd->getSignatureOfMemberRef(pRecord, &pbSig, &cbSig));
-
- // Do some semantic checks based on the signature.
- if (hr == S_OK)
- {
- ULONG ulCallingConv;
- ULONG ulArgCount;
- ULONG ulTyArgCount = 0;
- ULONG ulCurByte = 0;
-
- // Extract calling convention.
- pbSigTmp = pbSig;
- ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
- ulCallingConv = CorSigUncompressData(pbSigTmp);
-
- // Get the type argument count
- if (ulCallingConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
- ulTyArgCount = CorSigUncompressData(pbSigTmp);
- }
-
- // Get the argument count.
- ulCurByte += CorSigUncompressedDataSize(pbSigTmp);
- ulArgCount = CorSigUncompressData(pbSigTmp);
-
- // Calling convention must be one of IMAGE_CEE_CS_CALLCONV_DEFAULT,
- // IMAGE_CEE_CS_CALLCONV_VARARG or IMAGE_CEE_CS_CALLCONV_FIELD.
- if (!isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_DEFAULT) &&
- !isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG) &&
- !isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_FIELD))
- {
- REPORT_ERROR1(VLDTR_E_MR_BADCALLINGCONV, ulCallingConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // [CLS] Calling convention must not be VARARG
- if(isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG))
- {
- REPORT_ERROR0(VLDTR_E_MR_VARARGCALLINGCONV);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
-
- // If the parent is a MethodDef...
- if (TypeFromToken(tkClass) == mdtMethodDef)
- {
- if (RidFromToken(tkClass) != 0)
- {
- // The MethodDef must be the same name and the fixed part of the
- // vararg signature must be the same.
- MethodRec *pMethodRecord; // Method Record.
- LPCSTR szMethodName; // Method name.
- PCCOR_SIGNATURE pbMethodSig; // Method signature.
- ULONG cbMethodSig; // Size in bytes of signature.
-
- // Get Method record, name and signature.
- IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkClass), &pMethodRecord));
- IfFailGo(pMiniMd->getNameOfMethod(pMethodRecord, &szMethodName));
- IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRecord, &pbMethodSig, &cbMethodSig));
-
- // Verify that the name of the Method is the same as the MemberRef.
- if (strcmp(szName, szMethodName))
- {
- REPORT_ERROR1(VLDTR_E_MR_NAMEDIFF, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_VARARG))
- { // It's VARARG calling convention
- CQuickBytes qbFixedSig; // Quick bytes to hold the fixed part of the variable signature.
- ULONG cbFixedSig; // Size in bytes of the fixed part.
-
- // Get the fixed part of the vararg signature of the MemberRef.
- hr = _GetFixedSigOfVarArg(pbSig, cbSig, &qbFixedSig, &cbFixedSig);
- if (FAILED(hr) || cbFixedSig != cbMethodSig ||
- memcmp(pbMethodSig, qbFixedSig.Ptr(), cbFixedSig))
- {
- UnifiedAssemblySigComparer uasc(*this);
- MDSigComparer sc(MDSigParser(pbMethodSig, cbMethodSig),
- MDSigParser((PCCOR_SIGNATURE)qbFixedSig.Ptr(), cbFixedSig),
- uasc);
-
- hr = sc.CompareMethodSignature();
- if (FAILED(hr))
- {
- hr = S_OK;
- REPORT_ERROR1(VLDTR_E_MR_SIGDIFF, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- else
- { // It's not VARARG calling convention - a MemberRef is referencing MethodDef (part of
- // NoPIA)
- UnifiedAssemblySigComparer uasc(*this);
- MDSigComparer sc(MDSigParser(pbMethodSig, cbMethodSig),
- MDSigParser(pbSig, cbSig),
- uasc);
-
- // Compare signatures
- hr = sc.CompareMethodSignature();
- if (FAILED(hr))
- {
- hr = S_OK;
- REPORT_ERROR1(VLDTR_E_MR_SIGDIFF, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
-
- // There should be no duplicate MemberRefs.
- if (*szName && pbSig && cbSig)
- {
- hr = ImportHelper::FindMemberRef(pMiniMd, tkClass, szName, pbSig,
- cbSig, &tkMemberRef, rid,
- ImportHelper::CreateHash); // Optimize for multiple calls
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_MR_DUP, tkMemberRef);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- {
- hr = S_OK;
- }
- else
- {
- IfFailGo(hr);
- }
- }
-
- if (!isCallConv(ulCallingConv, IMAGE_CEE_CS_CALLCONV_FIELD))
- {
- hr = ValidateMethodSig(veCtxt.Token,pbSig, cbSig,0);
- SetVldtrCode(&hrSave,hr);
- }
- }
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMemberRef()
-
-//*****************************************************************************
-// Validate the given Constant.
-//*****************************************************************************
-HRESULT RegMeta::ValidateConstant(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- ConstantRec *pRecord; // Constant record.
- mdToken tkParent; // Constant parent.
- const VOID* pbBlob; // Constant value blob ptr
- DWORD cbBlob; // Constant value blob size
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Get the MemberRef record.
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
-
- ULONG maxrid = 0;
- ULONG typ = 0;
- IfFailGo(pMiniMd->GetConstantRecord(rid, &pRecord));
- IfFailGo(pMiniMd->getValueOfConstant(pRecord, (const BYTE **)&pbBlob, &cbBlob));
- switch(pRecord->GetType())
- {
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_R4:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_R8:
- if(pbBlob == NULL)
- {
- REPORT_ERROR1(VLDTR_E_CN_BLOBNULL, pRecord->GetType());
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- case ELEMENT_TYPE_STRING:
- break;
-
- case ELEMENT_TYPE_CLASS:
- if(GET_UNALIGNED_32(pbBlob) != 0)
- {
- REPORT_ERROR1(VLDTR_E_CN_BLOBNOTNULL, pRecord->GetType());
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
-
- default:
- REPORT_ERROR1(VLDTR_E_CN_BADTYPE, pRecord->GetType());
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- tkParent = pMiniMd->getParentOfConstant(pRecord);
- typ = TypeFromToken(tkParent);
- switch(typ)
- {
- case mdtFieldDef:
- maxrid = pMiniMd->getCountFields();
- break;
- case mdtParamDef:
- maxrid = pMiniMd->getCountParams();
- break;
- case mdtProperty:
- maxrid = pMiniMd->getCountPropertys();
- break;
- }
- switch(typ)
- {
- case mdtFieldDef:
- case mdtParamDef:
- case mdtProperty:
- {
- ULONG rid_p = RidFromToken(tkParent);
- if((0==rid_p)||(rid_p > maxrid))
- {
- REPORT_ERROR1(VLDTR_E_CN_PARENTRANGE, tkParent);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- break;
- }
-
- default:
- REPORT_ERROR1(VLDTR_E_CN_PARENTTYPE, tkParent);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- break;
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateConstant()
-
-//*****************************************************************************
-// Validate the given CustomAttribute.
-//*****************************************************************************
-HRESULT RegMeta::ValidateCustomAttribute(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- CustomAttributeRec *pRecord;
- IfFailGo(pMiniMd->GetCustomAttributeRecord(rid, &pRecord));
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- veCtxt.Token = TokenFromRid(rid,mdtCustomAttribute);
- veCtxt.uOffset = 0;
-
- if (pRecord != NULL)
- {
- mdToken tkOwner = pMiniMd->getParentOfCustomAttribute(pRecord);
- if(RidFromToken(tkOwner))
- { // if 0, it's deleted CA, don't pay attention
- mdToken tkCAType = pMiniMd->getTypeOfCustomAttribute(pRecord);
- DWORD cbValue=0;
- const BYTE *pbValue;
- IfFailGo(pMiniMd->getValueOfCustomAttribute(pRecord, &pbValue, &cbValue));
- if((TypeFromToken(tkOwner)==mdtCustomAttribute)||(!IsValidToken(tkOwner)))
- {
- REPORT_ERROR1(VLDTR_E_CA_BADPARENT, tkOwner);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(((TypeFromToken(tkCAType)!=mdtMethodDef)&&(TypeFromToken(tkCAType)!=mdtMemberRef))
- ||(!IsValidToken(tkCAType))||(RidFromToken(tkCAType)==0))
- {
- REPORT_ERROR1(VLDTR_E_CA_BADTYPE, tkCAType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- { //i.e. Type is valid MethodDef or MemberRef
- LPCUTF8 szName;
- PCCOR_SIGNATURE pSig=NULL;
- DWORD cbSig=0;
- DWORD dwFlags=0;
- if (TypeFromToken(tkCAType) == mdtMethodDef)
- {
- MethodRec *pTypeRec;
- IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkCAType), &pTypeRec));
- IfFailGo(pMiniMd->getNameOfMethod(pTypeRec, &szName));
- IfFailGo(pMiniMd->getSignatureOfMethod(pTypeRec, &pSig, &cbSig));
- dwFlags = pTypeRec->GetFlags();
- }
- else // it can be only MemberRef, otherwise we wouldn't be here
- {
- MemberRefRec *pTypeRec;
- IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkCAType), &pTypeRec));
- IfFailGo(pMiniMd->getNameOfMemberRef(pTypeRec, &szName));
- IfFailGo(pMiniMd->getSignatureOfMemberRef(pTypeRec, &pSig, &cbSig));
- }
- if (strcmp(szName, ".ctor") != 0)
- {
- REPORT_ERROR1(VLDTR_E_CA_NOTCTOR, tkCAType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if ((cbSig > 0) && (pSig != NULL))
- {
- if(FAILED(ValidateMethodSig(tkCAType, pSig,cbSig,dwFlags))
- || (!((*pSig) & IMAGE_CEE_CS_CALLCONV_HASTHIS)))
- {
- REPORT_ERROR1(VLDTR_E_CA_BADSIG, tkCAType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- { // sig seems to be OK
- if ((pbValue != NULL) && (cbValue > 0))
- {
- // Check if prolog is OK
- WORD pW = *((UNALIGNED WORD*)pbValue);
- if(pW != 0x0001)
- {
- REPORT_ERROR1(VLDTR_E_CA_BADPROLOG, pW);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check if blob corresponds to the signature
- }
- }
-
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_CA_NOSIG, tkCAType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- } // end if bad Type - else
- } // end if RidFromToken(tkOwner)
- } // end if pRecord
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateCustomAttribute()
-
-//*****************************************************************************
-// Validate the given FieldMarshal.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFieldMarshal(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateFieldMarshal()
-
-//*****************************************************************************
-// Validate the given DeclSecurity.
-//*****************************************************************************
-HRESULT RegMeta::ValidateDeclSecurity(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- DeclSecurityRec *pRecord;
- mdToken tkOwner; // Owner of the decl security
- DWORD dwAction; // action flags
- BOOL bIsValidOwner = FALSE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- IfFailGo(pMiniMd->GetDeclSecurityRecord(rid, &pRecord));
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- veCtxt.Token = TokenFromRid(rid,mdtPermission);
- veCtxt.uOffset = 0;
-
- // Must have a valid owner
- tkOwner = pMiniMd->getParentOfDeclSecurity(pRecord);
- if(RidFromToken(tkOwner)==0) goto ErrExit; // deleted record, no need to validate
- switch(TypeFromToken(tkOwner))
- {
- case mdtModule:
- case mdtAssembly:
- case mdtTypeDef:
- case mdtMethodDef:
- case mdtFieldDef:
- case mdtInterfaceImpl:
- bIsValidOwner = IsValidToken(tkOwner);
- break;
- default:
- break;
- }
- if(!bIsValidOwner)
- {
- REPORT_ERROR1(VLDTR_E_DS_BADOWNER, tkOwner);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must have one and only one flag set
- dwAction = pRecord->GetAction() & dclActionMask;
- if(dwAction > dclMaximumValue) // the flags are 0,1,2,3,...,dclMaximumValue
- {
- REPORT_ERROR1(VLDTR_E_DS_BADFLAGS, dwAction);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // If field has DeclSecurity, verify its parent is not an interface.-- checked in ValidateField
- // If method has DeclSecurity, verify its parent is not an interface.-- checked in ValidateMethod
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateDeclSecurity()
-
-//*****************************************************************************
-// Validate the given ClassLayout.
-//*****************************************************************************
-HRESULT RegMeta::ValidateClassLayout(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- ClassLayoutRec *pRecord; // ClassLayout record.
- TypeDefRec *pTypeDefRec; // Parent TypeDef record.
- DWORD dwPackingSize; // Packing size.
- mdTypeDef tkParent; // Parent TypeDef token.
- DWORD dwTypeDefFlags; // Parent TypeDef flags.
- RID clRid; // Duplicate ClassLayout rid.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- // Extract the record.
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetClassLayoutRecord(rid, &pRecord));
-
- // Get the parent, if parent is nil its a deleted record. Skip validation.
- tkParent = pMiniMd->getParentOfClassLayout(pRecord);
- if (IsNilToken(tkParent))
- goto ErrExit;
-
- // Parent should not have AutoLayout set on it.
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkParent), &pTypeDefRec));
- dwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
- if (IsTdAutoLayout(dwTypeDefFlags))
- {
- REPORT_ERROR1(VLDTR_E_CL_TDAUTO, tkParent);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Parent must not be an Interface
- if(IsTdInterface(dwTypeDefFlags))
- {
- REPORT_ERROR1(VLDTR_E_CL_TDINTF, tkParent);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate the PackingSize.
- dwPackingSize = pMiniMd->getPackingSizeOfClassLayout(pRecord);
- if((dwPackingSize > 128)||((dwPackingSize & (dwPackingSize-1)) !=0 ))
- {
- REPORT_ERROR2(VLDTR_E_CL_BADPCKSZ, tkParent, dwPackingSize);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate that there are no duplicates.
- hr = _FindClassLayout(pMiniMd, tkParent, &clRid, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR2(VLDTR_E_CL_DUP, tkParent, clRid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateClassLayout()
-
-//*****************************************************************************
-// Validate the given FieldLayout.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFieldLayout(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- FieldLayoutRec *pRecord; // FieldLayout record.
- mdFieldDef tkField; // Field token.
- ULONG ulOffset; // Field offset.
- FieldRec *pFieldRec; // Field record.
- TypeDefRec *pTypeDefRec; // Parent TypeDef record.
- mdTypeDef tkTypeDef; // Parent TypeDef token.
- RID clRid; // Corresponding ClassLayout token.
- RID flRid = 0; // Duplicate FieldLayout rid.
- DWORD dwTypeDefFlags; // Parent TypeDef flags.
- DWORD dwFieldFlags; // Field flags.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Extract the record.
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetFieldLayoutRecord(rid, &pRecord));
-
- // Get the field, if it's nil it's a deleted record, so just skip it.
- tkField = pMiniMd->getFieldOfFieldLayout(pRecord);
- if (IsNilToken(tkField))
- goto ErrExit;
-
- // Validate the Offset value.
- ulOffset = pMiniMd->getOffSetOfFieldLayout(pRecord);
- if (ulOffset == ULONG_MAX)
- {
- REPORT_ERROR2(VLDTR_E_FL_BADOFFSET, tkField, ulOffset);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Get the parent of the Field.
- IfFailGo(pMiniMd->FindParentOfFieldHelper(tkField, &tkTypeDef));
- // Validate that the parent is not nil.
- if (IsNilToken(tkTypeDef))
- {
- REPORT_ERROR1(VLDTR_E_FL_TDNIL, tkField);
- SetVldtrCode(&hr, hrSave);
- goto ErrExit;
- }
-
- // Validate that there exists a ClassLayout record associated with
- // this TypeDef.
- IfFailGo(pMiniMd->FindClassLayoutHelper(tkTypeDef, &clRid));
- if (InvalidRid(rid))
- {
- REPORT_ERROR2(VLDTR_E_FL_NOCL, tkField, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate that ExplicitLayout is set on the TypeDef flags.
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkTypeDef), &pTypeDefRec));
- dwTypeDefFlags = pMiniMd->getFlagsOfTypeDef(pTypeDefRec);
- if (IsTdAutoLayout(dwTypeDefFlags))
- {
- REPORT_ERROR2(VLDTR_E_FL_TDNOTEXPLCT, tkField, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Extract Field record.
- IfFailGo(pMiniMd->GetFieldRecord(RidFromToken(tkField), &pFieldRec));
- // Validate that the field is non-static.
- dwFieldFlags = pMiniMd->getFlagsOfField(pFieldRec);
- if (IsFdStatic(dwFieldFlags))
- {
- REPORT_ERROR1(VLDTR_E_FL_FLDSTATIC, tkField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Look for duplicates.
- hr = _FindFieldLayout(pMiniMd, tkField, &flRid, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_FL_DUP, flRid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateFieldLayout()
-
-//*****************************************************************************
-// Validate the given StandAloneSig.
-//*****************************************************************************
-HRESULT RegMeta::ValidateStandAloneSig(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- StandAloneSigRec *pRecord; // FieldLayout record.
- PCCOR_SIGNATURE pbSig; // Signature.
- ULONG cbSig; // Size in bytes of the signature.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulCallConv; // Calling convention.
- ULONG ulArgCount; // Count of arguments.
- ULONG ulTyArgCount = 0; // Count of type arguments.
- ULONG i; // Looping index.
- ULONG ulNSentinels = 0; // Number of sentinels in the signature
- BOOL bNoVoidAllowed=TRUE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-
- // Extract the record.
- veCtxt.Token = TokenFromRid(rid,mdtSignature);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetStandAloneSigRecord(rid, &pRecord));
- IfFailGo(pMiniMd->getSignatureOfStandAloneSig(pRecord, &pbSig, &cbSig));
-
- // Validate the signature is well-formed with respect to the compression
- // scheme. If this fails, no further validation needs to be done.
- if ( (hr = ValidateSigCompression(veCtxt.Token, pbSig, cbSig)) != S_OK)
- goto ErrExit;
-
- //_ASSERTE((rid != 0x2c2)&&(rid!=0x2c8)&&(rid!=0x2c9)&&(rid!=0x2d6)&&(rid!=0x38b));
- // Validate the calling convention.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulCallConv = CorSigUncompressData(pbSig);
- i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
- if(i == IMAGE_CEE_CS_CALLCONV_FIELD) // <REVISIT_TODO>it's a temporary bypass (VB bug)</REVISIT_TODO>
- ulArgCount = 1;
- else
- {
- if(i != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) // then it is function sig for calli
- {
- if((i >= IMAGE_CEE_CS_CALLCONV_FIELD)
- ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
- &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS))))
- {
- REPORT_ERROR1(VLDTR_E_MD_BADCALLINGCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- bNoVoidAllowed = FALSE;
- }
- // Is there any sig left for arguments?
- _ASSERTE(ulCurByte <= cbSig);
- if (cbSig == ulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_MD_NOARGCNT, ulCurByte+1);
- SetVldtrCode(&hr, hrSave);
- goto ErrExit;
- }
-
- // Get the type argument count.
- if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulTyArgCount = CorSigUncompressData(pbSig);
- }
-
- // Get the argument count.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulArgCount = CorSigUncompressData(pbSig);
- }
- // Validate the the arguments.
- if(ulArgCount)
- {
- for(i=1; ulCurByte < cbSig; i++)
- {
- hr = ValidateOneArg(veCtxt.Token, pbSig, cbSig, &ulCurByte,&ulNSentinels,bNoVoidAllowed);
- if (hr != S_OK)
- {
- if(hr == VLDTR_E_SIG_MISSARG)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i);
- }
- SetVldtrCode(&hr, hrSave);
- hrSave = hr;
- break;
- }
- bNoVoidAllowed = TRUE; // whatever it was for the 1st arg, it must be TRUE for the rest
- }
- if((ulNSentinels != 0) && (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_VARARG )))
- {
- REPORT_ERROR0(VLDTR_E_SIG_SENTMUSTVARARG);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(ulNSentinels > 1)
- {
- REPORT_ERROR0(VLDTR_E_SIG_MULTSENTINELS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateStandAloneSig()
-
-//*****************************************************************************
-// Validate the given EventMap.
-//*****************************************************************************
-HRESULT RegMeta::ValidateEventMap(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateEventMap()
-
-//*****************************************************************************
-// Validate the given EventPtr.
-//*****************************************************************************
-HRESULT RegMeta::ValidateEventPtr(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateEventPtr()
-
-//*****************************************************************************
-// Validate the given Event.
-//*****************************************************************************
-HRESULT RegMeta::ValidateEvent(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkClass; // Declaring TypeDef
- mdToken tkEventType; // Event Type (TypeDef/TypeRef)
- EventRec *pRecord;
- HENUMInternal hEnum;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- IfFailGo(pMiniMd->GetEventRecord(rid, &pRecord));
-
- memset(&veCtxt, 0, sizeof(VEContext));
- memset(&hEnum, 0, sizeof(HENUMInternal));
- veCtxt.Token = TokenFromRid(rid,mdtEvent);
- veCtxt.uOffset = 0;
-
- // The scope must be a valid TypeDef
- if (FAILED(pMiniMd->FindParentOfEventHelper(veCtxt.Token, &tkClass)) ||
- (TypeFromToken(tkClass) != mdtTypeDef) ||
- !IsValidToken(tkClass))
- {
- REPORT_ERROR1(VLDTR_E_EV_BADSCOPE, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- tkClass = 0;
- }
- // Must have name
- {
- LPCUTF8 szName;
- IfFailGo(pMiniMd->getNameOfEvent(pRecord, &szName));
-
- if (*szName == 0)
- {
- REPORT_ERROR0(VLDTR_E_EV_NONAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if (strcmp(szName, COR_DELETED_NAME_A) == 0)
- goto ErrExit;
- if (tkClass != 0) // Must be no duplicates
- {
- RID ridEventMap;
- EventMapRec *pEventMapRec;
- EventRec *pRec;
- ULONG ridStart;
- ULONG ridEnd;
- ULONG i;
-
- IfFailGo(pMiniMd->FindEventMapFor(RidFromToken(tkClass), &ridEventMap));
- if (!InvalidRid(ridEventMap))
- {
- IfFailGo(pMiniMd->GetEventMapRecord(ridEventMap, &pEventMapRec));
- ridStart = pMiniMd->getEventListOfEventMap(pEventMapRec);
- IfFailGo(pMiniMd->getEndEventListOfEventMap(ridEventMap, &ridEnd));
-
- for (i = ridStart; i < ridEnd; i++)
- {
- if (i == rid)
- continue;
- IfFailGo(pMiniMd->GetEventRecord(i, &pRec));
-
- LPCSTR szEventName;
- IfFailGo(pMiniMd->getNameOfEvent(pRec, &szEventName));
- if (strcmp(szName, szEventName) != 0)
- continue;
-
- REPORT_ERROR1(VLDTR_E_EV_DUP, TokenFromRid(i, mdtEvent));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
- }// end of name block
- // EventType must be Nil or valid TypeDef, TypeRef or TypeSpec representing an instantiated generic type
- tkEventType = pMiniMd->getEventTypeOfEvent(pRecord);
- if (!IsNilToken(tkEventType))
- {
- if(IsValidToken(tkEventType) &&
- ((TypeFromToken(tkEventType)==mdtTypeDef)||
- (TypeFromToken(tkEventType)==mdtTypeRef)||
- (TypeFromToken(tkEventType)==mdtTypeSpec)))
- {
- // TypeSpecs can be many things, we only handle instantiated generic types currently.
- if (TypeFromToken(tkEventType)==mdtTypeSpec)
- {
- TypeSpecRec *pRec;
- IfFailGo(pMiniMd->GetTypeSpecRecord(RidFromToken(tkEventType), &pRec));
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
-
- IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRec, &pSig, &cSig));
-
- if (CorSigUncompressElementType(pSig) == ELEMENT_TYPE_GENERICINST &&
- CorSigUncompressElementType(pSig) == ELEMENT_TYPE_CLASS)
- {
- // Just update the event type token variable and fall through to the validation code below (it doesn't care
- // whether the type is generic or not).
- tkEventType = CorSigUncompressToken(pSig);
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_EV_BADEVTYPE, tkEventType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // EventType must not be Interface or ValueType
- if(TypeFromToken(tkEventType)==mdtTypeDef) // can't say anything about TypeRef: no flags available!
- {
- TypeDefRec *pTypeDefRecord;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkEventType), &pTypeDefRecord));
- DWORD dwFlags = pTypeDefRecord->GetFlags();
- if(!IsTdClass(dwFlags))
- {
- REPORT_ERROR2(VLDTR_E_EV_EVTYPENOTCLASS, tkEventType, dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_EV_BADEVTYPE, tkEventType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // Validate related methods
- {
- MethodSemanticsRec *pSemantics;
- RID ridCur;
- ULONG ulSemantics;
- mdMethodDef tkMethod;
- bool bHasAddOn = false;
- bool bHasRemoveOn = false;
-
- IfFailGo( pMiniMd->FindMethodSemanticsHelper(veCtxt.Token, &hEnum) );
- while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&ridCur))
- {
- IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
- ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
- tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
- // Semantics must be Setter, Getter or Other
- switch (ulSemantics)
- {
- case msAddOn:
- bHasAddOn = true;
- break;
- case msRemoveOn:
- bHasRemoveOn = true;
- break;
- case msFire:
- case msOther:
- break;
- default:
- REPORT_ERROR2(VLDTR_E_EV_BADSEMANTICS, tkMethod,ulSemantics);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Method must be valid
- if(!IsValidToken(tkMethod))
- {
- REPORT_ERROR1(VLDTR_E_EV_BADMETHOD, tkMethod);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- // Method's parent must be the same
- mdToken tkTypeDef;
- IfFailGo(pMiniMd->FindParentOfMethodHelper(tkMethod, &tkTypeDef));
- if(tkTypeDef != tkClass)
- {
- REPORT_ERROR2(VLDTR_E_EV_ALIENMETHOD, tkMethod,tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- } // end loop over methods
- // AddOn and RemoveOn are a must
- if(!bHasAddOn)
- {
- REPORT_ERROR0(VLDTR_E_EV_NOADDON);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(!bHasRemoveOn)
- {
- REPORT_ERROR0(VLDTR_E_EV_NOREMOVEON);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }// end of related method validation block
-
- hr = hrSave;
-ErrExit:
- HENUMInternal::ClearEnum(&hEnum);
-
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateEvent()
-
-
-//*****************************************************************************
-// Validate the given PropertyMap.
-//*****************************************************************************
-HRESULT RegMeta::ValidatePropertyMap(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidatePropertyMap(0
-
-//*****************************************************************************
-// Validate the given PropertyPtr.
-//*****************************************************************************
-HRESULT RegMeta::ValidatePropertyPtr(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidatePropertyPtr()
-
-//*****************************************************************************
-// Validate the given Property.
-//*****************************************************************************
-HRESULT RegMeta::ValidateProperty(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkClass = mdTokenNil; // Declaring TypeDef
- PropertyRec *pRecord;
- HENUMInternal hEnum;
- RID tempRid;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- IfFailGo(pMiniMd->GetPropertyRecord(rid, &pRecord));
-
- memset(&veCtxt, 0, sizeof(VEContext));
- memset(&hEnum, 0, sizeof(HENUMInternal));
- veCtxt.Token = TokenFromRid(rid,mdtProperty);
- veCtxt.uOffset = 0;
- // The scope must be a valid TypeDef
- IfFailGo(pMiniMd->FindParentOfPropertyHelper( veCtxt.Token, &tkClass));
- if ((TypeFromToken(tkClass) != mdtTypeDef) ||
- !IsValidToken(tkClass) ||
- IsNilToken(tkClass))
- {
- REPORT_ERROR1(VLDTR_E_PR_BADSCOPE, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must have name and signature
- {
- ULONG cbSig;
- PCCOR_SIGNATURE pvSig;
- IfFailGo(pMiniMd->getTypeOfProperty(pRecord, &pvSig, &cbSig));
-
- LPCUTF8 szName;
- IfFailGo(pMiniMd->getNameOfProperty(pRecord, &szName));
- ULONG ulNameLen = (szName != NULL) ? (ULONG)strlen(szName) : 0;
-
- if (ulNameLen == 0)
- {
- REPORT_ERROR0(VLDTR_E_PR_NONAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(strcmp(szName, COR_DELETED_NAME_A) == 0)
- goto ErrExit;
- }
- if (cbSig == 0)
- {
- REPORT_ERROR0(VLDTR_E_PR_NOSIG);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Must be no duplicates
- if ((ulNameLen != 0) && (cbSig != 0))
- {
- RID ridPropertyMap;
- PropertyMapRec *pPropertyMapRec;
- PropertyRec *pRec;
- ULONG ridStart;
- ULONG ridEnd;
- ULONG i;
- ULONG cbSig1;
- PCCOR_SIGNATURE pvSig1;
-
- IfFailGo(pMiniMd->FindPropertyMapFor(RidFromToken(tkClass), &ridPropertyMap));
- if (!InvalidRid(ridPropertyMap) )
- {
- IfFailGo(pMiniMd->GetPropertyMapRecord(ridPropertyMap, &pPropertyMapRec));
- ridStart = pMiniMd->getPropertyListOfPropertyMap(pPropertyMapRec);
- IfFailGo(pMiniMd->getEndPropertyListOfPropertyMap(ridPropertyMap, &ridEnd));
-
- for (i = ridStart; i < ridEnd; i++)
- {
- if (i == rid)
- continue;
- IfFailGo(pMiniMd->GetPropertyRecord(i, &pRec));
- IfFailGo(pMiniMd->getTypeOfProperty(pRec, &pvSig1, &cbSig1));
-
- if (cbSig != cbSig1)
- continue;
- if (memcmp(pvSig,pvSig1,cbSig) != 0)
- continue;
-
- LPCSTR szPropertyName;
- IfFailGo(pMiniMd->getNameOfProperty(pRec, &szPropertyName));
- if (strcmp(szName, szPropertyName) != 0)
- continue;
-
- REPORT_ERROR1(VLDTR_E_PR_DUP, TokenFromRid(i,mdtProperty));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- // Validate the signature
- if ((pvSig != NULL) && (cbSig != 0))
- {
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulCallConv; // Calling convention.
- ULONG ulArgCount;
- ULONG i;
- ULONG ulNSentinels = 0;
-
- // Validate the calling convention.
- ulCurByte += CorSigUncompressedDataSize(pvSig);
- ulCallConv = CorSigUncompressData(pvSig);
- if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_PROPERTY ))
- {
- REPORT_ERROR1(VLDTR_E_PR_BADCALLINGCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Get the argument count.
- ulCurByte += CorSigUncompressedDataSize(pvSig);
- ulArgCount = CorSigUncompressData(pvSig);
-
- // Validate the arguments.
- for (i = 0; i < ulArgCount; i++)
- {
- hr = ValidateOneArg(veCtxt.Token, pvSig, cbSig, &ulCurByte,&ulNSentinels,(i>0));
- if (hr != S_OK)
- {
- if (hr == VLDTR_E_SIG_MISSARG)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i+1);
- }
- SetVldtrCode(&hr, hrSave);
- break;
- }
- }
- }//end if(pvSig && cbSig)
- }// end of name/signature block
-
- // Marked HasDefault <=> has default value
- IfFailGo(pMiniMd->FindConstantHelper(veCtxt.Token, &tempRid));
- if (InvalidRid(tempRid) == IsPrHasDefault(pRecord->GetPropFlags()))
- {
- REPORT_ERROR0(IsPrHasDefault(pRecord->GetPropFlags())? VLDTR_E_PR_MARKEDNODEFLT : VLDTR_E_PR_DEFLTNOTMARKED);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate related methods
- {
- MethodSemanticsRec *pSemantics;
- RID ridCur;
- ULONG ulSemantics;
- mdMethodDef tkMethod;
-
- IfFailGo( pMiniMd->FindMethodSemanticsHelper(veCtxt.Token, &hEnum) );
- while (HENUMInternal::EnumNext(&hEnum, (mdToken *) &ridCur))
- {
- IfFailGo(pMiniMd->GetMethodSemanticsRecord(ridCur, &pSemantics));
- ulSemantics = pMiniMd->getSemanticOfMethodSemantics(pSemantics);
- tkMethod = TokenFromRid( pMiniMd->getMethodOfMethodSemantics(pSemantics), mdtMethodDef );
- // Semantics must be Setter, Getter or Other
- switch (ulSemantics)
- {
- case msSetter:
- case msGetter:
- case msOther:
- break;
- default:
- REPORT_ERROR2(VLDTR_E_PR_BADSEMANTICS, tkMethod, ulSemantics);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Method must be valid
- if(!IsValidToken(tkMethod))
- {
- REPORT_ERROR1(VLDTR_E_PR_BADMETHOD, tkMethod);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- // Method's parent must be the same
- mdToken tkTypeDef;
- IfFailGo(pMiniMd->FindParentOfMethodHelper(tkMethod, &tkTypeDef));
- if(tkTypeDef != tkClass)
- {
- REPORT_ERROR2(VLDTR_E_PR_ALIENMETHOD, tkMethod, tkTypeDef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- } // end loop over methods
- }// end of related method validation block
-
- hr = hrSave;
-ErrExit:
- HENUMInternal::ClearEnum(&hEnum);
-
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateProperty()
-
-//*****************************************************************************
-// Validate the given MethodSemantics.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodSemantics(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateMethodSemantics()
-
-//*****************************************************************************
-// Validate the given MethodImpl.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodImpl(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- MethodImplRec* pRecord;
- MethodImplRec* pRec;
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkClass; // Declaring TypeDef
- mdToken tkBody; // Implementing method (MethodDef or MemberRef)
- mdToken tkDecl; // Implemented method (MethodDef or MemberRef)
- unsigned iCount;
- unsigned index;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = TokenFromRid(rid, mdtMethodImpl);
- veCtxt.uOffset = 0;
-
- PCCOR_SIGNATURE pbBodySig = NULL;
- PCCOR_SIGNATURE pbDeclSig = NULL;
-
- IfFailGo(pMiniMd->GetMethodImplRecord(rid, &pRecord));
- tkClass = pMiniMd->getClassOfMethodImpl(pRecord);
- // Class must be valid
- if(!IsValidToken(tkClass) || (TypeFromToken(tkClass) != mdtTypeDef))
- {
- REPORT_ERROR1(VLDTR_E_MI_BADCLASS, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- { // ... and not an Interface
- TypeDefRec *pTypeDefRecord;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkClass), &pTypeDefRecord));
- if(IsTdInterface(pTypeDefRecord->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_MI_CLASSISINTF, tkClass);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // Decl must be valid MethodDef or MemberRef
- tkDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pRecord);
- if(!(IsValidToken(tkDecl) &&
- ((TypeFromToken(tkDecl) == mdtMethodDef) || (TypeFromToken(tkDecl) == mdtMemberRef))))
- {
- REPORT_ERROR1(VLDTR_E_MI_BADDECL, tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Body must be valid MethodDef or MemberRef
- tkBody = pMiniMd->getMethodBodyOfMethodImpl(pRecord);
- if(!(IsValidToken(tkBody) &&
- ((TypeFromToken(tkBody) == mdtMethodDef) || (TypeFromToken(tkBody) == mdtMemberRef))))
- {
- REPORT_ERROR1(VLDTR_E_MI_BADBODY, tkBody);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // No duplicates based on (tkClass,tkDecl)
- iCount = pMiniMd->getCountMethodImpls();
- for(index = rid+1; index <= iCount; index++)
- {
- IfFailGo(pMiniMd->GetMethodImplRecord(index, &pRec));
- if((tkClass == pMiniMd->getClassOfMethodImpl(pRec)) &&
- (tkDecl == pMiniMd->getMethodDeclarationOfMethodImpl(pRec)))
- {
- REPORT_ERROR1(VLDTR_E_MI_DUP, index);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- mdToken tkBodyParent;
- ULONG cbBodySig;
-
- if(TypeFromToken(tkBody) == mdtMethodDef)
- {
- MethodRec *pBodyRec;
- IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkBody), &pBodyRec));
- IfFailGo(pMiniMd->getSignatureOfMethod(pBodyRec, &pbBodySig, &cbBodySig));
- IfFailGo(pMiniMd->FindParentOfMethodHelper(tkBody, &tkBodyParent));
- // Body must not be static
- if(IsMdStatic(pBodyRec->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_MI_BODYSTATIC, tkBody);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if(TypeFromToken(tkBody) == mdtMemberRef)
- {
- MemberRefRec *pBodyRec;
- IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkBody), &pBodyRec));
- tkBodyParent = pMiniMd->getClassOfMemberRef(pBodyRec);
- IfFailGo(pMiniMd->getSignatureOfMemberRef(pBodyRec, &pbBodySig, &cbBodySig));
- }
- // Body must belong to the same class
- if(tkBodyParent != tkClass)
- {
- REPORT_ERROR1(VLDTR_E_MI_ALIENBODY, tkBodyParent);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- mdToken tkDeclParent;
- ULONG cbDeclSig;
-
- if(TypeFromToken(tkDecl) == mdtMethodDef)
- {
- MethodRec *pDeclRec;
- IfFailGo(pMiniMd->GetMethodRecord(RidFromToken(tkDecl), &pDeclRec));
- IfFailGo(pMiniMd->getSignatureOfMethod(pDeclRec, &pbDeclSig, &cbDeclSig));
- IfFailGo(pMiniMd->FindParentOfMethodHelper(tkDecl, &tkDeclParent));
- // Decl must be virtual
- if(!IsMdVirtual(pDeclRec->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_MI_DECLNOTVIRT, tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Decl must not be final
- if(IsMdFinal(pDeclRec->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_MI_DECLFINAL, tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Decl must not be private
- if(IsMdPrivate(pDeclRec->GetFlags()) && IsMdCheckAccessOnOverride(pDeclRec->GetFlags()))
- {
- REPORT_ERROR1(VLDTR_E_MI_DECLPRIV, tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if(TypeFromToken(tkDecl) == mdtMemberRef)
- {
- MemberRefRec *pDeclRec;
- IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkDecl), &pDeclRec));
- tkDeclParent = pMiniMd->getClassOfMemberRef(pDeclRec);
- IfFailGo(pMiniMd->getSignatureOfMemberRef(pDeclRec, &pbDeclSig, &cbDeclSig));
- }
-
- // Compare the signatures as best we can, delegating some comparisons to the loader.
- if (*pbBodySig & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- // decl's callconv must be generic
- if (*pbDeclSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- // and the arities must match
- ULONG ulBodyArity = CorSigUncompressData(++pbBodySig);
- ULONG ulDeclArity = CorSigUncompressData(++pbDeclSig);
- if(ulBodyArity != ulDeclArity)
- {
- REPORT_ERROR3(VLDTR_E_MI_ARITYMISMATCH,tkDecl,ulDeclArity,ulBodyArity);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_MI_DECLNOTGENERIC,tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // delegate precise signature checking to the loader,
- // as this requires signature comparison modulo substitution
- }
- else if (*pbDeclSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- REPORT_ERROR1(VLDTR_E_MI_IMPLNOTGENERIC,tkDecl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (TypeFromToken(tkDeclParent) == mdtTypeSpec)
- {
- // do nothing for now...
- // delegate precise signature checking to the loader,
- // as this requires signature comparison modulo substitution
- }
- // Signatures must match (except call conv)
- else if((cbDeclSig != cbBodySig)||(memcmp(pbDeclSig+1,pbBodySig+1,cbDeclSig-1)))
- {
- //@GENERICSVER: todo:
- /*
- //@TODO: Fix to have peverify resolve assemblies
- // through the runtime. At that point, use this method instead
- // of the current compare
-
- // @TODO: check for other bad memcmp sig comparisons in peverify
-
- // Can't use memcmp because there may be two AssemblyRefs
- // in this scope, pointing to the same assembly, etc.).
- if (!MetaSig::CompareMethodSigs(pbDeclSig,
- cbDeclSig,
- Module* pModule1,
- pbBodySig,
- cbDeclSig,
- Module* pModule2))
- */
- UnifiedAssemblySigComparer uasc(*this);
- MDSigComparer sc(MDSigParser(pbDeclSig, cbDeclSig),
- MDSigParser(pbBodySig, cbBodySig),
- uasc);
-
- hr = sc.CompareMethodSignature();
-
- if (FAILED(hr))
- {
- REPORT_ERROR2(VLDTR_E_MI_SIGMISMATCH,tkDecl,tkBody);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMethodImpl()
-
-//*****************************************************************************
-// Validate the given ModuleRef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateModuleRef(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- ModuleRefRec *pRecord; // ModuleRef record.
- LPCUTF8 szName; // ModuleRef name.
- mdModuleRef tkModuleRef; // Duplicate ModuleRef.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Get the ModuleRef record.
- veCtxt.Token = TokenFromRid(rid, mdtModuleRef);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetModuleRefRecord(rid, &pRecord));
-
- // C++ emits IJW methods with ImplMaps
- // which have resolution=ModuleRef with empty name
- IfFailGo(pMiniMd->getNameOfModuleRef(pRecord, &szName));
- if (*szName)
- {
- // Look for a Duplicate, this function reports only one duplicate.
- hr = ImportHelper::FindModuleRef(pMiniMd, szName, &tkModuleRef, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_MODREF_DUP, tkModuleRef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
- else
- hrSave = S_FALSE;
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateModuleRef()
-
-//*****************************************************************************
-// Validate the given TypeSpec.
-//*****************************************************************************
-//@todo GENERICS: reject duplicate specs?
-HRESULT RegMeta::ValidateTypeSpec(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- TypeSpecRec *pRecord; // TypeSpec record.
- PCCOR_SIGNATURE pbSig; // Signature.
- ULONG cbSig; // Size in bytes of the signature.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulNSentinels = 0; // Number of sentinels in the signature
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Extract the record.
- veCtxt.Token = TokenFromRid(rid,mdtTypeSpec);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetTypeSpecRecord(rid, &pRecord));
- IfFailGo(pMiniMd->getSignatureOfTypeSpec(pRecord, &pbSig, &cbSig));
-
- // Validate the signature is well-formed with respect to the compression
- // scheme. If this fails, no further validation needs to be done.
- if ( (hr = ValidateSigCompression(veCtxt.Token, pbSig, cbSig)) != S_OK)
- goto ErrExit;
-
- hr = ValidateOneArg(veCtxt.Token, pbSig, cbSig, &ulCurByte,&ulNSentinels,FALSE);
- if (hr != S_OK)
- {
- if(hr == VLDTR_E_SIG_MISSARG)
- {
- REPORT_ERROR0(VLDTR_E_TS_EMPTY);
- }
- SetVldtrCode(&hr, hrSave);
- hrSave = hr;
- }
- if(ulNSentinels != 0)
- {
- REPORT_ERROR0(VLDTR_E_TS_HASSENTINALS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateTypeSpec()
-
-//*****************************************************************************
-// This function validates the given Field signature. This function works
-// with Field signature for both the MemberRef and FieldDef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodSpecSig(
- mdMethodSpec tk, // [IN] Token whose signature needs to be validated.
- PCCOR_SIGNATURE pbSig, // [IN] Signature.
- ULONG cbSig, // [IN] Size in bytes of the signature.
- ULONG *pArity) // [Out] Arity of the instantiation
-{
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulCallConv; // Calling convention.
- ULONG ulArity; // Arity of instantiation.
- ULONG ulArgCnt;
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- _ASSERTE(TypeFromToken(tk) == mdtMethodSpec);
-
- veCtxt.Token = tk;
- veCtxt.uOffset = 0;
-
- // Validate the calling convention.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulCallConv = CorSigUncompressData(pbSig);
- if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_GENERICINST))
- {
- REPORT_ERROR1(VLDTR_E_MS_BADCALLINGCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (cbSig == ulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_MS_MISSARITY, ulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulArity = CorSigUncompressData(pbSig);
-
- if (ulArity == 0)
- {
- REPORT_ERROR1(VLDTR_E_MS_ARITYZERO, ulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- ulArgCnt = ulArity;
-
- if(pArity != NULL)
- {
- *pArity = ulArity;
- }
-
- // Validate and consume the arguments.
- while(ulArgCnt--)
- {
-
- PCCOR_SIGNATURE pbTypeArg = pbSig;
- ULONG ulTypeArgByte = ulCurByte;
-
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, &ulCurByte, NULL, TRUE));
- if (hr != S_OK)
- {
- if(hr == VLDTR_E_SIG_MISSARG)
- {
- REPORT_ERROR1(VLDTR_E_MS_MISSARG, ulArity-ulArgCnt);
- }
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // reject byref-like args
- switch (CorSigUncompressData(pbTypeArg))
- {
- case ELEMENT_TYPE_TYPEDBYREF:
- case ELEMENT_TYPE_BYREF:
- {
- REPORT_ERROR1(VLDTR_E_MS_BYREFINST, ulTypeArgByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- default:
- break;
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMethodSpecSig()
-
-
-//*****************************************************************************
-// Validate the given MethodSpec.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodSpec(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- MethodSpecRec *pRecord; // MethodSpec record.
- mdToken tkMethod; // Method field (a MethodDefOrRef)
- PCCOR_SIGNATURE pInstantiation; // MethodSpec instantiation (a signature)
- ULONG cbInstantiation; // Size of instantiation.
- ULONG ulInstantiationArity; // Arity of the Instantiation
-
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Get the GenericParamConstraint record.
- veCtxt.Token = TokenFromRid(rid, mdtMethodSpec);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetMethodSpecRecord(rid, &pRecord));
-
- // 1. The MethodSpec table may contain zero or more rows.
- // (Nothing to check.)
-
- // Implicit (missing from spec): Method is not nil [ERROR]
- tkMethod = pMiniMd->getMethodOfMethodSpec(pRecord);
- if(IsNilToken(tkMethod))
- {
- REPORT_ERROR0(VLDTR_E_MS_METHODNIL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Implicit in ValidateRecord: Method is a valid mdMethodDefOrRef.
-
- // 2. One or more rows may refer to the same row in the MethodDef or MethodRef table.
- // (There may be more multiple instantions of the same generic method)
- // (nothing to check!)
-
- // 3. "The signature stored at Instantiation shall be a valid instantiation of the signature of the generic method stored at Method. [ERROR]
- {
- IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiation, &cbInstantiation));
- IfFailGo(ValidateMethodSpecSig(TokenFromRid(rid, mdtMethodSpec), pInstantiation, cbInstantiation,&ulInstantiationArity));
- if (hr != S_OK)
- SetVldtrCode(&hrSave, hr);
- }
-
- IfFailGo(pMiniMd->getInstantiationOfMethodSpec(pRecord, &pInstantiation, &cbInstantiation));
- // 4. There shall be no duplicate rows based upon Method and Instantiation [ERROR]
- {
- mdMethodSpec tkDupMethodSpec;
- hr = ImportHelper::FindMethodSpecByMethodAndInstantiation(pMiniMd, tkMethod, pInstantiation, cbInstantiation, &tkDupMethodSpec, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_MS_DUP, tkDupMethodSpec);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-
- // check the method is generic and that the arity of the instantiation is correct
- {
- PCCOR_SIGNATURE pbGenericMethodSig;
- ULONG cbGenericMethodSig;
-
- if(TypeFromToken(tkMethod) == mdtMethodDef)
- {
- MethodRec *pMethodRec;
- IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkMethod), &pMethodRec));
- IfFailGo(pMiniMd->getSignatureOfMethod(pMethodRec, &pbGenericMethodSig, &cbGenericMethodSig));
- }
- else
- {
- _ASSERTE(TypeFromToken(tkMethod) == mdtMemberRef);
- MemberRefRec *pMethodRefRec;
- IfFailGo(pMiniMd->GetMemberRefRecord(RidFromToken(tkMethod), &pMethodRefRec));
- IfFailGo(pMiniMd->getSignatureOfMemberRef(pMethodRefRec, &pbGenericMethodSig, &cbGenericMethodSig));
- }
-
- if (*pbGenericMethodSig & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- ULONG ulGenericArity = CorSigUncompressData(++pbGenericMethodSig);
- if(ulGenericArity != ulInstantiationArity)
- {
- REPORT_ERROR2(VLDTR_E_MS_ARITYMISMATCH,ulGenericArity,ulInstantiationArity);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else
- {
- REPORT_ERROR1(VLDTR_E_MS_METHODNOTGENERIC, tkMethod);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- hr = hrSave;
-
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMethodSpec()
-
-
-//*****************************************************************************
-// Validate the given GenericParamConstraint.
-//*****************************************************************************
-HRESULT RegMeta::ValidateGenericParamConstraint(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd of the scope.
- GenericParamConstraintRec *pRecord; // GenericParamConstraint record.
- mdGenericParam tkOwner; // GenericParamConstraint owner field.
- mdToken tkConstraint; // GenericParamConstraint constraint field.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Get the GenericParamConstraint record.
- veCtxt.Token = TokenFromRid(rid, mdtGenericParamConstraint);
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetGenericParamConstraintRecord(rid, &pRecord));
-
- // 1. GenericParamConstraint may contain zero or more rows.
- // (Nothing to check.)
-
- // 2. Each row shall have one, and only one, owner row in the GenericParamTable [ERROR]
- // (Nothing to check except owner not nil)
- tkOwner = pMiniMd->getOwnerOfGenericParamConstraint(pRecord);
- if(IsNilToken(tkOwner))
- {
- REPORT_ERROR0(VLDTR_E_GPC_OWNERNIL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // 3. Each row in the GenericParam table shall own a separate row in the GenericParamConstraint table for each constraint that type parameter has [ERROR]
- // (Nothing to check)
-
- // 4.All of the rows in the GenericParamConstraint table that are owned by a given row in the GenericParamTable
- // shall form a contiguous range of rows [ERROR]
- //@NOTE: this check is (iterated over all rows) is quadratic in the (typically small) number of constraints
- {
- RID curRid = rid;
- GenericParamConstraintRec *pCurRecord;
- mdGenericParam tkCurOwner = tkOwner;
- // find the first preceding row with a distinct owner
- while (curRid > 1 && tkCurOwner == tkOwner)
- {
- curRid--;
- IfFailGo(pMiniMd->GetGenericParamConstraintRecord(curRid, &pCurRecord));
- tkCurOwner = pMiniMd->getOwnerOfGenericParamConstraint(pCurRecord);
- };
- // reject this row if there is some row preceding the current row with this owner
- while (curRid > 1)
- {
- curRid--;
- IfFailGo(pMiniMd->GetGenericParamConstraintRecord(curRid, &pCurRecord));
- tkCurOwner = pMiniMd->getOwnerOfGenericParamConstraint(pCurRecord);
- if (tkCurOwner == tkOwner)
- {
- REPORT_ERROR1(VLDTR_E_GPC_NONCONTIGUOUS,tkOwner);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- };
- }
-
- // 5. "At most one class constraint per GenericParam" --- no longer required.
- // 6. "Zero or more interface constraints per GenericParam" --- no longer required.
-
- tkConstraint = pMiniMd->getConstraintOfGenericParamConstraint(pRecord);
- // 7. There shall be no duplicates based upon Owner and Constraint
- {
- mdGenericParamConstraint tkDupGenericParamConstraint;
- hr = ImportHelper::FindGenericParamConstraintByOwnerAndConstraint(pMiniMd, tkOwner, tkConstraint, &tkDupGenericParamConstraint, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_GPC_DUP, tkDupGenericParamConstraint);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-
- hr = hrSave;
-
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateGenericParamConstraint()
-
-//*****************************************************************************
-// Validate the given ImplMap.
-//*****************************************************************************
-HRESULT RegMeta::ValidateImplMap(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- ImplMapRec *pRecord;
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- HRESULT hrModuleRef=S_OK;
- mdToken tkModuleRef;
- mdToken tkMember;
- USHORT usFlags;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- for(unsigned jjj=0; jjj<g_nValidated; jjj++)
- {
- if(g_rValidated[jjj].tok == (rid | 0x51000000)) return g_rValidated[jjj].hr;
- }
-#endif
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetImplMapRecord(rid, &pRecord));
- if(pRecord == NULL) IfFailGo(E_FAIL);
- // ImplMap must have ModuleRef
- tkModuleRef = pMiniMd->getImportScopeOfImplMap(pRecord);
- if((TypeFromToken(tkModuleRef) != mdtModuleRef) || IsNilToken(tkModuleRef)
- || FAILED(hrModuleRef= ValidateModuleRef(RidFromToken(tkModuleRef))))
- {
- REPORT_ERROR1(VLDTR_E_IMAP_BADMODREF, tkModuleRef);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ImplMap must belong to FieldDef or MethodDef
- tkMember = pMiniMd->getMemberForwardedOfImplMap(pRecord);
- if((TypeFromToken(tkMember) != mdtFieldDef) && (TypeFromToken(tkMember) != mdtMethodDef))
- {
- REPORT_ERROR1(VLDTR_E_IMAP_BADMEMBER, tkMember);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // ImplMap must have import name, unless ModuleRef has no name
- // (special case for C++ IJW methods)
- if(hrModuleRef != S_FALSE)
- {
- LPCSTR szName; // Import name.
- IfFailGo(pMiniMd->getImportNameOfImplMap(pRecord, &szName));
- if((szName==NULL)||(*szName == 0))
- {
- REPORT_ERROR0(VLDTR_E_IMAP_BADIMPORTNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- // ImplMap must have valid flags:
- // one value of pmCharSetMask - always so, no check needed (values: 0,2,4,6, mask=6)
- // one value of pmCallConvMask...
- // ...and it's not pmCallConvThiscall
- usFlags = pRecord->GetMappingFlags() & pmCallConvMask;
- if((usFlags < pmCallConvWinapi)||(usFlags > pmCallConvFastcall))
- {
- REPORT_ERROR1(VLDTR_E_IMAP_BADCALLCONV, usFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-ErrExit:
-
-#ifdef CACHE_IMPLMAP_VALIDATION_RESULT
- g_rValidated[g_nValidated].tok = rid | 0x51000000;
- g_rValidated[g_nValidated].hr = hrSave;
- g_nValidated++;
-#endif
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateImplMap()
-
-//*****************************************************************************
-// Validate the given FieldRVA.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFieldRVA(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- FieldRVARec *pRecord;
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkField;
- ULONG ulRVA;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
- IfFailGo(pMiniMd->GetFieldRVARecord(rid, &pRecord));
- ulRVA = pRecord->GetRVA();
- tkField = pMiniMd->getFieldOfFieldRVA(pRecord);
- /*
- if(ulRVA == 0)
- {
- REPORT_ERROR1(VLDTR_E_FRVA_ZERORVA, tkField);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- */
- if((0==RidFromToken(tkField))||(TypeFromToken(tkField) != mdtFieldDef)||(!IsValidToken(tkField)))
- {
- REPORT_ERROR2(VLDTR_E_FRVA_BADFIELD, tkField, ulRVA);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- {
- RID N = pMiniMd->getCountFieldRVAs();
- RID tmp;
- FieldRVARec* pRecTmp;
- for(tmp = rid+1; tmp <= N; tmp++)
- {
- IfFailGo(pMiniMd->GetFieldRVARecord(tmp, &pRecTmp));
- if(tkField == pMiniMd->getFieldOfFieldRVA(pRecTmp))
- {
- REPORT_ERROR2(VLDTR_E_FRVA_DUPFIELD, tkField, tmp);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateFieldRVA()
-
-//*****************************************************************************
-// Validate the given ENCLog.
-//*****************************************************************************
-HRESULT RegMeta::ValidateENCLog(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateENCLog()
-
-//*****************************************************************************
-// Validate the given ENCMap.
-//*****************************************************************************
-HRESULT RegMeta::ValidateENCMap(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateENCMap()
-
-//*****************************************************************************
-// Validate the given Assembly.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssembly(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- AssemblyRec *pRecord; // Assembly record.
- CorAssemblyFlags dwFlags; // Assembly flags.
- LPCSTR szName; // Assembly Name.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- BOOL invalidAssemblyFlags; // Whether the CorAssemblyFlags are valid.
- BOOL fIsV2Assembly = FALSE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- // Get the Assembly record.
- veCtxt.Token = TokenFromRid(rid, mdtAssembly);
- veCtxt.uOffset = 0;
-
- IfFailGo(pMiniMd->GetAssemblyRecord(rid, &pRecord));
-
- // There can only be one Assembly record.
- if (rid > 1)
- {
- REPORT_ERROR0(VLDTR_E_AS_MULTI);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Do checks for name validity..
- IfFailGo(pMiniMd->getNameOfAssembly(pRecord, &szName));
- if (!*szName)
- {
- // Assembly Name is null.
- REPORT_ERROR0(VLDTR_E_AS_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- unsigned L = (unsigned)strlen(szName);
- if((*szName==' ')||strchr(szName,':') || strchr(szName,'\\') || strchr(szName, '/')
- || strchr(szName, ',') || strchr(szName, '\n') || strchr(szName, '\r')
- || ((L > 4)&&((!SString::_stricmp(&szName[L-4],".exe"))||(!SString::_stricmp(&szName[L-4],".dll")))))
- {
- //Assembly name has path and/or extension
- REPORT_ERROR0(VLDTR_E_AS_BADNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Get the flags value for the Assembly.
- dwFlags = (CorAssemblyFlags) pMiniMd->getFlagsOfAssembly(pRecord);
-
- // Validate the flags
- invalidAssemblyFlags = dwFlags & (~(afPublicKey | afRetargetable | afPA_FullMask | afDebuggableAttributeMask | afContentType_Mask));
-
- // Validate we only set a legal processor architecture flags
- // The processor architecture flags were introduced in CLR v2.0.
- // Note that METAMODEL_MINOR_VER_V2_0 is 0. GCC points out the comparison
- // is useless, so that part is commented out.
- fIsV2Assembly = (m_pStgdb->m_MiniMd.m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0
- /* && m_pStgdb->m_MiniMd.m_Schema.m_minor >= METAMODEL_MINOR_VER_V2_0*/);
- if (fIsV2Assembly)
- {
- if ((dwFlags & afPA_Mask) > afPA_AMD64 && !IsAfPA_NoPlatform(dwFlags))
- invalidAssemblyFlags = true;
- }
- else {
- if ((dwFlags & afPA_Mask) != 0)
- invalidAssemblyFlags = true;
- }
-
- if (!IsAfContentType_Default(dwFlags) && !IsAfContentType_WindowsRuntime(dwFlags))
- { // Unknown ContentType value
- invalidAssemblyFlags = true;
- }
-
- if (invalidAssemblyFlags)
- {
- REPORT_ERROR1(VLDTR_E_AS_BADFLAGS, dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate hash algorithm ID
- switch(pRecord->GetHashAlgId())
- {
- case CALG_MD2:
- case CALG_MD4:
- case CALG_MD5:
- case CALG_SHA:
- //case CALG_SHA1: // same as CALG_SHA
- case CALG_MAC:
- case CALG_SSL3_SHAMD5:
- case CALG_HMAC:
- case 0:
- break;
- default:
- REPORT_ERROR1(VLDTR_E_AS_HASHALGID, pRecord->GetHashAlgId());
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- // Validate locale
- {
- LPCSTR szLocale;
- IfFailGo(pMiniMd->getLocaleOfAssembly(pRecord, &szLocale));
- if(!_IsValidLocale(szLocale, fIsV2Assembly))
- {
- REPORT_ERROR0(VLDTR_E_AS_BADLOCALE);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateAssembly()
-
-//*****************************************************************************
-// Validate the given AssemblyProcessor.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssemblyProcessor(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateAssemblyProcessor()
-
-//*****************************************************************************
-// Validate the given AssemblyOS.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssemblyOS(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateAssemblyOS()
-
-//*****************************************************************************
-// Validate the given AssemblyRef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssemblyRef(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- AssemblyRefRec *pRecord; // Assembly record.
- LPCSTR szName; // AssemblyRef Name.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = TokenFromRid(rid, mdtAssemblyRef);
- veCtxt.uOffset = 0;
-
- // Get the AssemblyRef record.
- IfFailGo(pMiniMd->GetAssemblyRefRecord(rid, &pRecord));
-
- // Do checks for name and alias validity.
- IfFailGo(pMiniMd->getNameOfAssemblyRef(pRecord, &szName));
- if (!*szName)
- {
- // AssemblyRef Name is null.
- REPORT_ERROR0(VLDTR_E_AR_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- unsigned L = (unsigned)strlen(szName);
- if((*szName==' ')||strchr(szName,':') || strchr(szName,'\\') || strchr(szName, '/')
- || strchr(szName, ',') || strchr(szName, '\n') || strchr(szName, '\r')
- || ((L > 4)&&((!SString::_stricmp(&szName[L-4],".exe"))||(!SString::_stricmp(&szName[L-4],".dll")))))
- {
- //Assembly name has path and/or extension
- REPORT_ERROR0(VLDTR_E_AS_BADNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Validate locale
- {
- LPCSTR szLocale;
- IfFailGo(pMiniMd->getLocaleOfAssemblyRef(pRecord, &szLocale));
- BOOL fIsV2Assembly = (m_pStgdb->m_MiniMd.m_Schema.m_major >= METAMODEL_MAJOR_VER_V2_0
- /* && m_pStgdb->m_MiniMd.m_Schema.m_minor >= METAMODEL_MINOR_VER_V2_0*/);
- if(!_IsValidLocale(szLocale, fIsV2Assembly))
- {
- REPORT_ERROR0(VLDTR_E_AS_BADLOCALE);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateAssemblyRef()
-
-//*****************************************************************************
-// Validate the given AssemblyRefProcessor.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssemblyRefProcessor(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateAssemblyRefProcessor()
-
-//*****************************************************************************
-// Validate the given AssemblyRefOS.
-//*****************************************************************************
-HRESULT RegMeta::ValidateAssemblyRefOS(RID rid)
-{
- return S_OK;
-} // RegMeta::ValidateAssemblyRefOS()
-
-//*****************************************************************************
-// Validate the given File.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFile(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- FileRec *pRecord; // File record.
- mdFile tkFile; // Duplicate File token.
- LPCSTR szName; // File Name.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = TokenFromRid(rid, mdtFile);
- veCtxt.uOffset = 0;
-
- // Get the File record.
- IfFailGo(pMiniMd->GetFileRecord(rid, &pRecord));
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getNameOfFile(pRecord, &szName));
- if (!*szName)
- {
- // File Name is null.
- REPORT_ERROR0(VLDTR_E_FILE_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- ULONG L = (ULONG)strlen(szName);
- if(L >= MAX_PATH_FNAME)
- {
- // Name too long
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_PATH_FNAME-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check for duplicates based on Name.
- hr = ImportHelper::FindFile(pMiniMd, szName, &tkFile, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_FILE_DUP, tkFile);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
-
- // File name must not be fully qualified.
- if(strchr(szName,':') || strchr(szName,'\\') || strchr(szName,'/'))
- {
- REPORT_ERROR0(VLDTR_E_FILE_NAMEFULLQLFD);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // File name must not be one of system names.
- char *sysname[6]={"con","aux","lpt","prn","null","com"};
- char *syssymbol = "0123456789$:";
- for(unsigned i=0; i<6; i++)
- {
- L = (ULONG)strlen(sysname[i]);
- if(!SString::_strnicmp(szName,sysname[i],L))
- {
- if((szName[L]==0)|| strchr(syssymbol,szName[L]))
- {
- REPORT_ERROR0(VLDTR_E_FILE_SYSNAME);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- }
- }
-
- if (pRecord->GetFlags() & (~0x00000003))
- {
- REPORT_ERROR1(VLDTR_E_FILE_BADFLAGS, pRecord->GetFlags());
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate hash value
- {
- const BYTE *pbHashValue = NULL;
- ULONG cbHashValue;
- IfFailGo(m_pStgdb->m_MiniMd.getHashValueOfFile(pRecord, &pbHashValue, &cbHashValue));
- if ((pbHashValue == NULL) || (cbHashValue == 0))
- {
- REPORT_ERROR0(VLDTR_E_FILE_NULLHASH);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Validate that the name is not the same as the file containing
- // the manifest.
-
- // File name must be a valid file name.
-
- // Each ModuleRef in the assembly must have a corresponding File table entry.
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateFile()
-
-//*****************************************************************************
-// Validate the given ExportedType.
-//*****************************************************************************
-HRESULT RegMeta::ValidateExportedType(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- ExportedTypeRec *pRecord; // ExportedType record.
- mdExportedType tkExportedType; // Duplicate ExportedType.
- mdToken tkImpl; // Implementation token
- mdToken tkTypeDef; // TypeDef token
-
- LPCSTR szName; // ExportedType Name.
- LPCSTR szNamespace; // ExportedType Namespace.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = TokenFromRid(rid, mdtExportedType);
- veCtxt.uOffset = 0;
-
- // Get the ExportedType record.
- IfFailGo(pMiniMd->GetExportedTypeRecord(rid, &pRecord));
-
- tkImpl = pMiniMd->getImplementationOfExportedType(pRecord);
-
- tkTypeDef = pRecord->GetTypeDefId();
- if ((TypeFromToken(tkImpl) == mdtFile) && IsNilToken(tkTypeDef))
- { // Report 'No TypeDefId' warning only for types exported from other modules (do not report it for
- // type forwarders)
- REPORT_ERROR0(VLDTR_E_CT_NOTYPEDEFID);
- SetVldtrCode(&hrSave, VLDTR_S_WRN);
- }
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getTypeNameOfExportedType(pRecord, &szName));
- IfFailGo(pMiniMd->getTypeNamespaceOfExportedType(pRecord, &szNamespace));
- if (!*szName)
- {
- // ExportedType Name is null.
- REPORT_ERROR0(VLDTR_E_CT_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- if(!strcmp(szName,COR_DELETED_NAME_A)) goto ErrExit;
- ULONG L = (ULONG)(strlen(szName)+strlen(szNamespace));
- if(L >= MAX_CLASSNAME_LENGTH)
- {
- // Name too long
- REPORT_ERROR2(VLDTR_E_TD_NAMETOOLONG, L, (ULONG)(MAX_CLASSNAME_LENGTH-1));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check for duplicates based on Name and Enclosing ExportedType.
- hr = ImportHelper::FindExportedType(pMiniMd, szNamespace, szName, tkImpl, &tkExportedType, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_CT_DUP, tkExportedType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- // Check for duplicate TypeDef based on Name/NameSpace - only for top-level ExportedTypes.
- if(TypeFromToken(tkImpl)==mdtFile)
- {
- mdToken tkTypeDef2;
- hr = ImportHelper::FindTypeDefByName(pMiniMd, szNamespace, szName, mdTypeDefNil,
- &tkTypeDef2, 0);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_CT_DUPTDNAME, tkTypeDef2);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
- }
- // Check if flag value is valid
- {
- DWORD dwFlags = pRecord->GetFlags();
- DWORD dwInvalidMask, dwExtraBits;
- dwInvalidMask = (DWORD)~(tdVisibilityMask | tdLayoutMask | tdClassSemanticsMask |
- tdAbstract | tdSealed | tdSpecialName | tdImport | tdSerializable | tdForwarder |
- tdStringFormatMask | tdBeforeFieldInit | tdReservedMask);
- // check for extra bits
- dwExtraBits = dwFlags & dwInvalidMask;
- if(!dwExtraBits)
- {
- // if no extra bits, check layout
- dwExtraBits = dwFlags & tdLayoutMask;
- if(dwExtraBits != tdLayoutMask)
- {
- // layout OK, check string format
- dwExtraBits = dwFlags & tdStringFormatMask;
- if(dwExtraBits != tdStringFormatMask) dwExtraBits = 0;
- }
- }
- if(dwExtraBits)
- {
- REPORT_ERROR1(VLDTR_E_TD_EXTRAFLAGS, dwExtraBits);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- if(IsNilToken(tkImpl)
- || ((TypeFromToken(tkImpl) != mdtFile)&&(TypeFromToken(tkImpl) != mdtExportedType)&&(TypeFromToken(tkImpl) != mdtAssemblyRef))
- || (!IsValidToken(tkImpl)))
- {
- REPORT_ERROR1(VLDTR_E_CT_BADIMPL, tkImpl);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateExportedType()
-
-//*****************************************************************************
-// Validate the given ManifestResource.
-//*****************************************************************************
-HRESULT RegMeta::ValidateManifestResource(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- ManifestResourceRec *pRecord; // ManifestResource record.
- LPCSTR szName; // ManifestResource Name.
- DWORD dwFlags; // ManifestResource flags.
- mdManifestResource tkmar; // Duplicate ManifestResource.
- VEContext veCtxt; // Context structure.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- mdToken tkImplementation;
- BOOL bIsValidImplementation = TRUE;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = TokenFromRid(rid, mdtManifestResource);
- veCtxt.uOffset = 0;
-
- // Get the ManifestResource record.
- IfFailGo(pMiniMd->GetManifestResourceRecord(rid, &pRecord));
-
- // Do checks for name validity.
- IfFailGo(pMiniMd->getNameOfManifestResource(pRecord, &szName));
- if (!*szName)
- {
- // ManifestResource Name is null.
- REPORT_ERROR0(VLDTR_E_MAR_NAMENULL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- // Check for duplicates based on Name.
- hr = ImportHelper::FindManifestResource(pMiniMd, szName, &tkmar, rid);
- if (hr == S_OK)
- {
- REPORT_ERROR1(VLDTR_E_MAR_DUP, tkmar);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else if (hr == CLDB_E_RECORD_NOTFOUND)
- hr = S_OK;
- else
- IfFailGo(hr);
- }
-
- // Get the flags of the ManifestResource.
- dwFlags = pMiniMd->getFlagsOfManifestResource(pRecord);
- if(dwFlags &(~0x00000003))
- {
- REPORT_ERROR1(VLDTR_E_MAR_BADFLAGS, dwFlags);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Visibility of ManifestResource flags must either be public or private.
- if (!IsMrPublic(dwFlags) && !IsMrPrivate(dwFlags))
- {
- REPORT_ERROR0(VLDTR_E_MAR_NOTPUBPRIV);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Implementation must be Nil or valid AssemblyRef or File
- tkImplementation = pMiniMd->getImplementationOfManifestResource(pRecord);
- if(!IsNilToken(tkImplementation))
- {
- switch(TypeFromToken(tkImplementation))
- {
- case mdtAssemblyRef:
- bIsValidImplementation = IsValidToken(tkImplementation);
- break;
- case mdtFile:
- if((bIsValidImplementation = IsValidToken(tkImplementation)))
- { // if file not PE, offset must be 0
- FileRec *pFR;
- IfFailGo(pMiniMd->GetFileRecord(RidFromToken(tkImplementation), &pFR));
- if(IsFfContainsNoMetaData(pFR->GetFlags())
- && pRecord->GetOffset())
- {
- REPORT_ERROR1(VLDTR_E_MAR_BADOFFSET, tkImplementation);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- break;
- default:
- bIsValidImplementation = FALSE;
- }
- }
- if(!bIsValidImplementation)
- {
- REPORT_ERROR1(VLDTR_E_MAR_BADIMPL, tkImplementation);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate the Offset into the PE file.
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateManifestResource()
-
-//*****************************************************************************
-// Validate the given NestedClass.
-//*****************************************************************************
-HRESULT RegMeta::ValidateNestedClass(RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); // MiniMd for the scope.
- NestedClassRec *pRecord; // NestedClass record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save the current state.
- VEContext veCtxt; // Context structure.
- mdToken tkNested;
- mdToken tkEncloser;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = rid;
- veCtxt.uOffset = 0;
-
- // Get the NestedClass record.
- IfFailGo(pMiniMd->GetNestedClassRecord(rid, &pRecord));
- tkNested = pMiniMd->getNestedClassOfNestedClass(pRecord);
- tkEncloser = pMiniMd->getEnclosingClassOfNestedClass(pRecord);
-
- // Nested must be valid TypeDef
- if((TypeFromToken(tkNested) != mdtTypeDef) || !IsValidToken(tkNested))
- {
- REPORT_ERROR1(VLDTR_E_NC_BADNESTED, tkNested);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Encloser must be valid TypeDef
- if((TypeFromToken(tkEncloser) != mdtTypeDef) || !IsValidToken(tkEncloser))
- {
- REPORT_ERROR1(VLDTR_E_NC_BADENCLOSER, tkEncloser);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- // Check for duplicates
- {
- RID N = pMiniMd->getCountNestedClasss();
- RID tmp;
- NestedClassRec* pRecTmp;
- mdToken tkEncloserTmp;
- for(tmp = rid+1; tmp <= N; tmp++)
- {
- IfFailGo(pMiniMd->GetNestedClassRecord(tmp, &pRecTmp));
- if(tkNested == pMiniMd->getNestedClassOfNestedClass(pRecTmp))
- {
- if(tkEncloser == (tkEncloserTmp = pMiniMd->getEnclosingClassOfNestedClass(pRecTmp)))
- {
- REPORT_ERROR1(VLDTR_E_NC_DUP, tmp);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- else
- {
- REPORT_ERROR3(VLDTR_E_NC_DUPENCLOSER, tkNested, tkEncloser, tkEncloserTmp);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateLocalVariable()
-
-//*****************************************************************************
-// Given a Table ID and a Row ID, validate all the columns contain meaningful
-// values given the column definitions. Validate that the offsets into the
-// different pools are valid, the rids are within range and the coded tokens
-// are valid. Every failure here is considered an error.
-//*****************************************************************************
-HRESULT RegMeta::ValidateRecord(ULONG ixTbl, RID rid)
-{
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save the current state.
- ULONG ulCount; // Count of records in the table.
- ULONG ulRawColVal; // Raw value of the column.
- void *pRow; // Row with the data.
- CMiniTableDef *pTbl; // Table definition.
- CMiniColDef *pCol; // Column definition.
- const CCodedTokenDef *pCdTkn; // Coded token definition.
- ULONG ix; // Index into the array of coded tokens.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- // Get the table definition.
- pTbl = &pMiniMd->m_TableDefs[ixTbl];
-
- // Get the row. We may assume that the Row pointer we get back from
- // this call is correct since we do the verification on the Record
- // pools for each table during the open sequence. The only place
- // this is not valid is for Dynamic IL and we don't do this
- // verification in that case since we go through IMetaData* APIs
- // in that case and it should all be consistent.
- IfFailGo(m_pStgdb->m_MiniMd.getRow(ixTbl, rid, &pRow));
-
- for (ULONG ixCol = 0; ixCol < pTbl->m_cCols; ixCol++)
- {
- // Get the column definition.
- pCol = &pTbl->m_pColDefs[ixCol];
-
- // Get the raw value stored in the column. getIX currently doesn't
- // handle byte sized fields, but there are some BYTE fields in the
- // MetaData. So using the conditional to access BYTE fields.
- if (pCol->m_cbColumn == 1)
- ulRawColVal = pMiniMd->getI1(pRow, *pCol);
- else
- ulRawColVal = pMiniMd->getIX(pRow, *pCol);
-
- // Do some basic checks on the non-absurdity of the value stored in the
- // column.
- if (IsRidType(pCol->m_Type))
- {
- // Verify that the RID is within range.
- _ASSERTE(pCol->m_Type < pMiniMd->GetCountTables());
- ulCount = pMiniMd->GetCountRecs(pCol->m_Type);
- // For records storing rids to pointer tables, the stored value may
- // be one beyond the last record.
- if (IsTblPtr(pCol->m_Type, ixTbl))
- ulCount++;
- if (ulRawColVal > ulCount)
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_RID_OUTOFRANGE, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if (IsCodedTokenType(pCol->m_Type))
- {
- // Verify that the Coded token and rid are valid.
- pCdTkn = &g_CodedTokens[pCol->m_Type - iCodedToken];
- ix = ulRawColVal & ~(-1 << CMiniMdRW::m_cb[pCdTkn->m_cTokens]);
- if (ix >= pCdTkn->m_cTokens)
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_CDTKN_OUTOFRANGE, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- ulCount = pMiniMd->GetCountRecs(TypeFromToken(pCdTkn->m_pTokens[ix]) >> 24);
- if ( (ulRawColVal >> CMiniMdRW::m_cb[pCdTkn->m_cTokens]) > ulCount)
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_CDRID_OUTOFRANGE, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- else if (IsHeapType(pCol->m_Type))
- {
- // Verify that the offsets for the Heap type fields are valid offsets
- // into the heaps.
- switch (pCol->m_Type)
- {
- case iSTRING:
- if (!pMiniMd->m_StringHeap.IsValidIndex(ulRawColVal))
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_STRING_INVALID, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
- case iGUID:
- if (ulRawColVal == 0)
- { // GUID value 0 is valid value, though it's invalid GUID heap index
- break;
- }
- if (!pMiniMd->m_GuidHeap.IsValidIndex(ulRawColVal))
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_GUID_INVALID, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
- case iBLOB:
- if (! pMiniMd->m_BlobHeap.IsValidIndex(ulRawColVal))
- {
- VEContext veCtxt;
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = 0;
- veCtxt.uOffset = 0;
- REPORT_ERROR3(VLDTR_E_BLOB_INVALID, ixTbl, ixCol, rid);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
- default:
- _ASSERTE(!"Invalid heap type encountered!");
- }
- }
- else
- {
- // Not much checking that can be done on the fixed type in a generic sense.
- _ASSERTE (IsFixedType(pCol->m_Type));
- }
- hr = hrSave;
- }
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateRecord()
-
-//*****************************************************************************
-// This function validates that the given Method signature is consistent as per
-// the compression scheme.
-//*****************************************************************************
-HRESULT RegMeta::ValidateSigCompression(
- mdToken tk, // [IN] Token whose signature needs to be validated.
- PCCOR_SIGNATURE pbSig, // [IN] Signature.
- ULONG cbSig) // [IN] Size in bytes of the signature.
-{
- VEContext veCtxt; // Context record.
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulSize; // Size of uncompressed data at each point.
- HRESULT hr = S_OK; // Value returned.
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = tk;
- veCtxt.uOffset = 0;
-
- // Check for NULL signature.
- if (!cbSig)
- {
- REPORT_ERROR0(VLDTR_E_SIGNULL);
- SetVldtrCode(&hr, VLDTR_S_ERR);
- goto ErrExit;
- }
-
- // Walk through the signature. At each point make sure there is enough
- // room left in the signature based on the encoding in the current byte.
- while (cbSig - ulCurByte)
- {
- _ASSERTE(ulCurByte <= cbSig);
- // Get next chunk of uncompressed data size.
- if ((ulSize = CorSigUncompressedDataSize(pbSig)) > (cbSig - ulCurByte))
- {
- REPORT_ERROR1(VLDTR_E_SIGNODATA, ulCurByte+1);
- SetVldtrCode(&hr, VLDTR_S_ERR);
- goto ErrExit;
- }
- // Go past this chunk.
- ulCurByte += ulSize;
- CorSigUncompressData(pbSig);
- }
-ErrExit:
-
- return hr;
-} // RegMeta::ValidateSigCompression()
-
-//*****************************************************************************
-// This function validates one argument given an offset into the signature
-// where the argument begins. This function assumes that the signature is well
-// formed as far as the compression scheme is concerned.
-//*****************************************************************************
-//@GENERICS: todo: reject uninstantiated generic types used as types.
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
-#endif
-HRESULT RegMeta::ValidateOneArg(
- mdToken tk, // [IN] Token whose signature is being processed.
- PCCOR_SIGNATURE &pbSig, // [IN] Pointer to the beginning of argument.
- ULONG cbSig, // [IN] Size in bytes of the full signature.
- ULONG *pulCurByte, // [IN/OUT] Current offset into the signature..
- ULONG *pulNSentinels, // [IN/OUT] Number of sentinels
- BOOL bNoVoidAllowed) // [IN] Flag indicating whether "void" is disallowed for this arg
-{
- ULONG ulElementType; // Current element type being processed.
- ULONG ulElemSize; // Size of the element type.
- mdToken token; // Embedded token.
- ULONG ulArgCnt; // Argument count for function pointer.
- ULONG ulRank; // Rank of the array.
- ULONG ulSizes; // Count of sized dimensions of the array.
- ULONG ulLbnds; // Count of lower bounds of the array.
- ULONG ulTkSize; // Token size.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- BOOL bRepeat = TRUE; // MODOPT and MODREQ belong to the arg after them
- BOOL bByRefForbidden = FALSE;// ByRef is not allowed for fields
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- switch(TypeFromToken(tk))
- {
- case mdtFieldDef:
- bByRefForbidden = TRUE;
- break;
- case mdtName:
- tk = TokenFromRid(RidFromToken(tk),mdtFieldDef);
- // Field type can be a FNPTR with a sig containing ByRefs.
- // So we change the token type not to be mdtFieldDef and thus allow ByRefs,
- // but the token needs to be restored to its original type for reporting
- break;
- }
-
- _ASSERTE (pulCurByte);
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = tk;
- veCtxt.uOffset = 0;
-
- while(bRepeat)
- {
- bRepeat = FALSE;
- // Validate that the argument is not missing.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- hr = VLDTR_E_SIG_MISSARG;
- goto ErrExit;
- }
-
- // Get the element type.
- *pulCurByte += (ulElemSize = CorSigUncompressedDataSize(pbSig));
- ulElementType = CorSigUncompressData(pbSig);
-
- // Walk past all the modifier types.
- while (ulElementType & ELEMENT_TYPE_MODIFIER)
- {
- _ASSERTE(*pulCurByte <= cbSig);
- if(ulElementType == ELEMENT_TYPE_SENTINEL)
- {
- if(pulNSentinels) *pulNSentinels+=1;
- if(TypeFromToken(tk) == mdtMethodDef)
- {
- REPORT_ERROR0(VLDTR_E_SIG_SENTINMETHODDEF);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR0(VLDTR_E_SIG_LASTSENTINEL);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- goto ErrExit;
- }
- }
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR2(VLDTR_E_SIG_MISSELTYPE, ulElementType, *pulCurByte + 1);
- SetVldtrCode(&hr, hrSave);
- goto ErrExit;
- }
- *pulCurByte += (ulElemSize = CorSigUncompressedDataSize(pbSig));
- ulElementType = CorSigUncompressData(pbSig);
- }
-
- switch (ulElementType)
- {
- case ELEMENT_TYPE_VOID:
- if(bNoVoidAllowed)
- {
- IfBreakGo(m_pVEHandler->VEHandler(VLDTR_E_SIG_BADVOID, veCtxt, 0));
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_R4:
- case ELEMENT_TYPE_R8:
- case ELEMENT_TYPE_STRING:
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_TYPEDBYREF:
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_I:
- break;
- case ELEMENT_TYPE_BYREF: //fallthru
- if(bByRefForbidden)
- {
- IfBreakGo(m_pVEHandler->VEHandler(VLDTR_E_SIG_BYREFINFIELD, veCtxt, 0));
- SetVldtrCode(&hr, hrSave);
- }
- case ELEMENT_TYPE_PTR:
- // Validate the referenced type.
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,FALSE));
- if (hr != S_OK)
- SetVldtrCode(&hrSave, hr);
- break;
- case ELEMENT_TYPE_PINNED:
- case ELEMENT_TYPE_SZARRAY:
- // Validate the referenced type.
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,TRUE));
- if (hr != S_OK)
- SetVldtrCode(&hrSave, hr);
- break;
- case ELEMENT_TYPE_VALUETYPE: //fallthru
- case ELEMENT_TYPE_CLASS:
- case ELEMENT_TYPE_CMOD_OPT:
- case ELEMENT_TYPE_CMOD_REQD:
- // See if the token is missing.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSTKN, ulElementType);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // See if the token is a valid token.
- ulTkSize = CorSigUncompressedDataSize(pbSig);
- token = CorSigUncompressToken(pbSig);
- if (!IsValidToken(token))
- {
- REPORT_ERROR2(VLDTR_E_SIG_TKNBAD, token, *pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- *pulCurByte += ulTkSize;
- break;
- }
- *pulCurByte += ulTkSize;
- if ((ulElementType == ELEMENT_TYPE_CLASS) || (ulElementType == ELEMENT_TYPE_VALUETYPE))
- {
- // Check for long-form encoding
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
- LPCSTR szName = ""; // token's Name.
- LPCSTR szNameSpace = ""; // token's NameSpace.
-
-
- // Check for TypeDef or TypeRef
- // To prevent cycles in metadata, token must not be a TypeSpec.
- if ((TypeFromToken(token) != mdtTypeRef) && (TypeFromToken(token) != mdtTypeDef))
- {
- REPORT_ERROR2(VLDTR_E_SIG_BADTOKTYPE, token, *pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (TypeFromToken(token) == mdtTypeRef)
- {
- TypeRefRec *pTokenRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(token), &pTokenRec));
- mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pTokenRec);
- if (RidFromToken(tkResScope) && (TypeFromToken(tkResScope) == mdtAssemblyRef))
- {
- AssemblyRefRec * pARRec;
- IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
- LPCSTR szAssemblyRefName;
- IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
- if((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
- {
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pTokenRec, &szNameSpace));
- IfFailGo(pMiniMd->getNameOfTypeRef(pTokenRec, &szName));
- }
- }
- }
- else if (TypeFromToken(token) == mdtTypeDef)
- {
- TypeDefRec *pTokenRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(token), &pTokenRec));
- if(g_fValidatingMscorlib) // otherwise don't even bother checking the name
- {
- IfFailGo(pMiniMd->getNameOfTypeDef(pTokenRec, &szName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pTokenRec, &szNameSpace));
- }
- // while at it, check if token is indeed a class (valuetype)
- BOOL bValueType = FALSE;
- if(!IsTdInterface(pTokenRec->GetFlags()))
- {
- mdToken tkExtends = pMiniMd->getExtendsOfTypeDef(pTokenRec);
- if(RidFromToken(tkExtends))
- {
- LPCSTR szExtName = ""; // parent's Name.
- LPCSTR szExtNameSpace = ""; // parent's NameSpace.
- if(TypeFromToken(tkExtends)==mdtTypeRef)
- {
- TypeRefRec *pExtRec;
- IfFailGo(pMiniMd->GetTypeRefRecord(RidFromToken(tkExtends), &pExtRec));
- mdToken tkResScope = pMiniMd->getResolutionScopeOfTypeRef(pExtRec);
- if(RidFromToken(tkResScope) && (TypeFromToken(tkResScope)==mdtAssemblyRef))
- {
- AssemblyRefRec *pARRec;
- IfFailGo(pMiniMd->GetAssemblyRefRecord(RidFromToken(tkResScope), &pARRec));
- LPCSTR szAssemblyRefName;
- IfFailGo(pMiniMd->getNameOfAssemblyRef(pARRec, &szAssemblyRefName));
- if((0 == SString::_stricmp("mscorlib", szAssemblyRefName)) || (0 == SString::_stricmp("System.Runtime", szAssemblyRefName)))
- {
- IfFailGo(pMiniMd->getNamespaceOfTypeRef(pExtRec, &szExtNameSpace));
- IfFailGo(pMiniMd->getNameOfTypeRef(pExtRec, &szExtName));
- }
- }
- }
- else if(TypeFromToken(tkExtends)==mdtTypeDef)
- {
- if(g_fValidatingMscorlib) // otherwise don't even bother checking the name
- {
- TypeDefRec *pExtRec;
- IfFailGo(pMiniMd->GetTypeDefRecord(RidFromToken(tkExtends), &pExtRec));
- IfFailGo(pMiniMd->getNameOfTypeDef(pExtRec, &szExtName));
- IfFailGo(pMiniMd->getNamespaceOfTypeDef(pExtRec, &szExtNameSpace));
- }
- }
- if(0 == strcmp(szExtNameSpace,BASE_NAMESPACE))
- {
- if(0==strcmp(szExtName,BASE_ENUM_CLASSNAME)) bValueType = TRUE;
- else if(0==strcmp(szExtName,BASE_VTYPE_CLASSNAME))
- {
- bValueType = (strcmp(szNameSpace,BASE_NAMESPACE) ||
- strcmp(szName,BASE_ENUM_CLASSNAME));
- }
- }
- }
- }
- if(bValueType != (ulElementType == ELEMENT_TYPE_VALUETYPE))
- {
- REPORT_ERROR2(VLDTR_E_SIG_TOKTYPEMISMATCH, token, *pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- }
- if(0 == strcmp(szNameSpace,BASE_NAMESPACE))
- {
- for(unsigned jjj = 0; jjj < g_NumSigLongForms; jjj++)
- {
- if(0 == strcmp(szName,g_SigLongFormName[jjj]))
- {
- REPORT_ERROR2(VLDTR_E_SIG_LONGFORM, token, *pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- }
- }
- else // i.e. if(ELEMENT_TYPE_CMOD_OPT || ELEMENT_TYPE_CMOD_REQD)
- bRepeat = TRUE; // go on validating, we're not done with this arg
- break;
-
- case ELEMENT_TYPE_FNPTR:
- // Validate that calling convention is present.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSFPTR, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume calling convention.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- CorSigUncompressData(pbSig);
-
- // Validate that argument count is present.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSFPTRARGCNT, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume argument count.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- ulArgCnt = CorSigUncompressData(pbSig);
-
- // Checking the signature, ByRefs OK
- if(bByRefForbidden)
- tk = TokenFromRid(RidFromToken(tk),mdtName);
-
- // Validate and consume return type.
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,NULL,FALSE));
- if (hr != S_OK)
- {
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
-
- // Validate and consume the arguments.
- while(ulArgCnt--)
- {
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,NULL,TRUE));
- if (hr != S_OK)
- {
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- }
- break;
-
- case ELEMENT_TYPE_ARRAY:
- // Validate and consume the base type.
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte,pulNSentinels,TRUE));
-
- // Validate that the rank is present.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSRANK, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume the rank.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- ulRank = CorSigUncompressData(pbSig);
-
- // Process the sizes.
- if (ulRank)
- {
- // Validate that the count of sized-dimensions is specified.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSNSIZE, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume the count of sized dimensions.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- ulSizes = CorSigUncompressData(pbSig);
-
- // Loop over the sizes.
- while (ulSizes--)
- {
- // Validate the current size.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSSIZE, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume the current size.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- CorSigUncompressData(pbSig);
- }
-
- // Validate that the count of lower bounds is specified.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSNLBND, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume the count of lower bound.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- ulLbnds = CorSigUncompressData(pbSig);
-
- // Loop over the lower bounds.
- while (ulLbnds--)
- {
- // Validate the current lower bound.
- _ASSERTE(*pulCurByte <= cbSig);
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSLBND, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- // Consume the current size.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- CorSigUncompressData(pbSig);
- }
- }
- break;
-
- case ELEMENT_TYPE_VAR:
- case ELEMENT_TYPE_MVAR:
- // Consume index.
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- CorSigUncompressData(pbSig);
- break;
-
- case ELEMENT_TYPE_GENERICINST:
- {
- PCCOR_SIGNATURE pbGenericTypeSig = pbSig;
- BOOL fCheckArity = FALSE;
- ULONG ulGenericArity = 0;
-
- // Validate and consume the type constructor
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte, NULL, TRUE));
-
- // Extract its arity
- {
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
- switch(CorSigUncompressElementType(pbGenericTypeSig))
- {
- case ELEMENT_TYPE_VALUETYPE:
- case ELEMENT_TYPE_CLASS:
- {
- mdToken tkGenericType = CorSigUncompressToken(pbGenericTypeSig);
- if (TypeFromToken(tkGenericType) == mdtTypeDef)
- {
- HENUMInternal hEnumTyPars;
- hr = pMiniMd->FindGenericParamHelper(tkGenericType, &hEnumTyPars);
- if (SUCCEEDED(hr))
- {
- IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulGenericArity));
- HENUMInternal::ClearEnum(&hEnumTyPars);
- fCheckArity = TRUE;
- }
- ;
- }
- // for a mdtTypeRef, don't check anything until load time
- break;
- }
- default:
- break;
- }
-
- }
-
- // Consume argument count.
- if (cbSig == *pulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSARITY, *pulCurByte + 1);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
-
- *pulCurByte += CorSigUncompressedDataSize(pbSig);
- ulArgCnt = CorSigUncompressData(pbSig);
-
- if (ulArgCnt == 0)
- {
- REPORT_ERROR1(VLDTR_E_SIG_ARITYZERO,*pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (fCheckArity && ulArgCnt != ulGenericArity)
- {
- REPORT_ERROR3(VLDTR_E_SIG_ARITYMISMATCH,ulGenericArity,ulArgCnt,*pulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate and consume the arguments.
- while(ulArgCnt--)
- {
- PCCOR_SIGNATURE pbTypeArg = pbSig;
- ULONG ulTypeArgByte = *pulCurByte;
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, pulCurByte, NULL, TRUE));
- if (hr != S_OK)
- {
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
-
- // reject byref-like args
- switch (CorSigUncompressData(pbTypeArg))
- {
- case ELEMENT_TYPE_TYPEDBYREF:
- case ELEMENT_TYPE_BYREF:
- {
- REPORT_ERROR1(VLDTR_E_SIG_BYREFINST, ulTypeArgByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- }
- default:
- break;
- }
- }
-
- break;
- }
-
-
- case ELEMENT_TYPE_SENTINEL: // this case never works because all modifiers are skipped before switch
- if(TypeFromToken(tk) == mdtMethodDef)
- {
- REPORT_ERROR0(VLDTR_E_SIG_SENTINMETHODDEF);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- break;
- default:
- REPORT_ERROR2(VLDTR_E_SIG_BADELTYPE, ulElementType, *pulCurByte - ulElemSize);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- break;
- } // switch (ulElementType)
- } // end while(bRepeat)
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateOneArg()
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
-//*****************************************************************************
-// This function validates the given Method signature. This function works
-// with Method signature for both the MemberRef and MethodDef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateMethodSig(
- mdToken tk, // [IN] Token whose signature needs to be validated.
- PCCOR_SIGNATURE pbSig, // [IN] Signature.
- ULONG cbSig, // [IN] Size in bytes of the signature.
- DWORD dwFlags) // [IN] Method flags.
-{
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulCallConv; // Calling convention.
- ULONG ulArgCount; // Count of arguments.
- ULONG ulTyArgCount; // Count of type arguments.
- ULONG i; // Looping index.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
- ULONG ulNSentinels = 0;
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- _ASSERTE(TypeFromToken(tk) == mdtMethodDef ||
- TypeFromToken(tk) == mdtMemberRef);
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = tk;
- veCtxt.uOffset = 0;
-
- // Validate the signature is well-formed with respect to the compression
- // scheme. If this fails, no further validation needs to be done.
- if ((hr = ValidateSigCompression(tk, pbSig, cbSig)) != S_OK)
- goto ErrExit;
-
- // Validate the calling convention.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulCallConv = CorSigUncompressData(pbSig);
-
- i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
- if ((i != IMAGE_CEE_CS_CALLCONV_DEFAULT)&&( i != IMAGE_CEE_CS_CALLCONV_VARARG)
- || (ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS))
- {
- REPORT_ERROR1(VLDTR_E_MD_BADCALLINGCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (TypeFromToken(tk) == mdtMethodDef) // MemberRefs have no flags available
- {
- // If HASTHIS is set on the calling convention, the method should not be static.
- if ((ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
- IsMdStatic(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_THISSTATIC, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // If HASTHIS is not set on the calling convention, the method should be static.
- if (!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
- !IsMdStatic(dwFlags))
- {
- REPORT_ERROR1(VLDTR_E_MD_NOTTHISNOTSTATIC, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
-
- // Get the type argument count.
- if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
- {
- if (i != IMAGE_CEE_CS_CALLCONV_DEFAULT)
- {
- REPORT_ERROR1(VLDTR_E_MD_GENERIC_BADCALLCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- if (cbSig == ulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_MD_MISSARITY, ulCurByte+1);
- SetVldtrCode(&hr, hrSave);
- goto ErrExit;
- }
-
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulTyArgCount = CorSigUncompressData(pbSig);
-
- if (ulTyArgCount == 0)
- {
- REPORT_ERROR1(VLDTR_E_MD_ARITYZERO, ulCurByte);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // If this is a def, check the arity against the number of generic params
- if (TypeFromToken(tk) == mdtMethodDef)
- {
- CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd);
- ULONG ulGenericParamCount;
- HENUMInternal hEnumTyPars;
- hr = pMiniMd->FindGenericParamHelper(tk, &hEnumTyPars);
- if (SUCCEEDED(hr))
- {
- IfFailGo(HENUMInternal::GetCount(&hEnumTyPars,&ulGenericParamCount));
- HENUMInternal::ClearEnum(&hEnumTyPars);
- if (ulTyArgCount != ulGenericParamCount)
- {
- REPORT_ERROR2(VLDTR_E_MD_GPMISMATCH,ulTyArgCount,ulGenericParamCount);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- }
- }
- }
-
-
- // Is there any sig left for arguments?
- _ASSERTE(ulCurByte <= cbSig);
- if (cbSig == ulCurByte)
- {
- REPORT_ERROR1(VLDTR_E_MD_NOARGCNT, ulCurByte+1);
- SetVldtrCode(&hr, hrSave);
- goto ErrExit;
- }
-
- // Get the argument count.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulArgCount = CorSigUncompressData(pbSig);
-
- // Validate the return type and the arguments.
-// for (i = 0; i < (ulArgCount + 1); i++)
- for(i=1; ulCurByte < cbSig; i++)
- {
- hr = ValidateOneArg(tk, pbSig, cbSig, &ulCurByte,&ulNSentinels,(i > 1));
- if (hr != S_OK)
- {
- if(hr == VLDTR_E_SIG_MISSARG)
- {
- REPORT_ERROR1(VLDTR_E_SIG_MISSARG, i);
- }
- SetVldtrCode(&hr, hrSave);
- hrSave = hr;
- break;
- }
- }
- if((ulNSentinels != 0) && (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_VARARG )))
- {
- REPORT_ERROR0(VLDTR_E_SIG_SENTMUSTVARARG);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
- if(ulNSentinels > 1)
- {
- REPORT_ERROR0(VLDTR_E_SIG_MULTSENTINELS);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateMethodSig()
-
-//*****************************************************************************
-// This function validates the given Field signature. This function works
-// with Field signature for both the MemberRef and FieldDef.
-//*****************************************************************************
-HRESULT RegMeta::ValidateFieldSig(
- mdToken tk, // [IN] Token whose signature needs to be validated.
- PCCOR_SIGNATURE pbSig, // [IN] Signature.
- ULONG cbSig) // [IN] Size in bytes of the signature.
-{
- ULONG ulCurByte = 0; // Current index into the signature.
- ULONG ulCallConv; // Calling convention.
- VEContext veCtxt; // Context record.
- HRESULT hr = S_OK; // Value returned.
- HRESULT hrSave = S_OK; // Save state.
-
- BEGIN_ENTRYPOINT_NOTHROW;
-
- _ASSERTE(TypeFromToken(tk) == mdtFieldDef ||
- TypeFromToken(tk) == mdtMemberRef);
-
- memset(&veCtxt, 0, sizeof(VEContext));
- veCtxt.Token = tk;
- veCtxt.uOffset = 0;
-
- // Validate the calling convention.
- ulCurByte += CorSigUncompressedDataSize(pbSig);
- ulCallConv = CorSigUncompressData(pbSig);
- if (!isCallConv(ulCallConv, IMAGE_CEE_CS_CALLCONV_FIELD ))
- {
- REPORT_ERROR1(VLDTR_E_FD_BADCALLINGCONV, ulCallConv);
- SetVldtrCode(&hrSave, VLDTR_S_ERR);
- }
-
- // Validate the field.
- IfFailGo(ValidateOneArg(tk, pbSig, cbSig, &ulCurByte,NULL,TRUE));
- SetVldtrCode(&hrSave, hr);
-
- hr = hrSave;
-ErrExit:
- ;
- END_ENTRYPOINT_NOTHROW;
-
- return hr;
-} // RegMeta::ValidateFieldSig()
-
-//*****************************************************************************
-// This is a utility function to allocate a one-dimensional zero-based safe
-// array of variants.
-//*****************************************************************************
-static HRESULT _AllocSafeVariantArrayVector( // Return status.
- VARIANT *rVar, // [IN] Variant array.
- int cElem, // [IN] Size of the array.
- SAFEARRAY **ppArray) // [OUT] Double pointer to SAFEARRAY.
-{
- HRESULT hr = S_OK;
- LONG i;
-
- _ASSERTE(rVar && cElem && ppArray);
-
- IfNullGo(*ppArray = SafeArrayCreateVector(VT_VARIANT, 0, cElem));
- for (i = 0; i < cElem; i++)
- IfFailGo(SafeArrayPutElement(*ppArray, &i, &rVar[i]));
-ErrExit:
- return hr;
-} // _AllocSafeVariantArrayVector()
-
-//*****************************************************************************
-// Helper function for reporting error with no arguments
-//*****************************************************************************
-HRESULT RegMeta::_ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context)
-{
- HRESULT hr = S_OK;
-
- //
- // MDValidator does not zero out the Context. Fix it here. This fix relies
- // on the fact that MDValidator just uses the token and offset field of the
- // context.
- //
-
- if (Context.Token != 0) {
- Context.flags = VER_ERR_TOKEN;
- }
-
- IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, NULL));
-ErrExit:
-
- return hr;
-} // _ValidateErrorHelper()
-
-//*****************************************************************************
-// Helper function for reporting error with 1 argument
-//*****************************************************************************
-HRESULT RegMeta::_ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1)
-{
- HRESULT hr = S_OK;
- SAFEARRAY *psa = 0; // The SAFEARRAY.
- VARIANT rVar[1]; // The VARIANT array
-
- if (Context.Token != 0) {
- Context.flags = VER_ERR_TOKEN;
- }
-
- V_VT(&rVar[0]) = VT_UI4;
- V_UI4(&rVar[0]) = ulVal1;
- IfFailGo(_AllocSafeVariantArrayVector(rVar, 1, &psa));
- IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
-
-ErrExit:
- if (psa)
- {
- HRESULT hrSave = SafeArrayDestroy(psa);
- if (FAILED(hrSave))
- hr = hrSave;
- }
- return hr;
-} // _ValidateErrorHelper()
-
-//*****************************************************************************
-// Helper function for reporting error with 2 arguments
-//*****************************************************************************
-HRESULT RegMeta::_ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1,
- ULONG ulVal2)
-{
- HRESULT hr = S_OK;
- SAFEARRAY *psa = 0; // The SAFEARRAY.
- VARIANT rVar[2]; // The VARIANT array
-
- if (Context.Token != 0) {
- Context.flags = VER_ERR_TOKEN;
- }
-
- V_VT(&rVar[0]) = VT_UI4;
- V_UI4(&rVar[0]) = ulVal1;
- V_VT(&rVar[1]) = VT_UI4;
- V_UI4(&rVar[1]) = ulVal2;
-
- IfFailGo(_AllocSafeVariantArrayVector(rVar, 2, &psa));
- IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
-
-ErrExit:
- if (psa)
- {
- HRESULT hrSave = SafeArrayDestroy(psa);
- if (FAILED(hrSave))
- hr = hrSave;
- }
- return hr;
-} // _ValidateErrorHelper()
-
-//*****************************************************************************
-// Helper function for reporting error with 3 arguments
-//*****************************************************************************
-HRESULT RegMeta::_ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1,
- ULONG ulVal2,
- ULONG ulVal3)
-{
- HRESULT hr = S_OK;
- SAFEARRAY *psa = 0; // The SAFEARRAY.
- VARIANT rVar[3]; // The VARIANT array
-
- if (Context.Token != 0) {
- Context.flags = VER_ERR_TOKEN;
- }
-
- V_VT(&rVar[0]) = VT_UI4;
- V_UI4(&rVar[0]) = ulVal1;
- V_VT(&rVar[1]) = VT_UI4;
- V_UI4(&rVar[1]) = ulVal2;
- V_VT(&rVar[2]) = VT_UI4;
- V_UI4(&rVar[2]) = ulVal3;
-
- IfFailGo(_AllocSafeVariantArrayVector(rVar, 3, &psa));
- IfBreakGo(m_pVEHandler->VEHandler(VECode, Context, psa));
-
-ErrExit:
- if (psa)
- {
- HRESULT hrSave = SafeArrayDestroy(psa);
- if (FAILED(hrSave))
- hr = hrSave;
- }
- return hr;
-}
-
-//*****************************************************************************
-// Helper function to see if there is a duplicate record for ClassLayout.
-//*****************************************************************************
-static HRESULT _FindClassLayout(
- CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
- mdTypeDef tkParent, // [IN] the parent that ClassLayout is associated with
- RID *pclRid, // [OUT] rid for the ClassLayout.
- RID rid) // [IN] rid to be ignored.
-{
- HRESULT hr;
- ULONG cClassLayoutRecs;
- ClassLayoutRec *pRecord;
- mdTypeDef tkParTmp;
- ULONG i;
-
- _ASSERTE(pMiniMd && pclRid && rid);
- _ASSERTE(TypeFromToken(tkParent) == mdtTypeDef && RidFromToken(tkParent));
-
- cClassLayoutRecs = pMiniMd->getCountClassLayouts();
-
- for (i = 1; i <= cClassLayoutRecs; i++)
- {
- // Ignore the rid to be ignored!
- if (rid == i)
- continue;
-
- IfFailRet(pMiniMd->GetClassLayoutRecord(i, &pRecord));
- tkParTmp = pMiniMd->getParentOfClassLayout(pRecord);
- if (tkParTmp == tkParent)
- {
- *pclRid = i;
- return S_OK;
- }
- }
- return CLDB_E_RECORD_NOTFOUND;
-} // _FindClassLayout()
-
-//*****************************************************************************
-// Helper function to see if there is a duplicate for FieldLayout.
-//*****************************************************************************
-static HRESULT _FindFieldLayout(
- CMiniMdRW *pMiniMd, // [IN] the minimd to lookup
- mdFieldDef tkParent, // [IN] the parent that FieldLayout is associated with
- RID *pflRid, // [OUT] rid for the FieldLayout record.
- RID rid) // [IN] rid to be ignored.
-{
- HRESULT hr;
- ULONG cFieldLayoutRecs;
- FieldLayoutRec *pRecord;
- mdFieldDef tkField;
- ULONG i;
-
- _ASSERTE(pMiniMd && pflRid && rid);
- _ASSERTE(TypeFromToken(tkParent) == mdtFieldDef && RidFromToken(tkParent));
-
- cFieldLayoutRecs = pMiniMd->getCountFieldLayouts();
-
- for (i = 1; i <= cFieldLayoutRecs; i++)
- {
- // Ignore the rid to be ignored!
- if (rid == i)
- continue;
-
- IfFailRet(pMiniMd->GetFieldLayoutRecord(i, &pRecord));
- tkField = pMiniMd->getFieldOfFieldLayout(pRecord);
- if (tkField == tkParent)
- {
- *pflRid = i;
- return S_OK;
- }
- }
- return CLDB_E_RECORD_NOTFOUND;
-} // _FindFieldLayout()
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-MDSigComparer::CompareMethodSignature()
-{
- HRESULT hr = S_OK;
-
- EX_TRY
- {
- hr = _CompareMethodSignature();
- }
- EX_CATCH
- {
- hr = E_FAIL;
- }
- EX_END_CATCH(SwallowAllExceptions)
-
- return hr;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-MDSigComparer::_CompareMethodSignature()
-{
- HRESULT hr;
-
- // Test equivalency of method signature header
- ULONG cArgs;
- IfFailRet(_CompareMethodSignatureHeader(cArgs));
-
- // Iterate for cArgs + 1 to include the return type
- for (ULONG i = 0; i < cArgs + 1; i++)
- {
- IfFailRet(_CompareExactlyOne());
- }
-
- return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-MDSigComparer::_CompareExactlyOne()
-{
- HRESULT hr;
-
- CorElementType typ1, typ2;
- IfFailRet(m_sig1.GetElemType(&typ1));
- IfFailRet(m_sig2.GetElemType(&typ2));
-
- if (typ1 != typ2)
- {
- return E_FAIL;
- }
-
- CorElementType typ = typ1;
- if (!CorIsPrimitiveType((CorElementType)typ))
- {
- switch (typ)
- {
- default:
- {
- // _ASSERT(!"Illegal or unimplement type in COM+ sig.");
- return META_E_BAD_SIGNATURE;
- break;
- }
- case ELEMENT_TYPE_VAR:
- case ELEMENT_TYPE_MVAR:
- {
- IfFailRet(_CompareData(NULL)); // Skip variable number
- break;
- }
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_STRING:
- case ELEMENT_TYPE_TYPEDBYREF:
- {
- break;
- }
-
- case ELEMENT_TYPE_BYREF: // fallthru
- case ELEMENT_TYPE_PTR:
- case ELEMENT_TYPE_PINNED:
- case ELEMENT_TYPE_SZARRAY:
- {
- IfFailRet(_CompareExactlyOne()); // Compare referenced type
- break;
- }
-
- case ELEMENT_TYPE_VALUETYPE: // fallthru
- case ELEMENT_TYPE_CLASS:
- {
- mdToken tok1, tok2;
- IfFailRet(m_sig1.GetToken(&tok1));
- IfFailRet(m_sig2.GetToken(&tok2));
- IfFailRet(m_comparer.CompareToken(tok1, tok2));
- break;
- }
-
- case ELEMENT_TYPE_FNPTR:
- {
- IfFailRet(_CompareMethodSignature());
- break;
- }
-
- case ELEMENT_TYPE_ARRAY:
- {
- IfFailRet(_CompareExactlyOne()); // Compare element type
-
- ULONG rank;
- IfFailRet(_CompareData(&rank)); // Compare & get rank
-
- if (rank)
- {
- ULONG nsizes;
- IfFailRet(_CompareData(&nsizes)); // Compare & get # of sizes
- while (nsizes--)
- {
- IfFailRet(_CompareData(NULL)); // Compare size
- }
-
- ULONG nlbounds;
- IfFailRet(_CompareData(&nlbounds)); // Compare & get # of lower bounds
- while (nlbounds--)
- {
- IfFailRet(_CompareData(NULL)); // Compare lower bounds
- }
- }
-
- break;
- }
-
- case ELEMENT_TYPE_SENTINEL:
- {
- // Should be unreachable since GetElem strips it
- break;
- }
-
- case ELEMENT_TYPE_INTERNAL:
- {
- // Shouldn't ever get this since it is internal to the runtime,
- // but just in case we know how to compare and skip these.
- PVOID val1 = *((PVOID *)m_sig1.m_ptr);
- PVOID val2 = *((PVOID *)m_sig2.m_ptr);
-
- if (val1 != val2)
- {
- return E_FAIL;
- }
-
- m_sig1.SkipBytes(sizeof(void*));
- m_sig2.SkipBytes(sizeof(void*));
- break;
- }
-
- case ELEMENT_TYPE_GENERICINST:
- {
- IfFailRet(_CompareExactlyOne()); // Compare generic type
- ULONG argCnt;
- IfFailRet(_CompareData(&argCnt)); // Compare & get number of parameters
- _ASSERTE(argCnt > 0);
- while (argCnt--)
- {
- IfFailRet(_CompareExactlyOne()); // Compare the parameters
- }
- break;
- }
- }
- }
-
- return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-MDSigComparer::_CompareData(
- ULONG *pulData)
-{
- ULONG cbCompressedData1, cbCompressedData2;
- ULONG ulData1, ulData2;
-
- cbCompressedData1 = CorSigUncompressData(m_sig1.m_ptr, &ulData1);
- cbCompressedData2 = CorSigUncompressData(m_sig2.m_ptr, &ulData2);
-
- if ((cbCompressedData1 == ((ULONG)(-1))) ||
- (cbCompressedData2 == ((ULONG)(-1))) ||
- (cbCompressedData1 != cbCompressedData2) ||
- (ulData1 != ulData2))
- {
- return E_FAIL;
- }
-
- m_sig1.SkipBytes(cbCompressedData1);
- m_sig2.SkipBytes(cbCompressedData2);
-
- // Out data
- if (pulData)
- *pulData = ulData1;
-
- return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-MDSigComparer::_CompareMethodSignatureHeader(
- ULONG &cArgs)
-{
- HRESULT hr;
-
- // Get calling convention information, but only use it to get type param information.
- ULONG uCallConv1, uCallConv2;
- IfFailRet(m_sig1.GetData(&uCallConv1));
- IfFailRet(m_sig2.GetData(&uCallConv2));
-
- // Check type parameter information
- ULONG uTypeParamCount1 = 0;
- ULONG uTypeParamCount2 = 0;
-
- if (uCallConv1 & IMAGE_CEE_CS_CALLCONV_GENERIC)
- IfFailRet(m_sig1.GetData(&uTypeParamCount1));
-
- if (uCallConv2 & IMAGE_CEE_CS_CALLCONV_GENERIC)
- IfFailRet(m_sig2.GetData(&uTypeParamCount2));
-
- if (uTypeParamCount1 != uTypeParamCount2)
- {
- return E_FAIL;
- }
-
- // Get arg count
- ULONG cArgs1, cArgs2;
- IfFailRet(m_sig1.GetData(&cArgs1));
- IfFailRet(m_sig2.GetData(&cArgs2));
-
- if (cArgs1 != cArgs2)
- {
- return E_FAIL;
- }
-
- // Out parameter
- cArgs = cArgs1;
-
- return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-
-
-HRESULT UnifiedAssemblySigComparer::_CompareAssemblies(mdToken tkAsmRef1,mdToken tkAsmRef2, BOOL* pfEquivalent)
-{
-
- HRESULT hr;
- void const * pvPublicKey1;
- ULONG cbPublicKey1;
- ULONG cchName1;
- ASSEMBLYMETADATA amd1;
- void const * pvHashValue;
- ULONG cbHashValue;
- DWORD dwFlags1;
-
- void const * pvPublicKey2;
- ULONG cbPublicKey2;
- ULONG cchName2;
- ASSEMBLYMETADATA amd2;
- DWORD dwFlags2;
-
-
- ZeroMemory(&amd1, sizeof(amd1));
- ZeroMemory(&amd2, sizeof(amd2));
-
- IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef1,
- NULL,
- NULL,
- NULL,
- 0,
- &cchName1,
- &amd1,
- NULL,
- NULL,
- NULL));
-
- StackSString ssName1;
- StackSString ssLocale1;
- amd1.szLocale = ssLocale1.OpenUnicodeBuffer(amd1.cbLocale);
-
- IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef1,
- &pvPublicKey1,
- &cbPublicKey1,
- ssName1.OpenUnicodeBuffer(cchName1),
- cchName1,
- &cchName1,
- &amd1,
- &pvHashValue,
- &cbHashValue,
- &dwFlags1));
-
- ssName1.CloseBuffer();
- ssLocale1.CloseBuffer();
-
- IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef2,
- NULL,
- NULL,
- NULL,
- 0,
- &cchName2,
- &amd2,
- NULL,
- NULL,
- NULL));
-
- StackSString ssName2;
- StackSString ssLocale2;
- amd2.szLocale = ssLocale2.OpenUnicodeBuffer(amd2.cbLocale);
-
- IfFailRet(m_pRegMeta->GetAssemblyRefProps(tkAsmRef2,
- &pvPublicKey2,
- &cbPublicKey2,
- ssName2.OpenUnicodeBuffer(cchName2),
- cchName2,
- &cchName2,
- &amd2,
- &pvHashValue,
- &cbHashValue,
- &dwFlags2));
-
- ssName2.CloseBuffer();
- ssLocale2.CloseBuffer();
-
- StackSString sMscorlib(W("mscorlib"));
-
-
- if(ssName1.CompareCaseInsensitive(sMscorlib)==0 &&
- ssName2.CompareCaseInsensitive(sMscorlib)==0 )
- {
- *pfEquivalent=TRUE;
- return S_OK;
- }
-
- *pfEquivalent=FALSE;
-
- if (ssName1.CompareCaseInsensitive(ssName2)!=0)
- return S_OK;
- if (ssLocale1.CompareCaseInsensitive(ssLocale2)!=0)
- return S_OK;
- if(cbPublicKey1!=cbPublicKey2)
- return S_OK;
- if(memcmp(pvPublicKey1,pvPublicKey2,cbPublicKey1)!=0)
- return S_OK;
- if(dwFlags1!=dwFlags2)
- return S_OK;
- if(amd1.usMajorVersion!=amd2.usMajorVersion)
- return S_OK;
- if(amd1.usMinorVersion!=amd2.usMinorVersion)
- return S_OK;
- if(amd1.usBuildNumber!=amd2.usBuildNumber)
- return S_OK;
- if(amd1.usRevisionNumber!=amd2.usRevisionNumber)
- return S_OK;
-
- *pfEquivalent=TRUE;
- return S_OK;
-
-};
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-UnifiedAssemblySigComparer::_CreateTypeNameFromTypeRef(
- mdToken tkTypeRef,
- SString &ssName,
- mdToken &tkParent)
-{
- HRESULT hr;
-
- // Get the parent token as well as the name, and return.
- ULONG cchTypeRef;
- IfFailRet(m_pRegMeta->GetTypeRefProps(tkTypeRef, NULL, NULL, 0, &cchTypeRef));
- IfFailRet(m_pRegMeta->GetTypeRefProps(tkTypeRef, &tkParent, ssName.OpenUnicodeBuffer(cchTypeRef), cchTypeRef, NULL));
- ssName.CloseBuffer();
-
- return S_OK;
-}
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-UnifiedAssemblySigComparer::_CreateFullyQualifiedTypeNameFromTypeRef(
- mdToken tkTypeRef,
- SString &ssFullName,
- mdToken &tkParent)
-{
- HRESULT hr;
-
- StackSString ssBuf;
- StackSString ssName;
- mdToken tok = tkTypeRef;
- BOOL fFirstLoop = TRUE;
-
- // Loop stops at first non-typeref parent token.
- do
- {
- // Get the name for this token, as well as the parent token value.
- IfFailRet(_CreateTypeNameFromTypeRef(tok, ssName, tok));
-
- // If this is the first time through the loop, just assign values.
- if (fFirstLoop)
- {
- ssFullName = ssName;
- fFirstLoop = FALSE;
- }
- // If this isn't the first time through, make nested type name
- else
- {
- ns::MakeNestedTypeName(ssBuf, ssName, ssFullName);
- ssFullName = ssBuf;
- }
- } while (TypeFromToken(tok) == mdtTypeRef);
-
- // Assign non-typeref token parent
- tkParent = tok;
-
- return S_OK;
-}
-
-
-
-//*****************************************************************************
-//*****************************************************************************
-HRESULT
-UnifiedAssemblySigComparer::CompareToken(
- const mdToken &tok1,
- const mdToken &tok2)
-{
- HRESULT hr;
-
- // Check binary equality
- if (tok1 == tok2)
- {
- return S_OK;
- }
-
- // Currently only want to do extra checking on TypeRefs
- if (TypeFromToken(tok1) != mdtTypeRef || TypeFromToken(tok2) != mdtTypeRef)
- {
- return E_FAIL;
- }
-
- // Get the fully qualified type names as well as the non-typeref parents.
- mdToken tkParent1, tkParent2;
- StackSString ssName1, ssName2;
-
- IfFailRet(_CreateFullyQualifiedTypeNameFromTypeRef(tok1, ssName1, tkParent1));
- IfFailRet(_CreateFullyQualifiedTypeNameFromTypeRef(tok2, ssName2, tkParent2));
-
- // Currently only want to do extra checking if the parent tokens are AssemblyRefs
- if (TypeFromToken(tkParent1) != mdtAssemblyRef || TypeFromToken(tkParent2) != mdtAssemblyRef)
- {
- return E_FAIL;
- }
-
- // If the type names are not equal, no need to check the assembly refs for unification since
- // we know the types couldn't possibly match.
- if (!ssName1.Equals(ssName2))
- {
- return E_FAIL;
- }
- BOOL fEquivalent;
-
- // no redirects supported
- IfFailRet(_CompareAssemblies(tkParent1,tkParent2,&fEquivalent));
-
- if (!fEquivalent)
- {
- return E_FAIL;
- }
-
- return S_OK;
-}
-
-
-//*****************************************************************************
-// Helper function to validate a locale.
-//*****************************************************************************
-static const char* const g_szValidLocale_V1[] = {
-"ar","ar-SA","ar-IQ","ar-EG","ar-LY","ar-DZ","ar-MA","ar-TN","ar-OM","ar-YE","ar-SY","ar-JO","ar-LB","ar-KW","ar-AE","ar-BH","ar-QA",
-"bg","bg-BG",
-"ca","ca-ES",
-"zh-CHS","zh-TW","zh-CN","zh-HK","zh-SG","zh-MO","zh-CHT",
-"cs","cs-CZ",
-"da","da-DK",
-"de","de-DE","de-CH","de-AT","de-LU","de-LI",
-"el","el-GR",
-"en","en-US","en-GB","en-AU","en-CA","en-NZ","en-IE","en-ZA","en-JM","en-CB","en-BZ","en-TT","en-ZW","en-PH",
-"es","es-ES-Ts","es-MX","es-ES","es-GT","es-CR","es-PA","es-DO","es-VE","es-CO","es-PE","es-AR","es-EC","es-CL",
-"es-UY","es-PY","es-BO","es-SV","es-HN","es-NI","es-PR",
-"fi","fi-FI",
-"fr","fr-FR","fr-BE","fr-CA","fr-CH","fr-LU","fr-MC",
-"he","he-IL",
-"hu","hu-HU",
-"is","is-IS",
-"it","it-IT","it-CH",
-"ja","ja-JP",
-"ko","ko-KR",
-"nl","nl-NL","nl-BE",
-"no",
-"nb-NO",
-"nn-NO",
-"pl","pl-PL",
-"pt","pt-BR","pt-PT",
-"ro","ro-RO",
-"ru","ru-RU",
-"hr","hr-HR",
-"sk","sk-SK",
-"sq","sq-AL",
-"sv","sv-SE","sv-FI",
-"th","th-TH",
-"tr","tr-TR",
-"ur","ur-PK",
-"id","id-ID",
-"uk","uk-UA",
-"be","be-BY",
-"sl","sl-SI",
-"et","et-EE",
-"lv","lv-LV",
-"lt","lt-LT",
-"fa","fa-IR",
-"vi","vi-VN",
-"hy","hy-AM",
-"az",
-"eu","eu-ES",
-"mk","mk-MK",
-"af","af-ZA",
-"ka","ka-GE",
-"fo","fo-FO",
-"hi","hi-IN",
-"ms","ms-MY","ms-BN",
-"kk","kk-KZ",
-"ky","ky-KZ",
-"sw","sw-KE",
-"uz",
-"tt","tt-RU",
-"pa","pa-IN",
-"gu","gu-IN",
-"ta","ta-IN",
-"te","te-IN",
-"kn","kn-IN",
-"mr","mr-IN",
-"sa","sa-IN",
-"mn","mn-MN",
-"gl","gl-ES",
-"kok","kok-IN",
-"syr","syr-SY",
-"div"
-};
-
-static const char* const g_szValidLocale_V2[] = {
- "bn", "bn-IN",
- "bs-Latn-BA", "bs-Cyrl-BA",
- "hr-BA",
- "fil", "fil-PH",
- "fy", "fy-NL",
- "iu-Latn-CA",
- "ga", "ga-IE",
- "ky-KG",
- "lb", "lb-LU",
- "ml", "ml-IN",
- "mt", "mt-MT",
- "mi", "mi-NZ",
- "arn", "arn-CL",
- "moh", "moh-CA",
- "ne", "ne-NP",
- "ps", "ps-AF",
- "quz", "quz-BO", "quz-EC", "quz-PE",
- "rm", "rm-CH",
- "smn", "smn-FI",
- "smj" , "smj-SE", "smj-NO",
- "se", "se-NO", "se-SE", "se-FI",
- "sms", "sms-FI",
- "sma", "sma-NO", "sma-SE",
- "sr-Latn-BA", "sr-Cyrl-BA",
- "nso", "nso-ZA"
-};
-
-// Pre-vista specific cultures (renamed on Vista)
-static const char* const g_szValidLocale_PreVista[] = {
- "div-MV",
- "sr-SP-Latn", "sr-SP-Cyrl",
- "az-AZ-Latn", "az-AZ-Cyrl",
- "uz-UZ-Latn", "uz-UZ-Cyrl",
-};
-
-// Vista only specific cultures (renamed and freshly introduced)
-static const char * const g_szValidLocale_Vista[] = {
- "dv-MV",
- "sr-Latn-CS", "sr-Cyrl-CS",
- "az-Latn-AZ", "az-Cyrl-AZ",
- "uz-Latn-UZ", "uz-Cyrl-UZ",
- "zh-Hant", "zh-Hans",
- "gsw", "gsw-FR",
- "am", "am-ET",
- "as", "as-IN",
- "ba", "ba-RU",
- "br", "br-FR",
- "en-IN",
- "kl", "kl-GL",
- "iu-Cans-CA",
- "km", "km-KH",
- "lo", "lo-LA",
- "dsb", "dsb-DE",
- "mn-Mong-CN",
- "oc", "oc-FR",
- "or", "or-IN"
-};
-
-static BOOL FindInArray(LPCUTF8 szLocale, const char * const *cultureArr, const int nCultures)
-{
- for (int i = 0; i < nCultures; i++)
- {
- if(!SString::_stricmp(szLocale, cultureArr[i]))
- return TRUE;
- }
- return FALSE;
-}
-
-#define LENGTH_OF(x) (sizeof(x) / sizeof(x[0]))
-
-// For Everett assemblies, only the preVista cultures are valid even if running on Vista.
-static BOOL _IsValidLocale(LPCUTF8 szLocale,
- BOOL fIsV2Assembly)
-{
- if (szLocale && *szLocale)
- {
- // Locales valid for Everett and Whidbey
- if (FindInArray(szLocale, g_szValidLocale_V1, LENGTH_OF(g_szValidLocale_V1)))
- return TRUE;
-
- // Locales valid for Whidbey assemblies only
- if (fIsV2Assembly &&
- FindInArray(szLocale, g_szValidLocale_V2, LENGTH_OF(g_szValidLocale_V2)))
- return TRUE;
-
- // Finally search OS specific cultures
- if (fIsV2Assembly)
- return FindInArray(szLocale, g_szValidLocale_Vista, LENGTH_OF(g_szValidLocale_Vista));
- else
- return FindInArray(szLocale, g_szValidLocale_PreVista, LENGTH_OF(g_szValidLocale_PreVista));
- }
-
- return TRUE;
-}
-
-#endif //FEATURE_METADATA_VALIDATOR
diff --git a/src/md/compiler/regmeta.cpp b/src/md/compiler/regmeta.cpp
index f591a6e01b..170893e054 100644
--- a/src/md/compiler/regmeta.cpp
+++ b/src/md/compiler/regmeta.cpp
@@ -67,7 +67,6 @@ RegMeta::RegMeta() :
m_trLanguageType(0),
m_SetAPICaller(EXTERNAL_CALLER),
m_ModuleType(ValidatorModuleTypeInvalid),
- m_pVEHandler(0),
m_bKeepKnownCa(false),
m_pCorProfileData(NULL),
m_ReorderingOptions(NoReordering)
@@ -156,9 +155,6 @@ RegMeta::~RegMeta()
delete pCur;
}
- if (m_pVEHandler)
- m_pVEHandler->Release();
-
// If This RegMeta spun up the runtime (probably to process security
// attributes), shut it down now.
if (m_fStartedEE)
diff --git a/src/md/compiler/regmeta.h b/src/md/compiler/regmeta.h
index 04456d8548..0c6124653d 100644
--- a/src/md/compiler/regmeta.h
+++ b/src/md/compiler/regmeta.h
@@ -22,7 +22,6 @@
#include "rwutil.h"
#include "mdperf.h"
-#include <ivehandler.h>
#include "sigparser.h"
@@ -157,10 +156,6 @@ class RegMeta :
, public IMetaDataAssemblyEmit
#endif
-#ifdef FEATURE_METADATA_VALIDATOR
- , public IMetaDataValidate
-#endif
-
#ifdef FEATURE_METADATA_EMIT_ALL
, public IMetaDataFilter
#endif
@@ -1195,18 +1190,6 @@ public:
#endif //FEATURE_METADATA_EMIT
-#ifdef FEATURE_METADATA_VALIDATOR
-//*****************************************************************************
-// IMetaDataValidator
-//*****************************************************************************
-
- STDMETHODIMP ValidatorInit(
- DWORD dwModuleType, // [IN] Specifies whether the module is a PE file or an obj.
- IUnknown * pUnk); // [IN] Validation error handler.
-
- STDMETHODIMP ValidateMetaData();
-#endif //FEATURE_METADATA_VALIDATOR
-
#ifdef FEATURE_METADATA_EMIT_ALL
//*****************************************************************************
// IMetaDataFilter
@@ -2040,7 +2023,6 @@ private:
SetAPICallerType m_SetAPICaller;
CorValidatorModuleType m_ModuleType;
- IVEHandler *m_pVEHandler;
CCustAttrHash m_caHash; // Hashed list of custom attribute types seen.
bool m_bKeepKnownCa; // Should all known CA's be kept?
@@ -2055,28 +2037,6 @@ private:
// There is an equivalent state in MiniMD, and both must be
// TRUE in order to delete safely.
#endif
-
- HRESULT _ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context);
-
- HRESULT _ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1);
-
- HRESULT _ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1,
- ULONG ulVal2);
-
- HRESULT _ValidateErrorHelper(
- HRESULT VECode,
- VEContext Context,
- ULONG ulVal1,
- ULONG ulVal2,
- ULONG ulVal3);
private:
// Returns pointer to zeros of size (cbSize).
diff --git a/src/mscorlib/Common/System/SR.cs b/src/mscorlib/Common/System/SR.cs
index 29f3970633..0b6db1298e 100644
--- a/src/mscorlib/Common/System/SR.cs
+++ b/src/mscorlib/Common/System/SR.cs
@@ -56,7 +56,7 @@ namespace System
{
if (key == null || key.Length == 0)
{
- Debug.Assert(false, "SR::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
+ Debug.Fail("SR::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
return key;
}
@@ -100,7 +100,6 @@ namespace System
// Note: our infrastructure for reporting this exception will again cause resource lookup.
// This is the most direct way of dealing with that problem.
string message = $"Infinite recursion during resource lookup within {System.CoreLib.Name}. This may be a bug in {System.CoreLib.Name}, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names. Resource name: {key}";
- Assert.Fail("[Recursive resource lookup bug]", message, Assert.COR_E_FAILFAST, System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
Environment.FailFast(message);
}
if (_currentlyLoading == null)
diff --git a/src/mscorlib/Resources/Strings.resx b/src/mscorlib/Resources/Strings.resx
index bbe3636170..0ded8ea294 100644
--- a/src/mscorlib/Resources/Strings.resx
+++ b/src/mscorlib/Resources/Strings.resx
@@ -2086,6 +2086,9 @@
<data name="EventSource_AddScalarOutOfRange" xml:space="preserve">
<value>Getting out of bounds during scalar addition.</value>
</data>
+ <data name="EventSource_BadHexDigit" xml:space="preserve">
+ <value>Bad Hexidecimal digit "{0}".</value>
+ </data>
<data name="EventSource_ChannelTypeDoesNotMatchEventChannelValue" xml:space="preserve">
<value>Channel {0} does not match event channel value {1}.</value>
</data>
@@ -2098,6 +2101,9 @@
<data name="EventSource_EnumKindMismatch" xml:space="preserve">
<value>The type of {0} is not expected in {1}.</value>
</data>
+ <data name="EventSource_EvenHexDigits" xml:space="preserve">
+ <value>Must have an even number of Hexidecimal digits.</value>
+ </data>
<data name="EventSource_EventChannelOutOfRange" xml:space="preserve">
<value>Channel {0} has a value of {1} which is outside the legal range (16-254).</value>
</data>
@@ -2122,6 +2128,9 @@
<data name="EventSource_EventSourceGuidInUse" xml:space="preserve">
<value>An instance of EventSource with Guid {0} already exists.</value>
</data>
+ <data name="EventSource_EventTooBig" xml:space="preserve">
+ <value>The payload for a single event is too large.</value>
+ </data>
<data name="EventSource_EventWithAdminChannelMustHaveMessage" xml:space="preserve">
<value>Event {0} specifies an Admin channel {1}. It must specify a Message property.</value>
</data>
@@ -2134,6 +2143,9 @@
<data name="EventSource_IllegalTaskValue" xml:space="preserve">
<value>Task {0} has a value of {1} which is outside the legal range (1-65535).</value>
</data>
+ <data name="EventSource_IllegalValue" xml:space="preserve">
+ <value>Illegal value "{0}" (prefix strings with @ to indicate a literal string).</value>
+ </data>
<data name="EventSource_IncorrentlyAuthoredTypeInfo" xml:space="preserve">
<value>Incorrectly-authored TypeInfo - a type should be serialized as one field or as one group</value>
</data>
@@ -2230,6 +2242,9 @@
<data name="EventSource_ToString" xml:space="preserve">
<value>EventSource({0}, {1})</value>
</data>
+ <data name="EventSource_TraitEven" xml:space="preserve">
+ <value>There must be an even number of trait strings (they are key-value pairs).</value>
+ </data>
<data name="EventSource_TypeMustBeSealedOrAbstract" xml:space="preserve">
<value>Event source types must be sealed or abstract.</value>
</data>
@@ -2245,6 +2260,9 @@
<data name="EventSource_UndefinedOpcode" xml:space="preserve">
<value>Use of undefined opcode value {0} for event {1}.</value>
</data>
+ <data name="EventSource_UnknownEtwTrait" xml:space="preserve">
+ <value>Unknown ETW trait "{0}".</value>
+ </data>
<data name="EventSource_UnsupportedEventTypeInManifest" xml:space="preserve">
<value>Unsupported type {0} in event source.</value>
</data>
diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj
index 77758fbcea..72368f0c08 100644
--- a/src/mscorlib/System.Private.CoreLib.csproj
+++ b/src/mscorlib/System.Private.CoreLib.csproj
@@ -39,6 +39,7 @@
<_TargetFrameworkDirectories>$(MSBuildThisFileDirectory)/Documentation</_TargetFrameworkDirectories>
<_FullFrameworkReferenceAssemblyPaths>$(MSBuildThisFileDirectory)/Documentation</_FullFrameworkReferenceAssemblyPaths>
<SkipCommonResourcesIncludes>true</SkipCommonResourcesIncludes>
+ <LangVersion>7.2</LangVersion>
</PropertyGroup>
<!-- Add Serviceable attribute to the project's metadata -->
<ItemGroup>
@@ -72,14 +73,14 @@
<DebugSymbols>true</DebugSymbols>
<Optimize Condition="'$(Optimize)' == '' and '$(Configuration)' == 'Debug'">false</Optimize>
<Optimize Condition="'$(Optimize)' == '' and '$(Configuration)' == 'Checked'">true</Optimize>
- <DebugType>full</DebugType>
- <DefineConstants>DBG;_DEBUG;_LOGGING;DEBUG;TRACE;$(DefineConstants)</DefineConstants>
+ <DebugType Condition="'$(DebugType)' == ''">full</DebugType>
+ <DefineConstants>_LOGGING;DEBUG;TRACE;$(DefineConstants)</DefineConstants>
<DefineConstants Condition="'$(Platform)' == 'x86' or '$(Platform)' == 'amd64'">CODE_ANALYSIS;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugSymbols>true</DebugSymbols>
<Optimize Condition="'$(Optimize)' == ''">true</Optimize>
- <DebugType>pdbOnly</DebugType>
+ <DebugType Condition="'$(DebugType)' == ''">pdbOnly</DebugType>
<DefineConstants>TRACE;$(DefineConstants)</DefineConstants>
</PropertyGroup>
<!-- Make portable PDBs on Unix -->
@@ -314,11 +315,9 @@
<Compile Include="$(BclSourcesRoot)\System\Array.cs" />
<Compile Include="$(BclSourcesRoot)\System\ArraySegment.cs" />
<Compile Include="$(BclSourcesRoot)\System\ThrowHelper.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Tuple.cs" />
<Compile Include="$(BclSourcesRoot)\System\String.cs" />
<Compile Include="$(BclSourcesRoot)\System\String.Comparison.cs" />
<Compile Include="$(BclSourcesRoot)\System\String.Manipulation.cs" />
- <Compile Include="$(BclSourcesRoot)\System\String.Searching.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\StringBuilder.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\StringBuilderCache.cs" />
<Compile Include="$(BclSourcesRoot)\System\Exception.cs" />
@@ -463,8 +462,6 @@
<Compile Include="$(BclSourcesRoot)\System\Globalization\BidiCategory.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CharUnicodeInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CharUnicodeInfoData.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\CompareInfo.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Globalization\CompareInfo.Invariant.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureData.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.cs" />
@@ -597,7 +594,6 @@
<Compile Include="$(BclSourcesRoot)\System\Nullable.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\Generic\Comparer.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\Generic\ComparerHelpers.cs" />
- <Compile Include="$(BclSourcesRoot)\System\Collections\Generic\Dictionary.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\Generic\EqualityComparer.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\Generic\ArraySortHelper.cs" />
<Compile Include="$(BclSourcesRoot)\System\Collections\ObjectModel\ReadOnlyDictionary.cs" />
@@ -616,7 +612,6 @@
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
<Compile Include="$(BclSourcesRoot)\Interop\Unix\Interop.Libraries.cs" />
- <Compile Include="$(BclSourcesRoot)\Interop\Unix\System.Globalization.Native\Interop.ICU.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CompareInfo.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\CultureInfo.Unix.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\EncodingTable.Unix.cs" />
@@ -632,6 +627,7 @@
<Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Unix.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Compile Include="$(BclSourcesRoot)\Interop\Windows\Kernel32\Interop.GetSystemDirectoryW.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\Normaliz\Interop.Idna.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\Normaliz\Interop.Normalization.cs" />
<Compile Include="$(BclSourcesRoot)\System\Diagnostics\Debug.Windows.cs" />
@@ -644,6 +640,7 @@
<Compile Include="$(BclSourcesRoot)\System\Globalization\TextInfo.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Text\Normalization.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Windows.cs" />
+ <Compile Include="$(BclSourcesRoot)\System\Environment.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\System\TimeZoneInfo.Win32.cs" />
</ItemGroup>
<!-- Include additional sources shared files in the compilation -->
diff --git a/src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs b/src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
index c690884145..c690884145 100644
--- a/src/mscorlib/src/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
+++ b/src/mscorlib/shared/Interop/Unix/System.Globalization.Native/Interop.ICU.cs
diff --git a/src/mscorlib/shared/Interop/Windows/Interop.Errors.cs b/src/mscorlib/shared/Interop/Windows/Interop.Errors.cs
index ff2653765c..ec52a81bf6 100644
--- a/src/mscorlib/shared/Interop/Windows/Interop.Errors.cs
+++ b/src/mscorlib/shared/Interop/Windows/Interop.Errors.cs
@@ -40,5 +40,6 @@ internal partial class Interop
internal const int ERROR_NOT_FOUND = 0x490;
internal const int ERROR_BAD_IMPERSONATION_LEVEL = 0x542;
internal const int E_FILENOTFOUND = unchecked((int)0x80070002);
+ internal const int ERROR_TIMEOUT = 0x000005B4;
}
}
diff --git a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
index 0831e58af5..5b7629f245 100644
--- a/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
+++ b/src/mscorlib/shared/System.Private.CoreLib.Shared.projitems
@@ -53,6 +53,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\CharEnumerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\CLSCompliantAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\DictionaryEntry.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\Dictionary.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ICollection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\ICollectionDebugView.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IComparer.cs" />
@@ -67,7 +68,9 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\IReadOnlyList.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\KeyValuePair.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\NonRandomizedStringEqualityComparer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\Generic\List.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Collections\HashHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\ICollection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\IComparer.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Collections\IDictionary.cs" />
@@ -97,6 +100,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\CodeAnalysis\SuppressMessageAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\ConditionalAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Debug.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\StackTraceHiddenAttribute.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\DivideByZeroException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\DllNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Double.cs" />
@@ -115,6 +119,8 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarWeekRule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendricalCalculationsHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ChineseLunisolarCalendar.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Invariant.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\DateTimeFormat.cs" />
@@ -436,6 +442,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Single.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Span.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Span.NonGeneric.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\String.Searching.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StringSpanHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StackOverflowException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\StringComparer.cs" />
@@ -502,6 +509,7 @@
<Compile Include="$(MSBuildThisFileDirectory)System\TimeoutException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZone.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TimeZoneNotFoundException.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Tuple.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\TupleExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Type.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Type.Enum.cs" />
@@ -644,6 +652,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Calendar.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Casing.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Collation.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
+ <Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.ICU.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Idna.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Locale.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)Interop\Unix\System.Globalization.Native\Interop.Normalization.cs" Condition="'$(EnableDummyGlobalizationImplementation)' != 'true'" />
diff --git a/src/mscorlib/shared/System/AccessViolationException.cs b/src/mscorlib/shared/System/AccessViolationException.cs
index 103a4c0a9d..280d9b8a97 100644
--- a/src/mscorlib/shared/System/AccessViolationException.cs
+++ b/src/mscorlib/shared/System/AccessViolationException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class AccessViolationException : SystemException
{
public AccessViolationException()
@@ -38,7 +40,6 @@ namespace System
protected AccessViolationException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
#pragma warning disable 169 // Field is not used from managed.
diff --git a/src/mscorlib/shared/System/ApplicationException.cs b/src/mscorlib/shared/System/ApplicationException.cs
index 83ced79876..f36e2c1274 100644
--- a/src/mscorlib/shared/System/ApplicationException.cs
+++ b/src/mscorlib/shared/System/ApplicationException.cs
@@ -22,7 +22,8 @@ namespace System
// to create their own exceptions do so by extending this class.
// ApplicationException extends but adds no new functionality to
// RecoverableException.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ApplicationException : Exception
{
// Creates a new ApplicationException with its message string set to
@@ -52,7 +53,6 @@ namespace System
protected ApplicationException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ArgumentException.cs b/src/mscorlib/shared/System/ArgumentException.cs
index fe65d6443a..8a8fe3e5e4 100644
--- a/src/mscorlib/shared/System/ArgumentException.cs
+++ b/src/mscorlib/shared/System/ArgumentException.cs
@@ -19,7 +19,8 @@ namespace System
// The ArgumentException is thrown when an argument does not meet
// the contract of the method. Ideally it should give a meaningful error
// message describing what was wrong and which parameter is incorrect.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ArgumentException : SystemException
{
private String _paramName;
@@ -64,12 +65,13 @@ namespace System
protected ArgumentException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ _paramName = info.GetString("ParamName");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("ParamName", _paramName, typeof(string));
}
public override String Message
diff --git a/src/mscorlib/shared/System/ArgumentNullException.cs b/src/mscorlib/shared/System/ArgumentNullException.cs
index 9b0732b2d2..80e43cc265 100644
--- a/src/mscorlib/shared/System/ArgumentNullException.cs
+++ b/src/mscorlib/shared/System/ArgumentNullException.cs
@@ -17,7 +17,8 @@ namespace System
{
// The ArgumentException is thrown when an argument
// is null when it shouldn't be.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ArgumentNullException : ArgumentException
{
// Creates a new ArgumentNullException with its message
@@ -49,7 +50,6 @@ namespace System
protected ArgumentNullException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs b/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs
index a25cd57763..604caa8ee8 100644
--- a/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs
+++ b/src/mscorlib/shared/System/ArgumentOutOfRangeException.cs
@@ -17,7 +17,9 @@ using System.Runtime.Serialization;
namespace System
{
// The ArgumentOutOfRangeException is thrown when an argument
- // is outside the legal range for that argument.
+ // is outside the legal range for that argument.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ArgumentOutOfRangeException : ArgumentException
{
private Object _actualValue;
@@ -61,12 +63,13 @@ namespace System
protected ArgumentOutOfRangeException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ _actualValue = info.GetValue("ActualValue", typeof(object));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("ActualValue", _actualValue, typeof(object));
}
public override String Message
diff --git a/src/mscorlib/shared/System/ArithmeticException.cs b/src/mscorlib/shared/System/ArithmeticException.cs
index 6285c8120e..606f1debfd 100644
--- a/src/mscorlib/shared/System/ArithmeticException.cs
+++ b/src/mscorlib/shared/System/ArithmeticException.cs
@@ -17,7 +17,8 @@ namespace System
{
// The ArithmeticException is thrown when overflow or underflow
// occurs.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ArithmeticException : SystemException
{
// Creates a new ArithmeticException with its message string set to
@@ -47,7 +48,6 @@ namespace System
protected ArithmeticException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ArrayTypeMismatchException.cs b/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
index 6964b1fa12..49820f58f5 100644
--- a/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
+++ b/src/mscorlib/shared/System/ArrayTypeMismatchException.cs
@@ -17,7 +17,8 @@ namespace System
{
// The ArrayMismatchException is thrown when an attempt to store
// an object of the wrong type within an array occurs.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ArrayTypeMismatchException : SystemException
{
// Creates a new ArrayMismatchException with its message string set to
@@ -47,7 +48,6 @@ namespace System
protected ArrayTypeMismatchException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/BadImageFormatException.cs b/src/mscorlib/shared/System/BadImageFormatException.cs
index a4661fc799..1743075a6f 100644
--- a/src/mscorlib/shared/System/BadImageFormatException.cs
+++ b/src/mscorlib/shared/System/BadImageFormatException.cs
@@ -17,6 +17,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public partial class BadImageFormatException : SystemException
{
private String _fileName; // The name of the corrupt PE file.
@@ -56,12 +58,15 @@ namespace System
protected BadImageFormatException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ _fileName = info.GetString("BadImageFormat_FileName");
+ _fusionLog = info.GetString("BadImageFormat_FusionLog");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("BadImageFormat_FileName", _fileName, typeof(string));
+ info.AddValue("BadImageFormat_FusionLog", _fusionLog, typeof(string));
}
public override String Message
diff --git a/src/mscorlib/shared/System/Buffers/MemoryHandle.cs b/src/mscorlib/shared/System/Buffers/MemoryHandle.cs
index bcbb527b50..60592144a5 100644
--- a/src/mscorlib/shared/System/Buffers/MemoryHandle.cs
+++ b/src/mscorlib/shared/System/Buffers/MemoryHandle.cs
@@ -14,10 +14,10 @@ namespace System.Buffers
private GCHandle _handle;
[CLSCompliant(false)]
- public MemoryHandle(IRetainable owner, void* pinnedPointer = null, GCHandle handle = default(GCHandle))
+ public MemoryHandle(IRetainable owner, void* pointer = null, GCHandle handle = default(GCHandle))
{
_owner = owner;
- _pointer = pinnedPointer;
+ _pointer = pointer;
_handle = handle;
}
@@ -34,7 +34,9 @@ namespace System.Buffers
}
[CLSCompliant(false)]
- public void* PinnedPointer => _pointer;
+ public void* Pointer => _pointer;
+
+ public bool HasPointer => _pointer != null;
public void Dispose()
{
diff --git a/src/mscorlib/shared/System/Byte.cs b/src/mscorlib/shared/System/Byte.cs
index e087bd4a43..eaa47b6843 100644
--- a/src/mscorlib/shared/System/Byte.cs
+++ b/src/mscorlib/shared/System/Byte.cs
@@ -2,17 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: This class will encapsulate a byte and provide an
-** Object representation of it.
-**
-**
-===========================================================*/
-
-using System.Diagnostics.Contracts;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -81,14 +70,12 @@ namespace System
return m_value;
}
- [Pure]
public static byte Parse(String s)
{
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
return Parse(s.AsReadOnlySpan(), NumberStyles.Integer, NumberFormatInfo.CurrentInfo);
}
- [Pure]
public static byte Parse(String s, NumberStyles style)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
@@ -96,7 +83,6 @@ namespace System
return Parse(s.AsReadOnlySpan(), style, NumberFormatInfo.CurrentInfo);
}
- [Pure]
public static byte Parse(String s, IFormatProvider provider)
{
if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
@@ -106,7 +92,6 @@ namespace System
// Parses an unsigned byte from a String in the given style. If
// a NumberFormatInfo isn't specified, the current culture's
// NumberFormatInfo is assumed.
- [Pure]
public static byte Parse(String s, NumberStyles style, IFormatProvider provider)
{
NumberFormatInfo.ValidateParseStyleInteger(style);
@@ -182,25 +167,21 @@ namespace System
return true;
}
- [Pure]
public override String ToString()
{
return Number.FormatInt32(m_value, null, NumberFormatInfo.CurrentInfo);
}
- [Pure]
public String ToString(String format)
{
return Number.FormatInt32(m_value, format, NumberFormatInfo.CurrentInfo);
}
- [Pure]
public String ToString(IFormatProvider provider)
{
return Number.FormatInt32(m_value, null, NumberFormatInfo.GetInstance(provider));
}
- [Pure]
public String ToString(String format, IFormatProvider provider)
{
return Number.FormatInt32(m_value, format, NumberFormatInfo.GetInstance(provider));
@@ -209,7 +190,6 @@ namespace System
//
// IConvertible implementation
//
- [Pure]
public TypeCode GetTypeCode()
{
return TypeCode.Byte;
diff --git a/src/mscorlib/shared/System/Char.cs b/src/mscorlib/shared/System/Char.cs
index 1152369869..6059830fbd 100644
--- a/src/mscorlib/shared/System/Char.cs
+++ b/src/mscorlib/shared/System/Char.cs
@@ -13,7 +13,6 @@
===========================================================*/
using System.Diagnostics;
-using System.Diagnostics.Contracts;
using System.Globalization;
using System.Runtime.InteropServices;
@@ -129,7 +128,6 @@ namespace System
// null is considered to be less than any instance.
// If object is not of type Char, this method throws an ArgumentException.
//
- [Pure]
public int CompareTo(Object value)
{
if (value == null)
@@ -144,20 +142,17 @@ namespace System
return (m_value - ((Char)value).m_value);
}
- [Pure]
public int CompareTo(Char value)
{
return (m_value - value);
}
// Overrides System.Object.ToString.
- [Pure]
public override String ToString()
{
return Char.ToString(m_value);
}
- [Pure]
public String ToString(IFormatProvider provider)
{
return Char.ToString(m_value);
@@ -171,7 +166,6 @@ namespace System
**This static methods takes a character and returns the String representation of it.
==============================================================================*/
// Provides a string representation of a character.
- [Pure]
public static string ToString(char c) => string.CreateFromChar(c);
public static char Parse(String s)
@@ -211,7 +205,6 @@ namespace System
**character c is considered to be a digit. **
==============================================================================*/
// Determines whether a character is a digit.
- [Pure]
public static bool IsDigit(char c)
{
if (IsLatin1(c))
@@ -244,7 +237,6 @@ namespace System
**character c is considered to be a letter. **
==============================================================================*/
// Determines whether a character is a letter.
- [Pure]
public static bool IsLetter(char c)
{
if (IsLatin1(c))
@@ -283,7 +275,6 @@ namespace System
**character c is considered to be a whitespace character. **
==============================================================================*/
// Determines whether a character is whitespace.
- [Pure]
public static bool IsWhiteSpace(char c)
{
if (IsLatin1(c))
@@ -299,7 +290,6 @@ namespace System
**Returns: True if c is an uppercase character.
==============================================================================*/
// Determines whether a character is upper-case.
- [Pure]
public static bool IsUpper(char c)
{
if (IsLatin1(c))
@@ -318,7 +308,6 @@ namespace System
**Returns: True if c is an lowercase character.
==============================================================================*/
// Determines whether a character is lower-case.
- [Pure]
public static bool IsLower(char c)
{
if (IsLatin1(c))
@@ -354,7 +343,6 @@ namespace System
**Returns: True if c is an punctuation mark
==============================================================================*/
// Determines whether a character is a punctuation mark.
- [Pure]
public static bool IsPunctuation(char c)
{
if (IsLatin1(c))
@@ -383,7 +371,6 @@ namespace System
}
// Determines whether a character is a letter or a digit.
- [Pure]
public static bool IsLetterOrDigit(char c)
{
if (IsLatin1(c))
@@ -459,7 +446,6 @@ namespace System
//
// IConvertible implementation
//
- [Pure]
public TypeCode GetTypeCode()
{
return TypeCode.Char;
@@ -762,13 +748,11 @@ namespace System
return (CheckSeparator(CharUnicodeInfo.GetUnicodeCategory(s, index)));
}
- [Pure]
public static bool IsSurrogate(char c)
{
return (c >= HIGH_SURROGATE_START && c <= LOW_SURROGATE_END);
}
- [Pure]
public static bool IsSurrogate(String s, int index)
{
if (s == null)
@@ -907,13 +891,11 @@ namespace System
/*================================= IsHighSurrogate ============================
** Check if a char is a high surrogate.
==============================================================================*/
- [Pure]
public static bool IsHighSurrogate(char c)
{
return ((c >= CharUnicodeInfo.HIGH_SURROGATE_START) && (c <= CharUnicodeInfo.HIGH_SURROGATE_END));
}
- [Pure]
public static bool IsHighSurrogate(String s, int index)
{
if (s == null)
@@ -930,13 +912,11 @@ namespace System
/*================================= IsLowSurrogate ============================
** Check if a char is a low surrogate.
==============================================================================*/
- [Pure]
public static bool IsLowSurrogate(char c)
{
return ((c >= CharUnicodeInfo.LOW_SURROGATE_START) && (c <= CharUnicodeInfo.LOW_SURROGATE_END));
}
- [Pure]
public static bool IsLowSurrogate(String s, int index)
{
if (s == null)
@@ -953,7 +933,6 @@ namespace System
/*================================= IsSurrogatePair ============================
** Check if the string specified by the index starts with a surrogate pair.
==============================================================================*/
- [Pure]
public static bool IsSurrogatePair(String s, int index)
{
if (s == null)
@@ -971,7 +950,6 @@ namespace System
return (false);
}
- [Pure]
public static bool IsSurrogatePair(char highSurrogate, char lowSurrogate)
{
return ((highSurrogate >= CharUnicodeInfo.HIGH_SURROGATE_START && highSurrogate <= CharUnicodeInfo.HIGH_SURROGATE_END) &&
diff --git a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs b/src/mscorlib/shared/System/Collections/Generic/Dictionary.cs
index 761f775905..5b576973aa 100644
--- a/src/mscorlib/src/System/Collections/Generic/Dictionary.cs
+++ b/src/mscorlib/shared/System/Collections/Generic/Dictionary.cs
@@ -2,31 +2,14 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-**
-** Purpose: Generic hash table implementation
-**
-** #DictionaryVersusHashtableThreadSafety
-** Hashtable has multiple reader/single writer (MR/SW) thread safety built into
-** certain methods and properties, whereas Dictionary doesn't. If you're
-** converting framework code that formerly used Hashtable to Dictionary, it's
-** important to consider whether callers may have taken a dependence on MR/SW
-** thread safety. If a reader writer lock is available, then that may be used
-** with a Dictionary to get the same thread safety guarantee.
-**
-===========================================================*/
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
namespace System.Collections.Generic
{
- using System;
- using System.Collections;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.Serialization;
-
/// <summary>
/// Used internally to control behavior of insertion into a <see cref="Dictionary{TKey, TValue}"/>.
/// </summary>
@@ -51,7 +34,7 @@ namespace System.Collections.Generic
[DebuggerTypeProxy(typeof(IDictionaryDebugView<,>))]
[DebuggerDisplay("Count = {Count}")]
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue>, ISerializable, IDeserializationCallback
{
private struct Entry
@@ -71,13 +54,13 @@ namespace System.Collections.Generic
private IEqualityComparer<TKey> comparer;
private KeyCollection keys;
private ValueCollection values;
- private Object _syncRoot;
+ private object _syncRoot;
// constants for serialization
- private const String VersionName = "Version"; // Do not rename (binary serialization)
- private const String HashSizeName = "HashSize"; // Do not rename (binary serialization). Must save buckets.Length
- private const String KeyValuePairsName = "KeyValuePairs"; // Do not rename (binary serialization)
- private const String ComparerName = "Comparer"; // Do not rename (binary serialization)
+ private const string VersionName = "Version"; // Do not rename (binary serialization)
+ private const string HashSizeName = "HashSize"; // Do not rename (binary serialization). Must save buckets.Length
+ private const string KeyValuePairsName = "KeyValuePairs"; // Do not rename (binary serialization)
+ private const string ComparerName = "Comparer"; // Do not rename (binary serialization)
public Dictionary() : this(0, null) { }
@@ -132,9 +115,7 @@ namespace System.Collections.Generic
}
}
- public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) :
- this(collection, null)
- { }
+ public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection) : this(collection, null) { }
public Dictionary(IEnumerable<KeyValuePair<TKey, TValue>> collection, IEqualityComparer<TKey> comparer) :
this((collection as ICollection<KeyValuePair<TKey, TValue>>)?.Count ?? 0, comparer)
@@ -152,9 +133,9 @@ namespace System.Collections.Generic
protected Dictionary(SerializationInfo info, StreamingContext context)
{
- //We can't do anything with the keys and values until the entire graph has been deserialized
- //and we have a resonable estimate that GetHashCode is not going to fail. For the time being,
- //we'll just cache this. The graph is not valid until OnDeserialization has been called.
+ // We can't do anything with the keys and values until the entire graph has been deserialized
+ // and we have a resonable estimate that GetHashCode is not going to fail. For the time being,
+ // we'll just cache this. The graph is not valid until OnDeserialization has been called.
HashHelpers.SerializationInfoTable.Add(this, info);
}
@@ -355,12 +336,14 @@ namespace System.Collections.Generic
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.info);
}
+
info.AddValue(VersionName, version);
info.AddValue(ComparerName, comparer, typeof(IEqualityComparer<TKey>));
- info.AddValue(HashSizeName, buckets == null ? 0 : buckets.Length); //This is the length of the bucket array.
+ info.AddValue(HashSizeName, buckets == null ? 0 : buckets.Length); // This is the length of the bucket array
+
if (buckets != null)
{
- KeyValuePair<TKey, TValue>[] array = new KeyValuePair<TKey, TValue>[Count];
+ var array = new KeyValuePair<TKey, TValue>[Count];
CopyTo(array, 0);
info.AddValue(KeyValuePairsName, array, typeof(KeyValuePair<TKey, TValue>[]));
}
@@ -402,7 +385,7 @@ namespace System.Collections.Generic
if (buckets == null) Initialize(0);
int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF;
- int targetBucket = hashCode % buckets.Length;
+ int targetBucket = hashCode % buckets.Length;
int collisionCount = 0;
for (int i = buckets[targetBucket]; i >= 0; i = entries[i].next)
@@ -423,9 +406,9 @@ namespace System.Collections.Generic
return false;
}
-
collisionCount++;
}
+
int index;
if (freeCount > 0)
{
@@ -454,7 +437,7 @@ namespace System.Collections.Generic
// If we hit the collision threshold we'll need to switch to the comparer which is using randomized string hashing
// i.e. EqualityComparer<string>.Default.
- if (collisionCount > HashHelpers.HashCollisionThreshold && comparer == NonRandomizedStringEqualityComparer.Default)
+ if (collisionCount > HashHelpers.HashCollisionThreshold && comparer is NonRandomizedStringEqualityComparer)
{
comparer = (IEqualityComparer<TKey>)EqualityComparer<string>.Default;
Resize(entries.Length, true);
@@ -463,17 +446,15 @@ namespace System.Collections.Generic
return true;
}
- public virtual void OnDeserialization(Object sender)
+ public virtual void OnDeserialization(object sender)
{
SerializationInfo siInfo;
HashHelpers.SerializationInfoTable.TryGetValue(this, out siInfo);
if (siInfo == null)
{
- // It might be necessary to call OnDeserialization from a container if the container object also implements
- // OnDeserialization. However, remoting will call OnDeserialization again.
// We can return immediately if this function is called twice.
- // Note we set remove the serialization info from the table at the end of this method.
+ // Note we remove the serialization info from the table at the end of this method.
return;
}
@@ -526,6 +507,7 @@ namespace System.Collections.Generic
for (int i = 0; i < newBuckets.Length; i++) newBuckets[i] = -1;
Entry[] newEntries = new Entry[newSize];
Array.Copy(entries, 0, newEntries, 0, count);
+
if (forceNewHashCodes)
{
for (int i = 0; i < count; i++)
@@ -536,6 +518,7 @@ namespace System.Collections.Generic
}
}
}
+
for (int i = 0; i < count; i++)
{
if (newEntries[i].hashCode >= 0)
@@ -545,6 +528,7 @@ namespace System.Collections.Generic
newBuckets[bucket] = i;
}
}
+
buckets = newBuckets;
entries = newEntries;
}
@@ -672,6 +656,7 @@ namespace System.Collections.Generic
value = default(TValue);
return false;
}
+
public bool TryAdd(TKey key, TValue value) => TryInsert(key, value, InsertionBehavior.None);
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
@@ -1170,7 +1155,7 @@ namespace System.Collections.Generic
get { return false; }
}
- Object ICollection.SyncRoot
+ object ICollection.SyncRoot
{
get { return ((ICollection)dictionary).SyncRoot; }
}
@@ -1225,7 +1210,7 @@ namespace System.Collections.Generic
}
}
- Object System.Collections.IEnumerator.Current
+ object System.Collections.IEnumerator.Current
{
get
{
@@ -1396,7 +1381,7 @@ namespace System.Collections.Generic
get { return false; }
}
- Object ICollection.SyncRoot
+ object ICollection.SyncRoot
{
get { return ((ICollection)dictionary).SyncRoot; }
}
@@ -1450,7 +1435,7 @@ namespace System.Collections.Generic
}
}
- Object System.Collections.IEnumerator.Current
+ object System.Collections.IEnumerator.Current
{
get
{
diff --git a/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs b/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
index c32bc623ba..48eddb8745 100644
--- a/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
+++ b/src/mscorlib/shared/System/Collections/Generic/KeyNotFoundException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.Collections.Generic
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class KeyNotFoundException : SystemException
{
public KeyNotFoundException()
@@ -29,7 +31,6 @@ namespace System.Collections.Generic
protected KeyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs b/src/mscorlib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
new file mode 100644
index 0000000000..ef44fefc8e
--- /dev/null
+++ b/src/mscorlib/shared/System/Collections/Generic/NonRandomizedStringEqualityComparer.cs
@@ -0,0 +1,38 @@
+// 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.Runtime.Serialization;
+
+namespace System.Collections.Generic
+{
+ // NonRandomizedStringEqualityComparer is the comparer used by default with the Dictionary<string,...>
+ // We use NonRandomizedStringEqualityComparer as default comparer as it doesnt use the randomized string hashing which
+ // keeps the performance not affected till we hit collision threshold and then we switch to the comparer which is using
+ // randomized string hashing.
+ [Serializable] // Required for compatibility with .NET Core 2.0 as we exposed the NonRandomizedStringEqualityComparer inside the serialization blob
+#if CORECLR
+ internal
+#else
+ public
+#endif
+ sealed class NonRandomizedStringEqualityComparer : EqualityComparer<string>, ISerializable
+ {
+ internal static new IEqualityComparer<string> Default { get; } = new NonRandomizedStringEqualityComparer();
+
+ private NonRandomizedStringEqualityComparer() { }
+
+ // This is used by the serialization engine.
+ private NonRandomizedStringEqualityComparer(SerializationInfo information, StreamingContext context) { }
+
+ public sealed override bool Equals(string x, string y) => string.Equals(x, y);
+
+ public sealed override int GetHashCode(string obj) => obj?.GetLegacyNonRandomizedHashCode() ?? 0;
+
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ // We are doing this to stay compatible with .NET Framework.
+ info.SetType(typeof(GenericEqualityComparer<string>));
+ }
+ }
+}
diff --git a/src/mscorlib/shared/System/Collections/HashHelpers.cs b/src/mscorlib/shared/System/Collections/HashHelpers.cs
new file mode 100644
index 0000000000..49cff85b58
--- /dev/null
+++ b/src/mscorlib/shared/System/Collections/HashHelpers.cs
@@ -0,0 +1,108 @@
+// 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;
+using System.Runtime.CompilerServices;
+using System.Runtime.Serialization;
+using System.Threading;
+
+namespace System.Collections
+{
+ internal static class HashHelpers
+ {
+ public const int HashCollisionThreshold = 100;
+
+ public const int HashPrime = 101;
+
+ // Table of prime numbers to use as hash table sizes.
+ // A typical resize algorithm would pick the smallest prime number in this array
+ // that is larger than twice the previous capacity.
+ // Suppose our Hashtable currently has capacity x and enough elements are added
+ // such that a resize needs to occur. Resizing first computes 2x then finds the
+ // first prime in the table greater than 2x, i.e. if primes are ordered
+ // p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
+ // Doubling is important for preserving the asymptotic complexity of the
+ // hashtable operations such as add. Having a prime guarantees that double
+ // hashing does not lead to infinite loops. IE, your hash function will be
+ // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
+ public static readonly int[] primes = {
+ 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
+ 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
+ 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
+ 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
+ 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
+
+ public static bool IsPrime(int candidate)
+ {
+ if ((candidate & 1) != 0)
+ {
+ int limit = (int)Math.Sqrt(candidate);
+ for (int divisor = 3; divisor <= limit; divisor += 2)
+ {
+ if ((candidate % divisor) == 0)
+ return false;
+ }
+ return true;
+ }
+ return (candidate == 2);
+ }
+
+ public static int GetPrime(int min)
+ {
+ if (min < 0)
+ throw new ArgumentException(SR.Arg_HTCapacityOverflow);
+
+ for (int i = 0; i < primes.Length; i++)
+ {
+ int prime = primes[i];
+ if (prime >= min) return prime;
+ }
+
+ //outside of our predefined table.
+ //compute the hard way.
+ for (int i = (min | 1); i < Int32.MaxValue; i += 2)
+ {
+ if (IsPrime(i) && ((i - 1) % HashPrime != 0))
+ return i;
+ }
+ return min;
+ }
+
+ // Returns size of hashtable to grow to.
+ public static int ExpandPrime(int oldSize)
+ {
+ int newSize = 2 * oldSize;
+
+ // Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
+ // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
+ if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
+ {
+ Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
+ return MaxPrimeArrayLength;
+ }
+
+ return GetPrime(newSize);
+ }
+
+
+ // This is the maximum prime smaller than Array.MaxArrayLength
+ public const int MaxPrimeArrayLength = 0x7FEFFFFD;
+
+
+ // Used by Hashtable and Dictionary's SeralizationInfo .ctor's to store the SeralizationInfo
+ // object until OnDeserialization is called.
+ private static ConditionalWeakTable<object, SerializationInfo> s_serializationInfoTable;
+
+ internal static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable
+ {
+ get
+ {
+ if (s_serializationInfoTable == null)
+ Interlocked.CompareExchange(ref s_serializationInfoTable, new ConditionalWeakTable<object, SerializationInfo>(), null);
+
+ return s_serializationInfoTable;
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/shared/System/Convert.cs b/src/mscorlib/shared/System/Convert.cs
index 4a60164f94..6c592a4923 100644
--- a/src/mscorlib/shared/System/Convert.cs
+++ b/src/mscorlib/shared/System/Convert.cs
@@ -134,7 +134,7 @@ namespace System
private const Int32 base64LineBreakPosition = 76;
-#if _DEBUG
+#if DEBUG
private static bool TriggerAsserts = DoAsserts();
private static bool DoAsserts()
{
@@ -2386,7 +2386,7 @@ namespace System
{
throw new ArgumentNullException(nameof(inArray));
}
- return ToBase64String(inArray, 0, inArray.Length, Base64FormattingOptions.None);
+ return ToBase64String(new ReadOnlySpan<byte>(inArray), Base64FormattingOptions.None);
}
public static String ToBase64String(byte[] inArray, Base64FormattingOptions options)
@@ -2395,7 +2395,7 @@ namespace System
{
throw new ArgumentNullException(nameof(inArray));
}
- return ToBase64String(inArray, 0, inArray.Length, options);
+ return ToBase64String(new ReadOnlySpan<byte>(inArray), options);
}
public static String ToBase64String(byte[] inArray, int offset, int length)
@@ -2403,42 +2403,46 @@ namespace System
return ToBase64String(inArray, offset, length, Base64FormattingOptions.None);
}
- public static unsafe String ToBase64String(byte[] inArray, int offset, int length, Base64FormattingOptions options)
+ public static String ToBase64String(byte[] inArray, int offset, int length, Base64FormattingOptions options)
{
- //Do data verfication
if (inArray == null)
throw new ArgumentNullException(nameof(inArray));
if (length < 0)
throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_Index);
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_GenericPositive);
- if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
- throw new ArgumentException(string.Format(SR.Arg_EnumIllegalVal, (int)options));
+ if (offset > (inArray.Length - length))
+ throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_OffsetLength);
- int inArrayLength;
- int stringLength;
+ return ToBase64String(new ReadOnlySpan<byte>(inArray, offset, length), options);
+ }
- inArrayLength = inArray.Length;
- if (offset > (inArrayLength - length))
- throw new ArgumentOutOfRangeException(nameof(offset), SR.ArgumentOutOfRange_OffsetLength);
+ public static string ToBase64String(ReadOnlySpan<byte> bytes, Base64FormattingOptions options = Base64FormattingOptions.None)
+ {
+ if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
+ {
+ throw new ArgumentException(string.Format(SR.Arg_EnumIllegalVal, (int)options), nameof(options));
+ }
- if (inArrayLength == 0)
- return String.Empty;
+ if (bytes.Length == 0)
+ {
+ return string.Empty;
+ }
bool insertLineBreaks = (options == Base64FormattingOptions.InsertLineBreaks);
- //Create the new string. This is the maximally required length.
- stringLength = ToBase64_CalculateAndValidateOutputLength(length, insertLineBreaks);
+ string result = string.FastAllocateString(ToBase64_CalculateAndValidateOutputLength(bytes.Length, insertLineBreaks));
- string returnString = string.FastAllocateString(stringLength);
- fixed (char* outChars = returnString)
+ unsafe
{
- fixed (byte* inData = &inArray[0])
+ fixed (byte* bytesPtr = &bytes.DangerousGetPinnableReference())
+ fixed (char* charsPtr = result)
{
- int j = ConvertToBase64Array(outChars, inData, offset, length, insertLineBreaks);
- Debug.Assert(returnString.Length == j, "returnString.Length == j");
- return returnString;
+ int charsWritten = ConvertToBase64Array(charsPtr, bytesPtr, 0, bytes.Length, insertLineBreaks);
+ Debug.Assert(result.Length == charsWritten, $"Expected {result.Length} == {charsWritten}");
}
}
+
+ return result;
}
public static int ToBase64CharArray(byte[] inArray, int offsetIn, int length, char[] outArray, int offsetOut)
@@ -2462,7 +2466,7 @@ namespace System
if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
{
- throw new ArgumentException(string.Format(SR.Arg_EnumIllegalVal, (int)options));
+ throw new ArgumentException(string.Format(SR.Arg_EnumIllegalVal, (int)options), nameof(options));
}
@@ -2501,6 +2505,36 @@ namespace System
return retVal;
}
+ public static unsafe bool TryToBase64Chars(ReadOnlySpan<byte> bytes, Span<char> chars, out int charsWritten, Base64FormattingOptions options = Base64FormattingOptions.None)
+ {
+ if (options < Base64FormattingOptions.None || options > Base64FormattingOptions.InsertLineBreaks)
+ {
+ throw new ArgumentException(string.Format(SR.Arg_EnumIllegalVal, (int)options), nameof(options));
+ }
+
+ if (bytes.Length == 0)
+ {
+ charsWritten = 0;
+ return true;
+ }
+
+ bool insertLineBreaks = (options == Base64FormattingOptions.InsertLineBreaks);
+
+ int charLengthRequired = ToBase64_CalculateAndValidateOutputLength(bytes.Length, insertLineBreaks);
+ if (charLengthRequired > chars.Length)
+ {
+ charsWritten = 0;
+ return false;
+ }
+
+ fixed (char* outChars = &chars.DangerousGetPinnableReference())
+ fixed (byte* inData = &bytes.DangerousGetPinnableReference())
+ {
+ charsWritten = ConvertToBase64Array(outChars, inData, 0, bytes.Length, insertLineBreaks);
+ return true;
+ }
+ }
+
private static unsafe int ConvertToBase64Array(char* outChars, byte* inData, int offset, int length, bool insertLineBreaks)
{
int lengthmod3 = length % 3;
@@ -2612,6 +2646,53 @@ namespace System
}
}
+ public static bool TryFromBase64String(string s, Span<byte> bytes, out int bytesWritten)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException(nameof(s));
+ }
+
+ return TryFromBase64Chars(s.AsReadOnlySpan(), bytes, out bytesWritten);
+ }
+
+ public static unsafe bool TryFromBase64Chars(ReadOnlySpan<char> chars, Span<byte> bytes, out int bytesWritten)
+ {
+ if (chars.Length == 0)
+ {
+ bytesWritten = 0;
+ return true;
+ }
+
+ // We need to get rid of any trailing white spaces.
+ // Otherwise we would be rejecting input such as "abc= ":
+ while (chars.Length > 0)
+ {
+ char lastChar = chars[chars.Length - 1];
+ if (lastChar != ' ' && lastChar != '\n' && lastChar != '\r' && lastChar != '\t')
+ {
+ break;
+ }
+ chars = chars.Slice(0, chars.Length - 1);
+ }
+
+ fixed (char* charsPtr = &chars.DangerousGetPinnableReference())
+ {
+ int resultLength = FromBase64_ComputeResultLength(charsPtr, chars.Length);
+ Debug.Assert(resultLength >= 0);
+ if (resultLength > bytes.Length)
+ {
+ bytesWritten = 0;
+ return false;
+ }
+
+ fixed (byte* bytesPtr = &bytes.DangerousGetPinnableReference())
+ {
+ bytesWritten = FromBase64_Decode(charsPtr, chars.Length, bytesPtr, bytes.Length);
+ return true;
+ }
+ }
+ }
/// <summary>
/// Converts the specified range of a Char array, which encodes binary data as Base64 digits, to the equivalent byte array.
@@ -2821,7 +2902,7 @@ namespace System
} // unchecked while
// 'd be nice to have an assert that we never get here, but CS0162: Unreachable code detected.
- // Debug.Assert(false, "We only leave the above loop by jumping; should never get here.");
+ // Debug.Fail("We only leave the above loop by jumping; should never get here.");
// We jump here out of the loop if we hit an '=':
_EqualityCharEncountered:
diff --git a/src/mscorlib/shared/System/DataMisalignedException.cs b/src/mscorlib/shared/System/DataMisalignedException.cs
index d8d36b5cb7..2a245b6ef7 100644
--- a/src/mscorlib/shared/System/DataMisalignedException.cs
+++ b/src/mscorlib/shared/System/DataMisalignedException.cs
@@ -13,6 +13,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class DataMisalignedException : SystemException
{
public DataMisalignedException()
@@ -32,5 +34,9 @@ namespace System
{
HResult = HResults.COR_E_DATAMISALIGNED;
}
+
+ internal DataMisalignedException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/DateTime.cs b/src/mscorlib/shared/System/DateTime.cs
index 99a444d5e9..ad4d3a0fd3 100644
--- a/src/mscorlib/shared/System/DateTime.cs
+++ b/src/mscorlib/shared/System/DateTime.cs
@@ -1090,7 +1090,8 @@ namespace System
//
public static DateTime Parse(String s)
{
- return (DateTimeParse.Parse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None));
}
// Constructs a DateTime from a string. The string must specify a
@@ -1099,13 +1100,21 @@ namespace System
//
public static DateTime Parse(String s, IFormatProvider provider)
{
- return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
}
public static DateTime Parse(String s, IFormatProvider provider, DateTimeStyles styles)
{
DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
- return (DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return (DateTimeParse.Parse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles));
+ }
+
+ public static DateTime Parse(ReadOnlySpan<char> s, IFormatProvider provider = null, DateTimeStyles styles = DateTimeStyles.None)
+ {
+ DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
+ return DateTimeParse.Parse(s, DateTimeFormatInfo.GetInstance(provider), styles);
}
// Constructs a DateTime from a string. The string must specify a
@@ -1114,7 +1123,8 @@ namespace System
//
public static DateTime ParseExact(String s, String format, IFormatProvider provider)
{
- return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), DateTimeStyles.None));
}
// Constructs a DateTime from a string. The string must specify a
@@ -1124,12 +1134,26 @@ namespace System
public static DateTime ParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
- return (DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return (DateTimeParse.ParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style));
+ }
+
+ public static DateTime ParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
+ {
+ DateTimeFormatInfo.ValidateStyles(style, nameof(style));
+ return DateTimeParse.ParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style);
}
public static DateTime ParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
+ if (s == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.s);
+ return DateTimeParse.ParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style);
+ }
+
+ public static DateTime ParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style = DateTimeStyles.None)
+ {
+ DateTimeFormatInfo.ValidateStyles(style, nameof(style));
return DateTimeParse.ParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style);
}
@@ -1266,6 +1290,9 @@ namespace System
return DateTimeFormat.Format(this, format, DateTimeFormatInfo.GetInstance(provider));
}
+ public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider provider = null) =>
+ DateTimeFormat.TryFormat(this, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(provider));
+
public DateTime ToUniversalTime()
{
return TimeZoneInfo.ConvertTimeToUtc(this, TimeZoneInfoOptions.NoThrowOnInvalidTime);
@@ -1273,24 +1300,73 @@ namespace System
public static Boolean TryParse(String s, out DateTime result)
{
+ if (s == null)
+ {
+ result = default(DateTime);
+ return false;
+ }
+ return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
+ }
+
+ public static bool TryParse(ReadOnlySpan<char> s, out DateTime result)
+ {
return DateTimeParse.TryParse(s, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out result);
}
public static Boolean TryParse(String s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
{
DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
+
+ if (s == null)
+ {
+ result = default(DateTime);
+ return false;
+ }
+
+ return DateTimeParse.TryParse(s.AsReadOnlySpan(), DateTimeFormatInfo.GetInstance(provider), styles, out result);
+ }
+
+ public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, DateTimeStyles styles, out DateTime result)
+ {
+ DateTimeFormatInfo.ValidateStyles(styles, nameof(styles));
return DateTimeParse.TryParse(s, DateTimeFormatInfo.GetInstance(provider), styles, out result);
}
public static Boolean TryParseExact(String s, String format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
+
+ if (s == null)
+ {
+ result = default(DateTime);
+ return false;
+ }
+
+ return DateTimeParse.TryParseExact(s.AsReadOnlySpan(), format, DateTimeFormatInfo.GetInstance(provider), style, out result);
+ }
+
+ public static bool TryParseExact(ReadOnlySpan<char> s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
+ {
+ DateTimeFormatInfo.ValidateStyles(style, nameof(style));
return DateTimeParse.TryParseExact(s, format, DateTimeFormatInfo.GetInstance(provider), style, out result);
}
public static Boolean TryParseExact(String s, String[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)
{
DateTimeFormatInfo.ValidateStyles(style, nameof(style));
+
+ if (s == null)
+ {
+ result = default(DateTime);
+ return false;
+ }
+
+ return DateTimeParse.TryParseExactMultiple(s.AsReadOnlySpan(), formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
+ }
+
+ public static bool TryParseExact(ReadOnlySpan<char> s, string[] formats, IFormatProvider provider, DateTimeStyles style, out DateTime result)
+ {
+ DateTimeFormatInfo.ValidateStyles(style, nameof(style));
return DateTimeParse.TryParseExactMultiple(s, formats, DateTimeFormatInfo.GetInstance(provider), style, out result);
}
diff --git a/src/mscorlib/shared/System/DateTimeOffset.cs b/src/mscorlib/shared/System/DateTimeOffset.cs
index e3366e2a7d..9dc63e04ce 100644
--- a/src/mscorlib/shared/System/DateTimeOffset.cs
+++ b/src/mscorlib/shared/System/DateTimeOffset.cs
@@ -599,8 +599,10 @@ namespace System
//
public static DateTimeOffset Parse(String input)
{
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+
TimeSpan offset;
- DateTime dateResult = DateTimeParse.Parse(input,
+ DateTime dateResult = DateTimeParse.Parse(input.AsReadOnlySpan(),
DateTimeFormatInfo.CurrentInfo,
DateTimeStyles.None,
out offset);
@@ -613,26 +615,37 @@ namespace System
//
public static DateTimeOffset Parse(String input, IFormatProvider formatProvider)
{
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
return Parse(input, formatProvider, DateTimeStyles.None);
}
public static DateTimeOffset Parse(String input, IFormatProvider formatProvider, DateTimeStyles styles)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+
TimeSpan offset;
- DateTime dateResult = DateTimeParse.Parse(input,
+ DateTime dateResult = DateTimeParse.Parse(input.AsReadOnlySpan(),
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
out offset);
return new DateTimeOffset(dateResult.Ticks, offset);
}
+ public static DateTimeOffset Parse(ReadOnlySpan<char> input, IFormatProvider formatProvider = null, DateTimeStyles styles = DateTimeStyles.None)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ DateTime dateResult = DateTimeParse.Parse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset);
+ return new DateTimeOffset(dateResult.Ticks, offset);
+ }
+
// Constructs a DateTimeOffset from a string. The string must specify a
// date and optionally a time in a culture-specific or universal format.
// Leading and trailing whitespace characters are allowed.
//
public static DateTimeOffset ParseExact(String input, String format, IFormatProvider formatProvider)
{
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
return ParseExact(input, format, formatProvider, DateTimeStyles.None);
}
@@ -643,8 +656,10 @@ namespace System
public static DateTimeOffset ParseExact(String input, String format, IFormatProvider formatProvider, DateTimeStyles styles)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+
TimeSpan offset;
- DateTime dateResult = DateTimeParse.ParseExact(input,
+ DateTime dateResult = DateTimeParse.ParseExact(input.AsReadOnlySpan(),
format,
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
@@ -652,11 +667,20 @@ namespace System
return new DateTimeOffset(dateResult.Ticks, offset);
}
+ public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ DateTime dateResult = DateTimeParse.ParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset);
+ return new DateTimeOffset(dateResult.Ticks, offset);
+ }
+
public static DateTimeOffset ParseExact(String input, String[] formats, IFormatProvider formatProvider, DateTimeStyles styles)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null) ThrowHelper.ThrowArgumentNullException(ExceptionArgument.index); // TODO: index => input
+
TimeSpan offset;
- DateTime dateResult = DateTimeParse.ParseExactMultiple(input,
+ DateTime dateResult = DateTimeParse.ParseExactMultiple(input.AsReadOnlySpan(),
formats,
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
@@ -664,6 +688,13 @@ namespace System
return new DateTimeOffset(dateResult.Ticks, offset);
}
+ public static DateTimeOffset ParseExact(ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles = DateTimeStyles.None)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ DateTime dateResult = DateTimeParse.ParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out TimeSpan offset);
+ return new DateTimeOffset(dateResult.Ticks, offset);
+ }
+
public TimeSpan Subtract(DateTimeOffset value)
{
return UtcDateTime.Subtract(value.UtcDateTime);
@@ -740,6 +771,9 @@ namespace System
return DateTimeFormat.Format(ClockDateTime, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
}
+ public bool TryFormat(Span<char> destination, out int charsWritten, string format = null, IFormatProvider formatProvider = null) =>
+ DateTimeFormat.TryFormat(ClockDateTime, destination, out charsWritten, format, DateTimeFormatInfo.GetInstance(formatProvider), Offset);
+
public DateTimeOffset ToUniversalTime()
{
return new DateTimeOffset(UtcDateTime);
@@ -749,7 +783,7 @@ namespace System
{
TimeSpan offset;
DateTime dateResult;
- Boolean parsed = DateTimeParse.TryParse(input,
+ Boolean parsed = DateTimeParse.TryParse(input.AsReadOnlySpan(),
DateTimeFormatInfo.CurrentInfo,
DateTimeStyles.None,
out dateResult,
@@ -758,12 +792,25 @@ namespace System
return parsed;
}
+ public static bool TryParse(ReadOnlySpan<char> input, out DateTimeOffset result)
+ {
+ bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.CurrentInfo, DateTimeStyles.None, out DateTime dateResult, out TimeSpan offset);
+ result = new DateTimeOffset(dateResult.Ticks, offset);
+ return parsed;
+ }
+
public static Boolean TryParse(String input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null)
+ {
+ result = default(DateTimeOffset);
+ return false;
+ }
+
TimeSpan offset;
DateTime dateResult;
- Boolean parsed = DateTimeParse.TryParse(input,
+ Boolean parsed = DateTimeParse.TryParse(input.AsReadOnlySpan(),
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
out dateResult,
@@ -772,13 +819,27 @@ namespace System
return parsed;
}
+ public static bool TryParse(ReadOnlySpan<char> input, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ bool parsed = DateTimeParse.TryParse(input, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset);
+ result = new DateTimeOffset(dateResult.Ticks, offset);
+ return parsed;
+ }
+
public static Boolean TryParseExact(String input, String format, IFormatProvider formatProvider, DateTimeStyles styles,
out DateTimeOffset result)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null)
+ {
+ result = default(DateTimeOffset);
+ return false;
+ }
+
TimeSpan offset;
DateTime dateResult;
- Boolean parsed = DateTimeParse.TryParseExact(input,
+ Boolean parsed = DateTimeParse.TryParseExact(input.AsReadOnlySpan(),
format,
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
@@ -788,13 +849,28 @@ namespace System
return parsed;
}
+ public static bool TryParseExact(
+ ReadOnlySpan<char> input, string format, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ bool parsed = DateTimeParse.TryParseExact(input, format, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset);
+ result = new DateTimeOffset(dateResult.Ticks, offset);
+ return parsed;
+ }
+
public static Boolean TryParseExact(String input, String[] formats, IFormatProvider formatProvider, DateTimeStyles styles,
out DateTimeOffset result)
{
styles = ValidateStyles(styles, nameof(styles));
+ if (input == null)
+ {
+ result = default(DateTimeOffset);
+ return false;
+ }
+
TimeSpan offset;
DateTime dateResult;
- Boolean parsed = DateTimeParse.TryParseExactMultiple(input,
+ Boolean parsed = DateTimeParse.TryParseExactMultiple(input.AsReadOnlySpan(),
formats,
DateTimeFormatInfo.GetInstance(formatProvider),
styles,
@@ -804,6 +880,15 @@ namespace System
return parsed;
}
+ public static bool TryParseExact(
+ ReadOnlySpan<char> input, string[] formats, IFormatProvider formatProvider, DateTimeStyles styles, out DateTimeOffset result)
+ {
+ styles = ValidateStyles(styles, nameof(styles));
+ bool parsed = DateTimeParse.TryParseExactMultiple(input, formats, DateTimeFormatInfo.GetInstance(formatProvider), styles, out DateTime dateResult, out TimeSpan offset);
+ result = new DateTimeOffset(dateResult.Ticks, offset);
+ return parsed;
+ }
+
// Ensures the TimeSpan is valid to go in a DateTimeOffset.
private static Int16 ValidateOffset(TimeSpan offset)
{
diff --git a/src/mscorlib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs b/src/mscorlib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs
new file mode 100644
index 0000000000..474274ac08
--- /dev/null
+++ b/src/mscorlib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs
@@ -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.
+
+namespace System.Diagnostics
+{
+ [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct, Inherited = false)]
+ internal sealed class StackTraceHiddenAttribute : Attribute
+ {
+ public StackTraceHiddenAttribute() { }
+ }
+}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
index cb0526c1cc..bb52a9bb94 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/ActivityTracker.cs
@@ -5,6 +5,12 @@
using System;
using System.Diagnostics;
using System.Threading;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
@@ -37,6 +43,7 @@ namespace System.Diagnostics.Tracing
/// </summary>
internal class ActivityTracker
{
+
/// <summary>
/// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix.
/// It updates CurrentActivityId to track.
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
index 6dce32ce99..b036b28b4b 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventDescriptor.cs
@@ -9,6 +9,12 @@ using System.Runtime.InteropServices;
using Environment = Microsoft.Diagnostics.Tracing.Internal.Environment;
#endif
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
@@ -83,12 +89,12 @@ namespace System.Diagnostics.Tracing
{
if (id < 0)
{
- throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(id), SR.ArgumentOutOfRange_NeedNonNegNum);
}
if (id > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException(nameof(id), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+ throw new ArgumentOutOfRangeException(nameof(id), SR.Format(SR.ArgumentOutOfRange_NeedValidId, 1, ushort.MaxValue));
}
m_traceloggingId = 0;
@@ -101,12 +107,12 @@ namespace System.Diagnostics.Tracing
if (task < 0)
{
- throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(task), SR.ArgumentOutOfRange_NeedNonNegNum);
}
if (task > ushort.MaxValue)
{
- throw new ArgumentOutOfRangeException(nameof(task), Resources.GetResourceString("ArgumentOutOfRange_NeedValidId", 1, ushort.MaxValue));
+ throw new ArgumentOutOfRangeException(nameof(task), SR.Format(SR.ArgumentOutOfRange_NeedValidId, 1, ushort.MaxValue));
}
m_task = (ushort)task;
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
index d9f1747131..a74125a35a 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventProvider.cs
@@ -14,6 +14,12 @@ using System.Security.Permissions;
using System.Threading;
using System;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_AGAINST_DOTNET_V35
using Microsoft.Internal; // for Tuple (can't define alias for open generic types so we "use" the whole namespace)
#endif
@@ -628,6 +634,7 @@ namespace System.Diagnostics.Tracing
if ((level <= m_level) ||
(m_level == 0))
{
+
//
// Check if Keyword is enabled
//
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
index fb15213984..f6d4899843 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs
@@ -197,6 +197,12 @@ using System.Threading.Tasks;
using Microsoft.Reflection;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if CORECLR || ES_BUILD_PN
using Internal.Runtime.Augments;
#endif
@@ -244,6 +250,7 @@ namespace System.Diagnostics.Tracing
/// </remarks>
public partial class EventSource : IDisposable
{
+
#if FEATURE_EVENTSOURCE_XPLAT
private static readonly EventListener persistent_Xplat_Listener = XplatEventLogger.InitializePersistentListener();
#endif //FEATURE_EVENTSOURCE_XPLAT
@@ -421,7 +428,7 @@ namespace System.Diagnostics.Tracing
if (name == null)
{
- throw new ArgumentException(Resources.GetResourceString("Argument_InvalidTypeName"), nameof(eventSourceType));
+ throw new ArgumentException(SR.Argument_InvalidTypeName, nameof(eventSourceType));
}
return GenerateGuidFromName(name.ToUpperInvariant()); // Make it case insensitive.
}
@@ -507,7 +514,7 @@ namespace System.Diagnostics.Tracing
// User-defined EventCommands should not conflict with the reserved commands.
if ((int)command <= (int)EventCommand.Update && (int)command != (int)EventCommand.SendManifest)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidCommand"), nameof(command));
+ throw new ArgumentException(SR.EventSource_InvalidCommand, nameof(command));
}
eventSource.SendCommand(null, 0, 0, command, true, EventLevel.LogAlways, EventKeywords.None, commandArguments);
@@ -586,7 +593,7 @@ namespace System.Diagnostics.Tracing
/// </summary>
public override string ToString()
{
- return Resources.GetResourceString("EventSource_ToString", Name, Guid);
+ return SR.Format(SR.EventSource_ToString, Name, Guid);
}
/// <summary>
@@ -1250,6 +1257,7 @@ namespace System.Diagnostics.Tracing
#if FEATURE_MANAGED_ETW
if (m_eventData[eventId].EnabledForETW)
{
+
#if FEATURE_ACTIVITYSAMPLING
// this code should be kept in sync with WriteEventVarargs().
SessionMask etwSessions = SessionMask.All;
@@ -1520,17 +1528,17 @@ namespace System.Diagnostics.Tracing
m_traits = traits;
if (m_traits != null && m_traits.Length % 2 != 0)
{
- throw new ArgumentException(Resources.GetResourceString("TraitEven"), nameof(traits));
+ throw new ArgumentException(SR.EventSource_TraitEven, nameof(traits));
}
if (eventSourceGuid == Guid.Empty)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_NeedGuid"));
+ throw new ArgumentException(SR.EventSource_NeedGuid);
}
if (eventSourceName == null)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_NeedName"));
+ throw new ArgumentException(SR.EventSource_NeedName);
}
m_name = eventSourceName;
@@ -1983,7 +1991,7 @@ namespace System.Diagnostics.Tracing
// which would cause a cryptic IndexOutOfRangeException later if we don't catch it here.
if (!m_eventData[eventId].HasRelatedActivityID)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_NoRelatedActivityId"));
+ throw new ArgumentException(SR.EventSource_NoRelatedActivityId);
}
}
@@ -2184,7 +2192,7 @@ namespace System.Diagnostics.Tracing
if (!typesMatch)
{
- System.Diagnostics.Debugger.Log(0, null, Resources.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n");
+ System.Diagnostics.Debugger.Log(0, null, SR.EventSource_VarArgsParameterMismatch + "\r\n");
}
#endif //!ES_BUILD_PCL
}
@@ -2211,7 +2219,7 @@ namespace System.Diagnostics.Tracing
}
if (eventDataCount != modifiedParamCount)
{
- ReportOutOfBandMessage(Resources.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true);
+ ReportOutOfBandMessage(SR.Format(SR.EventSource_EventParametersMismatch, eventId, eventDataCount, paramCount), true);
paramCount = Math.Min(paramCount, eventDataCount);
}
@@ -2501,20 +2509,20 @@ namespace System.Diagnostics.Tracing
switch (EventProvider.GetLastWriteEventError())
{
case EventProvider.WriteEventErrorCode.EventTooBig:
- ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_EventTooBig"), true);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_EventTooBig"), innerEx);
+ ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_EventTooBig, true);
+ if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_EventTooBig, innerEx);
break;
case EventProvider.WriteEventErrorCode.NoFreeBuffers:
- ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NoFreeBuffers"), true);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NoFreeBuffers"), innerEx);
+ ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_NoFreeBuffers, true);
+ if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_NoFreeBuffers, innerEx);
break;
case EventProvider.WriteEventErrorCode.NullInput:
- ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_NullInput"), true);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_NullInput"), innerEx);
+ ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_NullInput, true);
+ if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_NullInput, innerEx);
break;
case EventProvider.WriteEventErrorCode.TooManyArgs:
- ReportOutOfBandMessage(errorPrefix + ": " + Resources.GetResourceString("EventSource_TooManyArgs"), true);
- if (ThrowOnEventWriteErrors) throw new EventSourceException(Resources.GetResourceString("EventSource_TooManyArgs"), innerEx);
+ ReportOutOfBandMessage(errorPrefix + ": " + SR.EventSource_TooManyArgs, true);
+ if (ThrowOnEventWriteErrors) throw new EventSourceException(SR.EventSource_TooManyArgs, innerEx);
break;
default:
if (innerEx != null)
@@ -2671,8 +2679,16 @@ namespace System.Diagnostics.Tracing
else
{
// We can't do the command, simply remember it and we do it when we are fully constructed.
- commandArgs.nextCommand = m_deferredCommands;
- m_deferredCommands = commandArgs;
+ if (m_deferredCommands == null)
+ m_deferredCommands = commandArgs; // create the first entry
+ else
+ {
+ // We have one or more entries, find the last one and add it to that.
+ EventCommandEventArgs lastCommand = m_deferredCommands;
+ while (lastCommand.nextCommand != null)
+ lastCommand = lastCommand.nextCommand;
+ lastCommand.nextCommand = commandArgs;
+ }
}
}
}
@@ -2705,7 +2721,7 @@ namespace System.Diagnostics.Tracing
commandArgs.dispatcher = GetDispatcher(commandArgs.listener);
if (commandArgs.dispatcher == null && commandArgs.listener != null) // dispatcher == null means ETW dispatcher
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_ListenerNotFound"));
+ throw new ArgumentException(SR.EventSource_ListenerNotFound);
}
if (commandArgs.Arguments == null)
@@ -2786,7 +2802,7 @@ namespace System.Diagnostics.Tracing
if (commandArgs.listener == null && commandArgs.Arguments.Count > 0 && commandArgs.perEventSourceSessionId != sessionIdBit)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_SessionIdError",
+ throw new ArgumentException(SR.Format(SR.EventSource_SessionIdError,
commandArgs.perEventSourceSessionId + SessionMask.SHIFT_SESSION_TO_KEYWORD,
sessionIdBit + SessionMask.SHIFT_SESSION_TO_KEYWORD));
}
@@ -3143,7 +3159,7 @@ namespace System.Diagnostics.Tracing
{
if (eventSource != this)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_EventSourceGuidInUse", m_guid));
+ throw new ArgumentException(SR.Format(SR.EventSource_EventSourceGuidInUse, m_guid));
}
}
}
@@ -3182,7 +3198,7 @@ namespace System.Diagnostics.Tracing
Debug.Assert(!SelfDescribingEvents);
-#if FEATURE_MANAGED_ETW
+#if FEATURE_MANAGED_ETW
fixed (byte* dataPtr = rawManifest)
{
// we don't want the manifest to show up in the event log channels so we specify as keywords
@@ -3241,7 +3257,11 @@ namespace System.Diagnostics.Tracing
// 5 chunks, so only the largest manifests will hit the pause.
if ((envelope.ChunkNumber % 5) == 0)
{
+#if ES_BUILD_STANDALONE
+ Thread.Sleep(15);
+#else
RuntimeThread.Sleep(15);
+#endif
}
}
}
@@ -3326,7 +3346,7 @@ namespace System.Diagnostics.Tracing
return null;
#else // ES_BUILD_PCL && ES_BUILD_PN
// Don't use nameof here because the resource doesn't exist on some platforms, which results in a compilation error.
- throw new ArgumentException(Resources.GetResourceString("EventSource", "EventSource_PCLPlatformNotSupportedReflection"));
+ throw new ArgumentException("EventSource_PCLPlatformNotSupportedReflection", "EventSource");
#endif
}
@@ -3402,7 +3422,7 @@ namespace System.Diagnostics.Tracing
if (eventSourceType.IsAbstract() && (flags & EventManifestOptions.Strict) == 0)
return null;
-#if DEBUG && ES_BUILD_STANDALONE
+#if DEBUG && ES_BUILD_STANDALONE && TEST_SUPPORT
TestSupport.TestHooks.MaybeThrow(eventSourceType,
TestSupport.Category.ManifestError,
"EventSource_CreateManifestAndDescriptors",
@@ -3443,11 +3463,11 @@ namespace System.Diagnostics.Tracing
if (!typeMatch)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustDeriveFromEventSource"));
+ manifest.ManifestError(SR.EventSource_TypeMustDeriveFromEventSource);
}
if (!eventSourceType.IsAbstract() && !eventSourceType.IsSealed())
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_TypeMustBeSealedOrAbstract"));
+ manifest.ManifestError(SR.EventSource_TypeMustBeSealedOrAbstract);
}
}
@@ -3463,7 +3483,7 @@ namespace System.Diagnostics.Tracing
{
if (eventSourceType.IsAbstract())
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareKTOC", nestedType.Name));
+ manifest.ManifestError(SR.Format(SR.EventSource_AbstractMustNotDeclareKTOC, nestedType.Name));
}
else
{
@@ -3506,7 +3526,7 @@ namespace System.Diagnostics.Tracing
{
if (eventAttribute != null)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_AbstractMustNotDeclareEventMethods", method.Name, eventAttribute.EventId));
+ manifest.ManifestError(SR.Format(SR.EventSource_AbstractMustNotDeclareEventMethods, method.Name, eventAttribute.EventId));
}
continue;
}
@@ -3535,12 +3555,12 @@ namespace System.Diagnostics.Tracing
}
else if (eventAttribute.EventId <= 0)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_NeedPositiveId", method.Name), true);
+ manifest.ManifestError(SR.Format(SR.EventSource_NeedPositiveId, method.Name), true);
continue; // don't validate anything else for this event
}
if (method.Name.LastIndexOf('.') >= 0)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustNotBeExplicitImplementation", method.Name, eventAttribute.EventId));
+ manifest.ManifestError(SR.Format(SR.EventSource_EventMustNotBeExplicitImplementation, method.Name, eventAttribute.EventId));
}
eventId++;
@@ -3588,6 +3608,7 @@ namespace System.Diagnostics.Tracing
string.Compare(startEventMetadata.Name, 0, taskName, 0, taskName.Length) == 0 &&
string.Compare(startEventMetadata.Name, taskName.Length, s_ActivityStartSuffix, 0, Math.Max(startEventMetadata.Name.Length - taskName.Length, s_ActivityStartSuffix.Length)) == 0)
{
+
// Make the stop event match the start event
eventAttribute.Task = (EventTask)startEventMetadata.Descriptor.Task;
noTask = false;
@@ -3595,7 +3616,7 @@ namespace System.Diagnostics.Tracing
}
if (noTask && (flags & EventManifestOptions.Strict) != 0) // Throw an error if we can compatibly.
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_StopsFollowStarts"));
+ throw new ArgumentException(SR.EventSource_StopsFollowStarts);
}
}
}
@@ -3748,7 +3769,7 @@ namespace System.Diagnostics.Tracing
#endif
return;
Error:
- manifest.ManifestError(Resources.GetResourceString("EventSource_EnumKindMismatch", staticField.Name, staticField.FieldType.Name, providerEnumKind));
+ manifest.ManifestError(SR.Format(SR.EventSource_EnumKindMismatch, staticField.Name, staticField.FieldType.Name, providerEnumKind));
}
// Helper used by code:CreateManifestAndDescriptors to add a code:EventData descriptor for a method
@@ -3831,12 +3852,12 @@ namespace System.Diagnostics.Tracing
int eventArg = GetHelperCallFirstArg(method);
if (eventArg >= 0 && evtId != eventArg)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_MismatchIdToWriteEvent", evtName, evtId, eventArg), true);
+ manifest.ManifestError(SR.Format(SR.EventSource_MismatchIdToWriteEvent, evtName, evtId, eventArg), true);
}
if (evtId < eventData.Length && eventData[evtId].Descriptor.EventId != 0)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_EventIdReused", evtName, evtId, eventData[evtId].Name), true);
+ manifest.ManifestError(SR.Format(SR.EventSource_EventIdReused, evtName, evtId, eventData[evtId].Name), true);
}
// We give a task to things if they don't have one.
@@ -3850,7 +3871,7 @@ namespace System.Diagnostics.Tracing
if (eventData[idx].Descriptor.Task == (int)eventAttribute.Task && eventData[idx].Descriptor.Opcode == (int)eventAttribute.Opcode)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_TaskOpcodePairReused",
+ manifest.ManifestError(SR.Format(SR.EventSource_TaskOpcodePairReused,
evtName, evtId, eventData[idx].Name, idx));
// If we are not strict stop on first error. We have had problems with really large providers taking forever. because of many errors.
if ((options & EventManifestOptions.Strict) == 0)
@@ -3875,7 +3896,7 @@ namespace System.Diagnostics.Tracing
}
if (failure)
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId));
+ manifest.ManifestError(SR.Format(SR.EventSource_EventMustHaveTaskIfNonDefaultOpcode, evtName, evtId));
}
}
@@ -3885,7 +3906,7 @@ namespace System.Diagnostics.Tracing
// taskName & opcodeName could be passed in by the caller which has opTab & taskTab handy
// if (!(((int)eventAttribute.Opcode == 0 && evtName == taskName) || (evtName == taskName+opcodeName)))
// {
- // throw new WarningException(Resources.GetResourceString("EventSource_EventNameDoesNotEqualTaskPlusOpcode"));
+ // throw new WarningException(SR.EventSource_EventNameDoesNotEqualTaskPlusOpcode);
// }
if (eventsByName == null)
@@ -3893,7 +3914,7 @@ namespace System.Diagnostics.Tracing
if (eventsByName.ContainsKey(evtName))
{
- manifest.ManifestError(Resources.GetResourceString("EventSource_EventNameReused", evtName), true);
+ manifest.ManifestError(SR.Format(SR.EventSource_EventNameReused, evtName), true);
}
eventsByName[evtName] = evtName;
@@ -4025,7 +4046,7 @@ namespace System.Diagnostics.Tracing
goto default;
break;
default:
- /* Debug.Assert(false, "Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] +
+ /* Debug.Fail("Warning: User validation code sub-optimial: Unsuported opcode " + instrs[idx] +
" at " + idx + " in method " + method.Name); */
return -1;
}
@@ -4085,7 +4106,7 @@ namespace System.Diagnostics.Tracing
EventSourceSettings.EtwSelfDescribingEventFormat;
if ((settings & evtFormatMask) == evtFormatMask)
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_InvalidEventFormat"), nameof(settings));
+ throw new ArgumentException(SR.EventSource_InvalidEventFormat, nameof(settings));
}
// If you did not explicitly ask for manifest, you get self-describing.
@@ -4232,7 +4253,7 @@ namespace System.Diagnostics.Tracing
0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB,
};
- #endregion
+#endregion
}
/// <summary>
@@ -4509,7 +4530,7 @@ namespace System.Diagnostics.Tracing
}
- #region private
+#region private
/// <summary>
/// This routine adds newEventSource to the global list of eventSources, it also assigns the
/// ID to the eventSource (which is simply the ordinal in the global list).
@@ -4617,7 +4638,7 @@ namespace System.Diagnostics.Tracing
EventDispatcher cur = prev.m_Next;
if (cur == null)
{
- Debug.Assert(false, "EventSource did not have a registered EventListener!");
+ Debug.Fail("EventSource did not have a registered EventListener!");
break;
}
if (cur.m_Listener == listenerToRemove)
@@ -4705,7 +4726,7 @@ namespace System.Diagnostics.Tracing
// Disallow creating EventListener reentrancy.
if (s_CreatingListener)
{
- throw new InvalidOperationException(Resources.GetResourceString("EventSource_ListenerCreatedInsideCallback"));
+ throw new InvalidOperationException(SR.EventSource_ListenerCreatedInsideCallback);
}
try
@@ -4779,7 +4800,7 @@ namespace System.Diagnostics.Tracing
/// Used to register AD/Process shutdown callbacks.
/// </summary>
private static bool s_EventSourceShutdownRegistered = false;
- #endregion
+#endregion
}
/// <summary>
@@ -4821,7 +4842,7 @@ namespace System.Diagnostics.Tracing
return eventSource.EnableEventForDispatcher(dispatcher, eventId, false);
}
- #region private
+#region private
internal EventCommandEventArgs(EventCommand command, IDictionary<string, string> arguments, EventSource eventSource,
EventListener listener, int perEventSourceSessionId, int etwSessionId, bool enable, EventLevel level, EventKeywords matchAnyKeyword)
@@ -4849,7 +4870,7 @@ namespace System.Diagnostics.Tracing
internal EventKeywords matchAnyKeyword;
internal EventCommandEventArgs nextCommand; // We form a linked list of these deferred commands.
- #endregion
+#endregion
}
/// <summary>
@@ -4932,6 +4953,7 @@ namespace System.Diagnostics.Tracing
// do the lazy init if you know it is contract based (EventID >= 0)
if (EventId >= 0 && m_payloadNames == null)
{
+
var names = new List<string>();
foreach (var parameter in m_eventSource.m_eventData[EventId].Parameters)
{
@@ -5068,7 +5090,7 @@ namespace System.Diagnostics.Tracing
}
}
- #region private
+#region private
internal EventWrittenEventArgs(EventSource eventSource)
{
m_eventSource = eventSource;
@@ -5081,7 +5103,7 @@ namespace System.Diagnostics.Tracing
internal EventOpcode m_opcode;
internal EventLevel m_level;
internal EventKeywords m_keywords;
- #endregion
+#endregion
}
/// <summary>
@@ -5193,10 +5215,10 @@ namespace System.Diagnostics.Tracing
/// </summary>
public EventActivityOptions ActivityOptions { get; set; }
- #region private
+#region private
EventOpcode m_opcode;
private bool m_opcodeSet;
- #endregion
+#endregion
}
/// <summary>
@@ -5336,7 +5358,7 @@ namespace System.Diagnostics.Tracing
};
- #region private classes
+#region private classes
#if FEATURE_ACTIVITYSAMPLING
@@ -5684,7 +5706,7 @@ namespace System.Diagnostics.Tracing
}
}
- #region private
+#region private
/// <summary>
/// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever
@@ -5853,7 +5875,7 @@ namespace System.Diagnostics.Tracing
ActivityFilter m_next; // We create a linked list of these
Action<Guid> m_myActivityDelegate;
- #endregion
+#endregion
};
@@ -6161,12 +6183,12 @@ namespace System.Diagnostics.Tracing
{
if (value <= 10 || value >= 239)
{
- ManifestError(Resources.GetResourceString("EventSource_IllegalOpcodeValue", name, value));
+ ManifestError(SR.Format(SR.EventSource_IllegalOpcodeValue, name, value));
}
string prevName;
if (opcodeTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
{
- ManifestError(Resources.GetResourceString("EventSource_OpcodeCollision", name, prevName, value));
+ ManifestError(SR.Format(SR.EventSource_OpcodeCollision, name, prevName, value));
}
}
opcodeTab[value] = name;
@@ -6177,12 +6199,12 @@ namespace System.Diagnostics.Tracing
{
if (value <= 0 || value >= 65535)
{
- ManifestError(Resources.GetResourceString("EventSource_IllegalTaskValue", name, value));
+ ManifestError(SR.Format(SR.EventSource_IllegalTaskValue, name, value));
}
string prevName;
if (taskTab != null && taskTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
{
- ManifestError(Resources.GetResourceString("EventSource_TaskCollision", name, prevName, value));
+ ManifestError(SR.Format(SR.EventSource_TaskCollision, name, prevName, value));
}
}
if (taskTab == null)
@@ -6193,18 +6215,18 @@ namespace System.Diagnostics.Tracing
{
if ((value & (value - 1)) != 0) // Is it a power of 2?
{
- ManifestError(Resources.GetResourceString("EventSource_KeywordNeedPowerOfTwo", "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
+ ManifestError(SR.Format(SR.EventSource_KeywordNeedPowerOfTwo, "0x" + value.ToString("x", CultureInfo.CurrentCulture), name), true);
}
if ((flags & EventManifestOptions.Strict) != 0)
{
if (value >= 0x0000100000000000UL && !name.StartsWith("Session", StringComparison.Ordinal))
{
- ManifestError(Resources.GetResourceString("EventSource_IllegalKeywordsValue", name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+ ManifestError(SR.Format(SR.EventSource_IllegalKeywordsValue, name, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
}
string prevName;
if (keywordTab != null && keywordTab.TryGetValue(value, out prevName) && !name.Equals(prevName, StringComparison.Ordinal))
{
- ManifestError(Resources.GetResourceString("EventSource_KeywordCollision", name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
+ ManifestError(SR.Format(SR.EventSource_KeywordCollision, name, prevName, "0x" + value.ToString("x", CultureInfo.CurrentCulture)));
}
}
if (keywordTab == null)
@@ -6220,13 +6242,13 @@ namespace System.Diagnostics.Tracing
{
EventChannel chValue = (EventChannel)value;
if (value < (int)EventChannel.Admin || value > 255)
- ManifestError(Resources.GetResourceString("EventSource_EventChannelOutOfRange", name, value));
+ ManifestError(SR.Format(SR.EventSource_EventChannelOutOfRange, name, value));
else if (chValue >= EventChannel.Admin && chValue <= EventChannel.Debug &&
channelAttribute != null && EventChannelToChannelType(chValue) != channelAttribute.EventChannelType)
{
// we want to ensure developers do not define EventChannels that conflict with the builtin ones,
// but we want to allow them to override the default ones...
- ManifestError(Resources.GetResourceString("EventSource_ChannelTypeDoesNotMatchEventChannelValue",
+ ManifestError(SR.Format(SR.EventSource_ChannelTypeDoesNotMatchEventChannelValue,
name, ((EventChannel)value).ToString()));
}
@@ -6400,7 +6422,7 @@ namespace System.Diagnostics.Tracing
}
if (channelTab.Count == MaxCountChannels)
- ManifestError(Resources.GetResourceString("EventSource_MaxChannelExceeded"));
+ ManifestError(SR.EventSource_MaxChannelExceeded);
ChannelInfo info;
if (!channelTab.TryGetValue((int)channel, out info))
@@ -6446,6 +6468,7 @@ namespace System.Diagnostics.Tracing
private string CreateManifestString()
{
+
#if FEATURE_MANAGED_ETW_CHANNELS
// Write out the channels
if (channelTab != null)
@@ -6513,6 +6536,7 @@ namespace System.Diagnostics.Tracing
// Write out the tasks
if (taskTab != null)
{
+
sb.Append(" <tasks>").AppendLine();
var sortedTasks = new List<int>(taskTab.Keys);
sortedTasks.Sort();
@@ -6657,7 +6681,7 @@ namespace System.Diagnostics.Tracing
return sb.ToString();
}
- #region private
+#region private
private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elementName, string name)
{
stringBuilder.Append(" name=\"").Append(name).Append("\"");
@@ -6681,7 +6705,7 @@ namespace System.Diagnostics.Tracing
string prevValue;
if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value))
{
- ManifestError(Resources.GetResourceString("EventSource_DuplicateStringKey", key), true);
+ ManifestError(SR.Format(SR.EventSource_DuplicateStringKey, key), true);
return;
}
@@ -6737,7 +6761,7 @@ namespace System.Diagnostics.Tracing
if (channelTab == null || !channelTab.TryGetValue((int)channel, out info))
{
if (channel < EventChannel.Admin) // || channel > EventChannel.Debug)
- ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
+ ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName));
// allow channels to be auto-defined. The well known ones get their well known names, and the
// rest get names Channel<N>. This allows users to modify the Manifest if they want more advanced features.
@@ -6750,13 +6774,13 @@ namespace System.Diagnostics.Tracing
AddChannel(channelName, (int)channel, GetDefaultChannelAttribute(channel));
if (!channelTab.TryGetValue((int)channel, out info))
- ManifestError(Resources.GetResourceString("EventSource_UndefinedChannel", channel, eventName));
+ ManifestError(SR.Format(SR.EventSource_UndefinedChannel, channel, eventName));
}
// events that specify admin channels *must* have non-null "Message" attributes
if (resources != null && eventMessage == null)
eventMessage = resources.GetString("event_" + eventName, CultureInfo.InvariantCulture);
if (info.Attribs.EventChannelType == EventChannelType.Admin && eventMessage == null)
- ManifestError(Resources.GetResourceString("EventSource_EventWithAdminChannelMustHaveMessage", eventName, info.Name));
+ ManifestError(SR.Format(SR.EventSource_EventWithAdminChannelMustHaveMessage, eventName, info.Name));
return info.Name;
}
#endif
@@ -6804,7 +6828,7 @@ namespace System.Diagnostics.Tracing
string ret;
if (opcodeTab == null || !opcodeTab.TryGetValue((int)opcode, out ret))
{
- ManifestError(Resources.GetResourceString("EventSource_UndefinedOpcode", opcode, eventName), true);
+ ManifestError(SR.Format(SR.EventSource_UndefinedOpcode, opcode, eventName), true);
ret = null;
}
return ret;
@@ -6833,7 +6857,7 @@ namespace System.Diagnostics.Tracing
}
if (keyword == null)
{
- ManifestError(Resources.GetResourceString("EventSource_UndefinedKeyword", "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
+ ManifestError(SR.Format(SR.EventSource_UndefinedKeyword, "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true);
keyword = string.Empty;
}
if (ret.Length != 0 && keyword.Length != 0)
@@ -6926,7 +6950,7 @@ namespace System.Diagnostics.Tracing
}
else
{
- ManifestError(Resources.GetResourceString("EventSource_UnsupportedMessageProperty", evtName, eventMessage));
+ ManifestError(SR.Format(SR.EventSource_UnsupportedMessageProperty, evtName, eventMessage));
}
}
else if ((chIdx = "&<>'\"\r\n\t".IndexOf(eventMessage[i])) >= 0)
@@ -7003,7 +7027,7 @@ namespace System.Diagnostics.Tracing
string eventName; // Name of the event currently being processed.
int numParams; // keeps track of the number of args the event has.
List<int> byteArrArgIndices; // keeps track of the index of each byte[] argument
- #endregion
+#endregion
}
/// <summary>
@@ -7027,6 +7051,6 @@ namespace System.Diagnostics.Tracing
#endif
};
- #endregion
+#endregion
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs
index 73e32aaf53..be1bf3940a 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSourceException.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Resources;
using System.Runtime.Serialization;
#if ES_BUILD_STANDALONE
@@ -18,16 +19,16 @@ namespace System.Diagnostics.Tracing
/// <summary>
/// Exception that is thrown when an error occurs during EventSource operation.
/// </summary>
-#if !CORECLR && !ES_BUILD_PN && !ES_BUILD_PCL && !CORERT
+#if !ES_BUILD_PCL
[Serializable]
-#endif // !CORECLR && !ES_BUILD_PN && !ES_BUILD_PCL && !CORERT
+#endif
public class EventSourceException : Exception
{
/// <summary>
/// Initializes a new instance of the EventSourceException class.
/// </summary>
public EventSourceException() :
- base(Resources.GetResourceString("EventSource_ListenerWriteFailure")) { }
+ base(SR.EventSource_ListenerWriteFailure) { }
/// <summary>
/// Initializes a new instance of the EventSourceException class with a specified error message.
@@ -48,6 +49,6 @@ namespace System.Diagnostics.Tracing
#endif
internal EventSourceException(Exception innerException) :
- base(Resources.GetResourceString("EventSource_ListenerWriteFailure"), innerException) { }
+ base(SR.EventSource_ListenerWriteFailure, innerException) { }
}
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs
index 966dac2fef..d34f80eb51 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/IEventProvider.cs
@@ -2,6 +2,7 @@
// 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 Microsoft.Win32;
#if ES_BUILD_STANDALONE
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
index 5797d4d09c..1b3ca8004c 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/StubEnvironment.cs
@@ -356,3 +356,18 @@ namespace System
}
}
#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Win32
+{
+ using System.Runtime.InteropServices;
+ using System.Security;
+
+ [SuppressUnmanagedCodeSecurityAttribute()]
+ internal static class Win32Native
+ {
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern uint GetCurrentProcessId();
+ }
+}
+#endif
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
index 87df2d37a7..1444c267cb 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/DataCollector.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Resources;
using System.Runtime.InteropServices;
using System.Security;
@@ -85,7 +86,7 @@ namespace System.Diagnostics.Tracing
var scratchNew = scratchOld + size;
if (this.scratchEnd < scratchNew)
{
- throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_AddScalarOutOfRange"));
+ throw new IndexOutOfRangeException(SR.EventSource_AddScalarOutOfRange);
}
this.ScalarsBegin();
@@ -272,13 +273,13 @@ namespace System.Diagnostics.Tracing
var pinsTemp = this.pins;
if (this.pinsEnd <= pinsTemp)
{
- throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_PinArrayOutOfRange"));
+ throw new IndexOutOfRangeException(SR.EventSource_PinArrayOutOfRange);
}
var datasTemp = this.datas;
if (this.datasEnd <= datasTemp)
{
- throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+ throw new IndexOutOfRangeException(SR.EventSource_DataDescriptorsOutOfRange);
}
this.pins = pinsTemp + 1;
@@ -296,7 +297,7 @@ namespace System.Diagnostics.Tracing
var datasTemp = this.datas;
if (this.datasEnd <= datasTemp)
{
- throw new IndexOutOfRangeException(Resources.GetResourceString("EventSource_DataDescriptorsOutOfRange"));
+ throw new IndexOutOfRangeException(SR.EventSource_DataDescriptorsOutOfRange);
}
datasTemp->DataPointer = (IntPtr) this.scratch;
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
index abe9ece13c..5967ad6ab5 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventPayload.cs
@@ -6,6 +6,12 @@ using System.Collections.Generic;
using System.Collections;
using System.Diagnostics;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
index ef2ec4715c..865082f767 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/EventSourceActivity.cs
@@ -4,6 +4,12 @@
using System;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
index 309226b84d..9c7c6369ec 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/FieldMetadata.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
+using System.Resources;
using Encoding = System.Text.Encoding;
#if ES_BUILD_STANDALONE
@@ -128,17 +129,17 @@ namespace System.Diagnostics.Tracing
{
if (coreType == (int)TraceLoggingDataType.Nil)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNil"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfNil);
}
if (coreType == (int)TraceLoggingDataType.Binary)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfBinary"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfBinary);
}
#if !BROKEN_UNTIL_M3
if (coreType == (int)TraceLoggingDataType.Utf16String ||
coreType == (int)TraceLoggingDataType.MbcsString)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedArrayOfNullTerminatedString"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedArrayOfNullTerminatedString);
}
#endif
}
@@ -160,7 +161,7 @@ namespace System.Diagnostics.Tracing
this.outType++;
if ((this.outType & Statics.OutTypeMask) == 0)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_TooManyFields"));
+ throw new NotSupportedException(SR.EventSource_TooManyFields);
}
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
index d74494bc85..854bc06bb6 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/PropertyValue.cs
@@ -1,8 +1,19 @@
-using System.Reflection;
+using System;
+using System.Reflection;
using System.Runtime.InteropServices;
using System.Diagnostics;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
+#if ES_BUILD_STANDALONE
+namespace Microsoft.Diagnostics.Tracing
+#else
namespace System.Diagnostics.Tracing
+#endif
{
/// <summary>
/// Holds property values of any type. For common value types, we have inline storage so that we don't need
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
index 61cb92ffad..901a0ed1a2 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/SimpleTypeInfos.cs
@@ -7,6 +7,12 @@ using System.Collections.Generic;
using System.Reflection;
using System.Diagnostics;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
index 9fa776753d..05539ab4fd 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/Statics.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Reflection;
+using System.Resources;
using System.Runtime.CompilerServices;
using Encoding = System.Text.Encoding;
@@ -531,7 +532,7 @@ namespace System.Diagnostics.Tracing
if (recursionCheck.Contains(dataType))
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_RecursiveTypeDefinition"));
+ throw new NotSupportedException(SR.EventSource_RecursiveTypeDefinition);
}
recursionCheck.Add(dataType);
@@ -714,7 +715,7 @@ namespace System.Diagnostics.Tracing
}
else
{
- throw new ArgumentException(Resources.GetResourceString("EventSource_NonCompliantTypeError", dataType.Name));
+ throw new ArgumentException(SR.Format(SR.EventSource_NonCompliantTypeError, dataType.Name));
}
}
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
index 8d12b64a08..bf29d71844 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs
@@ -24,14 +24,17 @@ using EventDescriptor = Microsoft.Diagnostics.Tracing.EventDescriptor;
#endif
using System;
+using System.Resources;
using System.Runtime.InteropServices;
using System.Security;
using System.Collections.ObjectModel;
#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
using System.Collections.Generic;
using System.Text;
#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
using System.Collections.Generic;
using System.Text;
#endif
@@ -114,7 +117,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(eventName));
}
-
if (!this.IsEnabled())
{
return;
@@ -140,7 +142,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(eventName));
}
-
if (!this.IsEnabled())
{
return;
@@ -774,7 +775,7 @@ namespace System.Diagnostics.Tracing
}
else
{
- throw new ArgumentException(Resources.GetResourceString("UnknownEtwTrait", etwTrait), "traits");
+ throw new ArgumentException(SR.Format(SR.EventSource_UnknownEtwTrait, etwTrait), "traits");
}
}
string value = m_traits[i + 1];
@@ -817,7 +818,7 @@ namespace System.Diagnostics.Tracing
{
if (!(i + 1 < value.Length))
{
- throw new ArgumentException(Resources.GetResourceString("EvenHexDigits"), "traits");
+ throw new ArgumentException(SR.EventSource_EvenHexDigits, "traits");
}
metaData.Add((byte)(HexDigit(value[i]) * 16 + HexDigit(value[i + 1])));
i++;
@@ -830,7 +831,7 @@ namespace System.Diagnostics.Tracing
}
else
{
- throw new ArgumentException(Resources.GetResourceString("IllegalValue", value), "traits");
+ throw new ArgumentException(SR.Format(SR.EventSource_IllegalValue, value), "traits");
}
return metaData.Count - startPos;
@@ -854,7 +855,7 @@ namespace System.Diagnostics.Tracing
return (c - 'A' + 10);
}
- throw new ArgumentException(Resources.GetResourceString("BadHexDigit", c), "traits");
+ throw new ArgumentException(SR.Format(SR.EventSource_BadHexDigit, c), "traits");
}
private NameInfo UpdateDescriptor(
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
index d024b218d8..3c775a3cef 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventTypes.cs
@@ -6,6 +6,12 @@ using System;
using System.Collections.Generic;
using Interlocked = System.Threading.Interlocked;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
@@ -91,7 +97,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(name));
}
-
this.typeInfos = MakeArray(paramInfos);
this.name = name;
this.tags = tags;
@@ -128,7 +133,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(defaultName));
}
-
this.typeInfos = typeInfos;
this.name = defaultName;
this.tags = tags;
@@ -207,7 +211,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(paramInfos));
}
-
var recursionCheck = new List<Type>(paramInfos.Length);
var result = new TraceLoggingTypeInfo[paramInfos.Length];
for (int i = 0; i < paramInfos.Length; ++i)
@@ -225,7 +228,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(types));
}
-
var recursionCheck = new List<Type>(types.Length);
var result = new TraceLoggingTypeInfo[types.Length];
for (int i = 0; i < types.Length; i++)
@@ -244,7 +246,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(typeInfos));
}
-
return (TraceLoggingTypeInfo[])typeInfos.Clone(); ;
}
}
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
index 41225c8626..1db1a28c9d 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingMetadataCollector.cs
@@ -232,7 +232,7 @@ namespace System.Diagnostics.Tracing
if (this.BeginningBufferedArray)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedNestedArraysEnums);
}
this.impl.AddScalar(2);
@@ -244,7 +244,7 @@ namespace System.Diagnostics.Tracing
{
if (this.bufferedArrayFieldCount >= 0)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedNestedArraysEnums"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedNestedArraysEnums);
}
this.bufferedArrayFieldCount = 0;
@@ -255,7 +255,7 @@ namespace System.Diagnostics.Tracing
{
if (this.bufferedArrayFieldCount != 1)
{
- throw new InvalidOperationException(Resources.GetResourceString("EventSource_IncorrentlyAuthoredTypeInfo"));
+ throw new InvalidOperationException(SR.EventSource_IncorrentlyAuthoredTypeInfo);
}
this.bufferedArrayFieldCount = int.MinValue;
@@ -274,7 +274,7 @@ namespace System.Diagnostics.Tracing
{
if (this.BeginningBufferedArray)
{
- throw new NotSupportedException(Resources.GetResourceString("EventSource_NotSupportedCustomSerializedData"));
+ throw new NotSupportedException(SR.EventSource_NotSupportedCustomSerializedData);
}
this.impl.AddScalar(2);
diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
index 81f80c63f7..511a4fe480 100644
--- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
+++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingTypeInfo.cs
@@ -5,6 +5,12 @@
using System;
using System.Collections.Generic;
+#if !ES_BUILD_AGAINST_DOTNET_V35
+using Contract = System.Diagnostics.Contracts.Contract;
+#else
+using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract;
+#endif
+
#if ES_BUILD_STANDALONE
namespace Microsoft.Diagnostics.Tracing
#else
@@ -33,7 +39,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(dataType));
}
-
this.name = dataType.Name;
this.dataType = dataType;
this.propertyValueFactory = PropertyValue.GetFactory(dataType);
@@ -57,7 +62,6 @@ namespace System.Diagnostics.Tracing
throw new ArgumentNullException(nameof(name));
}
-
Statics.CheckName(name);
this.name = name;
diff --git a/src/mscorlib/shared/System/DivideByZeroException.cs b/src/mscorlib/shared/System/DivideByZeroException.cs
index ad74bde0fd..b309695ff3 100644
--- a/src/mscorlib/shared/System/DivideByZeroException.cs
+++ b/src/mscorlib/shared/System/DivideByZeroException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class DivideByZeroException : ArithmeticException
{
public DivideByZeroException()
@@ -37,7 +39,6 @@ namespace System
protected DivideByZeroException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/DllNotFoundException.cs b/src/mscorlib/shared/System/DllNotFoundException.cs
index 82d5bdd0c5..14fb50d9c5 100644
--- a/src/mscorlib/shared/System/DllNotFoundException.cs
+++ b/src/mscorlib/shared/System/DllNotFoundException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class DllNotFoundException : TypeLoadException
{
public DllNotFoundException()
@@ -38,7 +40,6 @@ namespace System
protected DllNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/DuplicateWaitObjectException.cs b/src/mscorlib/shared/System/DuplicateWaitObjectException.cs
index 95bdedd526..77303846a3 100644
--- a/src/mscorlib/shared/System/DuplicateWaitObjectException.cs
+++ b/src/mscorlib/shared/System/DuplicateWaitObjectException.cs
@@ -17,7 +17,8 @@ namespace System
{
// The DuplicateWaitObjectException is thrown when an object
// appears more than once in the list of objects to WaitAll or WaitAny.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class DuplicateWaitObjectException : ArgumentException
{
private static volatile String s_duplicateWaitObjectMessage = null;
@@ -60,7 +61,6 @@ namespace System
protected DuplicateWaitObjectException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/EntryPointNotFoundException.cs b/src/mscorlib/shared/System/EntryPointNotFoundException.cs
index e62ca0e11d..dac1cdb971 100644
--- a/src/mscorlib/shared/System/EntryPointNotFoundException.cs
+++ b/src/mscorlib/shared/System/EntryPointNotFoundException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class EntryPointNotFoundException : TypeLoadException
{
public EntryPointNotFoundException()
@@ -38,7 +40,6 @@ namespace System
protected EntryPointNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ExecutionEngineException.cs b/src/mscorlib/shared/System/ExecutionEngineException.cs
index c33435875e..5edd5cf19f 100644
--- a/src/mscorlib/shared/System/ExecutionEngineException.cs
+++ b/src/mscorlib/shared/System/ExecutionEngineException.cs
@@ -21,6 +21,8 @@ using System.Runtime.Serialization;
namespace System
{
[Obsolete("This type previously indicated an unspecified fatal error in the runtime. The runtime no longer raises this exception so this type is obsolete.")]
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class ExecutionEngineException : SystemException
{
public ExecutionEngineException()
@@ -40,5 +42,9 @@ namespace System
{
HResult = HResults.COR_E_EXECUTIONENGINE;
}
+
+ internal ExecutionEngineException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/FieldAccessException.cs b/src/mscorlib/shared/System/FieldAccessException.cs
index 883bbd8bc2..cb28264d61 100644
--- a/src/mscorlib/shared/System/FieldAccessException.cs
+++ b/src/mscorlib/shared/System/FieldAccessException.cs
@@ -13,6 +13,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class FieldAccessException : MemberAccessException
{
public FieldAccessException()
@@ -35,7 +37,6 @@ namespace System
protected FieldAccessException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/FormatException.cs b/src/mscorlib/shared/System/FormatException.cs
index 4af45cdd94..b0e273369c 100644
--- a/src/mscorlib/shared/System/FormatException.cs
+++ b/src/mscorlib/shared/System/FormatException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class FormatException : SystemException
{
public FormatException()
@@ -37,7 +39,6 @@ namespace System
protected FormatException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs b/src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs
index 35ee82d3cb..3a8029d9a0 100644
--- a/src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs
+++ b/src/mscorlib/shared/System/Globalization/CalendarData.Unix.cs
@@ -325,7 +325,7 @@ namespace System.Globalization
}
catch (Exception e)
{
- Debug.Assert(false, e.ToString());
+ Debug.Fail(e.ToString());
// we ignore the managed exceptions here because EnumCalendarInfoCallback will get called from the native code.
// If we don't ignore the exception here that can cause the runtime to fail fast.
}
diff --git a/src/mscorlib/shared/System/Globalization/CalendarData.cs b/src/mscorlib/shared/System/Globalization/CalendarData.cs
index 0991149e07..ea70a1ce9a 100644
--- a/src/mscorlib/shared/System/Globalization/CalendarData.cs
+++ b/src/mscorlib/shared/System/Globalization/CalendarData.cs
@@ -105,7 +105,7 @@ namespace System.Globalization
if (!LoadCalendarDataFromSystem(localeName, calendarId))
{
- Debug.Assert(false, "[CalendarData] LoadCalendarDataFromSystem call isn't expected to fail for calendar " + calendarId + " locale " + localeName);
+ Debug.Fail("[CalendarData] LoadCalendarDataFromSystem call isn't expected to fail for calendar " + calendarId + " locale " + localeName);
// Something failed, try invariant for missing parts
// This is really not good, but we don't want the callers to crash.
diff --git a/src/mscorlib/shared/System/Globalization/CalendricalCalculationsHelper.cs b/src/mscorlib/shared/System/Globalization/CalendricalCalculationsHelper.cs
index 7de75d6aee..e0a3072b22 100644
--- a/src/mscorlib/shared/System/Globalization/CalendricalCalculationsHelper.cs
+++ b/src/mscorlib/shared/System/Globalization/CalendricalCalculationsHelper.cs
@@ -215,7 +215,7 @@ namespace System.Globalization
}
}
- Debug.Assert(false, "Not expected to come here");
+ Debug.Fail("Not expected to come here");
return DefaultEphemerisCorrection(year);
}
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.Invariant.cs b/src/mscorlib/shared/System/Globalization/CompareInfo.Invariant.cs
index 13725bcc51..13725bcc51 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.Invariant.cs
+++ b/src/mscorlib/shared/System/Globalization/CompareInfo.Invariant.cs
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.cs b/src/mscorlib/shared/System/Globalization/CompareInfo.cs
index 1b794eceea..84fadd376e 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.cs
+++ b/src/mscorlib/shared/System/Globalization/CompareInfo.cs
@@ -51,8 +51,8 @@ namespace System.Globalization
~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
- // Mask used to check if we have the right flags.
- private const CompareOptions ValidSortkeyCtorMaskOffFlags =
+ // Mask used to check if we have the right flags.
+ private const CompareOptions ValidSortkeyCtorMaskOffFlags =
~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace |
CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
@@ -61,12 +61,11 @@ namespace System.Globalization
// ie: en-US would have an en-US sort. For haw-US (custom), then we serialize it as haw-US.
// The interesting part is that since haw-US doesn't have its own sort, it has to point at another
// locale, which is what SCOMPAREINFO does.
-
[OptionalField(VersionAdded = 2)]
private string m_name; // The name used to construct this CompareInfo. Do not rename (binary serialization)
[NonSerialized]
- private string _sortName; // The name that defines our behavior.
+ private string _sortName; // The name that defines our behavior
[OptionalField(VersionAdded = 3)]
private SortVersion m_SortVersion; // Do not rename (binary serialization)
@@ -74,7 +73,7 @@ namespace System.Globalization
// _invariantMode is defined for the perf reason as accessing the instance field is faster than access the static property GlobalizationMode.Invariant
[NonSerialized]
private readonly bool _invariantMode = GlobalizationMode.Invariant;
-
+
private int culture; // Do not rename (binary serialization). The fields sole purpose is to support Desktop serialization.
internal CompareInfo(CultureInfo culture)
@@ -102,7 +101,7 @@ namespace System.Globalization
{
throw new ArgumentNullException(nameof(assembly));
}
- if (assembly != typeof(Object).Module.Assembly)
+ if (assembly != typeof(Object).Module.Assembly)
{
throw new ArgumentException(SR.Argument_OnlyMscorlib);
}
@@ -189,7 +188,7 @@ namespace System.Globalization
public static unsafe bool IsSortable(string text)
{
- if (text == null)
+ if (text == null)
{
// A null param is invalid here.
throw new ArgumentNullException(nameof(text));
@@ -205,21 +204,20 @@ namespace System.Globalization
{
return true;
}
-
+
fixed (char *pChar = text)
{
return IsSortable(pChar, text.Length);
}
}
-
[OnDeserializing]
private void OnDeserializing(StreamingContext ctx)
{
m_name = null;
}
- void IDeserializationCallback.OnDeserialization(Object sender)
+ void IDeserializationCallback.OnDeserialization(object sender)
{
OnDeserialized();
}
@@ -342,9 +340,84 @@ namespace System.Globalization
return String.CompareOrdinal(string1, string2);
}
- return CompareString(string1, 0, string1.Length, string2, 0, string2.Length, options);
+ return CompareString(string1.AsReadOnlySpan(), string2.AsReadOnlySpan(), options);
}
+ // TODO https://github.com/dotnet/coreclr/issues/13827:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ internal unsafe int Compare(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan());
+ }
+
+ // Verify the options before we do any real comparison.
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options));
+ }
+
+ return string.CompareOrdinal(string1, string2.AsReadOnlySpan());
+ }
+
+ if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
+ }
+
+ // null sorts less than any other string.
+ if (string2 == null)
+ {
+ return 1;
+ }
+
+ if (_invariantMode)
+ {
+ return (options & CompareOptions.IgnoreCase) != 0 ?
+ CompareOrdinalIgnoreCase(string1, string2.AsReadOnlySpan()) :
+ string.CompareOrdinal(string1, string2.AsReadOnlySpan());
+ }
+
+ return CompareString(string1, string2, options);
+ }
+
+ // TODO https://github.com/dotnet/corefx/issues/21395: Expose this publicly?
+ internal unsafe virtual int Compare(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ {
+ if (options == CompareOptions.OrdinalIgnoreCase)
+ {
+ return CompareOrdinalIgnoreCase(string1, string2);
+ }
+
+ // Verify the options before we do any real comparison.
+ if ((options & CompareOptions.Ordinal) != 0)
+ {
+ if (options != CompareOptions.Ordinal)
+ {
+ throw new ArgumentException(SR.Argument_CompareOptionOrdinal, nameof(options));
+ }
+
+ return string.CompareOrdinal(string1, string2);
+ }
+
+ if ((options & ValidCompareMaskOffFlags) != 0)
+ {
+ throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options));
+ }
+
+ if (_invariantMode)
+ {
+ return (options & CompareOptions.IgnoreCase) != 0 ?
+ CompareOrdinalIgnoreCase(string1, string2) :
+ string.CompareOrdinal(string1, string2);
+ }
+
+ return CompareString(string1, string2, options);
+ }
////////////////////////////////////////////////////////////////////////
//
@@ -447,10 +520,11 @@ namespace System.Globalization
return CompareOrdinal(string1, offset1, length1, string2, offset2, length2);
}
-
- return CompareString(string1, offset1, length1,
- string2, offset2, length2,
- options);
+
+ return CompareString(
+ string1.AsReadOnlySpan().Slice(offset1, length1),
+ string2.AsReadOnlySpan().Slice(offset2, length2),
+ options);
}
private static int CompareOrdinal(string string1, int offset1, int length1, string string2, int offset2, int length2)
@@ -473,14 +547,19 @@ namespace System.Globalization
{
Debug.Assert(indexA + lengthA <= strA.Length);
Debug.Assert(indexB + lengthB <= strB.Length);
+ return CompareOrdinalIgnoreCase(strA.AsReadOnlySpan().Slice(indexA, lengthA), strB.AsReadOnlySpan().Slice(indexB, lengthB));
+ }
- int length = Math.Min(lengthA, lengthB);
+ internal static unsafe int CompareOrdinalIgnoreCase(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB)
+ {
+ int length = Math.Min(strA.Length, strB.Length);
int range = length;
- fixed (char* ap = strA) fixed (char* bp = strB)
+ fixed (char* ap = &strA.DangerousGetPinnableReference())
+ fixed (char* bp = &strB.DangerousGetPinnableReference())
{
- char* a = ap + indexA;
- char* b = bp + indexB;
+ char* a = ap;
+ char* b = bp;
// in InvariantMode we support all range and not only the ascii characters.
char maxChar = (char) (GlobalizationMode.Invariant ? 0xFFFF : 0x80);
@@ -498,8 +577,8 @@ namespace System.Globalization
}
// uppercase both chars - notice that we need just one compare per char
- if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
- if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+ if ((uint)(charA - 'a') <= 'z' - 'a') charA -= 0x20;
+ if ((uint)(charB - 'a') <= 'z' - 'a') charB -= 0x20;
// Return the (case-insensitive) difference between them.
if (charA != charB)
@@ -511,13 +590,13 @@ namespace System.Globalization
}
if (length == 0)
- return lengthA - lengthB;
+ return strA.Length - strB.Length;
Debug.Assert(!GlobalizationMode.Invariant);
range -= length;
- return CompareStringOrdinalIgnoreCase(a, lengthA - range, b, lengthB - range);
+ return CompareStringOrdinalIgnoreCase(a, strA.Length - range, b, strB.Length - range);
}
}
diff --git a/src/mscorlib/shared/System/Globalization/CultureData.Unix.cs b/src/mscorlib/shared/System/Globalization/CultureData.Unix.cs
index c21d8c3f22..3b4b60fc8a 100644
--- a/src/mscorlib/shared/System/Globalization/CultureData.Unix.cs
+++ b/src/mscorlib/shared/System/Globalization/CultureData.Unix.cs
@@ -148,7 +148,7 @@ namespace System.Globalization
{
// Failed, just use empty string
StringBuilderCache.Release(sb);
- Debug.Assert(false, "[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
+ Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
return String.Empty;
}
return StringBuilderCache.GetStringAndRelease(sb);
@@ -173,7 +173,7 @@ namespace System.Globalization
if (!result)
{
// Failed, just use 0
- Debug.Assert(false, "[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
+ Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
}
return value;
@@ -188,7 +188,7 @@ namespace System.Globalization
bool result = Interop.GlobalizationInterop.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
if (!result)
{
- Debug.Assert(false, "[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
+ Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
}
if (secondaryGroupingSize == 0)
@@ -215,7 +215,7 @@ namespace System.Globalization
{
// Failed, just use empty string
StringBuilderCache.Release(sb);
- Debug.Assert(false, "[CultureData.GetTimeFormatString(bool shortFormat)] Failed");
+ Debug.Fail("[CultureData.GetTimeFormatString(bool shortFormat)] Failed");
return String.Empty;
}
diff --git a/src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs b/src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs
index dde1a8b2ba..10e8b1f836 100644
--- a/src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs
+++ b/src/mscorlib/shared/System/Globalization/CultureNotFoundException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Globalization
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class CultureNotFoundException : ArgumentException
{
private string _invalidCultureName; // unrecognized culture name
@@ -58,12 +60,15 @@ namespace System.Globalization
protected CultureNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ _invalidCultureId = (int?)info.GetValue("InvalidCultureId", typeof(int?));
+ _invalidCultureName = (string)info.GetValue("InvalidCultureName", typeof(string));
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("InvalidCultureId", _invalidCultureId, typeof(int?));
+ info.AddValue("InvalidCultureName", _invalidCultureName, typeof(string));
}
public virtual Nullable<int> InvalidCultureId
diff --git a/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs b/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
index f129f73136..ac5d8a04ba 100644
--- a/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
+++ b/src/mscorlib/shared/System/Globalization/DateTimeFormat.cs
@@ -446,7 +446,7 @@ namespace System
//
// Actions: Format the DateTime instance using the specified format.
//
- private static String FormatCustomized(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
+ private static StringBuilder FormatCustomized(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
{
Calendar cal = dtfi.Calendar;
StringBuilder result = StringBuilderCache.Acquire();
@@ -532,6 +532,7 @@ namespace System
}
else
{
+ StringBuilderCache.Release(result);
throw new FormatException(SR.Format_InvalidString);
}
break;
@@ -700,6 +701,7 @@ namespace System
// This means that '%' is at the end of the format string or
// "%%" appears in the format string.
//
+ StringBuilderCache.Release(result);
throw new FormatException(SR.Format_InvalidString);
}
break;
@@ -723,6 +725,7 @@ namespace System
//
// This means that '\' is at the end of the formatting string.
//
+ StringBuilderCache.Release(result);
throw new FormatException(SR.Format_InvalidString);
}
break;
@@ -737,7 +740,7 @@ namespace System
}
i += tokenLen;
}
- return StringBuilderCache.GetStringAndRelease(result);
+ return result;
}
@@ -966,8 +969,32 @@ namespace System
return Format(dateTime, format, dtfi, NullOffset);
}
+ internal static string Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset) =>
+ StringBuilderCache.GetStringAndRelease(FormatStringBuilder(dateTime, format, dtfi, offset));
- internal static String Format(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
+ internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, string format, DateTimeFormatInfo dtfi) =>
+ TryFormat(dateTime, destination, out charsWritten, format, dtfi, NullOffset);
+
+ internal static bool TryFormat(DateTime dateTime, Span<char> destination, out int charsWritten, string format, DateTimeFormatInfo dtfi, TimeSpan offset)
+ {
+ StringBuilder sb = FormatStringBuilder(dateTime, format, dtfi, offset);
+
+ bool success = sb.Length <= destination.Length;
+ if (success)
+ {
+ sb.CopyTo(0, destination, sb.Length);
+ charsWritten = sb.Length;
+ }
+ else
+ {
+ charsWritten = 0;
+ }
+
+ StringBuilderCache.Release(sb);
+ return success;
+ }
+
+ internal static StringBuilder FormatStringBuilder(DateTime dateTime, String format, DateTimeFormatInfo dtfi, TimeSpan offset)
{
Debug.Assert(dtfi != null);
if (format == null || format.Length == 0)
@@ -1043,10 +1070,10 @@ namespace System
format = ExpandPredefinedFormat(format, ref dateTime, ref dtfi, ref offset);
}
- return (FormatCustomized(dateTime, format, dtfi, offset));
+ return FormatCustomized(dateTime, format, dtfi, offset);
}
- internal static string FastFormatRfc1123(DateTime dateTime, TimeSpan offset, DateTimeFormatInfo dtfi)
+ internal static StringBuilder FastFormatRfc1123(DateTime dateTime, TimeSpan offset, DateTimeFormatInfo dtfi)
{
// ddd, dd MMM yyyy HH:mm:ss GMT
const int Rfc1123FormatLength = 29;
@@ -1072,10 +1099,10 @@ namespace System
result.Append(' ');
result.Append(Gmt);
- return StringBuilderCache.GetStringAndRelease(result);
+ return result;
}
- internal static string FastFormatRoundtrip(DateTime dateTime, TimeSpan offset)
+ internal static StringBuilder FastFormatRoundtrip(DateTime dateTime, TimeSpan offset)
{
// yyyy-MM-ddTHH:mm:ss.fffffffK
const int roundTripFormatLength = 28;
@@ -1096,7 +1123,7 @@ namespace System
FormatCustomizedRoundripTimeZone(dateTime, offset, result);
- return StringBuilderCache.GetStringAndRelease(result);
+ return result;
}
private static void AppendHHmmssTimeOfDay(StringBuilder result, DateTime dateTime)
diff --git a/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs b/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs
index 7c4200af7b..9dbfeb2d55 100644
--- a/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs
+++ b/src/mscorlib/shared/System/Globalization/DateTimeFormatInfo.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
namespace System.Globalization
@@ -214,18 +215,16 @@ namespace System.Globalization
//
////////////////////////////////////////////////////////////////////////////
- private String[] internalGetAbbreviatedDayOfWeekNames()
+ private string[] internalGetAbbreviatedDayOfWeekNames() => this.abbreviatedDayNames ?? internalGetAbbreviatedDayOfWeekNamesCore();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private string[] internalGetAbbreviatedDayOfWeekNamesCore()
{
- if (this.abbreviatedDayNames == null)
- {
- // Get the abbreviated day names for our current calendar
- this.abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID);
- Debug.Assert(this.abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week");
- }
- return (this.abbreviatedDayNames);
+ // Get the abbreviated day names for our current calendar
+ this.abbreviatedDayNames = _cultureData.AbbreviatedDayNames(Calendar.ID);
+ Debug.Assert(this.abbreviatedDayNames.Length == 7, "[DateTimeFormatInfo.GetAbbreviatedDayOfWeekNames] Expected 7 day names in a week");
+ return this.abbreviatedDayNames;
}
-
////////////////////////////////////////////////////////////////////////
//
// Action: Returns the string array of the one-letter day of week names.
@@ -238,15 +237,14 @@ namespace System.Globalization
//
////////////////////////////////////////////////////////////////////////
- private String[] internalGetSuperShortDayNames()
+ private string[] internalGetSuperShortDayNames() => this.m_superShortDayNames ?? internalGetSuperShortDayNamesCore();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private string[] internalGetSuperShortDayNamesCore()
{
- if (this.m_superShortDayNames == null)
- {
- // Get the super short day names for our current calendar
- this.m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID);
- Debug.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week");
- }
- return (this.m_superShortDayNames);
+ // Get the super short day names for our current calendar
+ this.m_superShortDayNames = _cultureData.SuperShortDayNames(Calendar.ID);
+ Debug.Assert(this.m_superShortDayNames.Length == 7, "[DateTimeFormatInfo.internalGetSuperShortDayNames] Expected 7 day names in a week");
+ return this.m_superShortDayNames;
}
////////////////////////////////////////////////////////////////////////////
@@ -255,15 +253,14 @@ namespace System.Globalization
//
////////////////////////////////////////////////////////////////////////////
- private String[] internalGetDayOfWeekNames()
+ private string[] internalGetDayOfWeekNames() => this.dayNames ?? internalGetDayOfWeekNamesCore();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private string[] internalGetDayOfWeekNamesCore()
{
- if (this.dayNames == null)
- {
- // Get the day names for our current calendar
- this.dayNames = _cultureData.DayNames(Calendar.ID);
- Debug.Assert(this.dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week");
- }
- return (this.dayNames);
+ // Get the day names for our current calendar
+ this.dayNames = _cultureData.DayNames(Calendar.ID);
+ Debug.Assert(this.dayNames.Length == 7, "[DateTimeFormatInfo.GetDayOfWeekNames] Expected 7 day names in a week");
+ return this.dayNames;
}
////////////////////////////////////////////////////////////////////////////
@@ -272,16 +269,15 @@ namespace System.Globalization
//
////////////////////////////////////////////////////////////////////////////
- private String[] internalGetAbbreviatedMonthNames()
+ private String[] internalGetAbbreviatedMonthNames() => this.abbreviatedMonthNames ?? internalGetAbbreviatedMonthNamesCore();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private String[] internalGetAbbreviatedMonthNamesCore()
{
- if (this.abbreviatedMonthNames == null)
- {
- // Get the month names for our current calendar
- this.abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID);
- Debug.Assert(this.abbreviatedMonthNames.Length == 12 || this.abbreviatedMonthNames.Length == 13,
- "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year");
- }
- return (this.abbreviatedMonthNames);
+ // Get the month names for our current calendar
+ this.abbreviatedMonthNames = _cultureData.AbbreviatedMonthNames(Calendar.ID);
+ Debug.Assert(this.abbreviatedMonthNames.Length == 12 || this.abbreviatedMonthNames.Length == 13,
+ "[DateTimeFormatInfo.GetAbbreviatedMonthNames] Expected 12 or 13 month names in a year");
+ return this.abbreviatedMonthNames;
}
@@ -291,17 +287,15 @@ namespace System.Globalization
//
////////////////////////////////////////////////////////////////////////////
- private String[] internalGetMonthNames()
+ private string[] internalGetMonthNames() => this.monthNames ?? internalGetMonthNamesCore();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private string[] internalGetMonthNamesCore()
{
- if (this.monthNames == null)
- {
- // Get the month names for our current calendar
- this.monthNames = _cultureData.MonthNames(Calendar.ID);
- Debug.Assert(this.monthNames.Length == 12 || this.monthNames.Length == 13,
- "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year");
- }
-
- return (this.monthNames);
+ // Get the month names for our current calendar
+ this.monthNames = _cultureData.MonthNames(Calendar.ID);
+ Debug.Assert(this.monthNames.Length == 12 || this.monthNames.Length == 13,
+ "[DateTimeFormatInfo.GetMonthNames] Expected 12 or 13 month names in a year");
+ return this.monthNames;
}
@@ -460,35 +454,12 @@ namespace System.Globalization
}
}
-
- public static DateTimeFormatInfo GetInstance(IFormatProvider provider)
- {
- // Fast case for a regular CultureInfo
- DateTimeFormatInfo info;
- CultureInfo cultureProvider = provider as CultureInfo;
- if (cultureProvider != null && !cultureProvider._isInherited)
- {
- return cultureProvider.DateTimeFormat;
- }
- // Fast case for a DTFI;
- info = provider as DateTimeFormatInfo;
- if (info != null)
- {
- return info;
- }
- // Wasn't cultureInfo or DTFI, do it the slower way
- if (provider != null)
- {
- info = provider.GetFormat(typeof(DateTimeFormatInfo)) as DateTimeFormatInfo;
- if (info != null)
- {
- return info;
- }
- }
- // Couldn't get anything, just use currentInfo as fallback
- return CurrentInfo;
- }
-
+ public static DateTimeFormatInfo GetInstance(IFormatProvider provider) =>
+ provider == null ? CurrentInfo :
+ provider is CultureInfo cultureProvider && !cultureProvider._isInherited ? cultureProvider.DateTimeFormat :
+ provider is DateTimeFormatInfo info ? info :
+ provider.GetFormat(typeof(DateTimeFormatInfo)) is DateTimeFormatInfo info2 ? info2 :
+ CurrentInfo; // Couldn't get anything, just use currentInfo as fallback
public Object GetFormat(Type formatType)
{
@@ -1732,8 +1703,6 @@ namespace System.Globalization
return (internalGetDayOfWeekNames()[(int)dayofweek]);
}
-
-
public String GetAbbreviatedMonthName(int month)
{
if (month < 1 || month > 13)
@@ -1746,7 +1715,6 @@ namespace System.Globalization
return (internalGetAbbreviatedMonthNames()[month - 1]);
}
-
public String GetMonthName(int month)
{
if (month < 1 || month > 13)
@@ -2207,23 +2175,19 @@ namespace System.Globalization
// Actions: Return the internal flag used in formatting and parsing.
// The flag can be used to indicate things like if genitive forms is used in this DTFi, or if leap year gets different month names.
//
- internal DateTimeFormatFlags FormatFlags
+ internal DateTimeFormatFlags FormatFlags => formatFlags != DateTimeFormatFlags.NotInitialized ? formatFlags : InitializeFormatFlags();
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private DateTimeFormatFlags InitializeFormatFlags()
{
- get
- {
- if (formatFlags == DateTimeFormatFlags.NotInitialized)
- {
- // Build the format flags from the data in this DTFI
- formatFlags = DateTimeFormatFlags.None;
- formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth(
- MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
- formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames(
- MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true));
- formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames);
- formatFlags |= (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID);
- }
- return (formatFlags);
- }
+ // Build the format flags from the data in this DTFI
+ formatFlags =
+ (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagGenitiveMonth(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true)) |
+ (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInMonthNames(
+ MonthNames, internalGetGenitiveMonthNames(false), AbbreviatedMonthNames, internalGetGenitiveMonthNames(true)) |
+ (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseSpaceInDayNames(DayNames, AbbreviatedDayNames) |
+ (DateTimeFormatFlags)DateTimeFormatInfoScanner.GetFormatFlagUseHebrewCalendar((int)Calendar.ID);
+ return formatFlags;
}
internal Boolean HasForceTwoDigitYears
@@ -2777,7 +2741,7 @@ namespace System.Globalization
int hashcode = ch % TOKEN_HASH_SIZE;
int hashProbe = 1 + ch % SECOND_PRIME;
- int remaining = str.len - str.Index;
+ int remaining = str.Length - str.Index;
int i = 0;
TokenHashValue[] hashTable = _dtfiTokenHash;
@@ -2802,18 +2766,21 @@ namespace System.Globalization
// If this token starts with a letter, make sure that we won't allow partial match. So you can't tokenize "MarchWed" separately.
// Also an optimization to avoid string comparison
int nextCharIndex = str.Index + value.tokenString.Length;
- if (nextCharIndex > str.len)
+ if (nextCharIndex > str.Length)
{
compareStrings = false;
}
- else if (nextCharIndex < str.len)
+ else if (nextCharIndex < str.Length)
{
// Check word boundary. The next character should NOT be a letter.
char nextCh = str.Value[nextCharIndex];
compareStrings = !(Char.IsLetter(nextCh));
}
}
- if (compareStrings && CompareStringIgnoreCaseOptimized(str.Value, str.Index, value.tokenString.Length, value.tokenString, 0, value.tokenString.Length))
+
+ if (compareStrings &&
+ ((value.tokenString.Length == 1 && str.Value[str.Index] == value.tokenString[0]) ||
+ Culture.CompareInfo.Compare(str.Value.Slice(str.Index, value.tokenString.Length), value.tokenString, CompareOptions.IgnoreCase) == 0))
{
tokenType = value.tokenType & TokenMask;
tokenValue = value.tokenValue;
@@ -2872,7 +2839,7 @@ namespace System.Globalization
}
previousNode = temp;
};
- Debug.Assert(false, "The hashtable is full. This should not happen.");
+ Debug.Fail("The hashtable is full. This should not happen.");
}
private void InsertHash(TokenHashValue[] hashTable, String str, TokenType tokenType, int tokenValue)
@@ -2960,7 +2927,7 @@ namespace System.Globalization
hashcode += hashProbe;
if (hashcode >= TOKEN_HASH_SIZE) hashcode -= TOKEN_HASH_SIZE;
} while (i < TOKEN_HASH_SIZE);
- Debug.Assert(false, "The hashtable is full. This should not happen.");
+ Debug.Fail("The hashtable is full. This should not happen.");
}
private bool CompareStringIgnoreCaseOptimized(string string1, int offset1, int length1, string string2, int offset2, int length2)
diff --git a/src/mscorlib/shared/System/Globalization/DateTimeParse.cs b/src/mscorlib/shared/System/Globalization/DateTimeParse.cs
index 2825f0107e..ca6fe635b8 100644
--- a/src/mscorlib/shared/System/Globalization/DateTimeParse.cs
+++ b/src/mscorlib/shared/System/Globalization/DateTimeParse.cs
@@ -4,6 +4,7 @@
using System.Diagnostics;
using System.Globalization;
+using System.Runtime.CompilerServices;
using System.Text;
namespace System
@@ -16,7 +17,7 @@ namespace System
internal static MatchNumberDelegate m_hebrewNumberParser = new MatchNumberDelegate(DateTimeParse.MatchHebrewDigits);
- internal static DateTime ParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)
+ internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
result.Init();
@@ -30,7 +31,7 @@ namespace System
}
}
- internal static DateTime ParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
+ internal static DateTime ParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
offset = TimeSpan.Zero;
@@ -47,7 +48,7 @@ namespace System
}
}
- internal static bool TryParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
+ internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
{
result = DateTime.MinValue;
DateTimeResult resultData = new DateTimeResult(); // The buffer to store the parsing result.
@@ -60,7 +61,7 @@ namespace System
return false;
}
- internal static bool TryParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
+ internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
{
result = DateTime.MinValue;
offset = TimeSpan.Zero;
@@ -76,13 +77,8 @@ namespace System
return false;
}
- internal static bool TryParseExact(String s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
+ internal static bool TryParseExact(ReadOnlySpan<char> s, String format, DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
{
- if (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- return false;
- }
if (format == null)
{
result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(format));
@@ -105,7 +101,7 @@ namespace System
return DoStrictParse(s, format, style, dtfi, ref result);
}
- internal static DateTime ParseExactMultiple(String s, String[] formats,
+ internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
@@ -121,7 +117,7 @@ namespace System
}
- internal static DateTime ParseExactMultiple(String s, String[] formats,
+ internal static DateTime ParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style, out TimeSpan offset)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
@@ -139,7 +135,7 @@ namespace System
}
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result, out TimeSpan offset)
{
result = DateTime.MinValue;
@@ -157,7 +153,7 @@ namespace System
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style, out DateTime result)
{
result = DateTime.MinValue;
@@ -171,14 +167,9 @@ namespace System
return false;
}
- internal static bool TryParseExactMultiple(String s, String[] formats,
+ internal static bool TryParseExactMultiple(ReadOnlySpan<char> s, String[] formats,
DateTimeFormatInfo dtfi, DateTimeStyles style, ref DateTimeResult result)
{
- if (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- return false;
- }
if (formats == null)
{
result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(formats));
@@ -417,14 +408,12 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
private static bool MatchWord(ref __DTString str, String target)
{
- int length = target.Length;
- if (length > (str.Value.Length - str.Index))
+ if (target.Length > (str.Value.Length - str.Index))
{
return false;
}
- if (str.CompareInfo.Compare(str.Value, str.Index, length,
- target, 0, length, CompareOptions.IgnoreCase) != 0)
+ if (str.CompareInfo.Compare(str.Value.Slice(str.Index, target.Length), target, CompareOptions.IgnoreCase) != 0)
{
return (false);
}
@@ -440,7 +429,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
}
str.Index = nextCharIndex;
- if (str.Index < str.len)
+ if (str.Index < str.Length)
{
str.m_current = str.Value[str.Index];
}
@@ -467,11 +456,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return (false);
}
- internal static bool IsDigit(char ch)
- {
- return (ch >= '0' && ch <= '9');
- }
-
+ internal static bool IsDigit(char ch) => (uint)(ch - '0') <= 9;
/*=================================ParseFraction==========================
**Action: Starting at the str.Index, which should be a decimal symbol.
@@ -588,12 +573,12 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// This is the helper function to handle timezone in string in the format like +/-0800
private static bool HandleTimeZone(ref __DTString str, ref DateTimeResult result)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
char nextCh = str.Value[str.Index];
// Skip whitespace, but don't update the index unless we find a time zone marker
int whitespaceCount = 0;
- while (Char.IsWhiteSpace(nextCh) && str.Index + whitespaceCount < str.len - 1)
+ while (Char.IsWhiteSpace(nextCh) && str.Index + whitespaceCount < str.Length - 1)
{
whitespaceCount++;
nextCh = str.Value[str.Index + whitespaceCount];
@@ -673,7 +658,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// "11:22:33.1234" or "11:22:33-08".
if (dps == DS.T_NNt)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
char nextCh = str.Value[str.Index];
if (nextCh == '.')
@@ -688,7 +673,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
if (dps == DS.T_NNt || dps == DS.T_Nt)
{
- if ((str.Index < str.len - 1))
+ if ((str.Index < str.Length - 1))
{
if (false == HandleTimeZone(ref str, ref result))
{
@@ -1196,7 +1181,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
bool foundStart = false;
bool foundEnd = false;
- for (int i = 0; i < str.len; i++)
+ for (int i = 0; i < str.Length; i++)
{
ch = str.Value[i];
if (ch == '#')
@@ -1246,7 +1231,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
else if (ch == '\0')
{
- for (int i = str.Index; i < str.len; i++)
+ for (int i = str.Index; i < str.Length; i++)
{
if (str.Value[i] != '\0')
{
@@ -1255,7 +1240,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
}
// Move to the end of the string
- str.Index = str.len;
+ str.Index = str.Length;
return true;
}
return false;
@@ -2453,7 +2438,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return true;
}
- internal static DateTime Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
+ internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
result.Init();
@@ -2467,7 +2452,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
}
- internal static DateTime Parse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out TimeSpan offset)
+ internal static DateTime Parse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out TimeSpan offset)
{
DateTimeResult result = new DateTimeResult(); // The buffer to store the parsing result.
result.Init();
@@ -2484,7 +2469,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result)
{
result = DateTime.MinValue;
DateTimeResult resultData = new DateTimeResult(); // The buffer to store the parsing result.
@@ -2497,7 +2482,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return false;
}
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result, out TimeSpan offset)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, out DateTime result, out TimeSpan offset)
{
result = DateTime.MinValue;
offset = TimeSpan.Zero;
@@ -2517,13 +2502,8 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
// This is the real method to do the parsing work.
//
- internal static bool TryParse(String s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result)
+ internal static bool TryParse(ReadOnlySpan<char> s, DateTimeFormatInfo dtfi, DateTimeStyles styles, ref DateTimeResult result)
{
- if (s == null)
- {
- result.SetFailure(ParseFailureKind.ArgumentNull, nameof(SR.ArgumentNull_String), null, nameof(s));
- return false;
- }
if (s.Length == 0)
{
result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_BadDateTime), null);
@@ -3166,7 +3146,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
Debug.Assert(minDigitLen > 0, "minDigitLen > 0");
Debug.Assert(maxDigitLen < 9, "maxDigitLen < 9");
Debug.Assert(minDigitLen <= maxDigitLen, "minDigitLen <= maxDigitLen");
- result = 0;
+ int localResult = 0;
int startingIndex = str.Index;
int tokenLength = 0;
while (tokenLength < maxDigitLen)
@@ -3176,9 +3156,10 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
str.Index--;
break;
}
- result = result * 10 + str.GetDigit();
+ localResult = localResult * 10 + str.GetDigit();
tokenLength++;
}
+ result = localResult;
if (tokenLength < minDigitLen)
{
str.Index = startingIndex;
@@ -3217,7 +3198,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
result = result * 10 + str.GetDigit();
}
- result = ((double)result / Math.Pow(10, digitLen));
+ result /= TimeSpanParse.Pow10(digitLen);
return (digitLen == maxDigitLen);
}
@@ -4217,11 +4198,12 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
break;
case '\"':
case '\'':
- StringBuilder enquotedString = new StringBuilder();
+ StringBuilder enquotedString = StringBuilderCache.Acquire();
// Use ParseQuoteString so that we can handle escape characters within the quoted string.
if (!TryParseQuoteString(format.Value, format.Index, enquotedString, out tokenLen))
{
result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch);
+ StringBuilderCache.Release(enquotedString);
return (false);
}
format.Index += tokenLen - 1;
@@ -4229,7 +4211,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Some cultures uses space in the quoted string. E.g. Spanish has long date format as:
// "dddd, dd' de 'MMMM' de 'yyyy". When inner spaces flag is set, we should skip whitespaces if there is space
// in the quoted string.
- String quotedStr = enquotedString.ToString();
+ String quotedStr = StringBuilderCache.GetStringAndRelease(enquotedString);
for (int i = 0; i < quotedStr.Length; i++)
{
@@ -4379,7 +4361,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// The pos should point to a quote character. This method will
// get the string enclosed by the quote character.
//
- internal static bool TryParseQuoteString(String format, int pos, StringBuilder result, out int returnValue)
+ internal static bool TryParseQuoteString(ReadOnlySpan<char> format, int pos, StringBuilder result, out int returnValue)
{
//
// NOTE : pos will be the index of the quote character in the 'format' string.
@@ -4456,7 +4438,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
==============================================================================*/
private static bool DoStrictParse(
- String s,
+ ReadOnlySpan<char> s,
String formatParam,
DateTimeStyles styles,
DateTimeFormatInfo dtfi,
@@ -4496,7 +4478,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// if we have parsed every item twice.
result.Hour = result.Minute = result.Second = -1;
- __DTString format = new __DTString(formatParam, dtfi, false);
+ __DTString format = new __DTString(formatParam.AsReadOnlySpan(), dtfi, false);
__DTString str = new __DTString(s, dtfi, false);
if (parseInfo.fAllowTrailingWhite)
@@ -4665,7 +4647,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
case ParseFailureKind.FormatBadDateTimeCalendar:
return new FormatException(SR.Format(SR.GetResourceString(result.failureMessageID), result.calendar));
default:
- Debug.Assert(false, "Unkown DateTimeParseFailure: " + result);
+ Debug.Fail("Unkown DateTimeParseFailure: " + result);
return null;
}
}
@@ -4782,7 +4764,8 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return buffer.ToString();
}
// return a string in the form: "Sun"
- internal static string Hex(string str)
+ internal static string Hex(string str) => Hex(str.AsReadOnlySpan());
+ internal static string Hex(ReadOnlySpan<char> str)
{
StringBuilder buffer = new StringBuilder();
buffer.Append("\"");
@@ -4815,13 +4798,12 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// It has a Index property which tracks
// the current parsing pointer of the string.
//
- internal
- struct __DTString
+ internal ref struct __DTString
{
//
// Value propery: stores the real string to be parsed.
//
- internal String Value;
+ internal ReadOnlySpan<char> Value;
//
// Index property: points to the character that we are currently parsing.
@@ -4829,7 +4811,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal int Index;
// The length of Value string.
- internal int len;
+ internal int Length => Value.Length;
// The current chracter to be looked at.
internal char m_current;
@@ -4839,16 +4821,15 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// In some cultures, such as mn-MN, it uses "\x0031\x00a0\x0434\x04af\x0433\x044d\x044d\x0440\x00a0\x0441\x0430\x0440" in month names.
private bool m_checkDigitToken;
- internal __DTString(String str, DateTimeFormatInfo dtfi, bool checkDigitToken) : this(str, dtfi)
+ internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi, bool checkDigitToken) : this(str, dtfi)
{
m_checkDigitToken = checkDigitToken;
}
- internal __DTString(String str, DateTimeFormatInfo dtfi)
+ internal __DTString(ReadOnlySpan<char> str, DateTimeFormatInfo dtfi)
{
Index = -1;
Value = str;
- len = Value.Length;
m_current = '\0';
if (dtfi != null)
@@ -4880,7 +4861,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal bool GetNext()
{
Index++;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
return (true);
@@ -4890,14 +4871,14 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal bool AtEnd()
{
- return Index < len ? false : true;
+ return Index < Length ? false : true;
}
internal bool Advance(int count)
{
- Debug.Assert(Index + count <= len, "__DTString::Advance: Index + count <= len");
+ Debug.Assert(Index + count <= Length, "__DTString::Advance: Index + count <= len");
Index += count;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
return (true);
@@ -4910,7 +4891,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal void GetRegularToken(out TokenType tokenType, out int tokenValue, DateTimeFormatInfo dtfi)
{
tokenValue = 0;
- if (Index >= len)
+ if (Index >= Length)
{
tokenType = TokenType.EndOfString;
return;
@@ -4929,7 +4910,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
// Collect other digits.
//
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
value = m_current - '0';
@@ -4985,7 +4966,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
else if (Char.IsWhiteSpace(m_current))
{
// Just skip to the next character.
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
if (!(Char.IsWhiteSpace(m_current)))
@@ -5031,36 +5012,19 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return (tokenType);
}
- internal bool MatchSpecifiedWord(String target)
- {
- return MatchSpecifiedWord(target, target.Length + Index);
- }
-
- internal bool MatchSpecifiedWord(String target, int endIndex)
- {
- int count = endIndex - Index;
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool MatchSpecifiedWord(String target) =>
+ Index + target.Length <= Length &&
+ m_info.Compare(Value.Slice(Index, target.Length), target, CompareOptions.IgnoreCase) == 0;
- if (count != target.Length)
- {
- return false;
- }
-
- if (Index + count > len)
- {
- return false;
- }
-
- return (m_info.Compare(Value, Index, count, target, 0, count, CompareOptions.IgnoreCase) == 0);
- }
-
- private static Char[] WhiteSpaceChecks = new Char[] { ' ', '\u00A0' };
+ private static readonly Char[] WhiteSpaceChecks = new Char[] { ' ', '\u00A0' };
internal bool MatchSpecifiedWords(String target, bool checkWordBoundary, ref int matchLength)
{
int valueRemaining = Value.Length - Index;
matchLength = target.Length;
- if (matchLength > valueRemaining || m_info.Compare(Value, Index, matchLength, target, 0, matchLength, CompareOptions.IgnoreCase) != 0)
+ if (matchLength > valueRemaining || m_info.Compare(Value.Slice(Index, matchLength), target, CompareOptions.IgnoreCase) != 0)
{
// Check word by word
int targetPosition = 0; // Where we are in the target string
@@ -5090,7 +5054,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
return false;
}
- if (m_info.Compare(Value, thisPosition, segmentLength, target, targetPosition, segmentLength, CompareOptions.IgnoreCase) != 0)
+ if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
{
return false;
}
@@ -5116,7 +5080,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
return false;
}
- if (m_info.Compare(Value, thisPosition, segmentLength, target, targetPosition, segmentLength, CompareOptions.IgnoreCase) != 0)
+ if (m_info.Compare(Value.Slice(thisPosition, segmentLength), target.AsReadOnlySpan().Slice(targetPosition, segmentLength), CompareOptions.IgnoreCase) != 0)
{
return false;
}
@@ -5145,7 +5109,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
internal bool Match(String str)
{
- if (++Index >= len)
+ if (++Index >= Length)
{
return (false);
}
@@ -5155,7 +5119,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return false;
}
- if (m_info.Compare(Value, Index, str.Length, str, 0, str.Length, CompareOptions.Ordinal) == 0)
+ if (m_info.Compare(Value.Slice(Index, str.Length), str, CompareOptions.Ordinal) == 0)
{
// Update the Index to the end of the matching string.
// So the following GetNext()/Match() opeartion will get
@@ -5168,7 +5132,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal bool Match(char ch)
{
- if (++Index >= len)
+ if (++Index >= Length)
{
return (false);
}
@@ -5221,7 +5185,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
char repeatChar = Value[Index];
int pos = Index + 1;
- while ((pos < len) && (Value[pos] == repeatChar))
+ while ((pos < Length) && (Value[pos] == repeatChar))
{
pos++;
}
@@ -5234,21 +5198,17 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
}
// Return false when end of string is encountered or a non-digit character is found.
- internal bool GetNextDigit()
- {
- if (++Index >= len)
- {
- return (false);
- }
- return (DateTimeParse.IsDigit(Value[Index]));
- }
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal bool GetNextDigit() =>
+ ++Index < Length &&
+ DateTimeParse.IsDigit(Value[Index]);
//
// Get the current character.
//
internal char GetChar()
{
- Debug.Assert(Index >= 0 && Index < len, "Index >= 0 && Index < len");
+ Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len");
return (Value[Index]);
}
@@ -5257,7 +5217,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
internal int GetDigit()
{
- Debug.Assert(Index >= 0 && Index < len, "Index >= 0 && Index < len");
+ Debug.Assert(Index >= 0 && Index < Length, "Index >= 0 && Index < len");
Debug.Assert(DateTimeParse.IsDigit(Value[Index]), "IsDigit(Value[Index])");
return (Value[Index] - '0');
}
@@ -5271,7 +5231,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
{
// Look ahead to see if the next character
// is a whitespace.
- while (Index + 1 < len)
+ while (Index + 1 < Length)
{
char ch = Value[Index + 1];
if (!Char.IsWhiteSpace(ch))
@@ -5290,7 +5250,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
//
internal bool SkipWhiteSpaceCurrent()
{
- if (Index >= len)
+ if (Index >= Length)
{
return (false);
}
@@ -5300,7 +5260,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
return (true);
}
- while (++Index < len)
+ while (++Index < Length)
{
m_current = Value[Index];
if (!Char.IsWhiteSpace(m_current))
@@ -5314,20 +5274,19 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal void TrimTail()
{
- int i = len - 1;
+ int i = Length - 1;
while (i >= 0 && Char.IsWhiteSpace(Value[i]))
{
i--;
}
- Value = Value.Substring(0, i + 1);
- len = Value.Length;
+ Value = Value.Slice(0, i + 1);
}
// Trim the trailing spaces within a quoted string.
// Call this after TrimTail() is done.
internal void RemoveTrailingInQuoteSpaces()
{
- int i = len - 1;
+ int i = Length - 1;
if (i <= 1)
{
return;
@@ -5344,7 +5303,6 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
i--;
}
Value = Value.Remove(i, Value.Length - 1 - i);
- len = Value.Length;
}
}
}
@@ -5353,7 +5311,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Call this after the leading spaces before quoted string are trimmed.
internal void RemoveLeadingInQuoteSpaces()
{
- if (len <= 2)
+ if (Length <= 2)
{
return;
}
@@ -5362,14 +5320,13 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
// Check if the last character is a quote.
if (ch == '\'' || ch == '\"')
{
- while ((i + 1) < len && Char.IsWhiteSpace(Value[i + 1]))
+ while ((i + 1) < Length && Char.IsWhiteSpace(Value[i + 1]))
{
i++;
}
if (i != 0)
{
Value = Value.Remove(1, i);
- len = Value.Length;
}
}
}
@@ -5379,7 +5336,7 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
DTSubString sub = new DTSubString();
sub.index = Index;
sub.s = Value;
- while (Index + sub.length < len)
+ while (Index + sub.length < Length)
{
DTSubStringType currentType;
Char ch = Value[Index + sub.length];
@@ -5437,9 +5394,9 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
internal void ConsumeSubString(DTSubString sub)
{
Debug.Assert(sub.index == Index, "sub.index == Index");
- Debug.Assert(sub.index + sub.length <= len, "sub.index + sub.length <= len");
+ Debug.Assert(sub.index + sub.length <= Length, "sub.index + sub.length <= len");
Index = sub.index + sub.length;
- if (Index < len)
+ if (Index < Length)
{
m_current = Value[Index];
}
@@ -5455,9 +5412,9 @@ new DS[] { DS.ERROR, DS.TX_NNN, DS.TX_NNN, DS.TX_NNN, DS.ERROR, DS.ERROR,
Other = 4,
}
- internal struct DTSubString
+ internal ref struct DTSubString
{
- internal String s;
+ internal ReadOnlySpan<char> s;
internal Int32 index;
internal Int32 length;
internal DTSubStringType type;
diff --git a/src/mscorlib/shared/System/Globalization/GregorianCalendar.cs b/src/mscorlib/shared/System/Globalization/GregorianCalendar.cs
index 81058ff664..16023209ea 100644
--- a/src/mscorlib/shared/System/Globalization/GregorianCalendar.cs
+++ b/src/mscorlib/shared/System/Globalization/GregorianCalendar.cs
@@ -382,6 +382,22 @@ namespace System.Globalization
return time.Year;
}
+ internal override bool IsValidYear(int year, int era) => year >= 1 && year <= MaxYear;
+
+ internal override bool IsValidDay(int year, int month, int day, int era)
+ {
+ if ((era != CurrentEra && era != ADEra) ||
+ year < 1 || year > MaxYear ||
+ month < 1 || month > 12 ||
+ day < 1)
+ {
+ return false;
+ }
+
+ int[] days = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) ? DaysToMonth366 : DaysToMonth365;
+ return day <= (days[month] - days[month - 1]);
+ }
+
// Checks whether a given day in the specified era is a leap day. This method returns true if
// the date is a leap day, or false if not.
//
diff --git a/src/mscorlib/shared/System/Globalization/PersianCalendar.cs b/src/mscorlib/shared/System/Globalization/PersianCalendar.cs
index a80c6ece5b..10912f85b1 100644
--- a/src/mscorlib/shared/System/Globalization/PersianCalendar.cs
+++ b/src/mscorlib/shared/System/Globalization/PersianCalendar.cs
@@ -519,7 +519,6 @@ namespace System.Globalization
int daysInMonth = GetDaysInMonth(year, month, era);
if (day < 1 || day > daysInMonth)
{
- // BCLDebug.Log("year = " + year + ", month = " + month + ", day = " + day);
throw new ArgumentOutOfRangeException(
nameof(day),
String.Format(
diff --git a/src/mscorlib/shared/System/Globalization/TimeSpanParse.cs b/src/mscorlib/shared/System/Globalization/TimeSpanParse.cs
index f8443a1ea6..8f511b71a5 100644
--- a/src/mscorlib/shared/System/Globalization/TimeSpanParse.cs
+++ b/src/mscorlib/shared/System/Globalization/TimeSpanParse.cs
@@ -93,8 +93,7 @@ namespace System.Globalization
NumOverflow = 4, // Number that overflowed
}
- [IsByRefLike]
- private struct TimeSpanToken
+ private ref struct TimeSpanToken
{
internal TTT _ttt;
internal int _num; // Store the number that we are parsing (if any)
@@ -131,8 +130,7 @@ namespace System.Globalization
}
}
- [IsByRefLike]
- private struct TimeSpanTokenizer
+ private ref struct TimeSpanTokenizer
{
private ReadOnlySpan<char> _value;
private int _pos;
@@ -241,8 +239,7 @@ namespace System.Globalization
}
/// <summary>Stores intermediary parsing state for the standard formats.</summary>
- [IsByRefLike]
- private struct TimeSpanRawInfo
+ private ref struct TimeSpanRawInfo
{
internal TimeSpanFormat.FormatLiterals PositiveInvariant => TimeSpanFormat.PositiveInvariantFormatLiterals;
internal TimeSpanFormat.FormatLiterals NegativeInvariant => TimeSpanFormat.NegativeInvariantFormatLiterals;
@@ -1295,15 +1292,18 @@ namespace System.Globalization
case '\'':
case '\"':
- StringBuilder enquotedString = new StringBuilder();
- if (!DateTimeParse.TryParseQuoteString(format, i, enquotedString, out tokenLen))
+ StringBuilder enquotedString = StringBuilderCache.Acquire();
+ if (!DateTimeParse.TryParseQuoteString(format.AsReadOnlySpan(), i, enquotedString, out tokenLen))
{
+ StringBuilderCache.Release(enquotedString);
return result.SetFailure(ParseFailureKind.FormatWithParameter, nameof(SR.Format_BadQuote), ch);
}
if (!ParseExactLiteral(ref tokenizer, enquotedString))
{
+ StringBuilderCache.Release(enquotedString);
return result.SetFailure(ParseFailureKind.Format, nameof(SR.Format_InvalidString));
}
+ StringBuilderCache.Release(enquotedString);
break;
case '%':
@@ -1430,8 +1430,7 @@ namespace System.Globalization
private static bool TryParseTimeSpanConstant(ReadOnlySpan<char> input, ref TimeSpanResult result) =>
new StringParser().TryParse(input, ref result);
- [IsByRefLike]
- private struct StringParser
+ private ref struct StringParser
{
private ReadOnlySpan<char> _str;
private char _ch;
diff --git a/src/mscorlib/shared/System/Guid.cs b/src/mscorlib/shared/System/Guid.cs
index 496bc35327..19d63cf10c 100644
--- a/src/mscorlib/shared/System/Guid.cs
+++ b/src/mscorlib/shared/System/Guid.cs
@@ -604,12 +604,7 @@ namespace System
// Prepare for loop
numLen++;
- Span<byte> bytes;
- unsafe
- {
- byte* tmpBytes = stackalloc byte[8];
- bytes = new Span<byte>(tmpBytes, 8);
- }
+ Span<byte> bytes = stackalloc byte[8];
for (int i = 0; i < bytes.Length; i++)
{
diff --git a/src/mscorlib/shared/System/IO/BinaryWriter.cs b/src/mscorlib/shared/System/IO/BinaryWriter.cs
index 675e80922e..ad1d31f577 100644
--- a/src/mscorlib/shared/System/IO/BinaryWriter.cs
+++ b/src/mscorlib/shared/System/IO/BinaryWriter.cs
@@ -390,33 +390,33 @@ namespace System.IO
}
}
- public virtual void Write(ReadOnlySpan<byte> value)
+ public virtual void Write(ReadOnlySpan<byte> buffer)
{
if (GetType() == typeof(BinaryWriter))
{
- OutStream.Write(value);
+ OutStream.Write(buffer);
}
else
{
- byte[] buffer = ArrayPool<byte>.Shared.Rent(value.Length);
+ byte[] array = ArrayPool<byte>.Shared.Rent(buffer.Length);
try
{
- value.CopyTo(buffer);
- Write(buffer, 0, value.Length);
+ buffer.CopyTo(array);
+ Write(array, 0, buffer.Length);
}
finally
{
- ArrayPool<byte>.Shared.Return(buffer);
+ ArrayPool<byte>.Shared.Return(array);
}
}
}
- public virtual void Write(ReadOnlySpan<char> value)
+ public virtual void Write(ReadOnlySpan<char> chars)
{
- byte[] bytes = ArrayPool<byte>.Shared.Rent(_encoding.GetMaxByteCount(value.Length));
+ byte[] bytes = ArrayPool<byte>.Shared.Rent(_encoding.GetMaxByteCount(chars.Length));
try
{
- int bytesWritten = _encoding.GetBytes(value, bytes);
+ int bytesWritten = _encoding.GetBytes(chars, bytes);
Write(bytes, 0, bytesWritten);
}
finally
diff --git a/src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs b/src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs
index 87e610b86e..d7c6eacb9a 100644
--- a/src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs
+++ b/src/mscorlib/shared/System/IO/DirectoryNotFoundException.cs
@@ -12,6 +12,8 @@ namespace System.IO
* the Win32 errorcode-as-HRESULT ERROR_PATH_NOT_FOUND (0x80070003)
* and STG_E_PATHNOTFOUND (0x80030003).
*/
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class DirectoryNotFoundException : IOException
{
public DirectoryNotFoundException()
@@ -35,7 +37,6 @@ namespace System.IO
protected DirectoryNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/IO/DriveNotFoundException.cs b/src/mscorlib/shared/System/IO/DriveNotFoundException.cs
index c0f8c55af8..3f2c88c74b 100644
--- a/src/mscorlib/shared/System/IO/DriveNotFoundException.cs
+++ b/src/mscorlib/shared/System/IO/DriveNotFoundException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
//Thrown when trying to access a drive that is not available.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal class DriveNotFoundException : IOException
{
public DriveNotFoundException()
@@ -29,7 +31,6 @@ namespace System.IO
protected DriveNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/IO/EndOfStreamException.cs b/src/mscorlib/shared/System/IO/EndOfStreamException.cs
index ee37818dc5..606073ad9a 100644
--- a/src/mscorlib/shared/System/IO/EndOfStreamException.cs
+++ b/src/mscorlib/shared/System/IO/EndOfStreamException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class EndOfStreamException : IOException
{
public EndOfStreamException()
@@ -29,7 +31,6 @@ namespace System.IO
protected EndOfStreamException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/IO/FileLoadException.cs b/src/mscorlib/shared/System/IO/FileLoadException.cs
index b126424c22..8c31244e1d 100644
--- a/src/mscorlib/shared/System/IO/FileLoadException.cs
+++ b/src/mscorlib/shared/System/IO/FileLoadException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public partial class FileLoadException : IOException
{
public FileLoadException()
@@ -82,12 +84,15 @@ namespace System.IO
protected FileLoadException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ FileName = info.GetString("FileLoad_FileName");
+ FusionLog = info.GetString("FileLoad_FusionLog");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("FileLoad_FileName", FileName, typeof(string));
+ info.AddValue("FileLoad_FusionLog", FusionLog, typeof(string));
}
}
}
diff --git a/src/mscorlib/shared/System/IO/FileNotFoundException.cs b/src/mscorlib/shared/System/IO/FileNotFoundException.cs
index dc1ccf577a..72cff4cfc0 100644
--- a/src/mscorlib/shared/System/IO/FileNotFoundException.cs
+++ b/src/mscorlib/shared/System/IO/FileNotFoundException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
// Thrown when trying to access a file that doesn't exist on disk.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public partial class FileNotFoundException : IOException
{
public FileNotFoundException()
@@ -93,12 +95,15 @@ namespace System.IO
protected FileNotFoundException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ FileName = info.GetString("FileNotFound_FileName");
+ FusionLog = info.GetString("FileNotFound_FusionLog");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("FileNotFound_FileName", FileName, typeof(string));
+ info.AddValue("FileNotFound_FusionLog", FusionLog, typeof(string));
}
}
}
diff --git a/src/mscorlib/shared/System/IO/IOException.cs b/src/mscorlib/shared/System/IO/IOException.cs
index 1fbd352613..89b25d5142 100644
--- a/src/mscorlib/shared/System/IO/IOException.cs
+++ b/src/mscorlib/shared/System/IO/IOException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class IOException : SystemException
{
public IOException()
@@ -35,7 +37,6 @@ namespace System.IO
protected IOException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/IO/PathTooLongException.cs b/src/mscorlib/shared/System/IO/PathTooLongException.cs
index 15f282ebf6..7af2452736 100644
--- a/src/mscorlib/shared/System/IO/PathTooLongException.cs
+++ b/src/mscorlib/shared/System/IO/PathTooLongException.cs
@@ -8,6 +8,8 @@ using System.Runtime.Serialization;
namespace System.IO
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class PathTooLongException : IOException
{
public PathTooLongException()
@@ -31,7 +33,6 @@ namespace System.IO
protected PathTooLongException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/IndexOutOfRangeException.cs b/src/mscorlib/shared/System/IndexOutOfRangeException.cs
index bec63d73d6..b6d93ef568 100644
--- a/src/mscorlib/shared/System/IndexOutOfRangeException.cs
+++ b/src/mscorlib/shared/System/IndexOutOfRangeException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class IndexOutOfRangeException : SystemException
{
public IndexOutOfRangeException()
@@ -34,5 +36,9 @@ namespace System
{
HResult = HResults.COR_E_INDEXOUTOFRANGE;
}
+
+ internal IndexOutOfRangeException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/InsufficientExecutionStackException.cs b/src/mscorlib/shared/System/InsufficientExecutionStackException.cs
index a14cb67150..4822028f85 100644
--- a/src/mscorlib/shared/System/InsufficientExecutionStackException.cs
+++ b/src/mscorlib/shared/System/InsufficientExecutionStackException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class InsufficientExecutionStackException : SystemException
{
public InsufficientExecutionStackException()
@@ -25,5 +27,9 @@ namespace System
{
HResult = HResults.COR_E_INSUFFICIENTEXECUTIONSTACK;
}
+
+ internal InsufficientExecutionStackException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Int16.cs b/src/mscorlib/shared/System/Int16.cs
index 87004861cb..296b3d2d40 100644
--- a/src/mscorlib/shared/System/Int16.cs
+++ b/src/mscorlib/shared/System/Int16.cs
@@ -2,16 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: This class will encapsulate a short and provide an
-** Object representation of it.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/Int32.cs b/src/mscorlib/shared/System/Int32.cs
index d674e7b6bf..690faf3f36 100644
--- a/src/mscorlib/shared/System/Int32.cs
+++ b/src/mscorlib/shared/System/Int32.cs
@@ -2,16 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: A representation of a 32 bit 2's complement
-** integer.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/Int64.cs b/src/mscorlib/shared/System/Int64.cs
index e17c3ea6ed..1f1cf13e9c 100644
--- a/src/mscorlib/shared/System/Int64.cs
+++ b/src/mscorlib/shared/System/Int64.cs
@@ -2,16 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: This class will encapsulate a long and provide an
-** Object representation of it.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/InvalidCastException.cs b/src/mscorlib/shared/System/InvalidCastException.cs
index 00b393c60e..055643278a 100644
--- a/src/mscorlib/shared/System/InvalidCastException.cs
+++ b/src/mscorlib/shared/System/InvalidCastException.cs
@@ -12,6 +12,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidCastException : SystemException
{
public InvalidCastException()
@@ -40,7 +42,6 @@ namespace System
protected InvalidCastException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/InvalidOperationException.cs b/src/mscorlib/shared/System/InvalidOperationException.cs
index 74a4ffd74a..62c222af40 100644
--- a/src/mscorlib/shared/System/InvalidOperationException.cs
+++ b/src/mscorlib/shared/System/InvalidOperationException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidOperationException : SystemException
{
public InvalidOperationException()
@@ -38,7 +40,6 @@ namespace System
protected InvalidOperationException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/InvalidProgramException.cs b/src/mscorlib/shared/System/InvalidProgramException.cs
index e3521574ea..c8047c548b 100644
--- a/src/mscorlib/shared/System/InvalidProgramException.cs
+++ b/src/mscorlib/shared/System/InvalidProgramException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class InvalidProgramException : SystemException
{
public InvalidProgramException()
@@ -34,5 +36,7 @@ namespace System
{
HResult = HResults.COR_E_INVALIDPROGRAM;
}
+
+ internal InvalidProgramException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}
diff --git a/src/mscorlib/shared/System/InvalidTimeZoneException.cs b/src/mscorlib/shared/System/InvalidTimeZoneException.cs
index 8b300f453d..25b155e8d1 100644
--- a/src/mscorlib/shared/System/InvalidTimeZoneException.cs
+++ b/src/mscorlib/shared/System/InvalidTimeZoneException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidTimeZoneException : Exception
{
public InvalidTimeZoneException()
@@ -24,7 +26,6 @@ namespace System
protected InvalidTimeZoneException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Lazy.cs b/src/mscorlib/shared/System/Lazy.cs
index e71a37dd9e..4a56b1881f 100644
--- a/src/mscorlib/shared/System/Lazy.cs
+++ b/src/mscorlib/shared/System/Lazy.cs
@@ -84,7 +84,7 @@ namespace System
break;
default:
- Debug.Assert(false, "internal constructor, this should never occur");
+ Debug.Fail("internal constructor, this should never occur");
break;
}
@@ -119,7 +119,7 @@ namespace System
return LazyThreadSafetyMode.ExecutionAndPublication;
default:
- Debug.Assert(false, "Invalid logic; State should always have a valid value");
+ Debug.Fail("Invalid logic; State should always have a valid value");
return default(LazyThreadSafetyMode);
}
}
diff --git a/src/mscorlib/shared/System/Math.cs b/src/mscorlib/shared/System/Math.cs
index 5c69c84e45..bdb237da38 100644
--- a/src/mscorlib/shared/System/Math.cs
+++ b/src/mscorlib/shared/System/Math.cs
@@ -14,7 +14,6 @@
//This class contains only static members and doesn't require serialization.
using System.Diagnostics;
-using System.Diagnostics.Contracts;
using System.Runtime;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
diff --git a/src/mscorlib/shared/System/MemberAccessException.cs b/src/mscorlib/shared/System/MemberAccessException.cs
index bb26d9e3c4..dfea52dbed 100644
--- a/src/mscorlib/shared/System/MemberAccessException.cs
+++ b/src/mscorlib/shared/System/MemberAccessException.cs
@@ -14,7 +14,8 @@ namespace System
{
// The MemberAccessException is thrown when trying to access a class
// member fails.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MemberAccessException : SystemException
{
// Creates a new MemberAccessException with its message string set to
@@ -44,7 +45,6 @@ namespace System
protected MemberAccessException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Memory.cs b/src/mscorlib/shared/System/Memory.cs
index 63d36a9641..ecb33e8918 100644
--- a/src/mscorlib/shared/System/Memory.cs
+++ b/src/mscorlib/shared/System/Memory.cs
@@ -14,8 +14,11 @@ namespace System
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
- public struct Memory<T>
+ public readonly struct Memory<T>
{
+ // NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
+ // as code uses Unsafe.As to cast between them.
+
// The highest order bit of _index is used to discern whether _arrayOrOwnedMemory is an array or an owned memory
// if (_index >> 31) == 1, object _arrayOrOwnedMemory is an OwnedMemory<T>
// else, object _arrayOrOwnedMemory is a T[]
@@ -100,13 +103,8 @@ namespace System
/// <summary>
/// Defines an implicit conversion of a <see cref="Memory{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
/// </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static implicit operator ReadOnlyMemory<T>(Memory<T> memory)
- {
- if (memory._index < 0)
- return new ReadOnlyMemory<T>((OwnedMemory<T>)memory._arrayOrOwnedMemory, memory._index & RemoveOwnedFlagBitMask, memory._length);
- return new ReadOnlyMemory<T>((T[])memory._arrayOrOwnedMemory, memory._index, memory._length);
- }
+ public static implicit operator ReadOnlyMemory<T>(Memory<T> memory) =>
+ Unsafe.As<Memory<T>, ReadOnlyMemory<T>>(ref memory);
//Debugger Display = {T[length]}
private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);
diff --git a/src/mscorlib/shared/System/MethodAccessException.cs b/src/mscorlib/shared/System/MethodAccessException.cs
index 12691386c5..1ca0297b94 100644
--- a/src/mscorlib/shared/System/MethodAccessException.cs
+++ b/src/mscorlib/shared/System/MethodAccessException.cs
@@ -13,6 +13,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MethodAccessException : MemberAccessException
{
public MethodAccessException()
@@ -35,7 +37,6 @@ namespace System
protected MethodAccessException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/MissingMethodException.cs b/src/mscorlib/shared/System/MissingMethodException.cs
index 4f5e8b6562..abb6c0e97b 100644
--- a/src/mscorlib/shared/System/MissingMethodException.cs
+++ b/src/mscorlib/shared/System/MissingMethodException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MissingMethodException : MissingMemberException
{
public MissingMethodException()
@@ -44,7 +46,6 @@ namespace System
protected MissingMethodException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
public override string Message
diff --git a/src/mscorlib/shared/System/MulticastNotSupportedException.cs b/src/mscorlib/shared/System/MulticastNotSupportedException.cs
index 56a3ec9c00..cc6c77023e 100644
--- a/src/mscorlib/shared/System/MulticastNotSupportedException.cs
+++ b/src/mscorlib/shared/System/MulticastNotSupportedException.cs
@@ -11,6 +11,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class MulticastNotSupportedException : SystemException
{
public MulticastNotSupportedException()
@@ -30,5 +32,9 @@ namespace System
{
HResult = HResults.COR_E_MULTICASTNOTSUPPORTED;
}
+
+ internal MulticastNotSupportedException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/NotFiniteNumberException.cs b/src/mscorlib/shared/System/NotFiniteNumberException.cs
index ca47a21e5c..b9c9af06d3 100644
--- a/src/mscorlib/shared/System/NotFiniteNumberException.cs
+++ b/src/mscorlib/shared/System/NotFiniteNumberException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class NotFiniteNumberException : ArithmeticException
{
private double _offendingNumber;
@@ -24,27 +26,27 @@ namespace System
HResult = HResults.COR_E_NOTFINITENUMBER;
}
- public NotFiniteNumberException(String message)
+ public NotFiniteNumberException(string message)
: base(message)
{
_offendingNumber = 0;
HResult = HResults.COR_E_NOTFINITENUMBER;
}
- public NotFiniteNumberException(String message, double offendingNumber)
+ public NotFiniteNumberException(string message, double offendingNumber)
: base(message)
{
_offendingNumber = offendingNumber;
HResult = HResults.COR_E_NOTFINITENUMBER;
}
- public NotFiniteNumberException(String message, Exception innerException)
+ public NotFiniteNumberException(string message, Exception innerException)
: base(message, innerException)
{
HResult = HResults.COR_E_NOTFINITENUMBER;
}
- public NotFiniteNumberException(String message, double offendingNumber, Exception innerException)
+ public NotFiniteNumberException(string message, double offendingNumber, Exception innerException)
: base(message, innerException)
{
_offendingNumber = offendingNumber;
@@ -53,12 +55,13 @@ namespace System
protected NotFiniteNumberException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
+ _offendingNumber = info.GetInt32("OffendingNumber");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("OffendingNumber", _offendingNumber, typeof(int));
}
public double OffendingNumber
diff --git a/src/mscorlib/shared/System/NotImplementedException.cs b/src/mscorlib/shared/System/NotImplementedException.cs
index 98976c19db..1a3b6afcd4 100644
--- a/src/mscorlib/shared/System/NotImplementedException.cs
+++ b/src/mscorlib/shared/System/NotImplementedException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class NotImplementedException : SystemException
{
public NotImplementedException()
@@ -36,7 +38,6 @@ namespace System
protected NotImplementedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/NotSupportedException.cs b/src/mscorlib/shared/System/NotSupportedException.cs
index dc43261fbd..3180bc2837 100644
--- a/src/mscorlib/shared/System/NotSupportedException.cs
+++ b/src/mscorlib/shared/System/NotSupportedException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class NotSupportedException : SystemException
{
public NotSupportedException()
@@ -37,7 +39,6 @@ namespace System
protected NotSupportedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/NullReferenceException.cs b/src/mscorlib/shared/System/NullReferenceException.cs
index eb6d709dbf..c2e722470c 100644
--- a/src/mscorlib/shared/System/NullReferenceException.cs
+++ b/src/mscorlib/shared/System/NullReferenceException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class NullReferenceException : SystemException
{
public NullReferenceException()
@@ -37,7 +39,6 @@ namespace System
protected NullReferenceException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ObjectDisposedException.cs b/src/mscorlib/shared/System/ObjectDisposedException.cs
index 3d7ba5df15..be80c6dbbe 100644
--- a/src/mscorlib/shared/System/ObjectDisposedException.cs
+++ b/src/mscorlib/shared/System/ObjectDisposedException.cs
@@ -11,6 +11,8 @@ namespace System
/// <para> The exception that is thrown when accessing an object that was
/// disposed.</para>
/// </devdoc>
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ObjectDisposedException : InvalidOperationException
{
private String _objectName;
@@ -41,12 +43,13 @@ namespace System
protected ObjectDisposedException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ _objectName = info.GetString("ObjectName");
}
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("ObjectName", ObjectName, typeof(string));
}
/// <devdoc>
diff --git a/src/mscorlib/shared/System/OperationCanceledException.cs b/src/mscorlib/shared/System/OperationCanceledException.cs
index 44a0427c58..8a472c9ff0 100644
--- a/src/mscorlib/shared/System/OperationCanceledException.cs
+++ b/src/mscorlib/shared/System/OperationCanceledException.cs
@@ -17,6 +17,8 @@ using System.Threading;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class OperationCanceledException : SystemException
{
[NonSerialized]
@@ -67,7 +69,6 @@ namespace System
protected OperationCanceledException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/OverflowException.cs b/src/mscorlib/shared/System/OverflowException.cs
index bf6676ca2c..963825b350 100644
--- a/src/mscorlib/shared/System/OverflowException.cs
+++ b/src/mscorlib/shared/System/OverflowException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class OverflowException : ArithmeticException
{
public OverflowException()
@@ -37,7 +39,6 @@ namespace System
protected OverflowException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ParseNumbers.cs b/src/mscorlib/shared/System/ParseNumbers.cs
index 3b02250b0e..dab4cb2190 100644
--- a/src/mscorlib/shared/System/ParseNumbers.cs
+++ b/src/mscorlib/shared/System/ParseNumbers.cs
@@ -218,12 +218,7 @@ namespace System
public static string IntToString(int n, int radix, int width, char paddingChar, int flags)
{
- Span<char> buffer;
- unsafe
- {
- char* tmpBuffer = stackalloc char[66]; // Longest possible string length for an integer in binary notation with prefix
- buffer = new Span<char>(tmpBuffer, 66);
- }
+ Span<char> buffer = stackalloc char[66]; // Longest possible string length for an integer in binary notation with prefix
if (radix < MinRadix || radix > MaxRadix)
throw new ArgumentException(SR.Arg_InvalidBase, nameof(radix));
@@ -363,12 +358,7 @@ namespace System
public static string LongToString(long n, int radix, int width, char paddingChar, int flags)
{
- Span<char> buffer;
- unsafe
- {
- char* tmpBuffer = stackalloc char[67]; // Longest possible string length for an integer in binary notation with prefix
- buffer = new Span<char>(tmpBuffer, 67);
- }
+ Span<char> buffer = stackalloc char[67]; // Longest possible string length for an integer in binary notation with prefix
if (radix < MinRadix || radix > MaxRadix)
throw new ArgumentException(SR.Arg_InvalidBase, nameof(radix));
diff --git a/src/mscorlib/shared/System/PlatformNotSupportedException.cs b/src/mscorlib/shared/System/PlatformNotSupportedException.cs
index 4403c1da06..5039f3f441 100644
--- a/src/mscorlib/shared/System/PlatformNotSupportedException.cs
+++ b/src/mscorlib/shared/System/PlatformNotSupportedException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class PlatformNotSupportedException : NotSupportedException
{
public PlatformNotSupportedException()
@@ -37,7 +39,6 @@ namespace System
protected PlatformNotSupportedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/RankException.cs b/src/mscorlib/shared/System/RankException.cs
index f2c5d06548..bdd2cd51f1 100644
--- a/src/mscorlib/shared/System/RankException.cs
+++ b/src/mscorlib/shared/System/RankException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class RankException : SystemException
{
public RankException()
@@ -38,7 +40,6 @@ namespace System
protected RankException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/ReadOnlyMemory.cs b/src/mscorlib/shared/System/ReadOnlyMemory.cs
index ddbfbdde89..c2ba4ab41d 100644
--- a/src/mscorlib/shared/System/ReadOnlyMemory.cs
+++ b/src/mscorlib/shared/System/ReadOnlyMemory.cs
@@ -14,8 +14,11 @@ namespace System
{
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
- public struct ReadOnlyMemory<T>
+ public readonly struct ReadOnlyMemory<T>
{
+ // NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
+ // as code uses Unsafe.As to cast between them.
+
// The highest order bit of _index is used to discern whether _arrayOrOwnedMemory is an array or an owned memory
// if (_index >> 31) == 1, object _arrayOrOwnedMemory is an OwnedMemory<T>
// else, object _arrayOrOwnedMemory is a T[]
@@ -273,4 +276,4 @@ namespace System
}
}
-} \ No newline at end of file
+}
diff --git a/src/mscorlib/shared/System/ReadOnlySpan.cs b/src/mscorlib/shared/System/ReadOnlySpan.cs
index 4e1910df60..c5f301a6f2 100644
--- a/src/mscorlib/shared/System/ReadOnlySpan.cs
+++ b/src/mscorlib/shared/System/ReadOnlySpan.cs
@@ -16,10 +16,8 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
- [IsReadOnly]
- [IsByRefLike]
[NonVersionable]
- public struct ReadOnlySpan<T>
+ public readonly ref struct ReadOnlySpan<T>
{
/// <summary>A byref or a native ptr.</summary>
private readonly ByReference<T> _pointer;
diff --git a/src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs b/src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs
index c4aeca704d..643a127c49 100644
--- a/src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs
+++ b/src/mscorlib/shared/System/Reflection/AmbiguousMatchException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class AmbiguousMatchException : SystemException
{
public AmbiguousMatchException()
@@ -25,5 +27,9 @@ namespace System.Reflection
{
HResult = HResults.COR_E_AMBIGUOUSMATCH;
}
+
+ internal AmbiguousMatchException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs b/src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs
index ae67158a53..1d7d4a7671 100644
--- a/src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs
+++ b/src/mscorlib/shared/System/Reflection/CustomAttributeFormatException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class CustomAttributeFormatException : FormatException
{
public CustomAttributeFormatException()
@@ -27,7 +29,6 @@ namespace System.Reflection
protected CustomAttributeFormatException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Reflection/IntrospectionExtensions.cs b/src/mscorlib/shared/System/Reflection/IntrospectionExtensions.cs
index 6a18fdaa72..acf5987d44 100644
--- a/src/mscorlib/shared/System/Reflection/IntrospectionExtensions.cs
+++ b/src/mscorlib/shared/System/Reflection/IntrospectionExtensions.cs
@@ -13,7 +13,10 @@ namespace System.Reflection
if (type == null)
throw new ArgumentNullException(nameof(type));
- return ((IReflectableType)type).GetTypeInfo(); // Unguarded cast is unbecoming but kept for compatibility.
+ if (type is IReflectableType reflectableType)
+ return reflectableType.GetTypeInfo();
+
+ return new TypeDelegator(type);
}
}
}
diff --git a/src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs b/src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs
index 85a447707c..dedcc54f4c 100644
--- a/src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs
+++ b/src/mscorlib/shared/System/Reflection/InvalidFilterCriteriaException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidFilterCriteriaException : ApplicationException
{
public InvalidFilterCriteriaException()
@@ -27,7 +29,6 @@ namespace System.Reflection
protected InvalidFilterCriteriaException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs b/src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs
index 0e86d34056..a411387cff 100644
--- a/src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs
+++ b/src/mscorlib/shared/System/Reflection/ReflectionTypeLoadException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class ReflectionTypeLoadException : SystemException, ISerializable
{
public ReflectionTypeLoadException(Type[] classes, Exception[] exceptions)
@@ -24,9 +26,17 @@ namespace System.Reflection
HResult = HResults.COR_E_REFLECTIONTYPELOAD;
}
+ private ReflectionTypeLoadException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ LoaderExceptions = (Exception[])(info.GetValue("Exceptions", typeof(Exception[])));
+ }
+
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("Types", null, typeof(Type[]));
+ info.AddValue("Exceptions", LoaderExceptions, typeof(Exception[]));
}
public Type[] Types { get; }
diff --git a/src/mscorlib/shared/System/Reflection/SignatureConstructedGenericType.cs b/src/mscorlib/shared/System/Reflection/SignatureConstructedGenericType.cs
index afcdfda352..cd97ffa21b 100644
--- a/src/mscorlib/shared/System/Reflection/SignatureConstructedGenericType.cs
+++ b/src/mscorlib/shared/System/Reflection/SignatureConstructedGenericType.cs
@@ -28,6 +28,7 @@ namespace System.Reflection
public sealed override bool IsVariableBoundArray => false;
public sealed override bool IsConstructedGenericType => true;
public sealed override bool IsGenericParameter => false;
+ public sealed override bool IsGenericTypeParameter => false;
public sealed override bool IsGenericMethodParameter => false;
public sealed override bool ContainsGenericParameters
{
diff --git a/src/mscorlib/shared/System/Reflection/SignatureGenericMethodParameterType.cs b/src/mscorlib/shared/System/Reflection/SignatureGenericMethodParameterType.cs
index ae73272ab7..d0790283fb 100644
--- a/src/mscorlib/shared/System/Reflection/SignatureGenericMethodParameterType.cs
+++ b/src/mscorlib/shared/System/Reflection/SignatureGenericMethodParameterType.cs
@@ -10,7 +10,8 @@ namespace System.Reflection
: base(position)
{
}
-
+
+ public sealed override bool IsGenericTypeParameter => false;
public sealed override bool IsGenericMethodParameter => true;
public sealed override string Name => "!!" + GenericParameterPosition;
diff --git a/src/mscorlib/shared/System/Reflection/SignatureHasElementType.cs b/src/mscorlib/shared/System/Reflection/SignatureHasElementType.cs
index e1aa6c3584..e74e5f5aa2 100644
--- a/src/mscorlib/shared/System/Reflection/SignatureHasElementType.cs
+++ b/src/mscorlib/shared/System/Reflection/SignatureHasElementType.cs
@@ -26,6 +26,7 @@ namespace System.Reflection
public abstract override bool IsVariableBoundArray { get; }
public sealed override bool IsConstructedGenericType => false;
public sealed override bool IsGenericParameter => false;
+ public sealed override bool IsGenericTypeParameter => false;
public sealed override bool IsGenericMethodParameter => false;
public sealed override bool ContainsGenericParameters => _elementType.ContainsGenericParameters;
diff --git a/src/mscorlib/shared/System/Reflection/SignatureType.cs b/src/mscorlib/shared/System/Reflection/SignatureType.cs
index c3dfc49174..40a0590448 100644
--- a/src/mscorlib/shared/System/Reflection/SignatureType.cs
+++ b/src/mscorlib/shared/System/Reflection/SignatureType.cs
@@ -31,7 +31,8 @@ namespace System.Reflection
public abstract override bool IsGenericTypeDefinition { get; }
public abstract override bool IsConstructedGenericType { get; }
public abstract override bool IsGenericParameter { get; }
- public abstract bool IsGenericMethodParameter { get; }
+ public abstract override bool IsGenericTypeParameter { get; }
+ public abstract override bool IsGenericMethodParameter { get; }
public abstract override bool ContainsGenericParameters { get; }
public sealed override MemberTypes MemberType => MemberTypes.TypeInfo;
diff --git a/src/mscorlib/shared/System/Reflection/SignatureTypeExtensions.cs b/src/mscorlib/shared/System/Reflection/SignatureTypeExtensions.cs
index b30da50073..f0a33d0bad 100644
--- a/src/mscorlib/shared/System/Reflection/SignatureTypeExtensions.cs
+++ b/src/mscorlib/shared/System/Reflection/SignatureTypeExtensions.cs
@@ -84,7 +84,7 @@ namespace System.Reflection
}
else if (pattern.IsGenericMethodParameter)
{
- if (!(actual.IsGenericParameter && actual.DeclaringMethod != null))
+ if (!actual.IsGenericMethodParameter)
return false;
if (pattern.GenericParameterPosition != actual.GenericParameterPosition)
return false;
diff --git a/src/mscorlib/shared/System/Reflection/TargetException.cs b/src/mscorlib/shared/System/Reflection/TargetException.cs
index 2309daace1..c200000738 100644
--- a/src/mscorlib/shared/System/Reflection/TargetException.cs
+++ b/src/mscorlib/shared/System/Reflection/TargetException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TargetException : ApplicationException
{
public TargetException()
@@ -27,7 +29,6 @@ namespace System.Reflection
protected TargetException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Reflection/TargetInvocationException.cs b/src/mscorlib/shared/System/Reflection/TargetInvocationException.cs
index 7c4f60a03e..822ddfdfb2 100644
--- a/src/mscorlib/shared/System/Reflection/TargetInvocationException.cs
+++ b/src/mscorlib/shared/System/Reflection/TargetInvocationException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class TargetInvocationException : ApplicationException
{
public TargetInvocationException(Exception inner)
@@ -19,5 +21,10 @@ namespace System.Reflection
{
HResult = HResults.COR_E_TARGETINVOCATION;
}
+
+ internal TargetInvocationException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs b/src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs
index f31758b7ba..c68c467290 100644
--- a/src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs
+++ b/src/mscorlib/shared/System/Reflection/TargetParameterCountException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Reflection
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class TargetParameterCountException : ApplicationException
{
public TargetParameterCountException()
@@ -25,5 +27,10 @@ namespace System.Reflection
{
HResult = HResults.COR_E_TARGETPARAMCOUNT;
}
+
+ internal TargetParameterCountException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Reflection/TypeDelegator.cs b/src/mscorlib/shared/System/Reflection/TypeDelegator.cs
index 1dba278893..ac3972fb7c 100644
--- a/src/mscorlib/shared/System/Reflection/TypeDelegator.cs
+++ b/src/mscorlib/shared/System/Reflection/TypeDelegator.cs
@@ -105,6 +105,8 @@ namespace System.Reflection
protected override bool IsArrayImpl() => typeImpl.IsArray;
protected override bool IsPrimitiveImpl() => typeImpl.IsPrimitive;
protected override bool IsByRefImpl() => typeImpl.IsByRef;
+ public override bool IsGenericTypeParameter => typeImpl.IsGenericTypeParameter;
+ public override bool IsGenericMethodParameter => typeImpl.IsGenericMethodParameter;
protected override bool IsPointerImpl() => typeImpl.IsPointer;
protected override bool IsValueTypeImpl() => typeImpl.IsValueType;
protected override bool IsCOMObjectImpl() => typeImpl.IsCOMObject;
diff --git a/src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs b/src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs
index e11d15d200..20914ac7e1 100644
--- a/src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs
+++ b/src/mscorlib/shared/System/Resources/MissingManifestResourceException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.Resources
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MissingManifestResourceException : SystemException
{
public MissingManifestResourceException()
@@ -30,7 +32,6 @@ namespace System.Resources
protected MissingManifestResourceException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs b/src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs
index 615aed6a8c..af547b21f1 100644
--- a/src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs
+++ b/src/mscorlib/shared/System/Resources/MissingSatelliteAssemblyException.cs
@@ -20,6 +20,8 @@ using System.Runtime.Serialization;
namespace System.Resources
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MissingSatelliteAssemblyException : SystemException
{
private String _cultureName;
@@ -52,7 +54,6 @@ namespace System.Resources
protected MissingSatelliteAssemblyException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
public String CultureName
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
index 0784e6135c..f71067819b 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs
@@ -2,6 +2,7 @@
// 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;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -34,7 +35,7 @@ namespace System.Runtime.CompilerServices
/// <summary>Provides an awaiter for a <see cref="ConfiguredValueTaskAwaitable{TResult}"/>.</summary>
[StructLayout(LayoutKind.Auto)]
- public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion
+ public struct ConfiguredValueTaskAwaiter : ICriticalNotifyCompletion, IConfiguredValueTaskAwaiter
{
/// <summary>The value being awaited.</summary>
private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies
@@ -54,6 +55,7 @@ namespace System.Runtime.CompilerServices
public bool IsCompleted => _value.IsCompleted;
/// <summary>Gets the result of the ValueTask.</summary>
+ [StackTraceHidden]
public TResult GetResult() =>
_value._task == null ?
_value._result :
@@ -69,6 +71,10 @@ namespace System.Runtime.CompilerServices
/// <summary>Gets the task underlying <see cref="_value"/>.</summary>
internal Task<TResult> AsTask() => _value.AsTask();
+
+ /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary>
+ /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks>
+ (Task, bool) IConfiguredValueTaskAwaiter.GetTask() => (_value.AsTaskExpectNonNull(), _continueOnCapturedContext);
}
}
}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs
index e4af9be678..72996c6dfc 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/RuntimeWrappedException.cs
@@ -2,7 +2,6 @@
// 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.Serialization;
namespace System.Runtime.CompilerServices
@@ -10,24 +9,33 @@ namespace System.Runtime.CompilerServices
/// <summary>
/// Exception used to wrap all non-CLS compliant exceptions.
/// </summary>
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class RuntimeWrappedException : Exception
{
- private Object _wrappedException; // EE expects this name
+ private object _wrappedException; // EE expects this name
// Not an api but has to be public as System.Linq.Expression invokes this through Reflection when an expression
// throws an object that doesn't derive from Exception.
- public RuntimeWrappedException(Object thrownObject)
+ public RuntimeWrappedException(object thrownObject)
: base(SR.RuntimeWrappedException)
{
HResult = HResults.COR_E_RUNTIMEWRAPPED;
_wrappedException = thrownObject;
}
+ private RuntimeWrappedException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ _wrappedException = info.GetValue("WrappedException", typeof(object));
+ }
+
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("WrappedException", _wrappedException, typeof(object));
}
- public Object WrappedException => _wrappedException;
+ public object WrappedException => _wrappedException;
}
}
diff --git a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
index 30e688e077..7c4b0ceedb 100644
--- a/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
+++ b/src/mscorlib/shared/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
@@ -2,13 +2,13 @@
// 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.Runtime.InteropServices;
+using System.Diagnostics;
using System.Threading.Tasks;
namespace System.Runtime.CompilerServices
{
/// <summary>Provides an awaiter for a <see cref="ValueTask{TResult}"/>.</summary>
- public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion
+ public struct ValueTaskAwaiter<TResult> : ICriticalNotifyCompletion, IValueTaskAwaiter
{
/// <summary>The value being awaited.</summary>
private ValueTask<TResult> _value; // Methods are called on this; avoid making it readonly so as to avoid unnecessary copies
@@ -21,6 +21,7 @@ namespace System.Runtime.CompilerServices
public bool IsCompleted => _value.IsCompleted;
/// <summary>Gets the result of the ValueTask.</summary>
+ [StackTraceHidden]
public TResult GetResult() =>
_value._task == null ?
_value._result :
@@ -36,5 +37,9 @@ namespace System.Runtime.CompilerServices
/// <summary>Gets the task underlying <see cref="_value"/>.</summary>
internal Task<TResult> AsTask() => _value.AsTask();
+
+ /// <summary>Gets the task underlying the incomplete <see cref="_value"/>.</summary>
+ /// <remarks>This method is used when awaiting and IsCompleted returned false; thus we expect the value task to be wrapping a non-null task.</remarks>
+ Task IValueTaskAwaiter.GetTask() => _value.AsTaskExpectNonNull();
}
}
diff --git a/src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs b/src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs
index 0861d19362..160fe301e8 100644
--- a/src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs
+++ b/src/mscorlib/shared/System/Runtime/InteropServices/ExternalException.cs
@@ -20,7 +20,8 @@ namespace System.Runtime.InteropServices
{
// Base exception for COM Interop errors &; Structured Exception Handler
// exceptions.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ExternalException : SystemException
{
public ExternalException()
@@ -50,7 +51,6 @@ namespace System.Runtime.InteropServices
protected ExternalException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
public virtual int ErrorCode
diff --git a/src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs b/src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs
index 3e0af092c0..1c9c21eabb 100644
--- a/src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs
+++ b/src/mscorlib/shared/System/Runtime/Serialization/SerializationException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.Serialization
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SerializationException : SystemException
{
private static String s_nullMessage = SR.SerializationException;
@@ -33,7 +35,6 @@ namespace System.Runtime.Serialization
protected SerializationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Security/CryptographicException.cs b/src/mscorlib/shared/System/Security/CryptographicException.cs
index 7c4fa176f3..78ee290693 100644
--- a/src/mscorlib/shared/System/Security/CryptographicException.cs
+++ b/src/mscorlib/shared/System/Security/CryptographicException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.Security.Cryptography
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class CryptographicException : SystemException
{
public CryptographicException()
@@ -38,7 +40,6 @@ namespace System.Security.Cryptography
protected CryptographicException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Security/SecurityException.cs b/src/mscorlib/shared/System/Security/SecurityException.cs
index 2866a4780c..61504c3ba1 100644
--- a/src/mscorlib/shared/System/Security/SecurityException.cs
+++ b/src/mscorlib/shared/System/Security/SecurityException.cs
@@ -7,8 +7,17 @@ using System.Runtime.Serialization;
namespace System.Security
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SecurityException : SystemException
{
+ private const string DemandedName = "Demanded";
+ private const string GrantedSetName = "GrantedSet";
+ private const string RefusedSetName = "RefusedSet";
+ private const string DeniedName = "Denied";
+ private const string PermitOnlyName = "PermitOnly";
+ private const string UrlName = "Url";
+
public SecurityException()
: base(SR.Arg_SecurityException)
{
@@ -45,12 +54,26 @@ namespace System.Security
protected SecurityException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
+ Demanded = (string)info.GetValueNoThrow(DemandedName, typeof(string));
+ GrantedSet = (string)info.GetValueNoThrow(GrantedSetName, typeof(string));
+ RefusedSet = (string)info.GetValueNoThrow(RefusedSetName, typeof(string));
+ DenySetInstance = (string)info.GetValueNoThrow(DeniedName, typeof(string));
+ PermitOnlySetInstance = (string)info.GetValueNoThrow(PermitOnlyName, typeof(string));
+ Url = (string)info.GetValueNoThrow(UrlName, typeof(string));
}
public override string ToString() => base.ToString();
- public override void GetObjectData(SerializationInfo info, StreamingContext context) => base.GetObjectData(info, context);
+ public override void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ base.GetObjectData(info, context);
+ info.AddValue(DemandedName, Demanded, typeof(string));
+ info.AddValue(GrantedSetName, GrantedSet, typeof(string));
+ info.AddValue(RefusedSetName, RefusedSet, typeof(string));
+ info.AddValue(DeniedName, DenySetInstance, typeof(string));
+ info.AddValue(PermitOnlyName, PermitOnlySetInstance, typeof(string));
+ info.AddValue(UrlName, Url, typeof(string));
+ }
public object Demanded { get; set; }
public object DenySetInstance { get; set; }
diff --git a/src/mscorlib/shared/System/Security/VerificationException.cs b/src/mscorlib/shared/System/Security/VerificationException.cs
index bd095f3df4..e2afd4cabe 100644
--- a/src/mscorlib/shared/System/Security/VerificationException.cs
+++ b/src/mscorlib/shared/System/Security/VerificationException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Security
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class VerificationException : SystemException
{
public VerificationException()
@@ -29,7 +31,6 @@ namespace System.Security
protected VerificationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Span.cs b/src/mscorlib/shared/System/Span.cs
index f4f4e571de..261b15c078 100644
--- a/src/mscorlib/shared/System/Span.cs
+++ b/src/mscorlib/shared/System/Span.cs
@@ -22,10 +22,8 @@ namespace System
/// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
- [IsReadOnly]
- [IsByRefLike]
[NonVersionable]
- public struct Span<T>
+ public readonly ref struct Span<T>
{
/// <summary>A byref or a native ptr.</summary>
private readonly ByReference<T> _pointer;
diff --git a/src/mscorlib/shared/System/StackOverflowException.cs b/src/mscorlib/shared/System/StackOverflowException.cs
index 8b21eb769a..6f954cc75a 100644
--- a/src/mscorlib/shared/System/StackOverflowException.cs
+++ b/src/mscorlib/shared/System/StackOverflowException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class StackOverflowException : SystemException
{
public StackOverflowException()
@@ -34,5 +36,9 @@ namespace System
{
HResult = HResults.COR_E_STACKOVERFLOW;
}
+
+ internal StackOverflowException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/src/System/String.Searching.cs b/src/mscorlib/shared/System/String.Searching.cs
index 0be214d0d9..527a73b136 100644
--- a/src/mscorlib/src/System/String.Searching.cs
+++ b/src/mscorlib/shared/System/String.Searching.cs
@@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Globalization;
-using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace System
{
@@ -75,7 +75,7 @@ namespace System
}
// Returns the index of the first occurrence of any specified character in the current instance.
- // The search starts at startIndex and runs to startIndex + count -1.
+ // The search starts at startIndex and runs to startIndex + count - 1.
//
public int IndexOfAny(char[] anyOf)
{
@@ -90,19 +90,13 @@ namespace System
public int IndexOfAny(char[] anyOf, int startIndex, int count)
{
if (anyOf == null)
- {
throw new ArgumentNullException(nameof(anyOf));
- }
if ((uint)startIndex > (uint)Length)
- {
throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
- }
if ((uint)count > (uint)(Length - startIndex))
- {
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
- }
if (anyOf.Length == 2)
{
@@ -176,33 +170,114 @@ namespace System
}
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern int IndexOfCharArray(char[] anyOf, int startIndex, int count);
+ private unsafe int IndexOfCharArray(char[] anyOf, int startIndex, int count)
+ {
+ // use probabilistic map, see InitializeProbabilisticMap
+ ProbabilisticMap map = default(ProbabilisticMap);
+ uint* charMap = (uint*)&map;
+ InitializeProbabilisticMap(charMap, anyOf);
+
+ fixed (char* pChars = &_firstChar)
+ {
+ char* pCh = pChars + startIndex;
+
+ while (count > 0)
+ {
+ int thisChar = *pCh;
+
+ if (IsCharBitSet(charMap, (byte)thisChar) &&
+ IsCharBitSet(charMap, (byte)(thisChar >> 8)) &&
+ ArrayContains((char)thisChar, anyOf))
+ {
+ return (int)(pCh - pChars);
+ }
+
+ count--;
+ pCh++;
+ }
+
+ return -1;
+ }
+ }
+
+ private const int PROBABILISTICMAP_BLOCK_INDEX_MASK = 0x7;
+ private const int PROBABILISTICMAP_BLOCK_INDEX_SHIFT = 0x3;
+ private const int PROBABILISTICMAP_SIZE = 0x8;
+
+ // A probabilistic map is an optimization that is used in IndexOfAny/
+ // LastIndexOfAny methods. The idea is to create a bit map of the characters we
+ // are searching for and use this map as a "cheap" check to decide if the
+ // current character in the string exists in the array of input characters.
+ // There are 256 bits in the map, with each character mapped to 2 bits. Every
+ // character is divided into 2 bytes, and then every byte is mapped to 1 bit.
+ // The character map is an array of 8 integers acting as map blocks. The 3 lsb
+ // in each byte in the character is used to index into this map to get the
+ // right block, the value of the remaining 5 msb are used as the bit position
+ // inside this block.
+ private static unsafe void InitializeProbabilisticMap(uint* charMap, char[] anyOf)
+ {
+ bool hasAscii = false;
+ uint* charMapLocal = charMap; // https://github.com/dotnet/coreclr/issues/14264
+
+ for (int i = 0; i < anyOf.Length; ++i)
+ {
+ int c = anyOf[i];
+
+ // Map low bit
+ SetCharBit(charMapLocal, (byte)c);
+
+ // Map high bit
+ c >>= 8;
+
+ if (c == 0)
+ {
+ hasAscii = true;
+ }
+ else
+ {
+ SetCharBit(charMapLocal, (byte)c);
+ }
+ }
+
+ if (hasAscii)
+ {
+ // Common to search for ASCII symbols. Just set the high value once.
+ charMapLocal[0] |= 1u;
+ }
+ }
+
+ private static bool ArrayContains(char searchChar, char[] anyOf)
+ {
+ for (int i = 0; i < anyOf.Length; i++)
+ {
+ if (anyOf[i] == searchChar)
+ return true;
+ }
+
+ return false;
+ }
+
+ private unsafe static bool IsCharBitSet(uint* charMap, byte value)
+ {
+ return (charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] & (1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT))) != 0;
+ }
+
+ private unsafe static void SetCharBit(uint* charMap, byte value)
+ {
+ charMap[value & PROBABILISTICMAP_BLOCK_INDEX_MASK] |= 1u << (value >> PROBABILISTICMAP_BLOCK_INDEX_SHIFT);
+ }
- // Determines the position within this string of the first occurrence of the specified
- // string, according to the specified search criteria. The search begins at
- // the first character of this string, it is case-sensitive and the current culture
- // comparison is used.
- //
public int IndexOf(String value)
{
return IndexOf(value, StringComparison.CurrentCulture);
}
- // Determines the position within this string of the first occurrence of the specified
- // string, according to the specified search criteria. The search begins at
- // startIndex, it is case-sensitive and the current culture comparison is used.
- //
public int IndexOf(String value, int startIndex)
{
return IndexOf(value, startIndex, StringComparison.CurrentCulture);
}
- // Determines the position within this string of the first occurrence of the specified
- // string, according to the specified search criteria. The search begins at
- // startIndex, ends at endIndex and the current culture comparison is used.
- //
public int IndexOf(String value, int startIndex, int count)
{
if (startIndex < 0 || startIndex > this.Length)
@@ -258,10 +333,7 @@ namespace System
return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
case StringComparison.OrdinalIgnoreCase:
- if (value.IsAscii() && this.IsAscii())
- return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
- else
- return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
+ return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
default:
throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
@@ -334,8 +406,6 @@ namespace System
// The character at position startIndex is included in the search. startIndex is the larger
// index within the string.
//
-
- //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
public int LastIndexOfAny(char[] anyOf)
{
return LastIndexOfAny(anyOf, this.Length - 1, this.Length);
@@ -346,9 +416,68 @@ namespace System
return LastIndexOfAny(anyOf, startIndex, startIndex + 1);
}
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern int LastIndexOfAny(char[] anyOf, int startIndex, int count);
+ public unsafe int LastIndexOfAny(char[] anyOf, int startIndex, int count)
+ {
+ if (anyOf == null)
+ throw new ArgumentNullException(nameof(anyOf));
+
+ if (Length == 0)
+ return -1;
+
+ if ((uint)startIndex >= (uint)Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
+ }
+
+ if ((count < 0) || ((count - 1) > startIndex))
+ {
+ throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
+ }
+
+ if (anyOf.Length > 1)
+ {
+ return LastIndexOfCharArray(anyOf, startIndex, count);
+ }
+ else if (anyOf.Length == 1)
+ {
+ return LastIndexOf(anyOf[0], startIndex, count);
+ }
+ else // anyOf.Length == 0
+ {
+ return -1;
+ }
+ }
+
+ private unsafe int LastIndexOfCharArray(char[] anyOf, int startIndex, int count)
+ {
+ // use probabilistic map, see InitializeProbabilisticMap
+ ProbabilisticMap map = default(ProbabilisticMap);
+ uint* charMap = (uint*)&map;
+
+ InitializeProbabilisticMap(charMap, anyOf);
+
+ fixed (char* pChars = &_firstChar)
+ {
+ char* pCh = pChars + startIndex;
+
+ while (count > 0)
+ {
+ int thisChar = *pCh;
+
+ if (IsCharBitSet(charMap, (byte)thisChar) &&
+ IsCharBitSet(charMap, (byte)(thisChar >> 8)) &&
+ ArrayContains((char)thisChar, anyOf))
+ {
+ return (int)(pCh - pChars);
+ }
+ count--;
+ pCh--;
+ }
+
+ return -1;
+ }
+ }
// Returns the index of the last occurrence of any character in value in the current instance.
// The search starts at startIndex and runs backwards to startIndex - count + 1.
@@ -404,16 +533,15 @@ namespace System
startIndex--;
if (count > 0)
count--;
-
- // If we are looking for nothing, just return 0
- if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
- return startIndex;
}
// 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
if (count < 0 || startIndex - count + 1 < 0)
throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_Count);
+ // If we are looking for nothing, just return startIndex
+ if (value.Length == 0)
+ return startIndex;
switch (comparisonType)
{
@@ -428,17 +556,19 @@ namespace System
case StringComparison.InvariantCultureIgnoreCase:
return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+
case StringComparison.Ordinal:
return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
case StringComparison.OrdinalIgnoreCase:
- if (value.IsAscii() && this.IsAscii())
- return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
- else
- return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
+ return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
+
default:
throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
}
}
+
+ [StructLayout(LayoutKind.Explicit, Size = PROBABILISTICMAP_SIZE * sizeof(uint))]
+ private struct ProbabilisticMap { }
}
}
diff --git a/src/mscorlib/shared/System/StringSpanHelpers.cs b/src/mscorlib/shared/System/StringSpanHelpers.cs
index bdfd965641..a849035180 100644
--- a/src/mscorlib/shared/System/StringSpanHelpers.cs
+++ b/src/mscorlib/shared/System/StringSpanHelpers.cs
@@ -89,5 +89,28 @@ namespace System
return -1;
}
+
+ public static ReadOnlySpan<char> Remove(this ReadOnlySpan<char> source, int startIndex, int count)
+ {
+ if (startIndex < 0) throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
+ if (count < 0) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
+ if (count > source.Length - startIndex) throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount);
+
+ if (count == 0)
+ {
+ return source;
+ }
+
+ int newLength = source.Length - count;
+ if (newLength == 0)
+ {
+ return ReadOnlySpan<char>.Empty;
+ }
+
+ Span<char> result = new char[newLength];
+ source.Slice(0, startIndex).CopyTo(result);
+ source.Slice(startIndex + count).CopyTo(result.Slice(startIndex));
+ return result;
+ }
}
}
diff --git a/src/mscorlib/shared/System/SystemException.cs b/src/mscorlib/shared/System/SystemException.cs
index 64a4b9ca31..b7e8e42175 100644
--- a/src/mscorlib/shared/System/SystemException.cs
+++ b/src/mscorlib/shared/System/SystemException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SystemException : Exception
{
public SystemException()
@@ -28,7 +30,6 @@ namespace System
protected SystemException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Text/DecoderExceptionFallback.cs b/src/mscorlib/shared/System/Text/DecoderExceptionFallback.cs
index 26d604a919..8bfc1f32d3 100644
--- a/src/mscorlib/shared/System/Text/DecoderExceptionFallback.cs
+++ b/src/mscorlib/shared/System/Text/DecoderExceptionFallback.cs
@@ -4,6 +4,7 @@
using System;
using System.Globalization;
+using System.Runtime.Serialization;
namespace System.Text
{
@@ -98,6 +99,8 @@ namespace System.Text
}
// Exception for decoding unknown byte sequences.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class DecoderFallbackException : ArgumentException
{
private byte[] _bytesUnknown = null;
@@ -128,6 +131,11 @@ namespace System.Text
_index = index;
}
+ private DecoderFallbackException(SerializationInfo serializationInfo, StreamingContext streamingContext)
+ : base(serializationInfo, streamingContext)
+ {
+ }
+
public byte[] BytesUnknown
{
get
diff --git a/src/mscorlib/shared/System/Text/EncoderExceptionFallback.cs b/src/mscorlib/shared/System/Text/EncoderExceptionFallback.cs
index 4c71916901..66de1940f6 100644
--- a/src/mscorlib/shared/System/Text/EncoderExceptionFallback.cs
+++ b/src/mscorlib/shared/System/Text/EncoderExceptionFallback.cs
@@ -96,6 +96,8 @@ namespace System.Text
}
}
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class EncoderFallbackException : ArgumentException
{
private char _charUnknown;
@@ -147,6 +149,11 @@ namespace System.Text
_index = index;
}
+ private EncoderFallbackException(SerializationInfo serializationInfo, StreamingContext streamingContext)
+ : base(serializationInfo, streamingContext)
+ {
+ }
+
public char CharUnknown
{
get
diff --git a/src/mscorlib/shared/System/Text/StringBuilder.cs b/src/mscorlib/shared/System/Text/StringBuilder.cs
index f5003d8124..e5a894dfed 100644
--- a/src/mscorlib/shared/System/Text/StringBuilder.cs
+++ b/src/mscorlib/shared/System/Text/StringBuilder.cs
@@ -270,7 +270,7 @@ namespace System.Text
info.AddValue(ThreadIDField, 0);
}
- [System.Diagnostics.Conditional("_DEBUG")]
+ [System.Diagnostics.Conditional("DEBUG")]
private void AssertInvariants()
{
Debug.Assert(m_ChunkOffset + m_ChunkChars.Length >= m_ChunkOffset, "The length of the string is greater than int.MaxValue.");
diff --git a/src/mscorlib/shared/System/Threading/AbandonedMutexException.cs b/src/mscorlib/shared/System/Threading/AbandonedMutexException.cs
index c43148d22a..c7e604f33d 100644
--- a/src/mscorlib/shared/System/Threading/AbandonedMutexException.cs
+++ b/src/mscorlib/shared/System/Threading/AbandonedMutexException.cs
@@ -14,6 +14,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class AbandonedMutexException : SystemException
{
private int _mutexIndex = -1;
@@ -61,7 +63,6 @@ namespace System.Threading
protected AbandonedMutexException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
private void SetupException(int location, WaitHandle handle)
diff --git a/src/mscorlib/shared/System/Threading/LockRecursionException.cs b/src/mscorlib/shared/System/Threading/LockRecursionException.cs
index 86e19032b3..c76c7a5040 100644
--- a/src/mscorlib/shared/System/Threading/LockRecursionException.cs
+++ b/src/mscorlib/shared/System/Threading/LockRecursionException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class LockRecursionException : System.Exception
{
public LockRecursionException()
@@ -25,7 +27,6 @@ namespace System.Threading
protected LockRecursionException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Threading/ReaderWriterLockSlim.cs b/src/mscorlib/shared/System/Threading/ReaderWriterLockSlim.cs
index c34d6ea444..3c4aad603a 100644
--- a/src/mscorlib/shared/System/Threading/ReaderWriterLockSlim.cs
+++ b/src/mscorlib/shared/System/Threading/ReaderWriterLockSlim.cs
@@ -55,7 +55,7 @@ namespace System.Threading
{
private static readonly int ProcessorCount = Environment.ProcessorCount;
- //Specifying if locked can be reacquired recursively.
+ //Specifying if the lock can be reacquired recursively.
private readonly bool _fIsReentrant;
// Lock specification for _spinLock: This lock protects exactly the local fields associated with this
@@ -967,7 +967,51 @@ namespace System.Threading
Debug.Assert(_spinLock.IsHeld);
#endif
+ WaiterStates waiterSignaledState = WaiterStates.None;
+ EnterSpinLockReason enterMyLockReason;
+ switch (enterLockType)
+ {
+ case EnterLockType.UpgradeableRead:
+ waiterSignaledState = WaiterStates.UpgradeableReadWaiterSignaled;
+ goto case EnterLockType.Read;
+
+ case EnterLockType.Read:
+ enterMyLockReason = EnterSpinLockReason.EnterAnyRead;
+ break;
+
+ case EnterLockType.Write:
+ waiterSignaledState = WaiterStates.WriteWaiterSignaled;
+ enterMyLockReason = EnterSpinLockReason.EnterWrite;
+ break;
+
+ default:
+ Debug.Assert(enterLockType == EnterLockType.UpgradeToWrite);
+ enterMyLockReason = EnterSpinLockReason.UpgradeToWrite;
+ break;
+ }
+
+ // It was not possible to acquire the RW lock because some other thread was holding some type of lock. The other
+ // thread, when it releases its lock, will wake appropriate waiters. Along with resetting the wait event, clear the
+ // waiter signaled bit for this type of waiter if applicable, to indicate that a waiter of this type is no longer
+ // signaled.
+ //
+ // If the waiter signaled bit is not updated upon event reset, the following scenario would lead to deadlock:
+ // - Thread T0 signals the write waiter event or the upgradeable read waiter event to wake a waiter
+ // - There are no threads waiting on the event, but T1 is in WaitOnEvent() after exiting the spin lock and before
+ // actually waiting on the event (that is, it's recorded that there is one waiter for the event). It remains in
+ // this region for a while, in the repro case it typically gets context-switched out.
+ // - T2 acquires the RW lock in some fashion that blocks T0 or T3 from acquiring the RW lock
+ // - T0 or T3 fails to acquire the RW lock enough times for it to enter WaitOnEvent for the same event as T1
+ // - T0 or T3 resets the event
+ // - T2 releases the RW lock and does not wake a waiter because the reset at the previous step lost a signal but
+ // _waiterStates was not updated to reflect that
+ // - T1 and other threads begin waiting on the event, but there's no longer any thread that would wake them
+ if (waiterSignaledState != WaiterStates.None && (_waiterStates & waiterSignaledState) != WaiterStates.None)
+ {
+ _waiterStates &= ~waiterSignaledState;
+ }
waitEvent.Reset();
+
numWaiters++;
HasNoWaiters = false;
@@ -986,40 +1030,19 @@ namespace System.Threading
}
finally
{
- WaiterStates waiterSignaledState = WaiterStates.None;
- EnterSpinLockReason enterMyLockReason;
- switch (enterLockType)
- {
- case EnterLockType.UpgradeableRead:
- waiterSignaledState = WaiterStates.UpgradeableReadWaiterSignaled;
- goto case EnterLockType.Read;
-
- case EnterLockType.Read:
- enterMyLockReason = EnterSpinLockReason.EnterAnyRead;
- break;
-
- case EnterLockType.Write:
- waiterSignaledState = WaiterStates.WriteWaiterSignaled;
- enterMyLockReason = EnterSpinLockReason.EnterWrite;
- break;
-
- default:
- Debug.Assert(enterLockType == EnterLockType.UpgradeToWrite);
- enterMyLockReason = EnterSpinLockReason.UpgradeToWrite;
- break;
- }
_spinLock.Enter(enterMyLockReason);
--numWaiters;
- if (waitSuccessful && waiterSignaledState != WaiterStates.None)
+ if (waitSuccessful &&
+ waiterSignaledState != WaiterStates.None &&
+ (_waiterStates & waiterSignaledState) != WaiterStates.None)
{
// Indicate that a signaled waiter of this type has woken. Since non-read waiters are signaled to wake one
// at a time, we avoid waking up more than one waiter of that type upon successive enter/exit loops until
// the signaled thread actually wakes up. For example, if there are multiple write waiters and one thread is
// repeatedly entering and exiting a write lock, every exit would otherwise signal a different write waiter
// to wake up unnecessarily when only one woken waiter may actually succeed in entering the write lock.
- Debug.Assert((_waiterStates & waiterSignaledState) != WaiterStates.None);
_waiterStates &= ~waiterSignaledState;
}
diff --git a/src/mscorlib/shared/System/Threading/SemaphoreFullException.cs b/src/mscorlib/shared/System/Threading/SemaphoreFullException.cs
index 777463b60d..18558b19e0 100644
--- a/src/mscorlib/shared/System/Threading/SemaphoreFullException.cs
+++ b/src/mscorlib/shared/System/Threading/SemaphoreFullException.cs
@@ -7,6 +7,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SemaphoreFullException : SystemException
{
public SemaphoreFullException() : base(SR.Threading_SemaphoreFullException)
@@ -23,7 +25,6 @@ namespace System.Threading
protected SemaphoreFullException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Threading/SynchronizationLockException.cs b/src/mscorlib/shared/System/Threading/SynchronizationLockException.cs
index 5ab186ec9a..e050e1539d 100644
--- a/src/mscorlib/shared/System/Threading/SynchronizationLockException.cs
+++ b/src/mscorlib/shared/System/Threading/SynchronizationLockException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SynchronizationLockException : SystemException
{
public SynchronizationLockException()
@@ -38,7 +40,6 @@ namespace System.Threading
protected SynchronizationLockException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs b/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs
index 6657bcd36c..6f7fc682b3 100644
--- a/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs
+++ b/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs
@@ -19,6 +19,8 @@ namespace System.Threading.Tasks
/// <summary>
/// Represents an exception used to communicate task cancellation.
/// </summary>
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TaskCanceledException : OperationCanceledException
{
[NonSerialized]
@@ -70,7 +72,6 @@ namespace System.Threading.Tasks
/// <param name="context">The <see cref="T:System.Runtime.Serialization.StreamingContext"/> that contains contextual information about the source or destination. </param>
protected TaskCanceledException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
/// <summary>
diff --git a/src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs b/src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs
index 2888415d0d..85ec497219 100644
--- a/src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs
+++ b/src/mscorlib/shared/System/Threading/Tasks/TaskSchedulerException.cs
@@ -20,6 +20,8 @@ namespace System.Threading.Tasks
/// Represents an exception used to communicate an invalid operation by a
/// <see cref="T:System.Threading.Tasks.TaskScheduler"/>.
/// </summary>
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TaskSchedulerException : Exception
{
/// <summary>
@@ -71,7 +73,6 @@ namespace System.Threading.Tasks
protected TaskSchedulerException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs
index 384e4a8ab3..4ccf0f8a47 100644
--- a/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs
+++ b/src/mscorlib/shared/System/Threading/Tasks/ValueTask.cs
@@ -116,6 +116,15 @@ namespace System.Threading.Tasks
// and the hash code we generate in GetHashCode.
_task ?? AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result);
+ internal Task<TResult> AsTaskExpectNonNull() =>
+ // Return the task if we were constructed from one, otherwise manufacture one.
+ // Unlike AsTask(), this method is called only when we expect _task to be non-null,
+ // and thus we don't want GetTaskForResult inlined.
+ _task ?? GetTaskForResultNoInlining();
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private Task<TResult> GetTaskForResultNoInlining() => AsyncTaskMethodBuilder<TResult>.GetTaskForResult(_result);
+
/// <summary>Gets whether the <see cref="ValueTask{TResult}"/> represents a completed operation.</summary>
public bool IsCompleted => _task == null || _task.IsCompleted;
diff --git a/src/mscorlib/shared/System/Threading/ThreadAbortException.cs b/src/mscorlib/shared/System/Threading/ThreadAbortException.cs
index 01fdf1317b..360e84d256 100644
--- a/src/mscorlib/shared/System/Threading/ThreadAbortException.cs
+++ b/src/mscorlib/shared/System/Threading/ThreadAbortException.cs
@@ -18,6 +18,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class ThreadAbortException : SystemException
{
internal ThreadAbortException()
@@ -26,5 +28,10 @@ namespace System.Threading
}
public object ExceptionState => null;
+
+ internal ThreadAbortException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Threading/ThreadStartException.cs b/src/mscorlib/shared/System/Threading/ThreadStartException.cs
index 35930d1d2d..5172555418 100644
--- a/src/mscorlib/shared/System/Threading/ThreadStartException.cs
+++ b/src/mscorlib/shared/System/Threading/ThreadStartException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class ThreadStartException : SystemException
{
internal ThreadStartException()
@@ -19,5 +21,10 @@ namespace System.Threading
{
HResult = HResults.COR_E_THREADSTART;
}
+
+ private ThreadStartException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/shared/System/Threading/ThreadStateException.cs b/src/mscorlib/shared/System/Threading/ThreadStateException.cs
index d8f97a4f3b..6fc06a8516 100644
--- a/src/mscorlib/shared/System/Threading/ThreadStateException.cs
+++ b/src/mscorlib/shared/System/Threading/ThreadStateException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ThreadStateException : SystemException
{
public ThreadStateException()
@@ -39,7 +41,6 @@ namespace System.Threading
protected ThreadStateException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs b/src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs
index 47e127191d..e60e46d2be 100644
--- a/src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs
+++ b/src/mscorlib/shared/System/Threading/WaitHandleCannotBeOpenedException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class WaitHandleCannotBeOpenedException : ApplicationException
{
public WaitHandleCannotBeOpenedException() : base(SR.Threading_WaitHandleCannotBeOpenedException)
@@ -25,7 +27,6 @@ namespace System.Threading
protected WaitHandleCannotBeOpenedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/TimeZoneNotFoundException.cs b/src/mscorlib/shared/System/TimeZoneNotFoundException.cs
index 5b7ce10268..f83c6443c3 100644
--- a/src/mscorlib/shared/System/TimeZoneNotFoundException.cs
+++ b/src/mscorlib/shared/System/TimeZoneNotFoundException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TimeZoneNotFoundException : Exception
{
public TimeZoneNotFoundException()
@@ -24,7 +26,6 @@ namespace System
protected TimeZoneNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/TimeoutException.cs b/src/mscorlib/shared/System/TimeoutException.cs
index b50ae2f902..ddaa47747d 100644
--- a/src/mscorlib/shared/System/TimeoutException.cs
+++ b/src/mscorlib/shared/System/TimeoutException.cs
@@ -15,6 +15,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TimeoutException : SystemException
{
public TimeoutException()
@@ -37,7 +39,6 @@ namespace System
protected TimeoutException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Tuple.cs b/src/mscorlib/shared/System/Tuple.cs
index 3381c750d0..2d027cd40c 100644
--- a/src/mscorlib/src/System/Tuple.cs
+++ b/src/mscorlib/shared/System/Tuple.cs
@@ -2,12 +2,11 @@
// 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.Text;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+using System.Text;
//
// Note: F# compiler depends on the exact tuple hashing algorithm. Do not ever change it.
@@ -148,7 +147,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
return comparer.Compare(m_Item1, objTuple.m_Item1);
@@ -171,14 +170,14 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
string ITupleInternal.ToString(StringBuilder sb)
{
sb.Append(m_Item1);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -251,7 +250,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -280,7 +279,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -289,7 +288,7 @@ namespace System
sb.Append(m_Item1);
sb.Append(", ");
sb.Append(m_Item2);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -369,7 +368,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -402,7 +401,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -413,7 +412,7 @@ namespace System
sb.Append(m_Item2);
sb.Append(", ");
sb.Append(m_Item3);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -498,7 +497,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -535,7 +534,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -548,7 +547,7 @@ namespace System
sb.Append(m_Item3);
sb.Append(", ");
sb.Append(m_Item4);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -638,7 +637,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -679,7 +678,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -694,7 +693,7 @@ namespace System
sb.Append(m_Item4);
sb.Append(", ");
sb.Append(m_Item5);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -789,7 +788,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -834,7 +833,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -851,7 +850,7 @@ namespace System
sb.Append(m_Item5);
sb.Append(", ");
sb.Append(m_Item6);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -951,7 +950,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -1000,7 +999,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
@@ -1019,7 +1018,7 @@ namespace System
sb.Append(m_Item6);
sb.Append(", ");
sb.Append(m_Item7);
- sb.Append(")");
+ sb.Append(')');
return sb.ToString();
}
@@ -1129,7 +1128,7 @@ namespace System
if (objTuple == null)
{
- throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), "other");
+ throw new ArgumentException(SR.Format(SR.ArgumentException_TupleIncorrectType, this.GetType().ToString()), nameof(other));
}
int c = 0;
@@ -1195,7 +1194,7 @@ namespace System
case 7:
return Tuple.CombineHashCodes(comparer.GetHashCode(m_Item1), comparer.GetHashCode(m_Item2), comparer.GetHashCode(m_Item3), comparer.GetHashCode(m_Item4), comparer.GetHashCode(m_Item5), comparer.GetHashCode(m_Item6), comparer.GetHashCode(m_Item7), t.GetHashCode(comparer));
}
- Debug.Assert(false, "Missed all cases for computing Tuple hash code");
+ Debug.Fail("Missed all cases for computing Tuple hash code");
return -1;
}
@@ -1206,7 +1205,7 @@ namespace System
public override string ToString()
{
StringBuilder sb = new StringBuilder();
- sb.Append("(");
+ sb.Append('(');
return ((ITupleInternal)this).ToString(sb);
}
diff --git a/src/mscorlib/shared/System/Type.cs b/src/mscorlib/shared/System/Type.cs
index ab3d55bc66..6b6a7b3769 100644
--- a/src/mscorlib/shared/System/Type.cs
+++ b/src/mscorlib/shared/System/Type.cs
@@ -41,6 +41,8 @@ namespace System
protected abstract bool IsPointerImpl();
public virtual bool IsConstructedGenericType { get { throw NotImplemented.ByDesign; } }
public virtual bool IsGenericParameter => false;
+ public virtual bool IsGenericTypeParameter => IsGenericParameter && DeclaringMethod == null;
+ public virtual bool IsGenericMethodParameter => IsGenericParameter && DeclaringMethod != null;
public virtual bool IsGenericType => false;
public virtual bool IsGenericTypeDefinition => false;
diff --git a/src/mscorlib/shared/System/TypeAccessException.cs b/src/mscorlib/shared/System/TypeAccessException.cs
index ff081582b6..e12a8b08dd 100644
--- a/src/mscorlib/shared/System/TypeAccessException.cs
+++ b/src/mscorlib/shared/System/TypeAccessException.cs
@@ -8,6 +8,8 @@ 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.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TypeAccessException : TypeLoadException
{
public TypeAccessException()
@@ -30,7 +32,6 @@ namespace System
protected TypeAccessException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/TypeInitializationException.cs b/src/mscorlib/shared/System/TypeInitializationException.cs
index 03a1bad3a7..4bf2906217 100644
--- a/src/mscorlib/shared/System/TypeInitializationException.cs
+++ b/src/mscorlib/shared/System/TypeInitializationException.cs
@@ -19,6 +19,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class TypeInitializationException : SystemException
{
private String _typeName;
@@ -51,9 +53,16 @@ namespace System
HResult = HResults.COR_E_TYPEINITIALIZATION;
}
+ internal TypeInitializationException(SerializationInfo info, StreamingContext context)
+ : base(info, context)
+ {
+ _typeName = info.GetString("TypeName");
+ }
+
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("TypeName", TypeName, typeof(string));
}
public String TypeName
diff --git a/src/mscorlib/shared/System/TypeUnloadedException.cs b/src/mscorlib/shared/System/TypeUnloadedException.cs
index 97039bb8f1..a01ef37a8b 100644
--- a/src/mscorlib/shared/System/TypeUnloadedException.cs
+++ b/src/mscorlib/shared/System/TypeUnloadedException.cs
@@ -6,6 +6,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TypeUnloadedException : SystemException
{
public TypeUnloadedException()
@@ -29,7 +31,6 @@ namespace System
protected TypeUnloadedException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/shared/System/UInt16.cs b/src/mscorlib/shared/System/UInt16.cs
index be61313e30..d437ad95a6 100644
--- a/src/mscorlib/shared/System/UInt16.cs
+++ b/src/mscorlib/shared/System/UInt16.cs
@@ -2,15 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-** Purpose: This class will encapsulate a short and provide an
-** Object representation of it.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/UInt32.cs b/src/mscorlib/shared/System/UInt32.cs
index 3cd016cba1..ca73b61589 100644
--- a/src/mscorlib/shared/System/UInt32.cs
+++ b/src/mscorlib/shared/System/UInt32.cs
@@ -2,16 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-**
-** Purpose: This class will encapsulate an uint and
-** provide an Object representation of it.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/UInt64.cs b/src/mscorlib/shared/System/UInt64.cs
index 175d763308..75b183ac80 100644
--- a/src/mscorlib/shared/System/UInt64.cs
+++ b/src/mscorlib/shared/System/UInt64.cs
@@ -2,15 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-/*============================================================
-**
-**
-** Purpose: This class will encapsulate an unsigned long and
-** provide an Object representation of it.
-**
-**
-===========================================================*/
-
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
diff --git a/src/mscorlib/shared/System/UnauthorizedAccessException.cs b/src/mscorlib/shared/System/UnauthorizedAccessException.cs
index 679a1a762d..a28f6dd73c 100644
--- a/src/mscorlib/shared/System/UnauthorizedAccessException.cs
+++ b/src/mscorlib/shared/System/UnauthorizedAccessException.cs
@@ -18,7 +18,9 @@ using System.Runtime.Serialization;
namespace System
{
// The UnauthorizedAccessException is thrown when access errors
- // occur from IO or other OS methods.
+ // occur from IO or other OS methods.
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class UnauthorizedAccessException : SystemException
{
public UnauthorizedAccessException()
@@ -41,7 +43,6 @@ namespace System
protected UnauthorizedAccessException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs b/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
index 3e485ec6e8..541566c3ff 100644
--- a/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
+++ b/src/mscorlib/src/Internal/Runtime/Augments/EnvironmentAugments.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
-using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
@@ -22,11 +21,6 @@ namespace Internal.Runtime.Augments
public static int TickCount => Environment.TickCount;
public static string GetEnvironmentVariable(string variable) => Environment.GetEnvironmentVariable(variable);
public static string GetEnvironmentVariable(string variable, EnvironmentVariableTarget target) => Environment.GetEnvironmentVariable(variable, target);
- // TODO Perf: Once CoreCLR gets EnumerateEnvironmentVariables(), get rid of GetEnvironmentVariables() and have
- // corefx call EnumerateEnvironmentVariables() instead so we don't have to create a dictionary just to copy it into
- // another dictionary.
- public static IDictionary GetEnvironmentVariables() => new Dictionary<string, string>(EnumerateEnvironmentVariables());
- public static IDictionary GetEnvironmentVariables(EnvironmentVariableTarget target) => new Dictionary<string, string>(EnumerateEnvironmentVariables(target));
public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables() => Environment.EnumerateEnvironmentVariables();
public static IEnumerable<KeyValuePair<string, string>> EnumerateEnvironmentVariables(EnvironmentVariableTarget target) => Environment.EnumerateEnvironmentVariables(target);
diff --git a/src/mscorlib/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs b/src/mscorlib/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs
new file mode 100644
index 0000000000..25c59d743b
--- /dev/null
+++ b/src/mscorlib/src/Interop/Windows/Kernel32/Interop.GetSystemDirectoryW.cs
@@ -0,0 +1,23 @@
+// 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;
+
+internal static partial class Interop
+{
+ internal static partial class Kernel32
+ {
+ [DllImport(Libraries.Kernel32, CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern unsafe int GetSystemDirectoryW(char* lpBuffer, int uSize);
+
+ internal static unsafe int GetSystemDirectoryW(Span<char> buffer)
+ {
+ fixed (char* bufferPtr = &buffer.DangerousGetPinnableReference())
+ {
+ return GetSystemDirectoryW(bufferPtr, buffer.Length);
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/Microsoft/Win32/OAVariantLib.cs b/src/mscorlib/src/Microsoft/Win32/OAVariantLib.cs
index 52224637b0..053507b2d4 100644
--- a/src/mscorlib/src/Microsoft/Win32/OAVariantLib.cs
+++ b/src/mscorlib/src/Microsoft/Win32/OAVariantLib.cs
@@ -100,9 +100,7 @@ namespace Microsoft.Win32
private static int GetCVTypeFromClass(Type ctype)
{
Debug.Assert(ctype != null);
-#if _DEBUG
- BCLDebug.Assert(ClassTypes[CV_OBJECT] == typeof(Object), "OAVariantLib::ClassTypes[CV_OBJECT] == Object.class");
-#endif
+ Debug.Assert(ClassTypes[CV_OBJECT] == typeof(Object), "OAVariantLib::ClassTypes[CV_OBJECT] == Object.class");
int cvtype = -1;
for (int i = 0; i < ClassTypes.Length; i++)
diff --git a/src/mscorlib/src/Microsoft/Win32/Registry.cs b/src/mscorlib/src/Microsoft/Win32/Registry.cs
index d0dbb0ff7f..11f95903af 100644
--- a/src/mscorlib/src/Microsoft/Win32/Registry.cs
+++ b/src/mscorlib/src/Microsoft/Win32/Registry.cs
@@ -4,6 +4,7 @@
using System;
+using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
@@ -123,7 +124,7 @@ namespace Microsoft.Win32
{
string subKeyName;
RegistryKey basekey = GetBaseKeyFromKeyName(keyName, out subKeyName);
- BCLDebug.Assert(basekey != null, "basekey can't be null.");
+ Debug.Assert(basekey != null, "basekey can't be null.");
RegistryKey key = basekey.OpenSubKey(subKeyName);
if (key == null)
{ // if the key doesn't exist, do nothing
diff --git a/src/mscorlib/src/Microsoft/Win32/RegistryKey.cs b/src/mscorlib/src/Microsoft/Win32/RegistryKey.cs
index e314c48167..350880e52f 100644
--- a/src/mscorlib/src/Microsoft/Win32/RegistryKey.cs
+++ b/src/mscorlib/src/Microsoft/Win32/RegistryKey.cs
@@ -216,7 +216,7 @@ namespace Microsoft.Win32
}
// We really should throw an exception here if errorCode was bad,
// but we can't for compatibility reasons.
- BCLDebug.Correctness(errorCode == 0, "RegDeleteValue failed. Here's your error code: " + errorCode);
+ Debug.Assert(errorCode == 0, "RegDeleteValue failed. Here's your error code: " + errorCode);
}
/**
@@ -243,8 +243,8 @@ namespace Microsoft.Win32
internal static RegistryKey GetBaseKey(IntPtr hKey, RegistryView view)
{
int index = ((int)hKey) & 0x0FFFFFFF;
- BCLDebug.Assert(index >= 0 && index < hkeyNames.Length, "index is out of range!");
- BCLDebug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");
+ Debug.Assert(index >= 0 && index < hkeyNames.Length, "index is out of range!");
+ Debug.Assert((((int)hKey) & 0xFFFFFFF0) == 0x80000000, "Invalid hkey value!");
bool isPerf = hKey == HKEY_PERFORMANCE_DATA;
// only mark the SafeHandle as ownsHandle if the key is HKEY_PERFORMANCE_DATA.
@@ -539,7 +539,7 @@ namespace Microsoft.Win32
if (datasize < 0)
{
// unexpected code path
- BCLDebug.Assert(false, "[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
+ Debug.Fail("[InternalGetValue] RegQueryValue returned ERROR_SUCCESS but gave a negative datasize");
datasize = 0;
}
@@ -563,7 +563,7 @@ namespace Microsoft.Win32
goto case Win32Native.REG_BINARY;
}
long blob = 0;
- BCLDebug.Assert(datasize == 8, "datasize==8");
+ Debug.Assert(datasize == 8, "datasize==8");
// Here, datasize must be 8 when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
@@ -578,7 +578,7 @@ namespace Microsoft.Win32
goto case Win32Native.REG_QWORD;
}
int blob = 0;
- BCLDebug.Assert(datasize == 4, "datasize==4");
+ Debug.Assert(datasize == 4, "datasize==4");
// Here, datasize must be four when calling this
ret = Win32Native.RegQueryValueEx(hkey, name, null, ref type, ref blob, ref datasize);
@@ -702,7 +702,7 @@ namespace Microsoft.Win32
if (nextNull < len)
{
- BCLDebug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
+ Debug.Assert(blob[nextNull] == (char)0, "blob[nextNull] should be 0");
if (nextNull - cur > 0)
{
strings.Add(new String(blob, cur, nextNull - cur));
@@ -996,7 +996,7 @@ namespace Microsoft.Win32
internal static String FixupName(String name)
{
- BCLDebug.Assert(name != null, "[FixupName]name!=null");
+ Debug.Assert(name != null, "[FixupName]name!=null");
if (name.IndexOf('\\') == -1)
return name;
diff --git a/src/mscorlib/src/Microsoft/Win32/Win32Native.cs b/src/mscorlib/src/Microsoft/Win32/Win32Native.cs
index eaa9cedfc6..dab609fcb6 100644
--- a/src/mscorlib/src/Microsoft/Win32/Win32Native.cs
+++ b/src/mscorlib/src/Microsoft/Win32/Win32Native.cs
@@ -531,9 +531,6 @@ namespace Microsoft.Win32
[DllImport(Interop.Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Auto, BestFitMapping = false)]
internal static extern SafeWaitHandle OpenSemaphore(uint desiredAccess, bool inheritHandle, string name);
- [DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
- internal static extern int GetSystemDirectory([Out]StringBuilder sb, int length);
-
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); // WinBase.h
// Note, these are #defines used to extract handles, and are NOT handles.
@@ -687,7 +684,15 @@ namespace Microsoft.Win32
internal static extern bool SetEnvironmentVariable(string lpName, string lpValue);
[DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Auto, SetLastError = true, BestFitMapping = false)]
- internal static extern int GetEnvironmentVariable(string lpName, [Out]StringBuilder lpValue, int size);
+ private static extern unsafe int GetEnvironmentVariable(string lpName, char* lpValue, int size);
+
+ internal static unsafe int GetEnvironmentVariable(string lpName, Span<char> lpValue)
+ {
+ fixed (char* lpValuePtr = &lpValue.DangerousGetPinnableReference())
+ {
+ return GetEnvironmentVariable(lpName, lpValuePtr, lpValue.Length);
+ }
+ }
[DllImport(Interop.Libraries.Kernel32, CharSet = CharSet.Unicode)]
internal static unsafe extern char* GetEnvironmentStrings();
diff --git a/src/mscorlib/src/System/AppDomainUnloadedException.cs b/src/mscorlib/src/System/AppDomainUnloadedException.cs
index b673d8c998..597a39c5a1 100644
--- a/src/mscorlib/src/System/AppDomainUnloadedException.cs
+++ b/src/mscorlib/src/System/AppDomainUnloadedException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal class AppDomainUnloadedException : SystemException
{
public AppDomainUnloadedException()
@@ -24,12 +26,8 @@ namespace System
HResult = HResults.COR_E_APPDOMAINUNLOADED;
}
- //
- //This constructor is required for serialization.
- //
protected AppDomainUnloadedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Array.cs b/src/mscorlib/src/System/Array.cs
index 0841d7ac63..7be16c40e4 100644
--- a/src/mscorlib/src/System/Array.cs
+++ b/src/mscorlib/src/System/Array.cs
@@ -2455,7 +2455,7 @@ namespace System
// It is never legal to instantiate this class.
private SZArrayHelper()
{
- Debug.Assert(false, "Hey! How'd I get here?");
+ Debug.Fail("Hey! How'd I get here?");
}
// -----------------------------------------------------------
diff --git a/src/mscorlib/src/System/Attribute.cs b/src/mscorlib/src/System/Attribute.cs
index 37445cc23b..5934284c0f 100644
--- a/src/mscorlib/src/System/Attribute.cs
+++ b/src/mscorlib/src/System/Attribute.cs
@@ -627,7 +627,7 @@ namespace System
return element.IsDefined(attributeType, false);
default:
- Debug.Assert(false, "Invalid type for ParameterInfo member in Attribute class");
+ Debug.Fail("Invalid type for ParameterInfo member in Attribute class");
throw new ArgumentException(SR.Argument_InvalidParamInfo);
}
}
diff --git a/src/mscorlib/src/System/BCLDebug.cs b/src/mscorlib/src/System/BCLDebug.cs
index 9170a55c38..e9435aff2f 100644
--- a/src/mscorlib/src/System/BCLDebug.cs
+++ b/src/mscorlib/src/System/BCLDebug.cs
@@ -48,12 +48,6 @@ namespace System
{
internal static volatile bool m_registryChecked = false;
internal static volatile bool m_loggingNotEnabled = false;
- internal static bool m_perfWarnings;
- internal static bool m_correctnessWarnings;
- internal static bool m_safeHandleStackTraces;
-#if _DEBUG
- internal static volatile bool m_domainUnloadAdded;
-#endif
private static readonly SwitchStructure[] switches = {
new SwitchStructure("NLS", 0x00000001),
@@ -86,40 +80,6 @@ namespace System
LogLevel.Trace
};
-
-#if _DEBUG
- internal static void WaitForFinalizers(Object sender, EventArgs e)
- {
- if (!m_registryChecked)
- {
- CheckRegistry();
- }
- if (m_correctnessWarnings)
- {
- GC.GetTotalMemory(true);
- GC.WaitForPendingFinalizers();
- }
- }
-#endif
- [Conditional("_DEBUG")]
- static public void Assert(bool condition)
- {
-#if _DEBUG
- Assert(condition, "Assert failed.");
-#endif
- }
-
- [Conditional("_DEBUG")]
- static public void Assert(bool condition, String message)
- {
-#if _DEBUG
- // Speed up debug builds marginally by avoiding the garbage from
- // concatinating "BCL Assert: " and the message.
- if (!condition)
- System.Diagnostics.Assert.Check(condition, "BCL Assert", message);
-#endif
- }
-
[Conditional("_LOGGING")]
static public void Log(String message)
{
@@ -165,7 +125,7 @@ namespace System
// just a small helper in native code instead of that.
//
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- private extern static int GetRegistryLoggingValues(out bool loggingEnabled, out bool logToConsole, out int logLevel, out bool perfWarnings, out bool correctnessWarnings, out bool safeHandleStackTraces);
+ private extern static int GetRegistryLoggingValues(out bool loggingEnabled, out bool logToConsole, out int logLevel);
private static void CheckRegistry()
{
@@ -182,7 +142,7 @@ namespace System
bool logToConsole;
int logLevel;
int facilityValue;
- facilityValue = GetRegistryLoggingValues(out loggingEnabled, out logToConsole, out logLevel, out m_perfWarnings, out m_correctnessWarnings, out m_safeHandleStackTraces);
+ facilityValue = GetRegistryLoggingValues(out loggingEnabled, out logToConsole, out logLevel);
// Note we can get into some recursive situations where we call
// ourseves recursively through the .cctor. That's why we have the
@@ -198,7 +158,7 @@ namespace System
//The values returned for the logging levels in the registry don't map nicely onto the
//values which we support internally (which are an approximation of the ones that
//the System.Diagnostics namespace uses) so we have a quick map.
- Assert(logLevel >= 0 && logLevel <= 10, "logLevel>=0 && logLevel<=10");
+ Debug.Assert(logLevel >= 0 && logLevel <= 10, "logLevel>=0 && logLevel<=10");
logLevel = (int)levelConversions[logLevel];
if (facilityValue > 0)
@@ -314,70 +274,6 @@ namespace System
System.Diagnostics.Log.LogMessage(LoggingLevels.TraceLevel0, logSwitch, StringBuilderCache.GetStringAndRelease(sb));
}
-
- // For perf-related asserts. On a debug build, set the registry key
- // BCLPerfWarnings to non-zero.
- [Conditional("_DEBUG")]
- internal static void Perf(bool expr, String msg)
- {
- if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
- return;
- if (!m_registryChecked)
- CheckRegistry();
- if (!m_perfWarnings)
- return;
-
- if (!expr)
- {
- Log("PERF", "BCL Perf Warning: " + msg);
- }
- System.Diagnostics.Assert.Check(expr, "BCL Perf Warning: Your perf may be less than perfect because...", msg);
- }
-
- // For correctness-related asserts. On a debug build, set the registry key
- // BCLCorrectnessWarnings to non-zero.
- [Conditional("_DEBUG")]
-#if _DEBUG
-#endif
- internal static void Correctness(bool expr, String msg)
- {
-#if _DEBUG
- if (AppDomain.CurrentDomain.IsUnloadingForcedFinalize())
- return;
- if (!m_registryChecked)
- CheckRegistry();
- if (!m_correctnessWarnings)
- return;
-
- if (!m_domainUnloadAdded)
- {
- m_domainUnloadAdded = true;
- AppDomain.CurrentDomain.DomainUnload += new EventHandler(WaitForFinalizers);
- }
-
- if (!expr)
- {
- Log("CORRECTNESS", "BCL Correctness Warning: " + msg);
- }
- System.Diagnostics.Assert.Check(expr, "BCL Correctness Warning: Your program may not work because...", msg);
-#endif
- }
-
- // Whether SafeHandles include a stack trace showing where they
- // were allocated. Only useful in checked & debug builds.
- internal static bool SafeHandleStackTracesEnabled
- {
- get
- {
-#if _DEBUG
- if (!m_registryChecked)
- CheckRegistry();
- return m_safeHandleStackTraces;
-#else
- return false;
-#endif
- }
- }
}
}
diff --git a/src/mscorlib/src/System/Buffer.cs b/src/mscorlib/src/System/Buffer.cs
index 1a5a4b6ad9..b21ee7132f 100644
--- a/src/mscorlib/src/System/Buffer.cs
+++ b/src/mscorlib/src/System/Buffer.cs
@@ -263,9 +263,9 @@ namespace System
const nuint CopyThreshold = 2048;
#elif ARM64
#if PLATFORM_WINDOWS
- // TODO-ARM64-WINDOWS-OPT determine optimal value for Windows
+ // Determined optimal value for Windows.
// https://github.com/dotnet/coreclr/issues/13843
- const nuint CopyThreshold = 2048;
+ const nuint CopyThreshold = UInt64.MaxValue;
#else // PLATFORM_WINDOWS
// Managed code is currently faster than glibc unoptimized memmove
// TODO-ARM64-UNIX-OPT revisit when glibc optimized memmove is in Linux distros
diff --git a/src/mscorlib/src/System/Collections/Generic/Comparer.cs b/src/mscorlib/src/System/Collections/Generic/Comparer.cs
index bb9e07d491..d3ec0ddce8 100644
--- a/src/mscorlib/src/System/Collections/Generic/Comparer.cs
+++ b/src/mscorlib/src/System/Collections/Generic/Comparer.cs
@@ -2,15 +2,9 @@
// 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.Collections;
-using System.Collections.Generic;
using System.Diagnostics;
-//using System.Globalization;
using System.Runtime.CompilerServices;
-using System.Security;
using System.Runtime.Serialization;
namespace System.Collections.Generic
@@ -50,7 +44,7 @@ namespace System.Collections.Generic
// means another generic instantiation, which can be costly esp.
// for value types.
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class GenericComparer<T> : Comparer<T> where T : IComparable<T>
{
public override int Compare(T x, T y)
@@ -65,7 +59,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -73,7 +67,7 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class NullableComparer<T> : Comparer<T?> where T : struct, IComparable<T>
{
public override int Compare(T? x, T? y)
@@ -88,7 +82,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -96,7 +90,7 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class ObjectComparer<T> : Comparer<T>
{
public override int Compare(T x, T y)
@@ -105,7 +99,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -133,7 +127,6 @@ namespace System.Collections.Generic
// since we want to serialize as ObjectComparer for
// back-compat reasons (see below).
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class Int32EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public Int32EnumComparer()
@@ -152,7 +145,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -169,7 +162,6 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class UInt32EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public UInt32EnumComparer()
@@ -188,7 +180,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -201,7 +193,6 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class Int64EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public Int64EnumComparer()
@@ -217,7 +208,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -230,7 +221,6 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class UInt64EnumComparer<T> : Comparer<T>, ISerializable where T : struct
{
public UInt64EnumComparer()
@@ -249,7 +239,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
diff --git a/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs
index 1c4b9bbc09..2575d4e346 100644
--- a/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs
+++ b/src/mscorlib/src/System/Collections/Generic/ComparerHelpers.cs
@@ -187,17 +187,13 @@ namespace System.Collections.Generic
TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType));
// Depending on the enum type, we need to special case the comparers so that we avoid boxing.
- // Note: We have different comparers for short and sbyte, since for those types GetHashCode does not simply return the value.
- // We need to preserve what they would return.
switch (underlyingTypeCode)
{
- case TypeCode.Int16:
- return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ShortEnumEqualityComparer<short>), enumType);
- case TypeCode.SByte:
- return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(SByteEnumEqualityComparer<sbyte>), enumType);
case TypeCode.Int32:
case TypeCode.UInt32:
+ case TypeCode.SByte:
case TypeCode.Byte:
+ case TypeCode.Int16:
case TypeCode.UInt16:
return RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<int>), enumType);
case TypeCode.Int64:
diff --git a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
index 06af626526..57b63eb0e1 100644
--- a/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
+++ b/src/mscorlib/src/System/Collections/Generic/EqualityComparer.cs
@@ -67,8 +67,8 @@ namespace System.Collections.Generic
// The methods in this class look identical to the inherited methods, but the calls
// to Equal bind to IEquatable<T>.Equals(T) instead of Object.Equals(Object)
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ internal sealed class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(T x, T y)
@@ -127,7 +127,7 @@ namespace System.Collections.Generic
// Equals method for the comparer itself.
// If in the future this type is made sealed, change the is check to obj != null && GetType() == obj.GetType().
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj is GenericEqualityComparer<T>;
// If in the future this type is made sealed, change typeof(...) to GetType().
@@ -136,7 +136,7 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class NullableEqualityComparer<T> : EqualityComparer<T?> where T : struct, IEquatable<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -195,7 +195,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -203,7 +203,7 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class ObjectEqualityComparer<T> : EqualityComparer<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -262,45 +262,17 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
GetType().GetHashCode();
}
- // We use NonRandomizedStringEqualityComparer as default comparer as it doesnt use the randomized string hashing which
- // keeps the performance unaffected till we hit collision threshold and then we switch to the comparer which is using
- // randomized string hashing GenericEqualityComparer<string>
- [Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal class NonRandomizedStringEqualityComparer : GenericEqualityComparer<string>
- {
- private static IEqualityComparer<string> s_nonRandomizedComparer;
-
- internal static new IEqualityComparer<string> Default
- {
- get
- {
- if (s_nonRandomizedComparer == null)
- {
- s_nonRandomizedComparer = new NonRandomizedStringEqualityComparer();
- }
- return s_nonRandomizedComparer;
- }
- }
-
- public override int GetHashCode(string obj)
- {
- if (obj == null) return 0;
- return obj.GetLegacyNonRandomizedHashCode();
- }
- }
-
// Performance of IndexOf on byte array is very important for some scenarios.
// We will call the C runtime function memchr, which is optimized.
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
internal sealed class ByteEqualityComparer : EqualityComparer<byte>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -343,7 +315,7 @@ namespace System.Collections.Generic
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -351,9 +323,22 @@ namespace System.Collections.Generic
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+ internal sealed class EnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
{
+ internal EnumEqualityComparer() { }
+
+ // This is used by the serialization engine.
+ private EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
+
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer
+ if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) {
+ info.SetType(typeof(ObjectEqualityComparer<T>));
+ }
+ }
+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(T x, T y)
{
@@ -365,17 +350,11 @@ namespace System.Collections.Generic
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode(T obj)
{
- int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
- return x_final.GetHashCode();
+ return obj.GetHashCode();
}
- public EnumEqualityComparer() { }
-
- // This is used by the serialization engine.
- protected EnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
-
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
@@ -404,54 +383,23 @@ namespace System.Collections.Generic
}
return -1;
}
-
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- // For back-compat we need to serialize the comparers for enums with underlying types other than int as ObjectEqualityComparer
- if (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))) != TypeCode.Int32) {
- info.SetType(typeof(ObjectEqualityComparer<T>));
- }
- }
- }
-
- [Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal sealed class SByteEnumEqualityComparer<T> : EnumEqualityComparer<T> where T : struct
- {
- public SByteEnumEqualityComparer() { }
-
- // This is used by the serialization engine.
- public SByteEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override int GetHashCode(T obj)
- {
- int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
- return ((sbyte)x_final).GetHashCode();
- }
}
[Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal sealed class ShortEnumEqualityComparer<T> : EnumEqualityComparer<T>, ISerializable where T : struct
+ internal sealed class LongEnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
{
- public ShortEnumEqualityComparer() { }
+ internal LongEnumEqualityComparer() { }
// This is used by the serialization engine.
- public ShortEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
+ private LongEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public override int GetHashCode(T obj)
+ public void GetObjectData(SerializationInfo info, StreamingContext context)
{
- int x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCast(obj);
- return ((short)x_final).GetHashCode();
+ // The LongEnumEqualityComparer does not exist on 4.0 so we need to serialize this comparer as ObjectEqualityComparer
+ // to allow for roundtrip between 4.0 and 4.5.
+ info.SetType(typeof(ObjectEqualityComparer<T>));
}
- }
- [Serializable]
- [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
- internal sealed class LongEnumEqualityComparer<T> : EqualityComparer<T>, ISerializable where T : struct
- {
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(T x, T y)
{
@@ -463,19 +411,16 @@ namespace System.Collections.Generic
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode(T obj)
{
- long x_final = System.Runtime.CompilerServices.JitHelpers.UnsafeEnumCastLong(obj);
- return x_final.GetHashCode();
+ return obj.GetHashCode();
}
// Equals method for the comparer itself.
- public override bool Equals(Object obj) =>
+ public override bool Equals(object obj) =>
obj != null && GetType() == obj.GetType();
public override int GetHashCode() =>
GetType().GetHashCode();
- public LongEnumEqualityComparer() { }
-
internal override int IndexOf(T[] array, T value, int startIndex, int count)
{
long toFind = JitHelpers.UnsafeEnumCastLong(value);
@@ -499,15 +444,5 @@ namespace System.Collections.Generic
}
return -1;
}
-
- // This is used by the serialization engine.
- public LongEnumEqualityComparer(SerializationInfo information, StreamingContext context) { }
-
- public void GetObjectData(SerializationInfo info, StreamingContext context)
- {
- // The LongEnumEqualityComparer does not exist on 4.0 so we need to serialize this comparer as ObjectEqualityComparer
- // to allow for roundtrip between 4.0 and 4.5.
- info.SetType(typeof(ObjectEqualityComparer<T>));
- }
}
}
diff --git a/src/mscorlib/src/System/Collections/Hashtable.cs b/src/mscorlib/src/System/Collections/Hashtable.cs
index 0550030e7c..6a23fde786 100644
--- a/src/mscorlib/src/System/Collections/Hashtable.cs
+++ b/src/mscorlib/src/System/Collections/Hashtable.cs
@@ -123,7 +123,6 @@ namespace System.Collections
--
*/
- internal const Int32 HashPrime = 101;
private const Int32 InitialSize = 3;
private const String LoadFactorName = "LoadFactor";
private const String VersionName = "Version";
@@ -268,7 +267,7 @@ namespace System.Collections
// visit every bucket in the table exactly once within hashsize
// iterations. Violate this and it'll cause obscure bugs forever.
// If you change this calculation for h2(key), update putEntry too!
- incr = (uint)(1 + ((seed * HashPrime) % ((uint)hashsize - 1)));
+ incr = (uint)(1 + ((seed * HashHelpers.HashPrime) % ((uint)hashsize - 1)));
return hashcode;
}
@@ -475,7 +474,7 @@ namespace System.Collections
// (3) compare the key, if equal, go to step 4. Otherwise end.
// (4) return the value contained in the bucket.
// After step 3 and before step 4. A writer can kick in a remove the old item and add a new one
- // in the same bukcet. So in the reader we need to check if the hash table is modified during above steps.
+ // in the same bucket. So in the reader we need to check if the hash table is modified during above steps.
//
// Writers (Insert, Remove, Clear) will set 'isWriterInProgress' flag before it starts modifying
// the hashtable and will ckear the flag when it is done. When the flag is cleared, the 'version'
@@ -797,7 +796,7 @@ namespace System.Collections
// If you see this assert, make sure load factor & count are reasonable.
// Then verify that our double hash function (h2, described at top of file)
// meets the requirements described above. You should never see this assert.
- Debug.Assert(false, "hash table insert failed! Load factor too high, or our double hashing function is incorrect.");
+ Debug.Fail("hash table insert failed! Load factor too high, or our double hashing function is incorrect.");
throw new InvalidOperationException(SR.InvalidOperation_HashInsertFailed);
}
@@ -806,7 +805,7 @@ namespace System.Collections
Debug.Assert(hashcode >= 0, "hashcode >= 0"); // make sure collision bit (sign bit) wasn't set.
uint seed = (uint)hashcode;
- uint incr = (uint)(1 + ((seed * HashPrime) % ((uint)newBuckets.Length - 1)));
+ uint incr = (uint)(1 + ((seed * HashHelpers.HashPrime) % ((uint)newBuckets.Length - 1)));
int bucketNumber = (int)(seed % (uint)newBuckets.Length);
do
{
@@ -1378,102 +1377,4 @@ namespace System.Collections
private Hashtable hashtable;
}
}
-
- [FriendAccessAllowed]
- internal static class HashHelpers
- {
- public const int HashCollisionThreshold = 100;
-
- // Table of prime numbers to use as hash table sizes.
- // A typical resize algorithm would pick the smallest prime number in this array
- // that is larger than twice the previous capacity.
- // Suppose our Hashtable currently has capacity x and enough elements are added
- // such that a resize needs to occur. Resizing first computes 2x then finds the
- // first prime in the table greater than 2x, i.e. if primes are ordered
- // p_1, p_2, ..., p_i, ..., it finds p_n such that p_n-1 < 2x < p_n.
- // Doubling is important for preserving the asymptotic complexity of the
- // hashtable operations such as add. Having a prime guarantees that double
- // hashing does not lead to infinite loops. IE, your hash function will be
- // h1(key) + i*h2(key), 0 <= i < size. h2 and the size must be relatively prime.
- public static readonly int[] primes = {
- 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919,
- 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
- 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437,
- 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
- 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369};
-
- // Used by Hashtable and Dictionary's SeralizationInfo .ctor's to store the SeralizationInfo
- // object until OnDeserialization is called.
- private static ConditionalWeakTable<object, SerializationInfo> s_SerializationInfoTable;
-
- internal static ConditionalWeakTable<object, SerializationInfo> SerializationInfoTable
- {
- get
- {
- if (s_SerializationInfoTable == null)
- {
- ConditionalWeakTable<object, SerializationInfo> newTable = new ConditionalWeakTable<object, SerializationInfo>();
- Interlocked.CompareExchange(ref s_SerializationInfoTable, newTable, null);
- }
-
- return s_SerializationInfoTable;
- }
- }
-
- public static bool IsPrime(int candidate)
- {
- if ((candidate & 1) != 0)
- {
- int limit = (int)Math.Sqrt(candidate);
- for (int divisor = 3; divisor <= limit; divisor += 2)
- {
- if ((candidate % divisor) == 0)
- return false;
- }
- return true;
- }
- return (candidate == 2);
- }
-
- public static int GetPrime(int min)
- {
- if (min < 0)
- throw new ArgumentException(SR.Arg_HTCapacityOverflow);
-
- for (int i = 0; i < primes.Length; i++)
- {
- int prime = primes[i];
- if (prime >= min) return prime;
- }
-
- //outside of our predefined table.
- //compute the hard way.
- for (int i = (min | 1); i < Int32.MaxValue; i += 2)
- {
- if (IsPrime(i) && ((i - 1) % Hashtable.HashPrime != 0))
- return i;
- }
- return min;
- }
-
- // Returns size of hashtable to grow to.
- public static int ExpandPrime(int oldSize)
- {
- int newSize = 2 * oldSize;
-
- // Allow the hashtables to grow to maximum possible size (~2G elements) before encoutering capacity overflow.
- // Note that this check works even when _items.Length overflowed thanks to the (uint) cast
- if ((uint)newSize > MaxPrimeArrayLength && MaxPrimeArrayLength > oldSize)
- {
- Debug.Assert(MaxPrimeArrayLength == GetPrime(MaxPrimeArrayLength), "Invalid MaxPrimeArrayLength");
- return MaxPrimeArrayLength;
- }
-
- return GetPrime(newSize);
- }
-
-
- // This is the maximum prime smaller than Array.MaxArrayLength
- public const int MaxPrimeArrayLength = 0x7FEFFFFD;
- }
}
diff --git a/src/mscorlib/src/System/Delegate.cs b/src/mscorlib/src/System/Delegate.cs
index 188657aa7a..72586143dc 100644
--- a/src/mscorlib/src/System/Delegate.cs
+++ b/src/mscorlib/src/System/Delegate.cs
@@ -257,7 +257,7 @@ namespace System
// RCWs don't need to be "strongly-typed" in which case we don't find a base type
// that matches the declaring type of the method. This is fine because interop needs
// to work with exact methods anyway so declaringType is never shared at this point.
- BCLDebug.Assert(currentType != null || _target.GetType().IsCOMObject, "The class hierarchy should declare the method");
+ Debug.Assert(currentType != null || _target.GetType().IsCOMObject, "The class hierarchy should declare the method");
}
else
{
diff --git a/src/mscorlib/src/System/Diagnostics/Contracts/Contracts.cs b/src/mscorlib/src/System/Diagnostics/Contracts/Contracts.cs
index 5b74f601b1..dc1dcb67cf 100644
--- a/src/mscorlib/src/System/Diagnostics/Contracts/Contracts.cs
+++ b/src/mscorlib/src/System/Diagnostics/Contracts/Contracts.cs
@@ -774,6 +774,7 @@ namespace System.Diagnostics.Contracts
#endregion
}
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public enum ContractFailureKind
{
Precondition,
diff --git a/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs b/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
index e4bbe1d71e..e7cc2570d9 100644
--- a/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
+++ b/src/mscorlib/src/System/Diagnostics/Contracts/ContractsBCL.cs
@@ -185,21 +185,28 @@ namespace System.Diagnostics.Contracts
}
}
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
+#if CORECLR
[SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")]
- internal sealed class ContractException : Exception
+ internal
+#else
+ public // On CoreRT this must be public to support binary serialization with type forwarding.
+#endif
+ sealed class ContractException : Exception
{
- private readonly ContractFailureKind _Kind;
- private readonly string _UserMessage;
- private readonly string _Condition;
+ private readonly ContractFailureKind _kind;
+ private readonly string _userMessage;
+ private readonly string _condition;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public ContractFailureKind Kind { get { return _Kind; } }
+ public ContractFailureKind Kind { get { return _kind; } }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
public string Failure { get { return this.Message; } }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public string UserMessage { get { return _UserMessage; } }
+ public string UserMessage { get { return _userMessage; } }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
- public string Condition { get { return _Condition; } }
+ public string Condition { get { return _condition; } }
// Called by COM Interop, if we see COR_E_CODECONTRACTFAILED as an HRESULT.
private ContractException()
@@ -211,14 +218,26 @@ namespace System.Diagnostics.Contracts
: base(failure, innerException)
{
HResult = System.Runtime.CompilerServices.ContractHelper.COR_E_CODECONTRACTFAILED;
- _Kind = kind;
- _UserMessage = userMessage;
- _Condition = condition;
+ _kind = kind;
+ _userMessage = userMessage;
+ _condition = condition;
+ }
+
+ private ContractException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
+ : base(info, context)
+ {
+ _kind = (ContractFailureKind)info.GetInt32("Kind");
+ _userMessage = info.GetString("UserMessage");
+ _condition = info.GetString("Condition");
}
+
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("Kind", _kind);
+ info.AddValue("UserMessage", _userMessage);
+ info.AddValue("Condition", _condition);
}
}
}
@@ -228,14 +247,14 @@ namespace System.Runtime.CompilerServices
{
public static partial class ContractHelper
{
- #region Private fields
+#region Private fields
private static volatile EventHandler<ContractFailedEventArgs> contractFailedEvent;
private static readonly Object lockObject = new Object();
internal const int COR_E_CODECONTRACTFAILED = unchecked((int)0x80131542);
- #endregion
+#endregion
/// <summary>
/// Allows a managed application environment such as an interactive interpreter (IronPython) or a
diff --git a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
index 022c72ce01..e2588392e4 100644
--- a/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
+++ b/src/mscorlib/src/System/Diagnostics/Stacktrace.cs
@@ -537,7 +537,8 @@ namespace System.Diagnostics
{
StackFrame sf = GetFrame(iFrameIndex);
MethodBase mb = sf.GetMethod();
- if (mb != null)
+ if (mb != null && (ShowInStackTrace(mb) ||
+ (iFrameIndex == m_iNumOfFrames - 1))) // Don't filter last frame
{
// We want a newline at the end of every line except for the last
if (fFirstFrame)
@@ -657,6 +658,12 @@ namespace System.Diagnostics
return sb.ToString();
}
+ private static bool ShowInStackTrace(MethodBase mb)
+ {
+ Debug.Assert(mb != null);
+ return !(mb.IsDefined(typeof(StackTraceHiddenAttribute)) || (mb.DeclaringType?.IsDefined(typeof(StackTraceHiddenAttribute)) ?? false));
+ }
+
// This helper is called from within the EE to construct a string representation
// of the current stack trace.
private static String GetManagedStackTraceStringHelper(bool fNeedFileInfo)
diff --git a/src/mscorlib/src/System/Enum.cs b/src/mscorlib/src/System/Enum.cs
index 96bf31c889..af6cc9c148 100644
--- a/src/mscorlib/src/System/Enum.cs
+++ b/src/mscorlib/src/System/Enum.cs
@@ -340,7 +340,7 @@ namespace System
return m_innerException;
default:
- Debug.Assert(false, "Unknown EnumParseFailure: " + m_failure);
+ Debug.Fail("Unknown EnumParseFailure: " + m_failure);
return new ArgumentException(SR.Arg_EnumValueNotFound);
}
}
@@ -757,7 +757,7 @@ namespace System
case CorElementType.U:
return *(UIntPtr*)pValue;
default:
- Debug.Assert(false, "Invalid primitive type");
+ Debug.Fail("Invalid primitive type");
return null;
}
}
@@ -809,7 +809,7 @@ namespace System
return *(uint*)pValue;
}
default:
- Debug.Assert(false, "Invalid primitive type");
+ Debug.Fail("Invalid primitive type");
return 0;
}
}
@@ -866,7 +866,7 @@ namespace System
case CorElementType.U:
return (*(UIntPtr*)pValue).GetHashCode();
default:
- Debug.Assert(false, "Invalid primitive type");
+ Debug.Fail("Invalid primitive type");
return 0;
}
}
diff --git a/src/mscorlib/src/System/Environment.Windows.cs b/src/mscorlib/src/System/Environment.Windows.cs
new file mode 100644
index 0000000000..5bf7bea158
--- /dev/null
+++ b/src/mscorlib/src/System/Environment.Windows.cs
@@ -0,0 +1,34 @@
+// 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.IO;
+
+namespace System
+{
+ internal static partial class Environment
+ {
+ internal static string SystemDirectory
+ {
+ get
+ {
+ // The path will likely be under 32 characters, e.g. C:\Windows\system32
+ Span<char> buffer = stackalloc char[32];
+ int requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
+
+ if (requiredSize > buffer.Length)
+ {
+ buffer = new char[requiredSize];
+ requiredSize = Interop.Kernel32.GetSystemDirectoryW(buffer);
+ }
+
+ if (requiredSize == 0)
+ {
+ throw Win32Marshal.GetExceptionForLastWin32Error();
+ }
+
+ return new string(buffer.Slice(0, requiredSize));
+ }
+ }
+ }
+}
diff --git a/src/mscorlib/src/System/Environment.cs b/src/mscorlib/src/System/Environment.cs
index 4ea73e4d9c..f230577fac 100644
--- a/src/mscorlib/src/System/Environment.cs
+++ b/src/mscorlib/src/System/Environment.cs
@@ -14,6 +14,7 @@
namespace System
{
+ using System.Buffers;
using System.IO;
using System.Security;
using System.Resources;
@@ -115,21 +116,6 @@ namespace System
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public static extern void FailFast(String message, Exception exception);
- // Returns the system directory (ie, C:\WinNT\System32).
- internal static String SystemDirectory
- {
- get
- {
- StringBuilder sb = new StringBuilder(Path.MaxPath);
- int r = Win32Native.GetSystemDirectory(sb, Path.MaxPath);
- Debug.Assert(r < Path.MaxPath, "r < Path.MaxPath");
- if (r == 0) throw Win32Marshal.GetExceptionForLastWin32Error();
- String path = sb.ToString();
-
- return path;
- }
- }
-
public static String ExpandEnvironmentVariables(String name)
{
if (name == null)
@@ -536,23 +522,33 @@ namespace System
private static string GetEnvironmentVariableCore(string variable)
{
- StringBuilder sb = StringBuilderCache.Acquire(128); // A somewhat reasonable default size
- int requiredSize = Win32Native.GetEnvironmentVariable(variable, sb, sb.Capacity);
+ Span<char> buffer = stackalloc char[128]; // A somewhat reasonable default size
+ return GetEnvironmentVariableCoreHelper(variable, buffer);
+ }
+
+ private static string GetEnvironmentVariableCoreHelper(string variable, Span<char> buffer)
+ {
+ int requiredSize = Win32Native.GetEnvironmentVariable(variable, buffer);
if (requiredSize == 0 && Marshal.GetLastWin32Error() == Win32Native.ERROR_ENVVAR_NOT_FOUND)
{
- StringBuilderCache.Release(sb);
return null;
}
- while (requiredSize > sb.Capacity)
+ if (requiredSize > buffer.Length)
{
- sb.Capacity = requiredSize;
- sb.Length = 0;
- requiredSize = Win32Native.GetEnvironmentVariable(variable, sb, sb.Capacity);
+ char[] chars = ArrayPool<char>.Shared.Rent(requiredSize);
+ try
+ {
+ return GetEnvironmentVariableCoreHelper(variable, chars);
+ }
+ finally
+ {
+ ArrayPool<char>.Shared.Return(chars);
+ }
}
- return StringBuilderCache.GetStringAndRelease(sb);
+ return new string(buffer.Slice(0, requiredSize));
}
private static string GetEnvironmentVariableCore(string variable, EnvironmentVariableTarget target)
@@ -577,7 +573,6 @@ namespace System
}
else if (target == EnvironmentVariableTarget.User)
{
- Debug.Assert(target == EnvironmentVariableTarget.User);
baseKey = Registry.CurrentUser;
keyName = "Environment";
}
@@ -667,7 +662,6 @@ namespace System
}
else if (target == EnvironmentVariableTarget.User)
{
- Debug.Assert(target == EnvironmentVariableTarget.User);
baseKey = Registry.CurrentUser;
keyName = @"Environment";
}
@@ -745,8 +739,6 @@ namespace System
}
else if (target == EnvironmentVariableTarget.User)
{
- Debug.Assert(target == EnvironmentVariableTarget.User);
-
// User-wide environment variables stored in the registry are limited to 255 chars for the environment variable name.
const int MaxUserEnvVariableLength = 255;
if (variable.Length >= MaxUserEnvVariableLength)
@@ -781,7 +773,7 @@ namespace System
IntPtr r = Interop.User32.SendMessageTimeout(new IntPtr(Interop.User32.HWND_BROADCAST),
Interop.User32.WM_SETTINGCHANGE, IntPtr.Zero, "Environment", 0, 1000, IntPtr.Zero);
- if (r == IntPtr.Zero) Debug.Assert(false, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
+ Debug.Assert(r != IntPtr.Zero, "SetEnvironmentVariable failed: " + Marshal.GetLastWin32Error());
#endif // FEATURE_WIN32_REGISTRY
}
}
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.Unix.cs b/src/mscorlib/src/System/Globalization/CompareInfo.Unix.cs
index 612c99e98e..fb64e4f407 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.Unix.cs
+++ b/src/mscorlib/src/System/Globalization/CompareInfo.Unix.cs
@@ -143,20 +143,31 @@ namespace System.Globalization
return Interop.GlobalizationInterop.CompareStringOrdinalIgnoreCase(string1, count1, string2, count2);
}
- private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ // TODO https://github.com/dotnet/coreclr/issues/13827:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
{
Debug.Assert(!_invariantMode);
-
- Debug.Assert(string1 != null);
Debug.Assert(string2 != null);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
- fixed (char* pString1 = string1)
+ fixed (char* pString1 = &string1.DangerousGetPinnableReference())
+ fixed (char* pString2 = &string2.GetRawStringData())
{
- fixed (char* pString2 = string2)
- {
- return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1 + offset1, length1, pString2 + offset2, length2, options);
- }
+ return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options);
+ }
+ }
+
+ private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
+
+ fixed (char* pString1 = &string1.DangerousGetPinnableReference())
+ fixed (char* pString2 = &string2.DangerousGetPinnableReference())
+ {
+ return Interop.GlobalizationInterop.CompareString(_sortHandle, pString1, string1.Length, pString2, string2.Length, options);
}
}
diff --git a/src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs b/src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs
index 6fdb8b20e6..ff0c240b6e 100644
--- a/src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs
+++ b/src/mscorlib/src/System/Globalization/CompareInfo.Windows.cs
@@ -116,27 +116,60 @@ namespace System.Globalization
return Interop.Kernel32.CompareStringOrdinal(string1, count1, string2, count2, true) - 2;
}
- private unsafe int CompareString(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
+ // TODO https://github.com/dotnet/coreclr/issues/13827:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
{
+ Debug.Assert(string2 != null);
Debug.Assert(!_invariantMode);
+ Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
- Debug.Assert(string1 != null);
- Debug.Assert(string2 != null);
+ string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
+
+ fixed (char* pLocaleName = localeName)
+ fixed (char* pString1 = &string1.DangerousGetPinnableReference())
+ fixed (char* pString2 = &string2.GetRawStringData())
+ {
+ int result = Interop.Kernel32.CompareStringEx(
+ pLocaleName,
+ (uint)GetNativeCompareFlags(options),
+ pString1,
+ string1.Length,
+ pString2,
+ string2.Length,
+ null,
+ null,
+ _sortHandle);
+
+ if (result == 0)
+ {
+ Environment.FailFast("CompareStringEx failed");
+ }
+
+ // Map CompareStringEx return value to -1, 0, 1.
+ return result - 2;
+ }
+ }
+
+ private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ {
+ Debug.Assert(!_invariantMode);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
string localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
fixed (char* pLocaleName = localeName)
- fixed (char* pString1 = string1)
- fixed (char* pString2 = string2)
+ fixed (char* pString1 = &string1.DangerousGetPinnableReference())
+ fixed (char* pString2 = &string2.DangerousGetPinnableReference())
{
int result = Interop.Kernel32.CompareStringEx(
pLocaleName,
(uint)GetNativeCompareFlags(options),
- pString1 + offset1,
- length1,
- pString2 + offset2,
- length2,
+ pString1,
+ string1.Length,
+ pString2,
+ string2.Length,
null,
null,
_sortHandle);
diff --git a/src/mscorlib/src/System/IO/BinaryReader.cs b/src/mscorlib/src/System/IO/BinaryReader.cs
index 33ff5fa503..c5cd6cb6bf 100644
--- a/src/mscorlib/src/System/IO/BinaryReader.cs
+++ b/src/mscorlib/src/System/IO/BinaryReader.cs
@@ -346,12 +346,12 @@ namespace System.IO
return InternalReadChars(new Span<char>(buffer, index, count));
}
- public virtual int Read(Span<char> destination)
+ public virtual int Read(Span<char> buffer)
{
if (_stream == null)
__Error.FileNotOpen();
- return InternalReadChars(destination);
+ return InternalReadChars(buffer);
}
private int InternalReadChars(Span<char> buffer)
@@ -560,12 +560,12 @@ namespace System.IO
return _stream.Read(buffer, index, count);
}
- public virtual int Read(Span<byte> destination)
+ public virtual int Read(Span<byte> buffer)
{
if (_stream == null)
__Error.FileNotOpen();
- return _stream.Read(destination);
+ return _stream.Read(buffer);
}
public virtual byte[] ReadBytes(int count)
diff --git a/src/mscorlib/src/System/IO/File.cs b/src/mscorlib/src/System/IO/File.cs
index b393feac3f..6754baae16 100644
--- a/src/mscorlib/src/System/IO/File.cs
+++ b/src/mscorlib/src/System/IO/File.cs
@@ -193,7 +193,7 @@ namespace System.IO
// if we're already returning an error, don't throw another one.
if (!error)
{
- Debug.Assert(false, "File::FillAttributeInfo - FindClose failed!");
+ Debug.Fail("File::FillAttributeInfo - FindClose failed!");
throw Win32Marshal.GetExceptionForLastWin32Error();
}
}
diff --git a/src/mscorlib/src/System/IO/MemoryStream.cs b/src/mscorlib/src/System/IO/MemoryStream.cs
index 330efcc1e7..d2fd83d2c3 100644
--- a/src/mscorlib/src/System/IO/MemoryStream.cs
+++ b/src/mscorlib/src/System/IO/MemoryStream.cs
@@ -634,7 +634,6 @@ namespace System.IO
public virtual byte[] ToArray()
{
- BCLDebug.Perf(_exposable, "MemoryStream::GetBuffer will let you avoid a copy.");
byte[] copy = new byte[_length - _origin];
Buffer.InternalBlockCopy(_buffer, _origin, copy, 0, _length - _origin);
return copy;
diff --git a/src/mscorlib/src/System/InsufficientMemoryException.cs b/src/mscorlib/src/System/InsufficientMemoryException.cs
index b4bc588f18..b5f369ef9b 100644
--- a/src/mscorlib/src/System/InsufficientMemoryException.cs
+++ b/src/mscorlib/src/System/InsufficientMemoryException.cs
@@ -22,6 +22,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public sealed class InsufficientMemoryException : OutOfMemoryException
{
public InsufficientMemoryException()
@@ -41,5 +43,9 @@ namespace System
{
HResult = HResults.COR_E_INSUFFICIENTMEMORY;
}
+
+ private InsufficientMemoryException(SerializationInfo info, StreamingContext context) : base(info, context)
+ {
+ }
}
}
diff --git a/src/mscorlib/src/System/MissingFieldException.cs b/src/mscorlib/src/System/MissingFieldException.cs
index 31931bf91c..0225414a38 100644
--- a/src/mscorlib/src/System/MissingFieldException.cs
+++ b/src/mscorlib/src/System/MissingFieldException.cs
@@ -17,6 +17,8 @@ using System.Globalization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MissingFieldException : MissingMemberException, ISerializable
{
public MissingFieldException()
@@ -39,7 +41,6 @@ namespace System
protected MissingFieldException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
public override String Message
diff --git a/src/mscorlib/src/System/MissingMemberException.cs b/src/mscorlib/src/System/MissingMemberException.cs
index 44ceaaf1e1..ba16b27680 100644
--- a/src/mscorlib/src/System/MissingMemberException.cs
+++ b/src/mscorlib/src/System/MissingMemberException.cs
@@ -12,14 +12,13 @@
=============================================================================*/
-using System;
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
-using System.Globalization;
-using System.Runtime.Versioning;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MissingMemberException : MemberAccessException, ISerializable
{
public MissingMemberException()
@@ -42,7 +41,9 @@ namespace System
protected MissingMemberException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
+ ClassName = info.GetString("MMClassName");
+ MemberName = info.GetString("MMMemberName");
+ Signature = (byte[])info.GetValue("MMSignature", typeof(byte[]));
}
public override String Message
@@ -74,6 +75,9 @@ namespace System
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("MMClassName", ClassName, typeof(string));
+ info.AddValue("MMMemberName", MemberName, typeof(string));
+ info.AddValue("MMSignature", Signature, typeof(byte[]));
}
diff --git a/src/mscorlib/src/System/OutOfMemoryException.cs b/src/mscorlib/src/System/OutOfMemoryException.cs
index 8ef2d7b265..33cf6399e4 100644
--- a/src/mscorlib/src/System/OutOfMemoryException.cs
+++ b/src/mscorlib/src/System/OutOfMemoryException.cs
@@ -17,6 +17,8 @@ using System.Runtime.Serialization;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class OutOfMemoryException : SystemException
{
public OutOfMemoryException()
@@ -39,7 +41,6 @@ namespace System
protected OutOfMemoryException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Reflection/CustomAttribute.cs b/src/mscorlib/src/System/Reflection/CustomAttribute.cs
index 7f50286996..f394b0100f 100644
--- a/src/mscorlib/src/System/Reflection/CustomAttribute.cs
+++ b/src/mscorlib/src/System/Reflection/CustomAttribute.cs
@@ -1912,7 +1912,7 @@ namespace System.Reflection
s_pca = temp_pca;
}
- [Conditional("_DEBUG")]
+ [Conditional("DEBUG")]
private static void VerifyPseudoCustomAttribute(RuntimeType pca)
{
// If any of these are invariants are no longer true will have to
diff --git a/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilder.cs
index bcd70c3b87..b483738213 100644
--- a/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilder.cs
@@ -375,8 +375,6 @@ namespace System.Reflection.Emit
if (name[0] == '\0')
throw new ArgumentException(SR.Argument_InvalidName, nameof(name));
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: AssemblyBuilder.DefineDynamicModule( " + name + " )");
-
Debug.Assert(m_assemblyData != null, "m_assemblyData is null in DefineDynamicModuleInternal");
ModuleBuilder dynModule;
@@ -672,7 +670,6 @@ namespace System.Reflection.Emit
if (name.Length == 0)
throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: AssemblyBuilder.GetDynamicModule( " + name + " )");
int size = m_assemblyData.m_moduleBuilderList.Count;
for (int i = 0; i < size; i++)
{
diff --git a/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderData.cs b/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderData.cs
index 99c055a991..ea1f6994e9 100644
--- a/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderData.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/AssemblyBuilderData.cs
@@ -97,7 +97,6 @@ namespace System.Reflection.Emit
// Helper to ensure the type name is unique underneath assemblyBuilder
internal void CheckTypeNameConflict(String strTypeName, TypeBuilder enclosingType)
{
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: AssemblyBuilderData.CheckTypeNameConflict( " + strTypeName + " )");
for (int i = 0; i < m_moduleBuilderList.Count; i++)
{
ModuleBuilder curModule = m_moduleBuilderList[i];
diff --git a/src/mscorlib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
index cdc9f469b3..94a9becf98 100644
--- a/src/mscorlib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
@@ -348,7 +348,7 @@ namespace System.Reflection.Emit
writer.Write((byte)CustomAttributeEncoding.Double);
break;
default:
- Debug.Assert(false, "Invalid primitive type");
+ Debug.Fail("Invalid primitive type");
break;
}
}
@@ -432,7 +432,7 @@ namespace System.Reflection.Emit
writer.Write((ulong)value);
break;
default:
- Debug.Assert(false, "Invalid enum base type");
+ Debug.Fail("Invalid enum base type");
break;
}
}
@@ -509,7 +509,7 @@ namespace System.Reflection.Emit
writer.Write((double)value);
break;
default:
- Debug.Assert(false, "Invalid primitive type");
+ Debug.Fail("Invalid primitive type");
break;
}
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
index 53566c16b1..28c7074d06 100644
--- a/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/EnumBuilder.cs
@@ -33,8 +33,6 @@ namespace System.Reflection.Emit
public FieldBuilder DefineLiteral(String literalName, Object literalValue)
{
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: EnumBuilder.DefineLiteral( " + literalName + " )");
-
// Define the underlying field for the enum. It will be a non-static, private field with special name bit set.
FieldBuilder fieldBuilder = m_typeBuilder.DefineField(
literalName,
@@ -46,14 +44,12 @@ namespace System.Reflection.Emit
public TypeInfo CreateTypeInfo()
{
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: EnumBuilder.CreateType() ");
return m_typeBuilder.CreateTypeInfo();
}
// CreateType cause EnumBuilder to be baked.
public Type CreateType()
{
- BCLDebug.Log("DYNIL", "## DYNIL LOGGING: EnumBuilder.CreateType() ");
return m_typeBuilder.CreateType();
}
diff --git a/src/mscorlib/src/System/Reflection/Emit/MethodBuilder.cs b/src/mscorlib/src/System/Reflection/Emit/MethodBuilder.cs
index fda22ab1d6..928b2e3084 100644
--- a/src/mscorlib/src/System/Reflection/Emit/MethodBuilder.cs
+++ b/src/mscorlib/src/System/Reflection/Emit/MethodBuilder.cs
@@ -352,7 +352,7 @@ namespace System.Reflection.Emit
}
else
{
- Debug.Assert(false, "We should never get here!");
+ Debug.Fail("We should never get here!");
return null;
}
}
diff --git a/src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs b/src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs
index 5048af3950..e9d27ef7ae 100644
--- a/src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs
+++ b/src/mscorlib/src/System/Reflection/RuntimeParameterInfo.cs
@@ -403,7 +403,7 @@ namespace System.Reflection
if (namedArgument.MemberInfo.Name.Equals("Value"))
{
// This is not possible because Decimal cannot be represented directly in the metadata.
- Debug.Assert(false, "Decimal cannot be represented directly in the metadata.");
+ Debug.Fail("Decimal cannot be represented directly in the metadata.");
return (Decimal)namedArgument.TypedValue.Value;
}
}
diff --git a/src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs b/src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs
index 58c99242a8..cb091f1c14 100644
--- a/src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs
+++ b/src/mscorlib/src/System/Resources/FileBasedResourceGroveler.cs
@@ -89,27 +89,13 @@ namespace System.Resources
// qualified name, append path to that.
if (_mediator.ModuleDir != null)
{
-#if _DEBUG
- if (ResourceManager.DEBUG >= 3)
- BCLDebug.Log("FindResourceFile: checking module dir: \"" + _mediator.ModuleDir + '\"');
-#endif
-
String path = Path.Combine(_mediator.ModuleDir, fileName);
if (File.Exists(path))
{
-#if _DEBUG
- if (ResourceManager.DEBUG >= 3)
- BCLDebug.Log("Found resource file in module dir! " + path);
-#endif
return path;
}
}
-#if _DEBUG
- if (ResourceManager.DEBUG >= 3)
- BCLDebug.Log("Couldn't find resource file in module dir, checking .\\" + fileName);
-#endif
-
// look in .
if (File.Exists(fileName))
return fileName;
diff --git a/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs b/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs
index 4548b93dd4..83d5b6c8e8 100644
--- a/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs
+++ b/src/mscorlib/src/System/Resources/ManifestBasedResourceGroveler.cs
@@ -180,7 +180,7 @@ namespace System.Resources
// fires, please fix the build process for the BCL directory.
if (a == typeof(Object).Assembly)
{
- Debug.Assert(false, System.CoreLib.Name + "'s NeutralResourcesLanguageAttribute is a malformed culture name! name: \"" + cultureName + "\" Exception: " + e);
+ Debug.Fail(System.CoreLib.Name + "'s NeutralResourcesLanguageAttribute is a malformed culture name! name: \"" + cultureName + "\" Exception: " + e);
return CultureInfo.InvariantCulture;
}
@@ -417,14 +417,14 @@ namespace System.Resources
int hr = fle._HResult;
if (hr != Win32Marshal.MakeHRFromErrorCode(Win32Native.ERROR_ACCESS_DENIED))
{
- Debug.Assert(false, "[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + " with error code 0x" + hr.ToString("X", CultureInfo.InvariantCulture) + Environment.NewLine + "Exception: " + fle);
+ Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + " with error code 0x" + hr.ToString("X", CultureInfo.InvariantCulture) + Environment.NewLine + "Exception: " + fle);
}
}
// Don't throw for zero-length satellite assemblies, for compat with v1
catch (BadImageFormatException bife)
{
- Debug.Assert(false, "[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + Environment.NewLine + "Exception: " + bife);
+ Debug.Fail("[This assert catches satellite assembly build/deployment problems - report this message to your build lab & loc engineer]" + Environment.NewLine + "GetSatelliteAssembly failed for culture " + lookForCulture.Name + " and version " + (_mediator.SatelliteContractVersion == null ? _mediator.MainAssembly.GetVersion().ToString() : _mediator.SatelliteContractVersion.ToString()) + " of assembly " + _mediator.MainAssembly.GetSimpleName() + Environment.NewLine + "Exception: " + bife);
}
return satellite;
@@ -505,7 +505,7 @@ namespace System.Resources
if (_mediator.MainAssembly == typeof(Object).Assembly && _mediator.BaseName.Equals(System.CoreLib.Name))
{
// This would break CultureInfo & all our exceptions.
- Debug.Assert(false, "Couldn't get " + System.CoreLib.Name + ResourceManager.ResFileExtension + " from " + System.CoreLib.Name + "'s assembly" + Environment.NewLine + Environment.NewLine + "Are you building the runtime on your machine? Chances are the BCL directory didn't build correctly. Type 'build -c' in the BCL directory. If you get build errors, look at buildd.log. If you then can't figure out what's wrong (and you aren't changing the assembly-related metadata code), ask a BCL dev.\n\nIf you did NOT build the runtime, you shouldn't be seeing this and you've found a bug.");
+ Debug.Fail("Couldn't get " + System.CoreLib.Name + ResourceManager.ResFileExtension + " from " + System.CoreLib.Name + "'s assembly" + Environment.NewLine + Environment.NewLine + "Are you building the runtime on your machine? Chances are the BCL directory didn't build correctly. Type 'build -c' in the BCL directory. If you get build errors, look at buildd.log. If you then can't figure out what's wrong (and you aren't changing the assembly-related metadata code), ask a BCL dev.\n\nIf you did NOT build the runtime, you shouldn't be seeing this and you've found a bug.");
// We cannot continue further - simply FailFast.
string mesgFailFast = System.CoreLib.Name + ResourceManager.ResFileExtension + " couldn't be found! Large parts of the BCL won't work!";
diff --git a/src/mscorlib/src/System/Resources/ResourceManager.cs b/src/mscorlib/src/System/Resources/ResourceManager.cs
index 0e9780169a..490a322c14 100644
--- a/src/mscorlib/src/System/Resources/ResourceManager.cs
+++ b/src/mscorlib/src/System/Resources/ResourceManager.cs
@@ -243,10 +243,6 @@ namespace System.Resources
internal const String ResFileExtension = ".resources";
internal const int ResFileExtensionLength = 10;
- // My private debugging aid. Set to 5 or 6 for verbose output. Set to 3
- // for summary level information.
- internal static readonly int DEBUG = 0; //Making this const causes C# to consider all of the code that it guards unreachable.
-
private static volatile bool s_IsAppXModel;
[System.Security.DynamicSecurityMethod] // Methods containing StackCrawlMark local var has to be marked DynamicSecurityMethod
diff --git a/src/mscorlib/src/System/Resources/ResourceReader.cs b/src/mscorlib/src/System/Resources/ResourceReader.cs
index 0658032f7d..75c17686b3 100644
--- a/src/mscorlib/src/System/Resources/ResourceReader.cs
+++ b/src/mscorlib/src/System/Resources/ResourceReader.cs
@@ -106,16 +106,11 @@ namespace System.Resources
// Version number of .resources file, for compatibility
private int _version;
-#if RESOURCE_FILE_FORMAT_DEBUG
- private bool _debug; // Whether this file has debugging stuff in it.
-#endif
-
public ResourceReader(String fileName)
{
_resCache = new Dictionary<String, ResourceLocator>(FastResourceComparer.Default);
_store = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.RandomAccess), Encoding.UTF8);
- BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(String). UnmanagedMemoryStream: " + (_ums != null));
try
{
@@ -140,7 +135,6 @@ namespace System.Resources
// We have a faster code path for reading resource files from an assembly.
_ums = stream as UnmanagedMemoryStream;
- BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream). UnmanagedMemoryStream: " + (_ums != null));
ReadResources();
}
@@ -159,7 +153,6 @@ namespace System.Resources
_ums = stream as UnmanagedMemoryStream;
- BCLDebug.Log("RESMGRFILEFORMAT", "ResourceReader .ctor(Stream, Hashtable). UnmanagedMemoryStream: " + (_ums != null));
ReadResources();
}
@@ -268,7 +261,7 @@ namespace System.Resources
{
Debug.Assert(_store != null, "ResourceReader is closed!");
int hash = FastResourceComparer.HashFunction(name);
- BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for " + name + " hash: " + hash.ToString("x", CultureInfo.InvariantCulture));
+
// Binary search over the hashes. Use the _namePositions array to
// determine where they exist in the underlying stream.
int lo = 0;
@@ -288,7 +281,7 @@ namespace System.Resources
c = -1;
else
c = 1;
- //BCLDebug.Log("RESMGRFILEFORMAT", " Probing index "+index+" lo: "+lo+" hi: "+hi+" c: "+c);
+
if (c == 0)
{
success = true;
@@ -301,14 +294,6 @@ namespace System.Resources
}
if (!success)
{
-#if RESOURCE_FILE_FORMAT_DEBUG
- String lastReadString;
- lock(this) {
- _store.BaseStream.Seek(_nameSectionOffset + GetNamePosition(index), SeekOrigin.Begin);
- lastReadString = _store.ReadString();
- }
- BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "FindPosForResource for ", name, " failed. i: ", index, " lo: ", lo, " hi: ", hi, " last read string: \"", lastReadString, '\'');
-#endif
return -1;
}
@@ -346,7 +331,6 @@ namespace System.Resources
}
}
}
- BCLDebug.Log("RESMGRFILEFORMAT", "FindPosForResource for " + name + ": Found a hash collision, HOWEVER, neither of these collided values equaled the given string.");
return -1;
}
@@ -463,13 +447,13 @@ namespace System.Resources
{
_store.BaseStream.Seek(nameVA + _nameSectionOffset, SeekOrigin.Begin);
SkipString();
- //BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex for index: "+index+" skip (name length): "+skip);
+
int dataPos = _store.ReadInt32();
if (dataPos < 0 || dataPos >= _store.BaseStream.Length - _dataSectionOffset)
{
throw new FormatException(SR.Format(SR.BadImageFormat_ResourcesDataInvalidOffset, dataPos));
}
- BCLDebug.Log("RESMGRFILEFORMAT", "GetValueForNameIndex: dataPos: " + dataPos);
+
ResourceTypeCode junk;
if (_version == 1)
return LoadObjectV1(dataPos);
@@ -511,7 +495,7 @@ namespace System.Resources
if (typeCode == ResourceTypeCode.String) // ignore Null
s = _store.ReadString();
}
- BCLDebug.Log("RESMGRFILEFORMAT", "LoadString(" + pos.ToString("x", CultureInfo.InvariantCulture) + " returned " + (s == null ? "[a null string]" : s));
+
return s;
}
@@ -567,7 +551,6 @@ namespace System.Resources
if (typeIndex == -1)
return null;
RuntimeType type = FindType(typeIndex);
- BCLDebug.Log("RESMGRFILEFORMAT", "LoadObject type: " + type.Name + " pos: 0x" + _store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture));
// Consider putting in logic to see if this type is a
// primitive or a value type first, so we can reach the
// deserialization code faster for arbitrary objects.
@@ -641,8 +624,6 @@ namespace System.Resources
_store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
typeCode = (ResourceTypeCode)_store.Read7BitEncodedInt();
- BCLDebug.Log("RESMGRFILEFORMAT", "LoadObjectV2 type: " + typeCode + " pos: 0x" + _store.BaseStream.Position.ToString("x", CultureInfo.InvariantCulture));
-
switch (typeCode)
{
case ResourceTypeCode.Null:
@@ -812,12 +793,10 @@ namespace System.Resources
}
if (resMgrHeaderVersion > 1)
{
- BCLDebug.Log("RESMGRFILEFORMAT", LogLevel.Status, "ReadResources: Unexpected ResMgr header version: {0} Skipping ahead {1} bytes.", resMgrHeaderVersion, numBytesToSkip);
_store.BaseStream.Seek(numBytesToSkip, SeekOrigin.Current);
}
else
{
- BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Parsing ResMgr header v1.");
// We don't care about numBytesToSkip; read the rest of the header
// Read in type name for a suitable ResourceReader
@@ -840,36 +819,11 @@ namespace System.Resources
throw new ArgumentException(SR.Format(SR.Arg_ResourceFileUnsupportedVersion, RuntimeResourceSet.Version, version));
_version = version;
-#if RESOURCE_FILE_FORMAT_DEBUG
- // Look for ***DEBUG*** to see if this is a debuggable file.
- long oldPos = _store.BaseStream.Position;
- _debug = false;
- try {
- String debugString = _store.ReadString();
- _debug = String.Equals("***DEBUG***", debugString);
- }
- catch(IOException) {
- }
- catch(OutOfMemoryException) {
- }
- if (_debug) {
- Console.WriteLine("ResourceReader is looking at a debuggable .resources file, version {0}", _version);
- }
- else {
- _store.BaseStream.Position = oldPos;
- }
-#endif
-
_numResources = _store.ReadInt32();
if (_numResources < 0)
{
throw new BadImageFormatException(SR.BadImageFormat_ResourcesHeaderCorrupted);
}
- BCLDebug.Log("RESMGRFILEFORMAT", "ReadResources: Expecting " + _numResources + " resources.");
-#if RESOURCE_FILE_FORMAT_DEBUG
- if (ResourceManager.DEBUG >= 4)
- Console.WriteLine("ResourceReader::ReadResources - Reading in "+_numResources+" resources");
-#endif
// Read type positions into type positions array.
// But delay initialize the type table.
@@ -888,11 +842,6 @@ namespace System.Resources
SkipString();
}
-#if RESOURCE_FILE_FORMAT_DEBUG
- if (ResourceManager.DEBUG >= 5)
- Console.WriteLine("ResourceReader::ReadResources - Reading in "+numTypes+" type table entries");
-#endif
-
// Prepare to read in the array of name hashes
// Note that the name hashes array is aligned to 8 bytes so
// we can use pointers into it on 64 bit machines. (4 bytes
@@ -910,13 +859,6 @@ namespace System.Resources
}
// Read in the array of name hashes
-#if RESOURCE_FILE_FORMAT_DEBUG
- // Skip over "HASHES->"
- if (_debug) {
- _store.BaseStream.Position += 8;
- }
-#endif
-
if (_ums == null)
{
_nameHashes = new int[_numResources];
@@ -943,12 +885,6 @@ namespace System.Resources
}
// Read in the array of relative positions for all the names.
-#if RESOURCE_FILE_FORMAT_DEBUG
- // Skip over "POS---->"
- if (_debug) {
- _store.BaseStream.Position += 8;
- }
-#endif
if (_ums == null)
{
_namePositions = new int[_numResources];
@@ -995,8 +931,6 @@ namespace System.Resources
{
throw new BadImageFormatException(SR.BadImageFormat_ResourcesHeaderCorrupted);
}
-
- BCLDebug.Log("RESMGRFILEFORMAT", String.Format(CultureInfo.InvariantCulture, "ReadResources: _nameOffset = 0x{0:x} _dataOffset = 0x{1:x}", _nameSectionOffset, _dataSectionOffset));
}
// This allows us to delay-initialize the Type[]. This might be a
diff --git a/src/mscorlib/src/System/RtType.cs b/src/mscorlib/src/System/RtType.cs
index e5bc0c5293..141cb166e8 100644
--- a/src/mscorlib/src/System/RtType.cs
+++ b/src/mscorlib/src/System/RtType.cs
@@ -46,7 +46,7 @@ namespace System
FormatAssembly = 0x00000004, // Include assembly display name in type names
FormatSignature = 0x00000008, // Include signature in method names
FormatNoVersion = 0x00000010, // Suppress version and culture information in all assembly names
-#if _DEBUG
+#if DEBUG
FormatDebug = 0x00000020, // For debug printing of types only
#endif
FormatAngleBrackets = 0x00000040, // Whether generic types are C<T> or C[T]
@@ -389,7 +389,7 @@ namespace System
list = PopulateInterfaces(filter);
break;
default:
- BCLDebug.Assert(false, "Invalid CacheType");
+ Debug.Fail("Invalid CacheType");
break;
}
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
index e8e0d60202..85eb17c5ba 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/AsyncMethodBuilder.cs
@@ -11,12 +11,15 @@
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
using System.Diagnostics;
+using System.Diagnostics.Tracing;
+using System.Reflection;
using System.Runtime.ExceptionServices;
-using System.Threading;
-using System.Threading.Tasks;
#if FEATURE_COMINTEROP
using System.Runtime.InteropServices.WindowsRuntime;
#endif // FEATURE_COMINTEROP
+using System.Threading;
+using System.Threading.Tasks;
+using System.Text;
namespace System.Runtime.CompilerServices
{
@@ -89,12 +92,14 @@ namespace System.Runtime.CompilerServices
AsyncCausalityTracer.TraceOperationCompletion(CausalityTraceLevel.Required, this.Task.Id, AsyncCausalityStatus.Completed);
}
+ // Mark the builder as completed. As this is a void-returning method, this mostly
+ // doesn't matter, but it can affect things like debug events related to finalization.
+ _builder.SetResult();
+
if (_synchronizationContext != null)
{
NotifySynchronizationContextOfCompletion();
}
-
- // No need to call _builder.SetResult, as no one pays attention to the task's completion.
}
/// <summary>Faults the method builder with an exception.</summary>
@@ -134,7 +139,8 @@ namespace System.Runtime.CompilerServices
AsyncMethodBuilderCore.ThrowAsync(exception, targetContext: null);
}
- // No need to call _builder.SetException, as no one pays attention to the task's completion.
+ // The exception was propagated already; we don't need or want to fault the builder, just mark it as completed.
+ _builder.SetResult();
}
/// <summary>Notifies the current synchronization context that the operation completed.</summary>
@@ -387,108 +393,39 @@ namespace System.Runtime.CompilerServices
{
IAsyncStateMachineBox box = GetStateMachineBox(ref stateMachine);
- // TODO https://github.com/dotnet/coreclr/issues/12877:
- // Once the JIT is able to recognize "awaiter is ITaskAwaiter" and "awaiter is IConfiguredTaskAwaiter",
- // use those in order to a) consolidate a lot of this code, and b) handle all Task/Task<T> and not just
- // the few types special-cased here. For now, handle common {Configured}TaskAwaiter. Having the types
- // explicitly listed here allows the JIT to generate the best code for them; otherwise we'll fall through
- // to the later workaround.
- if (typeof(TAwaiter) == typeof(TaskAwaiter) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<object>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<string>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<byte[]>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<bool>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<byte>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<int>) ||
- typeof(TAwaiter) == typeof(TaskAwaiter<long>))
+ // The null tests here ensure that the jit can optimize away the interface
+ // tests when TAwaiter is is a ref type.
+ if ((null != (object)default(TAwaiter)) && (awaiter is ITaskAwaiter))
{
ref TaskAwaiter ta = ref Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter); // relies on TaskAwaiter/TaskAwaiter<T> having the same layout
TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, continueOnCapturedContext: true);
}
- else if (
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<object>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<string>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<byte[]>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<bool>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<byte>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<int>.ConfiguredTaskAwaiter) ||
- typeof(TAwaiter) == typeof(ConfiguredTaskAwaitable<long>.ConfiguredTaskAwaiter))
+ else if ((null != (object)default(TAwaiter)) && (awaiter is IConfiguredTaskAwaiter))
{
ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ta = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter);
TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, ta.m_continueOnCapturedContext);
}
-
- // Handle common {Configured}ValueTaskAwaiter<T> types. Unfortunately these need to be special-cased
- // individually, as we don't have good way to extract the task from a ValueTaskAwaiter<T> when we don't
- // know what the T is; we could make ValueTaskAwaiter<T> implement an IValueTaskAwaiter interface, but
- // calling a GetTask method on that would end up boxing the awaiter. This hard-coded list here is
- // somewhat arbitrary and is based on types currently in use with ValueTask<T> in coreclr/corefx.
- else if (typeof(TAwaiter) == typeof(ValueTaskAwaiter<int>))
- {
- var vta = (ValueTaskAwaiter<int>)(object)awaiter;
- TaskAwaiter.UnsafeOnCompletedInternal(vta.AsTask(), box, continueOnCapturedContext: true);
- }
- else if (typeof(TAwaiter) == typeof(ConfiguredValueTaskAwaitable<int>.ConfiguredValueTaskAwaiter))
- {
- var vta = (ConfiguredValueTaskAwaitable<int>.ConfiguredValueTaskAwaiter)(object)awaiter;
- TaskAwaiter.UnsafeOnCompletedInternal(vta.AsTask(), box, vta._continueOnCapturedContext);
- }
- else if (typeof(TAwaiter) == typeof(ConfiguredValueTaskAwaitable<System.IO.Stream>.ConfiguredValueTaskAwaiter))
- {
- var vta = (ConfiguredValueTaskAwaitable<System.IO.Stream>.ConfiguredValueTaskAwaiter)(object)awaiter;
- TaskAwaiter.UnsafeOnCompletedInternal(vta.AsTask(), box, vta._continueOnCapturedContext);
- }
- else if (typeof(TAwaiter) == typeof(ConfiguredValueTaskAwaitable<ArraySegment<byte>>.ConfiguredValueTaskAwaiter))
- {
- var vta = (ConfiguredValueTaskAwaitable<ArraySegment<byte>>.ConfiguredValueTaskAwaiter)(object)awaiter;
- TaskAwaiter.UnsafeOnCompletedInternal(vta.AsTask(), box, vta._continueOnCapturedContext);
- }
- else if (typeof(TAwaiter) == typeof(ConfiguredValueTaskAwaitable<object>.ConfiguredValueTaskAwaiter))
- {
- var vta = (ConfiguredValueTaskAwaitable<object>.ConfiguredValueTaskAwaiter)(object)awaiter;
- TaskAwaiter.UnsafeOnCompletedInternal(vta.AsTask(), box, vta._continueOnCapturedContext);
- }
-
- // To catch all Task/Task<T> awaits, do the currently more expensive interface checks.
- // Eventually these and the above Task/Task<T> checks should be replaced by "is" checks,
- // once that's recognized and optimized by the JIT. We do these after all of the hardcoded
- // checks above so that they don't incur the costs of these checks.
- else if (InterfaceIsCheckWorkaround<TAwaiter>.IsITaskAwaiter)
+ else if ((null != (object)default(TAwaiter)) && (awaiter is IValueTaskAwaiter))
{
- ref TaskAwaiter ta = ref Unsafe.As<TAwaiter, TaskAwaiter>(ref awaiter);
- TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, continueOnCapturedContext: true);
+ Task t = ((IValueTaskAwaiter)awaiter).GetTask();
+ TaskAwaiter.UnsafeOnCompletedInternal(t, box, continueOnCapturedContext: true);
}
- else if (InterfaceIsCheckWorkaround<TAwaiter>.IsIConfiguredTaskAwaiter)
+ else if ((null != (object)default(TAwaiter)) && (awaiter is IConfiguredValueTaskAwaiter))
{
- ref ConfiguredTaskAwaitable.ConfiguredTaskAwaiter ta = ref Unsafe.As<TAwaiter, ConfiguredTaskAwaitable.ConfiguredTaskAwaiter>(ref awaiter);
- TaskAwaiter.UnsafeOnCompletedInternal(ta.m_task, box, ta.m_continueOnCapturedContext);
+ (Task task, bool continueOnCapturedContext) t = ((IConfiguredValueTaskAwaiter)awaiter).GetTask();
+ TaskAwaiter.UnsafeOnCompletedInternal(t.task, box, t.continueOnCapturedContext);
}
-
// The awaiter isn't specially known. Fall back to doing a normal await.
else
{
- // TODO https://github.com/dotnet/coreclr/issues/14177:
- // Move the code back into this method once the JIT is able to
- // elide it successfully when one of the previous branches is hit.
- AwaitArbitraryAwaiterUnsafeOnCompleted(ref awaiter, box);
- }
- }
-
- /// <summary>Schedules the specified state machine to be pushed forward when the specified awaiter completes.</summary>
- /// <typeparam name="TAwaiter">Specifies the type of the awaiter.</typeparam>
- /// <param name="awaiter">The awaiter.</param>
- /// <param name="box">The state machine box.</param>
- private static void AwaitArbitraryAwaiterUnsafeOnCompleted<TAwaiter>(ref TAwaiter awaiter, IAsyncStateMachineBox box)
- where TAwaiter : ICriticalNotifyCompletion
- {
- try
- {
- awaiter.UnsafeOnCompleted(box.MoveNextAction);
- }
- catch (Exception e)
- {
- AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
+ try
+ {
+ awaiter.UnsafeOnCompleted(box.MoveNextAction);
+ }
+ catch (Exception e)
+ {
+ AsyncMethodBuilderCore.ThrowAsync(e, targetContext: null);
+ }
}
}
@@ -555,17 +492,40 @@ namespace System.Runtime.CompilerServices
// cases is we lose the ability to properly step in the debugger, as the debugger uses that
// object's identity to track this specific builder/state machine. As such, we proceed to
// overwrite whatever's there anyway, even if it's non-null.
- var box = new AsyncStateMachineBox<TStateMachine>();
+ var box = AsyncMethodBuilderCore.TrackAsyncMethodCompletion ?
+ new DebugFinalizableAsyncStateMachineBox<TStateMachine>() :
+ new AsyncStateMachineBox<TStateMachine>();
m_task = box; // important: this must be done before storing stateMachine into box.StateMachine!
box.StateMachine = stateMachine;
box.Context = currentContext;
return box;
}
+ /// <summary>
+ /// Provides an async state machine box with a finalizer that will fire an EventSource
+ /// event about the state machine if it's being finalized without having been completed.
+ /// </summary>
+ /// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
+ private sealed class DebugFinalizableAsyncStateMachineBox<TStateMachine> :
+ AsyncStateMachineBox<TStateMachine>
+ where TStateMachine : IAsyncStateMachine
+ {
+ ~DebugFinalizableAsyncStateMachineBox()
+ {
+ // If the state machine is being finalized, something went wrong during its processing,
+ // e.g. it awaited something that got collected without itself having been completed.
+ // Fire an event with details about the state machine to help with debugging.
+ if (!IsCompleted) // double-check it's not completed, just to help minimize false positives
+ {
+ TplEtwProvider.Log.IncompleteAsyncMethod(this);
+ }
+ }
+ }
+
/// <summary>A strongly-typed box for Task-based async state machines.</summary>
/// <typeparam name="TStateMachine">Specifies the type of the state machine.</typeparam>
/// <typeparam name="TResult">Specifies the type of the Task's result.</typeparam>
- private sealed class AsyncStateMachineBox<TStateMachine> :
+ private class AsyncStateMachineBox<TStateMachine> :
Task<TResult>, IAsyncStateMachineBox
where TStateMachine : IAsyncStateMachine
{
@@ -595,6 +555,14 @@ namespace System.Runtime.CompilerServices
{
ExecutionContext.Run(Context, s_callback, this);
}
+
+ // In case this is a state machine box with a finalizer, suppress its finalization
+ // if it's now complete. We only need the finalizer to run if the box is collected
+ // without having been completed.
+ if (IsCompleted && AsyncMethodBuilderCore.TrackAsyncMethodCompletion)
+ {
+ GC.SuppressFinalize(this);
+ }
}
/// <summary>
@@ -642,7 +610,9 @@ namespace System.Runtime.CompilerServices
private Task<TResult> InitializeTaskAsStateMachineBox()
{
Debug.Assert(m_task == null);
- return (m_task = new AsyncStateMachineBox<IAsyncStateMachine>());
+ return (m_task = AsyncMethodBuilderCore.TrackAsyncMethodCompletion ?
+ new DebugFinalizableAsyncStateMachineBox<IAsyncStateMachine>() :
+ new AsyncStateMachineBox<IAsyncStateMachine>());
}
/// <summary>
@@ -922,17 +892,10 @@ namespace System.Runtime.CompilerServices
new Task<TResult>(false, result, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, default(CancellationToken));
}
- /// <summary>Temporary workaround for https://github.com/dotnet/coreclr/issues/12877.</summary>
- internal static class InterfaceIsCheckWorkaround<TAwaiter>
- {
- internal static readonly bool IsITaskAwaiter = typeof(TAwaiter).GetInterface("ITaskAwaiter") != null;
- internal static readonly bool IsIConfiguredTaskAwaiter = typeof(TAwaiter).GetInterface("IConfiguredTaskAwaiter") != null;
- }
-
/// <summary>
/// An interface implemented by all <see cref="AsyncStateMachineBox{TStateMachine, TResult}"/> instances, regardless of generics.
/// </summary>
- interface IAsyncStateMachineBox : ITaskCompletionAction
+ internal interface IAsyncStateMachineBox : ITaskCompletionAction
{
/// <summary>
/// Gets an action for moving forward the contained state machine.
@@ -947,6 +910,32 @@ namespace System.Runtime.CompilerServices
/// <summary>Shared helpers for manipulating state related to async state machines.</summary>
internal static class AsyncMethodBuilderCore // debugger depends on this exact name
{
+ /// <summary>Gets whether we should be tracking async method completions for eventing.</summary>
+ internal static bool TrackAsyncMethodCompletion
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => TplEtwProvider.Log.IsEnabled(EventLevel.Warning, TplEtwProvider.Keywords.AsyncMethod);
+ }
+
+ /// <summary>Gets a description of the state of the state machine object, suitable for debug purposes.</summary>
+ /// <param name="stateMachine">The state machine object.</param>
+ /// <returns>A description of the state machine.</returns>
+ internal static string GetAsyncStateMachineDescription(IAsyncStateMachine stateMachine)
+ {
+ Debug.Assert(stateMachine != null);
+
+ Type stateMachineType = stateMachine.GetType();
+ FieldInfo[] fields = stateMachineType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+
+ var sb = new StringBuilder();
+ sb.AppendLine(stateMachineType.FullName);
+ foreach (FieldInfo fi in fields)
+ {
+ sb.AppendLine($" {fi.Name}: {fi.GetValue(stateMachine)}");
+ }
+ return sb.ToString();
+ }
+
internal static Action OutputAsyncCausalityEvents(Task task, Action continuation) =>
CreateContinuationWrapper(continuation, (innerContinuation, innerTask) =>
{
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
index e13f05fe38..5b2ac28222 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/TaskAwaiter.cs
@@ -103,6 +103,7 @@ namespace System.Runtime.CompilerServices
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
+ [StackTraceHidden]
public void GetResult()
{
ValidateEnd(m_task);
@@ -113,6 +114,7 @@ namespace System.Runtime.CompilerServices
/// prior to completing the await.
/// </summary>
/// <param name="task">The awaited task.</param>
+ [StackTraceHidden]
internal static void ValidateEnd(Task task)
{
// Fast checks that can be inlined.
@@ -129,6 +131,7 @@ namespace System.Runtime.CompilerServices
/// the await on the task, and throws an exception if the task did not complete successfully.
/// </summary>
/// <param name="task">The awaited task.</param>
+ [StackTraceHidden]
private static void HandleNonSuccessAndDebuggerNotification(Task task)
{
// NOTE: The JIT refuses to inline ValidateEnd when it contains the contents
@@ -152,6 +155,7 @@ namespace System.Runtime.CompilerServices
}
/// <summary>Throws an exception to handle a task that completed in a state other than RanToCompletion.</summary>
+ [StackTraceHidden]
private static void ThrowForNonSuccess(Task task)
{
Debug.Assert(task.IsCompleted, "Task must have been completed by now.");
@@ -169,7 +173,7 @@ namespace System.Runtime.CompilerServices
if (oceEdi != null)
{
oceEdi.Throw();
- Debug.Assert(false, "Throw() should have thrown");
+ Debug.Fail("Throw() should have thrown");
}
throw new TaskCanceledException(task);
@@ -180,12 +184,12 @@ namespace System.Runtime.CompilerServices
if (edis.Count > 0)
{
edis[0].Throw();
- Debug.Assert(false, "Throw() should have thrown");
+ Debug.Fail("Throw() should have thrown");
break; // Necessary to compile: non-reachable, but compiler can't determine that
}
else
{
- Debug.Assert(false, "There should be exceptions if we're Faulted.");
+ Debug.Fail("There should be exceptions if we're Faulted.");
throw task.Exception;
}
}
@@ -365,6 +369,7 @@ namespace System.Runtime.CompilerServices
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
+ [StackTraceHidden]
public TResult GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
@@ -386,6 +391,22 @@ namespace System.Runtime.CompilerServices
/// </summary>
internal interface IConfiguredTaskAwaiter { }
+ /// <summary>
+ /// Internal interface used to enable extract the Task from arbitrary ValueTask awaiters.
+ /// </summary>>
+ internal interface IValueTaskAwaiter
+ {
+ Task GetTask();
+ }
+
+ /// <summary>
+ /// Internal interface used to enable extract the Task from arbitrary configured ValueTask awaiters.
+ /// </summary>
+ internal interface IConfiguredValueTaskAwaiter
+ {
+ (Task task, bool continueOnCapturedContext) GetTask();
+ }
+
/// <summary>Provides an awaitable object that allows for configured awaits on <see cref="System.Threading.Tasks.Task"/>.</summary>
/// <remarks>This type is intended for compiler use only.</remarks>
public struct ConfiguredTaskAwaitable
@@ -469,6 +490,7 @@ namespace System.Runtime.CompilerServices
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
+ [StackTraceHidden]
public void GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
@@ -557,6 +579,7 @@ namespace System.Runtime.CompilerServices
/// <exception cref="System.NullReferenceException">The awaiter was not properly initialized.</exception>
/// <exception cref="System.Threading.Tasks.TaskCanceledException">The task was canceled.</exception>
/// <exception cref="System.Exception">The task completed in a Faulted state.</exception>
+ [StackTraceHidden]
public TResult GetResult()
{
TaskAwaiter.ValidateEnd(m_task);
diff --git a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
index ef217d153f..f89f201c79 100644
--- a/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
+++ b/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
@@ -93,7 +93,7 @@ namespace System.Runtime.CompilerServices
return new StackCrawlMarkHandle(UnsafeCastToStackPointer(ref stackMark));
}
-#if _DEBUG
+#if DEBUG
static internal int UnsafeEnumCast<T>(T val) where T : struct // Actually T must be 4 byte (or less) enum
{
Debug.Assert(typeof(T).IsEnum
@@ -145,7 +145,7 @@ namespace System.Runtime.CompilerServices
// See getILIntrinsicImplementation for how this happens.
throw new InvalidOperationException();
}
-#else // _DEBUG
+#else // DEBUG
static internal int UnsafeEnumCast<T>(T val) where T : struct // Actually T must be 4 byte (or less) enum
{
@@ -167,7 +167,7 @@ namespace System.Runtime.CompilerServices
// See getILIntrinsicImplementation for how this happens.
throw new InvalidOperationException();
}
-#endif // _DEBUG
+#endif // DEBUG
// Set the given element in the array without any type or range checks
[MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -179,7 +179,7 @@ namespace System.Runtime.CompilerServices
return Unsafe.As<PinningHelper>(o);
}
-#if _DEBUG
+#if DEBUG
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private extern static bool IsAddressInStack(IntPtr ptr);
#endif
diff --git a/src/mscorlib/src/System/Runtime/ExceptionServices/ExceptionServicesCommon.cs b/src/mscorlib/src/System/Runtime/ExceptionServices/ExceptionServicesCommon.cs
index 8d5ced089f..0a379667d7 100644
--- a/src/mscorlib/src/System/Runtime/ExceptionServices/ExceptionServicesCommon.cs
+++ b/src/mscorlib/src/System/Runtime/ExceptionServices/ExceptionServicesCommon.cs
@@ -16,6 +16,7 @@
=============================================================================*/
using System;
+using System.Diagnostics;
namespace System.Runtime.ExceptionServices
{
@@ -123,6 +124,7 @@ namespace System.Runtime.ExceptionServices
// This method will restore the original stack trace and bucketing details before throwing
// the exception so that it is easy, from debugging standpoint, to understand what really went wrong on
// the original thread.
+ [StackTraceHidden]
public void Throw()
{
// Restore the exception dispatch details before throwing the exception.
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
index 6d9927fd97..c31a1576c4 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/COMException.cs
@@ -21,7 +21,8 @@ using Microsoft.Win32;
namespace System.Runtime.InteropServices
{
// Exception for COM Interop errors where we don't recognize the HResult.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class COMException : ExternalException
{
public COMException()
@@ -50,7 +51,6 @@ namespace System.Runtime.InteropServices
protected COMException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
public override String ToString()
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs
index 08f27dc038..b9f10bc5cb 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/ComEventsSink.cs
@@ -73,8 +73,8 @@ namespace System.Runtime.InteropServices
internal static ComEventsSink Remove(ComEventsSink sinks, ComEventsSink sink)
{
- BCLDebug.Assert(sinks != null, "removing event sink from empty sinks collection");
- BCLDebug.Assert(sink != null, "specify event sink is null");
+ Debug.Assert(sinks != null, "removing event sink from empty sinks collection");
+ Debug.Assert(sink != null, "specify event sink is null");
if (sink == sinks)
{
@@ -145,7 +145,7 @@ namespace System.Runtime.InteropServices
private void Advise(object rcw)
{
- BCLDebug.Assert(_connectionPoint == null, "comevent sink is already advised");
+ Debug.Assert(_connectionPoint == null, "comevent sink is already advised");
ComTypes.IConnectionPointContainer cpc = (ComTypes.IConnectionPointContainer)rcw;
ComTypes.IConnectionPoint cp;
@@ -160,7 +160,7 @@ namespace System.Runtime.InteropServices
private void Unadvise()
{
- BCLDebug.Assert(_connectionPoint != null, "can not unadvise from empty connection point");
+ Debug.Assert(_connectionPoint != null, "can not unadvise from empty connection point");
try
{
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs b/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs
index cc3462275e..2bce2ec6f4 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/CriticalHandle.cs
@@ -135,9 +135,6 @@ namespace System.Runtime.InteropServices
{
// ! Do not add or rearrange fields as the EE depends on this layout.
//------------------------------------------------------------------
-#if DEBUG
- private String _stackTrace; // Where we allocated this CriticalHandle.
-#endif
protected IntPtr handle; // This must be protected so derived classes can use out params.
private bool _isClosed; // Set by SetHandleAsInvalid or Close/Dispose/finalization.
@@ -146,13 +143,6 @@ namespace System.Runtime.InteropServices
{
handle = invalidHandleValue;
_isClosed = false;
-
-#if DEBUG
- if (BCLDebug.SafeHandleStackTracesEnabled)
- _stackTrace = Environment.GetStackTrace(null, false);
- else
- _stackTrace = "For a stack trace showing who allocated this CriticalHandle, set SafeHandleStackTraces to 1 and rerun your app.";
-#endif
}
// Adding an empty default constructor for annotation purposes
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
index c3ce68df4b..d1ae2e2a91 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidComObjectException.cs
@@ -17,6 +17,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidComObjectException : SystemException
{
public InvalidComObjectException()
@@ -39,7 +41,6 @@ namespace System.Runtime.InteropServices
protected InvalidComObjectException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
index f61010cda3..74029081ad 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/InvalidOleVariantTypeException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class InvalidOleVariantTypeException : SystemException
{
public InvalidOleVariantTypeException()
@@ -38,7 +40,6 @@ namespace System.Runtime.InteropServices
protected InvalidOleVariantTypeException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
index 48e2dcf411..1d0d59fab6 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/MarshalDirectiveException.cs
@@ -17,6 +17,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class MarshalDirectiveException : SystemException
{
public MarshalDirectiveException()
@@ -39,7 +41,6 @@ namespace System.Runtime.InteropServices
protected MarshalDirectiveException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
index 832c4d289e..039059e7e8 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SEHException.cs
@@ -18,7 +18,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
// Exception for Structured Exception Handler exceptions.
- //
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SEHException : ExternalException
{
public SEHException()
@@ -41,7 +42,6 @@ namespace System.Runtime.InteropServices
protected SEHException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
// Exceptions can be resumable, meaning a filtered exception
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
index 7109b4fe51..7f6a24f593 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayRankMismatchException.cs
@@ -16,6 +16,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SafeArrayRankMismatchException : SystemException
{
public SafeArrayRankMismatchException()
@@ -38,7 +40,6 @@ namespace System.Runtime.InteropServices
protected SafeArrayRankMismatchException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
index 13a6cf62a8..e155dcf64d 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeArrayTypeMismatchException.cs
@@ -17,6 +17,8 @@ using System.Runtime.Serialization;
namespace System.Runtime.InteropServices
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class SafeArrayTypeMismatchException : SystemException
{
public SafeArrayTypeMismatchException()
@@ -39,7 +41,6 @@ namespace System.Runtime.InteropServices
protected SafeArrayTypeMismatchException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs b/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs
index 6654ec9b00..7970324fef 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/SafeHandle.cs
@@ -17,6 +17,7 @@
namespace System.Runtime.InteropServices
{
using System;
+ using System.Diagnostics;
using System.Reflection;
using System.Threading;
using System.Runtime;
@@ -137,12 +138,6 @@ namespace System.Runtime.InteropServices
{
// ! Do not add or rearrange fields as the EE depends on this layout.
//------------------------------------------------------------------
-#if DEBUG
- // FxCop thinks this field is marshaled and so it raises a CA2101 error unless
- // we specify this. In practice this is never presented to Win32.
- [MarshalAs(UnmanagedType.LPWStr)]
- private String _stackTrace; // Where we allocated this SafeHandle.
-#endif
protected IntPtr handle; // this must be protected so derived classes can use out params.
private int _state; // Combined ref count and closed/disposed flags (so we can atomically modify them).
private bool _ownsHandle; // Whether we can release this handle.
@@ -162,13 +157,6 @@ namespace System.Runtime.InteropServices
if (!ownsHandle)
GC.SuppressFinalize(this);
-#if DEBUG
- if (BCLDebug.SafeHandleStackTracesEnabled)
- _stackTrace = Environment.GetStackTrace(null, false);
- else
- _stackTrace = "For a stack trace showing who allocated this SafeHandle, set SafeHandleStackTraces to 1 and rerun your app.";
-#endif
-
// Set this last to prevent SafeHandle's finalizer from freeing an
// invalid handle. This means we don't have to worry about
// ThreadAbortExceptions interrupting this constructor or the managed
@@ -179,7 +167,7 @@ namespace System.Runtime.InteropServices
// Migrating InheritanceDemands requires this default ctor, so we can mark it critical
protected SafeHandle()
{
- BCLDebug.Assert(false, "SafeHandle's protected default ctor should never be used!");
+ Debug.Fail("SafeHandle's protected default ctor should never be used!");
throw new NotImplementedException();
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs
index 014e63e89d..60686a8705 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToCollectionAdapter.cs
@@ -27,7 +27,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private BindableVectorToCollectionAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// int Count { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs
index 122c7a1b13..aa270a2aee 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/BindableVectorToListAdapter.cs
@@ -27,7 +27,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private BindableVectorToListAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// object this[int index] { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs
index 12c77a2254..2d15e31c26 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIPropertyValueImpl.cs
@@ -315,7 +315,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
}
// Array types are 1024 larger than their equivilent scalar counterpart
- BCLDebug.Assert((int)Type > 1024, "Unexpected array PropertyType value");
+ Debug.Assert((int)Type > 1024, "Unexpected array PropertyType value");
PropertyType scalarType = Type - 1024;
// If we do not have the correct array type, then we need to convert the array element-by-element
@@ -439,7 +439,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
}
else
{
- BCLDebug.Assert(false, "T in coersion function wasn't understood as a type that can be coerced - make sure that CoerceScalarValue and NumericScalarTypes are in sync");
+ Debug.Fail("T in coersion function wasn't understood as a type that can be coerced - make sure that CoerceScalarValue and NumericScalarTypes are in sync");
}
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs
index d8fa4b3cae..97473856ba 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/CLRIReferenceImpl.cs
@@ -19,7 +19,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
public CLRIReferenceImpl(PropertyType type, T obj)
: base(type, obj)
{
- BCLDebug.Assert(obj != null, "Must not be null");
+ Debug.Assert(obj != null, "Must not be null");
_value = obj;
}
@@ -73,7 +73,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
public CLRIReferenceArrayImpl(PropertyType type, T[] obj)
: base(type, obj)
{
- BCLDebug.Assert(obj != null, "Must not be null");
+ Debug.Assert(obj != null, "Must not be null");
_value = obj;
@@ -303,7 +303,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
return Activator.CreateInstance(specificType, new Object[] { propType.Value, obj });
}
- Debug.Assert(false, "We should not see non-WinRT type here");
+ Debug.Fail("We should not see non-WinRT type here");
return null;
}
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs
index 5d9f332a61..0a6f6e0c23 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/DictionaryToMapAdapter.cs
@@ -28,7 +28,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private DictionaryToMapAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// V Lookup(K key)
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs
index 95158b093d..d39516d117 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/EnumeratorToIteratorAdapter.cs
@@ -25,7 +25,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private EnumerableToIterableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// This method is invoked when First is called on a managed implementation of IIterable<T>.
@@ -40,7 +40,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private EnumerableToBindableIterableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
internal sealed class NonGenericToGenericEnumerator : IEnumerator<object>
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs
index 564b86e685..17624dfd1f 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IClosable.cs
@@ -26,7 +26,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IDisposableToIClosableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
public void Close()
@@ -41,7 +41,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IClosableToIDisposableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
private void Dispose()
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs
index aa7bf76750..4fbcd9975d 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IMapViewToIReadOnlyDictionaryAdapter.cs
@@ -27,7 +27,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IMapViewToIReadOnlyDictionaryAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// V this[K key] { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs
index f5bc58a7e5..64d16abe65 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyDictionaryToIMapViewAdapter.cs
@@ -27,7 +27,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IReadOnlyDictionaryToIMapViewAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// V Lookup(K key)
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs
index c69115d1eb..cd41ea0e69 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IReadOnlyListToIVectorViewAdapter.cs
@@ -27,7 +27,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IReadOnlyListToIVectorViewAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// T GetAt(uint index)
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs
index 1445670680..50149799e0 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IVectorViewToIReadOnlyListAdapter.cs
@@ -29,7 +29,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IVectorViewToIReadOnlyListAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// T this[int index] { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs
index 7bc2fa06a9..e681533f6b 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/IteratorToEnumeratorAdapter.cs
@@ -28,7 +28,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private IterableToEnumerableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// This method is invoked when GetEnumerator is called on a WinRT-backed implementation of IEnumerable<T>.
@@ -68,7 +68,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private BindableIterableToEnumerableAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
private sealed class NonGenericToGenericIterator : IIterator<object>
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs
index c0c8769b5a..2465908a2a 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToBindableVectorAdapter.cs
@@ -28,7 +28,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private ListToBindableVectorAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// object GetAt(uint index)
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs
index 4f23f639f2..8c7dfcaf04 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/ListToVectorAdapter.cs
@@ -28,7 +28,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private ListToVectorAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// T GetAt(uint index)
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs
index 8cc189b162..50e5f5e337 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToCollectionAdapter.cs
@@ -29,7 +29,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private MapToCollectionAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// int Count { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs
index a69acb7eeb..b8c4de8fb2 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapToDictionaryAdapter.cs
@@ -26,7 +26,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private MapToDictionaryAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// V this[K key] { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs
index 16e21e21a1..1e2a5f09c1 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/MapViewToReadOnlyCollectionAdapter.cs
@@ -29,7 +29,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private MapViewToReadOnlyCollectionAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// int Count { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs
index ff10971f91..07617929c8 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToCollectionAdapter.cs
@@ -26,7 +26,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private VectorToCollectionAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// int Count { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs
index 3e4e5ad67d..2c94129cd4 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorToListAdapter.cs
@@ -26,7 +26,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private VectorToListAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// T this[int index] { get }
diff --git a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs
index 679060bf4d..dcaa97fddb 100644
--- a/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs
+++ b/src/mscorlib/src/System/Runtime/InteropServices/WindowsRuntime/VectorViewToReadOnlyCollectionAdapter.cs
@@ -26,7 +26,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime
{
private VectorViewToReadOnlyCollectionAdapter()
{
- Debug.Assert(false, "This class is never instantiated");
+ Debug.Fail("This class is never instantiated");
}
// int Count { get }
diff --git a/src/mscorlib/src/System/Runtime/MemoryFailPoint.cs b/src/mscorlib/src/System/Runtime/MemoryFailPoint.cs
index 899bd44d96..660b0f30be 100644
--- a/src/mscorlib/src/System/Runtime/MemoryFailPoint.cs
+++ b/src/mscorlib/src/System/Runtime/MemoryFailPoint.cs
@@ -261,7 +261,7 @@ namespace System.Runtime
if (needPageFile || needAddressSpace)
{
InsufficientMemoryException e = new InsufficientMemoryException(SR.InsufficientMemory_MemFailPoint);
-#if _DEBUG
+#if DEBUG
e.Data["MemFailPointState"] = new MemoryFailPointState(sizeInMegabytes, segmentSize,
needPageFile, needAddressSpace, needContiguousVASpace,
availPageFile >> 20, totalAddressSpaceFree >> 20,
@@ -273,7 +273,7 @@ namespace System.Runtime
if (needContiguousVASpace)
{
InsufficientMemoryException e = new InsufficientMemoryException(SR.InsufficientMemory_MemFailPoint_VAFrag);
-#if _DEBUG
+#if DEBUG
e.Data["MemFailPointState"] = new MemoryFailPointState(sizeInMegabytes, segmentSize,
needPageFile, needAddressSpace, needContiguousVASpace,
availPageFile >> 20, totalAddressSpaceFree >> 20,
@@ -285,7 +285,7 @@ namespace System.Runtime
break;
default:
- Debug.Assert(false, "Fell through switch statement!");
+ Debug.Fail("Fell through switch statement!");
break;
}
}
@@ -422,7 +422,7 @@ namespace System.Runtime
*/
}
-#if _DEBUG
+#if DEBUG
[Serializable]
internal sealed class MemoryFailPointState
{
diff --git a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
index 694a382148..979d5fee2a 100644
--- a/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
+++ b/src/mscorlib/src/System/Runtime/Serialization/SerializationInfo.cs
@@ -323,7 +323,6 @@ namespace System.Runtime.Serialization
{
if (m_nameToIndex.ContainsKey(name))
{
- BCLDebug.Trace("SER", "[SerializationInfo.AddValue]Tried to add ", name, " twice to the SI.");
throw new SerializationException(SR.Serialization_SameNameTwice);
}
m_nameToIndex.Add(name, m_currMember);
@@ -383,7 +382,6 @@ namespace System.Runtime.Serialization
{
throw new ArgumentNullException(nameof(name));
}
- BCLDebug.Trace("SER", "[SerializationInfo.FindElement]Looking for ", name, " CurrMember is: ", m_currMember);
int index;
if (m_nameToIndex.TryGetValue(name, out index))
{
diff --git a/src/mscorlib/src/System/SharedStatics.cs b/src/mscorlib/src/System/SharedStatics.cs
index dd9c63b334..8111b9b1d1 100644
--- a/src/mscorlib/src/System/SharedStatics.cs
+++ b/src/mscorlib/src/System/SharedStatics.cs
@@ -29,7 +29,7 @@ namespace System
// when we set up _sharedStatics via AppDomain::SetupSharedStatics
private SharedStatics()
{
- BCLDebug.Assert(false, "SharedStatics..ctor() is never called.");
+ Debug.Fail("SharedStatics..ctor() is never called.");
}
// This is the total amount of memory currently "reserved" via
diff --git a/src/mscorlib/src/System/String.Comparison.cs b/src/mscorlib/src/System/String.Comparison.cs
index bcb0ee058a..fd318b3d08 100644
--- a/src/mscorlib/src/System/String.Comparison.cs
+++ b/src/mscorlib/src/System/String.Comparison.cs
@@ -219,13 +219,13 @@ namespace System
}
}
- private unsafe static int CompareOrdinalHelper(String strA, String strB)
+ private static unsafe int CompareOrdinalHelper(String strA, String strB)
{
Debug.Assert(strA != null);
Debug.Assert(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
+ // in the callers makes them small enough to be inlined
Debug.Assert(strA._firstChar == strB._firstChar,
"For performance reasons, callers of this method should " +
"check/short-circuit beforehand if the first char is the same.");
@@ -637,6 +637,24 @@ namespace System
return CompareOrdinalHelper(strA, strB);
}
+ // TODO https://github.com/dotnet/corefx/issues/21395: Expose this publicly?
+ internal static int CompareOrdinal(ReadOnlySpan<char> strA, ReadOnlySpan<char> strB)
+ {
+ // TODO: This needs to be optimized / unrolled. It can't just use CompareOrdinalHelper(str, str)
+ // (changed to accept spans) because its implementation is based on a string layout,
+ // in a way that doesn't work when there isn't guaranteed to be a null terminator.
+
+ int minLength = Math.Min(strA.Length, strB.Length);
+ for (int i = 0; i < minLength; i++)
+ {
+ if (strA[i] != strB[i])
+ {
+ return strA[i] - strB[i];
+ }
+ }
+
+ return strA.Length - strB.Length;
+ }
// Compares strA and strB using an ordinal (code-point) comparison.
//
diff --git a/src/mscorlib/src/System/String.Manipulation.cs b/src/mscorlib/src/System/String.Manipulation.cs
index 9cb4204159..14fca57a36 100644
--- a/src/mscorlib/src/System/String.Manipulation.cs
+++ b/src/mscorlib/src/System/String.Manipulation.cs
@@ -142,45 +142,82 @@ namespace System
if (values == null)
throw new ArgumentNullException(nameof(values));
- using (IEnumerator<T> en = values.GetEnumerator())
+ if (typeof(T) == typeof(char))
{
- if (!en.MoveNext())
- return string.Empty;
+ // Special-case T==char, as we can handle that case much more efficiently,
+ // and string.Concat(IEnumerable<char>) can be used as an efficient
+ // enumerable-based equivalent of new string(char[]).
+ using (IEnumerator<char> en = Unsafe.As<IEnumerable<char>>(values).GetEnumerator())
+ {
+ if (!en.MoveNext())
+ {
+ // There weren't any chars. Return the empty string.
+ return Empty;
+ }
- // We called MoveNext once, so this will be the first item
- T currentValue = en.Current;
+ char c = en.Current; // save the first char
- // Call ToString before calling MoveNext again, since
- // we want to stay consistent with the below loop
- // Everything should be called in the order
- // MoveNext-Current-ToString, unless further optimizations
- // can be made, to avoid breaking changes
- string firstString = currentValue?.ToString();
+ if (!en.MoveNext())
+ {
+ // There was only one char. Return a string from it directly.
+ return CreateFromChar(c);
+ }
- // If there's only 1 item, simply call ToString on that
- if (!en.MoveNext())
- {
- // We have to handle the case of either currentValue
- // or its ToString being null
- return firstString ?? string.Empty;
+ // Create the StringBuilder, add the chars we've already enumerated,
+ // add the rest, and then get the resulting string.
+ StringBuilder result = StringBuilderCache.Acquire();
+ result.Append(c); // first value
+ do
+ {
+ c = en.Current;
+ result.Append(c);
+ }
+ while (en.MoveNext());
+ return StringBuilderCache.GetStringAndRelease(result);
}
+ }
+ else
+ {
+ using (IEnumerator<T> en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ return string.Empty;
- StringBuilder result = StringBuilderCache.Acquire();
+ // We called MoveNext once, so this will be the first item
+ T currentValue = en.Current;
- result.Append(firstString);
+ // Call ToString before calling MoveNext again, since
+ // we want to stay consistent with the below loop
+ // Everything should be called in the order
+ // MoveNext-Current-ToString, unless further optimizations
+ // can be made, to avoid breaking changes
+ string firstString = currentValue?.ToString();
- do
- {
- currentValue = en.Current;
+ // If there's only 1 item, simply call ToString on that
+ if (!en.MoveNext())
+ {
+ // We have to handle the case of either currentValue
+ // or its ToString being null
+ return firstString ?? string.Empty;
+ }
- if (currentValue != null)
+ StringBuilder result = StringBuilderCache.Acquire();
+
+ result.Append(firstString);
+
+ do
{
- result.Append(currentValue.ToString());
+ currentValue = en.Current;
+
+ if (currentValue != null)
+ {
+ result.Append(currentValue.ToString());
+ }
}
- }
- while (en.MoveNext());
+ while (en.MoveNext());
- return StringBuilderCache.GetStringAndRelease(result);
+ return StringBuilderCache.GetStringAndRelease(result);
+ }
}
}
diff --git a/src/mscorlib/src/System/String.cs b/src/mscorlib/src/System/String.cs
index cd9689978e..fecbd7176f 100644
--- a/src/mscorlib/src/System/String.cs
+++ b/src/mscorlib/src/System/String.cs
@@ -858,19 +858,16 @@ namespace System
public CharEnumerator GetEnumerator()
{
- BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
return new CharEnumerator(this);
}
IEnumerator<char> IEnumerable<char>.GetEnumerator()
{
- BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
return new CharEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
- BCLDebug.Perf(false, "Avoid using String's CharEnumerator until C# special cases foreach on String - use the indexed property on String instead.");
return new CharEnumerator(this);
}
diff --git a/src/mscorlib/src/System/StubHelpers.cs b/src/mscorlib/src/System/StubHelpers.cs
index ff74d4c3c5..8bdcb76330 100644
--- a/src/mscorlib/src/System/StubHelpers.cs
+++ b/src/mscorlib/src/System/StubHelpers.cs
@@ -25,7 +25,7 @@ namespace System.StubHelpers
unsafe static internal byte[] DoAnsiConversion(string str, bool fBestFit, bool fThrowOnUnmappableChar, out int cbLength)
{
byte[] buffer = new byte[(str.Length + 1) * Marshal.SystemMaxDBCSCharSize];
- BCLDebug.Assert(buffer.Length != 0);
+ Debug.Assert(buffer.Length != 0);
fixed (byte* bufferPtr = &buffer[0])
{
cbLength = str.ConvertToAnsi(bufferPtr, buffer.Length, fBestFit, fThrowOnUnmappableChar);
@@ -40,7 +40,7 @@ namespace System.StubHelpers
int cbLength = managedChar.ToString().ConvertToAnsi(bufferPtr, cbAllocLength, fBestFit, fThrowOnUnmappableChar);
- BCLDebug.Assert(cbLength > 0, "Zero bytes returned from DoAnsiConversion in AnsiCharMarshaler.ConvertToNative");
+ Debug.Assert(cbLength > 0, "Zero bytes returned from DoAnsiConversion in AnsiCharMarshaler.ConvertToNative");
return bufferPtr[0];
}
@@ -254,10 +254,10 @@ namespace System.StubHelpers
{
// If caller provided a buffer, construct the BSTR manually. The size
// of the buffer must be at least (lengthInBytes + 6) bytes.
-#if _DEBUG
+#if DEBUG
uint length = *((uint*)pNativeBuffer.ToPointer());
- BCLDebug.Assert(length >= lengthInBytes + 6, "BSTR localloc'ed buffer is too small");
-#endif // _DEBUG
+ Debug.Assert(length >= lengthInBytes + 6, "BSTR localloc'ed buffer is too small");
+#endif
// set length
*((uint*)pNativeBuffer.ToPointer()) = lengthInBytes;
@@ -385,7 +385,7 @@ namespace System.StubHelpers
int nbytesused;
byte[] bytes = AnsiCharMarshaler.DoAnsiConversion(strManaged, fBestFit, fThrowOnUnmappableChar, out nbytesused);
- BCLDebug.Assert(nbytesused < nbytes, "Insufficient buffer allocated in VBByValStrMarshaler.ConvertToNative");
+ Debug.Assert(nbytesused < nbytes, "Insufficient buffer allocated in VBByValStrMarshaler.ConvertToNative");
Buffer.Memcpy(pNative, 0, bytes, 0, nbytesused);
pNative[nbytesused] = 0;
@@ -472,19 +472,19 @@ namespace System.StubHelpers
{
static internal IntPtr ConvertToNative(string strManaged)
{
- Debug.Assert(false, "NYI");
+ Debug.Fail("NYI");
return IntPtr.Zero;
}
static internal unsafe string ConvertToManaged(IntPtr bstr)
{
- Debug.Assert(false, "NYI");
+ Debug.Fail("NYI");
return null;
}
static internal void ClearNative(IntPtr pNative)
{
- Debug.Assert(false, "NYI");
+ Debug.Fail("NYI");
}
} // class WSTRBufferMarshaler
@@ -978,7 +978,7 @@ namespace System.StubHelpers
internal AsAnyMarshaler(IntPtr pvArrayMarshaler)
{
// we need this in case the value being marshaled turns out to be array
- BCLDebug.Assert(pvArrayMarshaler != IntPtr.Zero, "pvArrayMarshaler must not be null");
+ Debug.Assert(pvArrayMarshaler != IntPtr.Zero, "pvArrayMarshaler must not be null");
this.pvArrayMarshaler = pvArrayMarshaler;
backPropAction = BackPropAction.None;
@@ -1533,7 +1533,7 @@ namespace System.StubHelpers
public void Add(CleanupWorkListElement elem)
{
- BCLDebug.Assert(elem.m_owned == false, "m_owned is supposed to be false and set later by DangerousAddRef");
+ Debug.Assert(elem.m_owned == false, "m_owned is supposed to be false and set later by DangerousAddRef");
m_list.Add(elem);
}
diff --git a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
index e0a52581f6..b3571d8f69 100644
--- a/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
+++ b/src/mscorlib/src/System/Threading/CancellationTokenRegistration.cs
@@ -41,7 +41,7 @@ namespace System.Threading
/// registration isn't associated with a token (such as after the registration has been disposed),
/// this will return a default token.
/// </summary>
- internal CancellationToken Token => _node?.Partition.Source.Token ?? default(CancellationToken);
+ public CancellationToken Token => _node?.Partition.Source.Token ?? default(CancellationToken);
/// <summary>
/// Disposes of the registration and unregisters the target callback from the associated
diff --git a/src/mscorlib/src/System/Threading/Mutex.cs b/src/mscorlib/src/System/Threading/Mutex.cs
index 64bfc85234..991fd4da0d 100644
--- a/src/mscorlib/src/System/Threading/Mutex.cs
+++ b/src/mscorlib/src/System/Threading/Mutex.cs
@@ -2,216 +2,123 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
-//
-/*=============================================================================
-**
-**
-**
-** Purpose: synchronization primitive that can also be used for interprocess synchronization
-**
-**
-=============================================================================*/
+
+using System.IO;
+using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+using System.Runtime.InteropServices;
+using System.Diagnostics;
namespace System.Threading
{
- using System;
- using System.Threading;
- using System.Runtime.CompilerServices;
- using System.IO;
- using Microsoft.Win32;
- using Microsoft.Win32.SafeHandles;
- using System.Runtime.InteropServices;
- using System.Runtime.Versioning;
- using System.Security;
- using System.Diagnostics;
-
+ /// <summary>
+ /// Synchronization primitive that can also be used for interprocess synchronization
+ /// </summary>
public sealed class Mutex : WaitHandle
{
private const uint AccessRights =
(uint)Win32Native.MAXIMUM_ALLOWED | Win32Native.SYNCHRONIZE | Win32Native.MUTEX_MODIFY_STATE;
- private static bool dummyBool;
-
- internal class MutexSecurity
+ public Mutex(bool initiallyOwned, string name, out bool createdNew)
{
+#if !PLATFORM_UNIX
+ VerifyNameForCreate(name);
+#endif
+ CreateMutexCore(initiallyOwned, name, out createdNew);
}
- public Mutex(bool initiallyOwned, String name, out bool createdNew)
- : this(initiallyOwned, name, out createdNew, (MutexSecurity)null)
+ public Mutex(bool initiallyOwned, string name)
{
+#if !PLATFORM_UNIX
+ VerifyNameForCreate(name);
+#endif
+ CreateMutexCore(initiallyOwned, name, out _);
}
- internal unsafe Mutex(bool initiallyOwned, String name, out bool createdNew, MutexSecurity mutexSecurity)
+ public Mutex(bool initiallyOwned)
{
- if (name == string.Empty)
- {
- // Empty name is treated as an unnamed mutex. Set to null, and we will check for null from now on.
- name = null;
- }
-#if PLATFORM_WINDOWS
- if (name != null && System.IO.Path.MaxPath < name.Length)
- {
- throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
- }
-#endif // PLATFORM_WINDOWS
- Win32Native.SECURITY_ATTRIBUTES secAttrs = null;
-
- CreateMutexWithGuaranteedCleanup(initiallyOwned, name, out createdNew, secAttrs);
+ CreateMutexCore(initiallyOwned, null, out _);
}
- internal void CreateMutexWithGuaranteedCleanup(bool initiallyOwned, String name, out bool createdNew, Win32Native.SECURITY_ATTRIBUTES secAttrs)
+ public Mutex()
{
- RuntimeHelpers.CleanupCode cleanupCode = new RuntimeHelpers.CleanupCode(MutexCleanupCode);
- MutexCleanupInfo cleanupInfo = new MutexCleanupInfo(null, false);
- MutexTryCodeHelper tryCodeHelper = new MutexTryCodeHelper(initiallyOwned, cleanupInfo, name, secAttrs, this);
- RuntimeHelpers.TryCode tryCode = new RuntimeHelpers.TryCode(tryCodeHelper.MutexTryCode);
- RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(
- tryCode,
- cleanupCode,
- cleanupInfo);
- createdNew = tryCodeHelper.m_newMutex;
+ CreateMutexCore(false, null, out _);
}
- internal class MutexTryCodeHelper
+ private Mutex(SafeWaitHandle handle)
{
- private bool m_initiallyOwned;
- private MutexCleanupInfo m_cleanupInfo;
- internal bool m_newMutex;
- private String m_name;
- private Win32Native.SECURITY_ATTRIBUTES m_secAttrs;
- private Mutex m_mutex;
-
- internal MutexTryCodeHelper(bool initiallyOwned, MutexCleanupInfo cleanupInfo, String name, Win32Native.SECURITY_ATTRIBUTES secAttrs, Mutex mutex)
- {
- Debug.Assert(name == null || name.Length != 0);
-
- m_initiallyOwned = initiallyOwned;
- m_cleanupInfo = cleanupInfo;
- m_name = name;
- m_secAttrs = secAttrs;
- m_mutex = mutex;
- }
+ SafeWaitHandle = handle;
+ }
- internal void MutexTryCode(object userData)
+ public static Mutex OpenExisting(string name)
+ {
+ switch (OpenExistingWorker(name, out Mutex result))
{
- // try block
- if (m_initiallyOwned)
- {
- m_cleanupInfo.inCriticalRegion = true;
- }
-
- uint mutexFlags = m_initiallyOwned ? Win32Native.CREATE_MUTEX_INITIAL_OWNER : 0;
- SafeWaitHandle mutexHandle = Win32Native.CreateMutexEx(m_secAttrs, m_name, mutexFlags, AccessRights);
+ case OpenExistingResult.NameNotFound:
+ throw new WaitHandleCannotBeOpenedException();
- int errorCode = Marshal.GetLastWin32Error();
- if (mutexHandle.IsInvalid)
- {
- mutexHandle.SetHandleAsInvalid();
- if (m_name != null)
- {
- switch (errorCode)
- {
-#if PLATFORM_UNIX
- case Win32Native.ERROR_FILENAME_EXCED_RANGE:
- // On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
- throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Sys.MaxName), "name");
-#endif
+ case OpenExistingResult.NameInvalid:
+ throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
- case Win32Native.ERROR_INVALID_HANDLE:
- throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, m_name));
- }
- }
- throw Win32Marshal.GetExceptionForWin32Error(errorCode, m_name);
- }
- m_newMutex = errorCode != Win32Native.ERROR_ALREADY_EXISTS;
- m_mutex.SetHandleInternal(mutexHandle);
+ case OpenExistingResult.PathNotFound:
+ throw Win32Marshal.GetExceptionForWin32Error(Win32Native.ERROR_PATH_NOT_FOUND, name);
- m_mutex.hasThreadAffinity = true;
+ default:
+ return result;
}
}
- private void MutexCleanupCode(Object userData, bool exceptionThrown)
- {
- MutexCleanupInfo cleanupInfo = (MutexCleanupInfo)userData;
+ public static bool TryOpenExisting(string name, out Mutex result) =>
+ OpenExistingWorker(name, out result) == OpenExistingResult.Success;
- // If hasThreadAffinity isn't true, we've thrown an exception in the above try, and we must free the mutex
- // on this OS thread before ending our thread affninity.
- if (!hasThreadAffinity)
+ // Note: To call ReleaseMutex, you must have an ACL granting you
+ // MUTEX_MODIFY_STATE rights (0x0001). The other interesting value
+ // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001).
+ public void ReleaseMutex()
+ {
+ if (!Win32Native.ReleaseMutex(safeWaitHandle))
{
- if (cleanupInfo.mutexHandle != null && !cleanupInfo.mutexHandle.IsInvalid)
- {
- if (cleanupInfo.inCriticalRegion)
- {
- Win32Native.ReleaseMutex(cleanupInfo.mutexHandle);
- }
- cleanupInfo.mutexHandle.Dispose();
- }
+ throw new ApplicationException(SR.Arg_SynchronizationLockException);
}
}
- internal class MutexCleanupInfo
+#if !PLATFORM_UNIX
+ private static void VerifyNameForCreate(string name)
{
- internal SafeWaitHandle mutexHandle;
- internal bool inCriticalRegion;
- internal MutexCleanupInfo(SafeWaitHandle mutexHandle, bool inCriticalRegion)
+ if (name != null && (Path.MaxPath < name.Length))
{
- this.mutexHandle = mutexHandle;
- this.inCriticalRegion = inCriticalRegion;
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
}
}
+#endif
- public Mutex(bool initiallyOwned, String name) : this(initiallyOwned, name, out dummyBool)
- {
- }
-
- public Mutex(bool initiallyOwned) : this(initiallyOwned, null, out dummyBool)
+ private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew)
{
- }
+ Debug.Assert(name == null || name.Length <= Path.MaxPath);
- public Mutex() : this(false, null, out dummyBool)
- {
- }
+ uint mutexFlags = initiallyOwned ? Win32Native.CREATE_MUTEX_INITIAL_OWNER : 0;
- private Mutex(SafeWaitHandle handle)
- {
- SetHandleInternal(handle);
- hasThreadAffinity = true;
- }
+ SafeWaitHandle mutexHandle = Win32Native.CreateMutexEx(null, name, mutexFlags, AccessRights);
+ int errorCode = Marshal.GetLastWin32Error();
- public static Mutex OpenExisting(string name)
- {
- return OpenExisting(name, (MutexRights)0);
- }
-
- internal enum MutexRights
- {
- }
-
- internal static Mutex OpenExisting(string name, MutexRights rights)
- {
- Mutex result;
- switch (OpenExistingWorker(name, rights, out result))
+ if (mutexHandle.IsInvalid)
{
- case OpenExistingResult.NameNotFound:
- throw new WaitHandleCannotBeOpenedException();
-
- case OpenExistingResult.NameInvalid:
+ mutexHandle.SetHandleAsInvalid();
+#if PLATFORM_UNIX
+ if (errorCode == Interop.Errors.ERROR_FILENAME_EXCED_RANGE)
+ // On Unix, length validation is done by CoreCLR's PAL after converting to utf-8
+ throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Sys.MaxName), nameof(name));
+#endif
+ if (errorCode == Interop.Errors.ERROR_INVALID_HANDLE)
throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
-
- case OpenExistingResult.PathNotFound:
- throw Win32Marshal.GetExceptionForWin32Error(Win32Native.ERROR_PATH_NOT_FOUND, name);
-
- default:
- return result;
+ throw Win32Marshal.GetExceptionForWin32Error(errorCode, name);
}
- }
- public static bool TryOpenExisting(string name, out Mutex result)
- {
- return OpenExistingWorker(name, (MutexRights)0, out result) == OpenExistingResult.Success;
+ createdNew = errorCode != Interop.Errors.ERROR_ALREADY_EXISTS;
+ SafeWaitHandle = mutexHandle;
}
- private static OpenExistingResult OpenExistingWorker(string name, MutexRights rights, out Mutex result)
+ private static OpenExistingResult OpenExistingWorker(string name, out Mutex result)
{
if (name == null)
{
@@ -222,15 +129,12 @@ namespace System.Threading
{
throw new ArgumentException(SR.Argument_EmptyName, nameof(name));
}
+
#if !PLATFORM_UNIX
- if (System.IO.Path.MaxPath < name.Length)
- {
- throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Path.MaxPath), nameof(name));
- }
+ VerifyNameForCreate(name);
#endif
result = null;
-
// To allow users to view & edit the ACL's, call OpenMutex
// with parameters to allow us to view & edit the ACL. This will
// fail if we don't have permission to view or edit the ACL's.
@@ -248,7 +152,6 @@ namespace System.Threading
throw new ArgumentException(SR.Format(SR.Argument_WaitHandleNameTooLong, Interop.Sys.MaxName), nameof(name));
}
#endif
-
if (Win32Native.ERROR_FILE_NOT_FOUND == errorCode || Win32Native.ERROR_INVALID_NAME == errorCode)
return OpenExistingResult.NameNotFound;
if (Win32Native.ERROR_PATH_NOT_FOUND == errorCode)
@@ -261,21 +164,8 @@ namespace System.Threading
}
result = new Mutex(myHandle);
- return OpenExistingResult.Success;
- }
- // Note: To call ReleaseMutex, you must have an ACL granting you
- // MUTEX_MODIFY_STATE rights (0x0001). The other interesting value
- // in a Mutex's ACL is MUTEX_ALL_ACCESS (0x1F0001).
- public void ReleaseMutex()
- {
- if (Win32Native.ReleaseMutex(safeWaitHandle))
- {
- }
- else
- {
- throw new ApplicationException(SR.Arg_SynchronizationLockException);
- }
+ return OpenExistingResult.Success;
}
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
index bdfe8eeff9..b666d2b35d 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TPLETWProvider.cs
@@ -56,7 +56,8 @@ namespace System.Threading.Tasks
/// Defines the singleton instance for the TPL ETW provider.
/// The TPL Event provider GUID is {2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5}.
/// </summary>
- public static TplEtwProvider Log = new TplEtwProvider();
+ public static readonly TplEtwProvider Log = new TplEtwProvider();
+
/// <summary>Prevent external instantiation. All logging should go through the Log instance.</summary>
private TplEtwProvider() { }
@@ -128,6 +129,11 @@ namespace System.Threading.Tasks
public const EventKeywords TasksFlowActivityIds = (EventKeywords)0x80;
/// <summary>
+ /// Events related to the happenings of async methods.
+ /// </summary>
+ public const EventKeywords AsyncMethod = (EventKeywords)0x100;
+
+ /// <summary>
/// TasksSetActivityIds will cause the task operations to set Activity Ids
/// This option is incompatible with TasksFlowActivityIds flow is ignored
/// if that keyword is set. This option is likely to be removed in the future
@@ -528,6 +534,25 @@ namespace System.Threading.Tasks
WriteEvent(26, TaskID);
}
+ [NonEvent]
+ public void IncompleteAsyncMethod(IAsyncStateMachineBox stateMachineBox)
+ {
+ System.Diagnostics.Debug.Assert(stateMachineBox != null);
+ if (IsEnabled(EventLevel.Warning, Keywords.AsyncMethod))
+ {
+ IAsyncStateMachine stateMachine = stateMachineBox.GetStateMachineObject();
+ if (stateMachine != null)
+ {
+ string description = AsyncMethodBuilderCore.GetAsyncStateMachineDescription(stateMachine);
+ IncompleteAsyncMethod(description);
+ }
+ }
+ }
+
+ [Event(27, Level = EventLevel.Warning, Keywords = Keywords.AsyncMethod)]
+ private void IncompleteAsyncMethod(string stateMachineDescription) =>
+ WriteEvent(27, stateMachineDescription);
+
/// <summary>
/// Activity IDs are GUIDS but task IDS are integers (and are not unique across appdomains
/// This routine creates a process wide unique GUID given a task ID
diff --git a/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/mscorlib/src/System/Threading/Tasks/Task.cs
index e3dd01c0a9..37ae347649 100644
--- a/src/mscorlib/src/System/Threading/Tasks/Task.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/Task.cs
@@ -2498,7 +2498,7 @@ namespace System.Threading.Tasks
actionWithState(m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in Task");
+ Debug.Fail("Invalid m_action in Task");
}
/// <summary>
@@ -2644,10 +2644,10 @@ namespace System.Threading.Tasks
SynchronizationContext syncCtx = SynchronizationContext.CurrentNoFlow;
if (syncCtx != null && syncCtx.GetType() != typeof(SynchronizationContext))
{
- Action moveNextAction = stateMachineBox.MoveNextAction;
- if (!AddTaskContinuation(new SynchronizationContextAwaitTaskContinuation(syncCtx, moveNextAction, flowExecutionContext: false), addBeforeOthers: false))
+ var tc = new SynchronizationContextAwaitTaskContinuation(syncCtx, stateMachineBox.MoveNextAction, flowExecutionContext: false);
+ if (!AddTaskContinuation(tc, addBeforeOthers: false))
{
- AwaitTaskContinuation.UnsafeScheduleAction(moveNextAction, this);
+ tc.Run(this, canInlineContinuationTask: false);
}
return;
}
@@ -2656,10 +2656,10 @@ namespace System.Threading.Tasks
TaskScheduler scheduler = TaskScheduler.InternalCurrent;
if (scheduler != null && scheduler != TaskScheduler.Default)
{
- Action moveNextAction = stateMachineBox.MoveNextAction;
- if (!AddTaskContinuation(new TaskSchedulerAwaitTaskContinuation(scheduler, moveNextAction, flowExecutionContext: false), addBeforeOthers: false))
+ var tc = new TaskSchedulerAwaitTaskContinuation(scheduler, stateMachineBox.MoveNextAction, flowExecutionContext: false);
+ if (!AddTaskContinuation(tc, addBeforeOthers: false))
{
- AwaitTaskContinuation.UnsafeScheduleAction(moveNextAction, this);
+ tc.Run(this, canInlineContinuationTask: false);
}
return;
}
@@ -2879,6 +2879,13 @@ namespace System.Threading.Tasks
// to be able to see the method on the stack and inspect arguments).
private bool InternalWaitCore(int millisecondsTimeout, CancellationToken cancellationToken)
{
+ // If the task has already completed, there's nothing to wait for.
+ bool returnValue = IsCompleted;
+ if (returnValue)
+ {
+ return true;
+ }
+
// ETW event for Task Wait Begin
var etwLog = TplEtwProvider.Log;
bool etwIsEnabled = etwLog.IsEnabled();
@@ -2890,30 +2897,24 @@ namespace System.Threading.Tasks
this.Id, TplEtwProvider.TaskWaitBehavior.Synchronous, 0);
}
- bool returnValue = IsCompleted;
+ // Alert a listening debugger that we can't make forward progress unless it slips threads.
+ // We call NOCTD for two reasons:
+ // 1. If the task runs on another thread, then we'll be blocked here indefinitely.
+ // 2. If the task runs inline but takes some time to complete, it will suffer ThreadAbort with possible state corruption,
+ // and it is best to prevent this unless the user explicitly asks to view the value with thread-slipping enabled.
+ Debugger.NotifyOfCrossThreadDependency();
- // If the event hasn't already been set, we will wait.
- if (!returnValue)
+ // We will attempt inline execution only if an infinite wait was requested
+ // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified
+ // because we don't know how long the task delegate will take.
+ if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled &&
+ WrappedTryRunInline() && IsCompleted) // TryRunInline doesn't guarantee completion, as there may be unfinished children.
{
- // Alert a listening debugger that we can't make forward progress unless it slips threads.
- // We call NOCTD for two reasons:
- // 1. If the task runs on another thread, then we'll be blocked here indefinitely.
- // 2. If the task runs inline but takes some time to complete, it will suffer ThreadAbort with possible state corruption,
- // and it is best to prevent this unless the user explicitly asks to view the value with thread-slipping enabled.
- Debugger.NotifyOfCrossThreadDependency();
-
- // We will attempt inline execution only if an infinite wait was requested
- // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified
- // because we don't know how long the task delegate will take.
- if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled &&
- WrappedTryRunInline() && IsCompleted) // TryRunInline doesn't guarantee completion, as there may be unfinished children.
- {
- returnValue = true;
- }
- else
- {
- returnValue = SpinThenBlockingWait(millisecondsTimeout, cancellationToken);
- }
+ returnValue = true;
+ }
+ else
+ {
+ returnValue = SpinThenBlockingWait(millisecondsTimeout, cancellationToken);
}
Debug.Assert(IsCompleted || millisecondsTimeout != Timeout.Infinite);
@@ -5444,8 +5445,7 @@ namespace System.Threading.Tasks
// ... and create our timer and make sure that it stays rooted.
if (millisecondsDelay != Timeout.Infinite) // no need to create the timer if it's an infinite timeout
{
- promise.Timer = new Timer(state => ((DelayPromise)state).Complete(), promise, millisecondsDelay, Timeout.Infinite);
- promise.Timer.KeepRootedWhileScheduled();
+ promise.Timer = new TimerQueueTimer(state => ((DelayPromise)state).Complete(), promise, (uint)millisecondsDelay, Timeout.UnsignedInfinite);
}
// Return the timer proxy task
@@ -5470,7 +5470,7 @@ namespace System.Threading.Tasks
internal readonly CancellationToken Token;
internal CancellationTokenRegistration Registration;
- internal Timer Timer;
+ internal TimerQueueTimer Timer;
internal void Complete()
{
@@ -5496,7 +5496,7 @@ namespace System.Threading.Tasks
// If we set the value, also clean up.
if (setSucceeded)
{
- if (Timer != null) Timer.Dispose();
+ Timer?.Close();
Registration.Dispose();
}
}
@@ -6606,7 +6606,7 @@ namespace System.Threading.Tasks
Debug.Assert(result, "Expected TrySetFromTask from inner task to succeed");
break;
default:
- Debug.Assert(false, "UnwrapPromise in illegal state");
+ Debug.Fail("UnwrapPromise in illegal state");
break;
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
index 06539f956c..8835eb542d 100644
--- a/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/TaskContinuation.cs
@@ -65,7 +65,7 @@ namespace System.Threading.Tasks
actionWithState(antecedent, m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in ContinuationTaskFromTask");
+ Debug.Fail("Invalid m_action in ContinuationTaskFromTask");
}
}
@@ -112,7 +112,7 @@ namespace System.Threading.Tasks
m_result = funcWithState(antecedent, m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in ContinuationResultTaskFromTask");
+ Debug.Fail("Invalid m_action in ContinuationResultTaskFromTask");
}
}
@@ -159,7 +159,7 @@ namespace System.Threading.Tasks
actionWithState(antecedent, m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in ContinuationTaskFromResultTask");
+ Debug.Fail("Invalid m_action in ContinuationTaskFromResultTask");
}
}
@@ -206,7 +206,7 @@ namespace System.Threading.Tasks
m_result = funcWithState(antecedent, m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in ContinuationResultTaskFromResultTask");
+ Debug.Fail("Invalid m_action in ContinuationResultTaskFromResultTask");
}
}
diff --git a/src/mscorlib/src/System/Threading/Tasks/future.cs b/src/mscorlib/src/System/Threading/Tasks/future.cs
index d114f892f0..f9199d35cc 100644
--- a/src/mscorlib/src/System/Threading/Tasks/future.cs
+++ b/src/mscorlib/src/System/Threading/Tasks/future.cs
@@ -616,7 +616,7 @@ namespace System.Threading.Tasks
m_result = funcWithState(m_stateObject);
return;
}
- Debug.Assert(false, "Invalid m_action in Task<TResult>");
+ Debug.Fail("Invalid m_action in Task<TResult>");
}
#region Await Support
diff --git a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
index db42b77ca4..80e25e6e04 100644
--- a/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
+++ b/src/mscorlib/src/System/Threading/ThreadInterruptedException.cs
@@ -19,6 +19,8 @@ using System.Runtime.Serialization;
namespace System.Threading
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class ThreadInterruptedException : SystemException
{
public ThreadInterruptedException()
@@ -41,7 +43,6 @@ namespace System.Threading
protected ThreadInterruptedException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
}
}
}
diff --git a/src/mscorlib/src/System/Threading/Timer.cs b/src/mscorlib/src/System/Threading/Timer.cs
index 918cbd8598..84839e7b54 100644
--- a/src/mscorlib/src/System/Threading/Timer.cs
+++ b/src/mscorlib/src/System/Threading/Timer.cs
@@ -40,23 +40,27 @@ namespace System.Threading
// The data structure we've chosen is an unordered doubly-linked list of active timers. This gives O(1) insertion
// and removal, and O(N) traversal when finding expired timers.
//
- // Note that all instance methods of this class require that the caller hold a lock on TimerQueue.Instance.
+ // Note that all instance methods of this class require that the caller hold a lock on the TimerQueue instance.
//
internal class TimerQueue
{
- #region singleton pattern implementation
+ #region Shared TimerQueue instances
- // The one-and-only TimerQueue for the AppDomain.
- private static TimerQueue s_queue = new TimerQueue();
+ public static TimerQueue[] Instances { get; } = CreateTimerQueues();
- public static TimerQueue Instance
+ private TimerQueue(int id)
{
- get { return s_queue; }
+ m_id = id;
}
- private TimerQueue()
+ private static TimerQueue[] CreateTimerQueues()
{
- // empty private constructor to ensure we remain a singleton.
+ var queues = new TimerQueue[Environment.ProcessorCount];
+ for (int i = 0; i < queues.Length; i++)
+ {
+ queues[i] = new TimerQueue(i);
+ }
+ return queues;
}
#endregion
@@ -112,6 +116,7 @@ namespace System.Threading
}
}
+ private readonly int m_id; // TimerQueues[m_id] == this
private AppDomainTimerSafeHandle m_appDomainTimer;
private bool m_isAppDomainTimerScheduled;
@@ -154,8 +159,9 @@ namespace System.Threading
if (m_appDomainTimer == null || m_appDomainTimer.IsInvalid)
{
Debug.Assert(!m_isAppDomainTimerScheduled);
+ Debug.Assert(m_id >= 0 && m_id < Instances.Length && this == Instances[m_id]);
- m_appDomainTimer = CreateAppDomainTimer(actualDuration);
+ m_appDomainTimer = CreateAppDomainTimer(actualDuration, m_id);
if (!m_appDomainTimer.IsInvalid)
{
m_isAppDomainTimerScheduled = true;
@@ -185,16 +191,17 @@ namespace System.Threading
}
//
- // The VM calls this when the native timer fires.
+ // The VM calls this when a native timer fires.
//
- internal static void AppDomainTimerCallback()
+ internal static void AppDomainTimerCallback(int id)
{
- Instance.FireNextTimers();
+ Debug.Assert(id >= 0 && id < Instances.Length && Instances[id].m_id == id);
+ Instances[id].FireNextTimers();
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
- private static extern AppDomainTimerSafeHandle CreateAppDomainTimer(uint dueTime);
+ private static extern AppDomainTimerSafeHandle CreateAppDomainTimer(uint dueTime, int id);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
[SuppressUnmanagedCodeSecurity]
@@ -219,6 +226,9 @@ namespace System.Threading
//
// Fire any timers that have expired, and update the native timer to schedule the rest of them.
+ // We're in a thread pool work item here, and if there are multiple timers to be fired, we want
+ // to queue all but the first one. The first may can then be invoked synchronously or queued,
+ // a task left up to our caller, which might be firing timers from multiple queues.
//
private void FireNextTimers()
{
@@ -335,20 +345,8 @@ namespace System.Threading
private static void QueueTimerCompletion(TimerQueueTimer timer)
{
- WaitCallback callback = s_fireQueuedTimerCompletion;
- if (callback == null)
- s_fireQueuedTimerCompletion = callback = new WaitCallback(FireQueuedTimerCompletion);
-
- // Can use "unsafe" variant because we take care of capturing and restoring
- // the ExecutionContext.
- ThreadPool.UnsafeQueueUserWorkItem(callback, timer);
- }
-
- private static WaitCallback s_fireQueuedTimerCompletion;
-
- private static void FireQueuedTimerCompletion(object state)
- {
- ((TimerQueueTimer)state).Fire();
+ // Can use "unsafe" variant because we take care of capturing and restoring the ExecutionContext.
+ ThreadPool.UnsafeQueueCustomWorkItem(timer, forceGlobal: true);
}
#endregion
@@ -397,9 +395,14 @@ namespace System.Threading
//
// A timer in our TimerQueue.
//
- internal sealed class TimerQueueTimer
+ internal sealed class TimerQueueTimer : IThreadPoolWorkItem
{
//
+ // The associated timer queue.
+ //
+ private readonly TimerQueue m_associatedTimerQueue;
+
+ //
// All fields of this class are protected by a lock on TimerQueue.Instance.
//
// The first four fields are maintained by TimerQueue itself.
@@ -449,6 +452,7 @@ namespace System.Threading
m_dueTime = Timeout.UnsignedInfinite;
m_period = Timeout.UnsignedInfinite;
m_executionContext = ExecutionContext.Capture();
+ m_associatedTimerQueue = TimerQueue.Instances[Environment.CurrentExecutionId % TimerQueue.Instances.Length];
//
// After the following statement, the timer may fire. No more manipulation of timer state outside of
@@ -458,12 +462,11 @@ namespace System.Threading
Change(dueTime, period);
}
-
internal bool Change(uint dueTime, uint period)
{
bool success;
- lock (TimerQueue.Instance)
+ lock (m_associatedTimerQueue)
{
if (m_canceled)
throw new ObjectDisposedException(null, SR.ObjectDisposed_Generic);
@@ -476,7 +479,7 @@ namespace System.Threading
if (dueTime == Timeout.UnsignedInfinite)
{
- TimerQueue.Instance.DeleteTimer(this);
+ m_associatedTimerQueue.DeleteTimer(this);
success = true;
}
else
@@ -484,7 +487,7 @@ namespace System.Threading
if (FrameworkEventSource.IsInitialized && FrameworkEventSource.Log.IsEnabled(EventLevel.Informational, FrameworkEventSource.Keywords.ThreadTransfer))
FrameworkEventSource.Log.ThreadTransferSendObj(this, 1, string.Empty, true);
- success = TimerQueue.Instance.UpdateTimer(this, dueTime, period);
+ success = m_associatedTimerQueue.UpdateTimer(this, dueTime, period);
}
}
}
@@ -495,7 +498,7 @@ namespace System.Threading
public void Close()
{
- lock (TimerQueue.Instance)
+ lock (m_associatedTimerQueue)
{
// prevent ThreadAbort while updating state
try { }
@@ -504,7 +507,7 @@ namespace System.Threading
if (!m_canceled)
{
m_canceled = true;
- TimerQueue.Instance.DeleteTimer(this);
+ m_associatedTimerQueue.DeleteTimer(this);
}
}
}
@@ -516,7 +519,7 @@ namespace System.Threading
bool success;
bool shouldSignal = false;
- lock (TimerQueue.Instance)
+ lock (m_associatedTimerQueue)
{
// prevent ThreadAbort while updating state
try { }
@@ -530,7 +533,7 @@ namespace System.Threading
{
m_canceled = true;
m_notifyWhenNoCallbacksRunning = toSignal;
- TimerQueue.Instance.DeleteTimer(this);
+ m_associatedTimerQueue.DeleteTimer(this);
if (m_callbacksRunning == 0)
shouldSignal = true;
@@ -551,7 +554,7 @@ namespace System.Threading
{
bool canceled = false;
- lock (TimerQueue.Instance)
+ lock (m_associatedTimerQueue)
{
// prevent ThreadAbort while updating state
try { }
@@ -569,7 +572,7 @@ namespace System.Threading
CallCallback();
bool shouldSignal = false;
- lock (TimerQueue.Instance)
+ lock (m_associatedTimerQueue)
{
// prevent ThreadAbort while updating state
try { }
@@ -585,6 +588,10 @@ namespace System.Threading
SignalNoCallbacksRunning();
}
+ void IThreadPoolWorkItem.ExecuteWorkItem() => Fire();
+
+ void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae) { }
+
internal void SignalNoCallbacksRunning()
{
Win32Native.SetEvent(m_notifyWhenNoCallbacksRunning.SafeWaitHandle);
@@ -797,10 +804,5 @@ namespace System.Threading
{
m_timer.Close();
}
-
- internal void KeepRootedWhileScheduled()
- {
- GC.SuppressFinalize(m_timer);
- }
}
}
diff --git a/src/mscorlib/src/System/Threading/WaitHandle.cs b/src/mscorlib/src/System/Threading/WaitHandle.cs
index 125a29ed6c..69c34456cb 100644
--- a/src/mscorlib/src/System/Threading/WaitHandle.cs
+++ b/src/mscorlib/src/System/Threading/WaitHandle.cs
@@ -273,7 +273,7 @@ namespace System.Threading
internalWaitHandles[i] = waitHandle;
}
-#if _DEBUG
+#if DEBUG
// make sure we do not use waitHandles any more.
waitHandles = null;
#endif
@@ -362,7 +362,7 @@ namespace System.Threading
internalWaitHandles[i] = waitHandle;
}
-#if _DEBUG
+#if DEBUG
// make sure we do not use waitHandles any more.
waitHandles = null;
#endif
diff --git a/src/mscorlib/src/System/ThrowHelper.cs b/src/mscorlib/src/System/ThrowHelper.cs
index 68eff515f5..d3356eab6b 100644
--- a/src/mscorlib/src/System/ThrowHelper.cs
+++ b/src/mscorlib/src/System/ThrowHelper.cs
@@ -42,6 +42,7 @@ using System.Diagnostics;
namespace System
{
+ [StackTraceHidden]
internal static class ThrowHelper
{
internal static void ThrowArrayTypeMismatchException()
diff --git a/src/mscorlib/src/System/TypeLoadException.cs b/src/mscorlib/src/System/TypeLoadException.cs
index 90541dafef..e00d17449c 100644
--- a/src/mscorlib/src/System/TypeLoadException.cs
+++ b/src/mscorlib/src/System/TypeLoadException.cs
@@ -18,9 +18,12 @@ using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
+using System.Diagnostics.Contracts;
namespace System
{
+ [Serializable]
+ [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public class TypeLoadException : SystemException, ISerializable
{
public TypeLoadException()
@@ -103,7 +106,10 @@ namespace System
protected TypeLoadException(SerializationInfo info, StreamingContext context) : base(info, context)
{
- throw new PlatformNotSupportedException();
+ ClassName = info.GetString("TypeLoadClassName");
+ AssemblyName = info.GetString("TypeLoadAssemblyName");
+ MessageArg = info.GetString("TypeLoadMessageArg");
+ ResourceId = info.GetInt32("TypeLoadResourceID");
}
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
@@ -113,6 +119,10 @@ namespace System
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);
+ info.AddValue("TypeLoadClassName", ClassName, typeof(string));
+ info.AddValue("TypeLoadAssemblyName", AssemblyName, typeof(string));
+ info.AddValue("TypeLoadMessageArg", MessageArg, typeof(string));
+ info.AddValue("TypeLoadResourceID", ResourceId);
}
// If ClassName != null, GetMessage will construct on the fly using it
diff --git a/src/mscorlib/src/System/ValueType.cs b/src/mscorlib/src/System/ValueType.cs
index e5b5528314..cd8d0e05aa 100644
--- a/src/mscorlib/src/System/ValueType.cs
+++ b/src/mscorlib/src/System/ValueType.cs
@@ -24,7 +24,6 @@ namespace System
{
public override bool Equals(Object obj)
{
- BCLDebug.Perf(false, "ValueType::Equals is not fast. " + this.GetType().FullName + " should override Equals(Object)");
if (null == obj)
{
return false;
diff --git a/src/mscorlib/src/System/WeakReference.cs b/src/mscorlib/src/System/WeakReference.cs
index bde7586590..b99e3683a6 100644
--- a/src/mscorlib/src/System/WeakReference.cs
+++ b/src/mscorlib/src/System/WeakReference.cs
@@ -30,7 +30,7 @@ namespace System
// Migrating InheritanceDemands requires this default ctor, so we can mark it SafeCritical
protected WeakReference()
{
- Debug.Assert(false, "WeakReference's protected default ctor should never be used!");
+ Debug.Fail("WeakReference's protected default ctor should never be used!");
throw new NotImplementedException();
}
diff --git a/src/pal/CMakeLists.txt b/src/pal/CMakeLists.txt
index c687d832df..a510d25081 100644
--- a/src/pal/CMakeLists.txt
+++ b/src/pal/CMakeLists.txt
@@ -9,6 +9,7 @@ include_directories(${COREPAL_SOURCE_DIR}/src)
include_directories(${COREPAL_SOURCE_DIR}/../inc)
add_compile_options(-fexceptions)
+add_definitions(-DUSE_STL)
add_subdirectory(src)
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
index 1a1b6c8625..8f6bc12798 100644
--- a/src/pal/inc/pal.h
+++ b/src/pal/inc/pal.h
@@ -277,17 +277,13 @@ PAL_IsDebuggerPresent(VOID);
#define _UI32_MAX UINT_MAX
#define _UI32_MIN UINT_MIN
-#ifdef PAL_STDCPP_COMPAT
#undef NULL
-#endif
-#ifndef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
-#endif
#if defined(PAL_STDCPP_COMPAT) && !defined(__cplusplus)
#define nullptr NULL
diff --git a/src/pal/prebuilt/idl/corprof_i.cpp b/src/pal/prebuilt/idl/corprof_i.cpp
index 090f84452c..065be3dd4a 100644
--- a/src/pal/prebuilt/idl/corprof_i.cpp
+++ b/src/pal/prebuilt/idl/corprof_i.cpp
@@ -125,6 +125,9 @@ MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo7,0x9AEECC0D,0x63E0,0x4187,0x8C,0x00,0
MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo8,0xC5AC80A6,0x782E,0x4716,0x80,0x44,0x39,0x59,0x8C,0x60,0xCF,0xBF);
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo9,0X008170DB,0XF8CC,0X4796,0X9A,0X51,0XDC,0X8A,0XA0,0XB4,0X70,0x12);
+
+
MIDL_DEFINE_GUID(IID, IID_ICorProfilerMethodEnum,0xFCCEE788,0x0088,0x454B,0xA8,0x11,0xC9,0x9F,0x29,0x8D,0x19,0x42);
diff --git a/src/pal/prebuilt/idl/fusionpriv_i.cpp b/src/pal/prebuilt/idl/fusionpriv_i.cpp
deleted file mode 100644
index ece9622114..0000000000
--- a/src/pal/prebuilt/idl/fusionpriv_i.cpp
+++ /dev/null
@@ -1,121 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
-
-/* link this file in with the server and any clients */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#include <rpc.h>
-#include <rpcndr.h>
-
-#ifdef _MIDL_USE_GUIDDEF_
-
-#ifndef INITGUID
-#define INITGUID
-#include <guiddef.h>
-#undef INITGUID
-#else
-#include <guiddef.h>
-#endif
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
-
-#else // !_MIDL_USE_GUIDDEF_
-
-#ifndef __IID_DEFINED__
-#define __IID_DEFINED__
-
-typedef struct _IID
-{
- unsigned long x;
- unsigned short s1;
- unsigned short s2;
- unsigned char c[8];
-} IID;
-
-#endif // __IID_DEFINED__
-
-#ifndef CLSID_DEFINED
-#define CLSID_DEFINED
-typedef IID CLSID;
-#endif // CLSID_DEFINED
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-
-#endif !_MIDL_USE_GUIDDEF_
-
-MIDL_DEFINE_GUID(IID, IID_IHistoryAssembly,0xe6096a07,0xe188,0x4a49,0x8d,0x50,0x2a,0x01,0x72,0xa0,0xd2,0x05);
-
-
-MIDL_DEFINE_GUID(IID, IID_IHistoryReader,0x1d23df4d,0xa1e2,0x4b8b,0x93,0xd6,0x6e,0xa3,0xdc,0x28,0x5a,0x54);
-
-
-MIDL_DEFINE_GUID(IID, IID_IFusionBindLog,0x67E9F87D,0x8B8A,0x4a90,0x9D,0x3E,0x85,0xED,0x5B,0x2D,0xCC,0x83);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyManifestImport,0xde9a68ba,0x0fa2,0x11d3,0x94,0xaa,0x00,0xc0,0x4f,0xc3,0x08,0xff);
-
-
-MIDL_DEFINE_GUID(IID, IID_IApplicationContext,0x7c23ff90,0x33af,0x11d3,0x95,0xda,0x00,0xa0,0x24,0xa8,0x5b,0x51);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyNameBinder,0x56972d9d,0x0f6c,0x47de,0xa0,0x38,0xe8,0x2d,0x5d,0xe3,0xa7,0x77);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssembly,0xff08d7d4,0x04c2,0x11d3,0x94,0xaa,0x00,0xc0,0x4f,0xc3,0x08,0xff);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyBindingClosureEnumerator,0xb3f1e4ed,0xcb09,0x4b85,0x9a,0x1b,0x68,0x09,0x58,0x2f,0x1e,0xbc);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyBindingClosure,0x415c226a,0xe513,0x41ba,0x96,0x51,0x9c,0x48,0xe9,0x7a,0xa5,0xde);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyBindSink,0xaf0bc960,0x0b9a,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyBinding,0xcfe52a80,0x12bd,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyModuleImport,0xda0cd4b0,0x1117,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
-
-
-MIDL_DEFINE_GUID(IID, IID_IAssemblyScavenger,0x21b8916c,0xf28e,0x11d2,0xa4,0x73,0x00,0xcc,0xff,0x8e,0xf4,0x48);
-
-
-MIDL_DEFINE_GUID(IID, IID_ICodebaseList,0xD8FB9BD6,0x3969,0x11d3,0xB4,0xAF,0x00,0xC0,0x4F,0x8E,0xCB,0x26);
-
-
-MIDL_DEFINE_GUID(IID, IID_IDownloadMgr,0x0A6F16F8,0xACD7,0x11d3,0xB4,0xED,0x00,0xC0,0x4F,0x8E,0xCB,0x26);
-
-
-MIDL_DEFINE_GUID(IID, IID_IHostAssembly,0x711f7c2d,0x8234,0x4505,0xb0,0x2f,0x75,0x54,0xf4,0x6c,0xbf,0x29);
-
-
-MIDL_DEFINE_GUID(IID, IID_IHostAssemblyModuleImport,0xb6f2729d,0x6c0f,0x4944,0xb6,0x92,0xe5,0xa2,0xce,0x2c,0x6e,0x7a);
-
-#undef MIDL_DEFINE_GUID
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
diff --git a/src/pal/prebuilt/idl/ivalidator_i.cpp b/src/pal/prebuilt/idl/ivalidator_i.cpp
deleted file mode 100644
index 0edbec448a..0000000000
--- a/src/pal/prebuilt/idl/ivalidator_i.cpp
+++ /dev/null
@@ -1,76 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
-
-/* link this file in with the server and any clients */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#include <rpc.h>
-#include <rpcndr.h>
-
-#ifdef _MIDL_USE_GUIDDEF_
-
-#ifndef INITGUID
-#define INITGUID
-#include <guiddef.h>
-#undef INITGUID
-#else
-#include <guiddef.h>
-#endif
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
-
-#else // !_MIDL_USE_GUIDDEF_
-
-#ifndef __IID_DEFINED__
-#define __IID_DEFINED__
-
-typedef struct _IID
-{
- unsigned long x;
- unsigned short s1;
- unsigned short s2;
- unsigned char c[8];
-} IID;
-
-#endif // __IID_DEFINED__
-
-#ifndef CLSID_DEFINED
-#define CLSID_DEFINED
-typedef IID CLSID;
-#endif // CLSID_DEFINED
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-
-#endif !_MIDL_USE_GUIDDEF_
-
-MIDL_DEFINE_GUID(IID, IID_IValidator,0x63DF8730,0xDC81,0x4062,0x84,0xA2,0x1F,0xF9,0x43,0xF5,0x9F,0xAC);
-
-
-MIDL_DEFINE_GUID(IID, IID_ICLRValidator,0x63DF8730,0xDC81,0x4062,0x84,0xA2,0x1F,0xF9,0x43,0xF5,0x9F,0xDD);
-
-#undef MIDL_DEFINE_GUID
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
diff --git a/src/pal/prebuilt/idl/ivehandler_i.cpp b/src/pal/prebuilt/idl/ivehandler_i.cpp
deleted file mode 100644
index 44d0b961bb..0000000000
--- a/src/pal/prebuilt/idl/ivehandler_i.cpp
+++ /dev/null
@@ -1,79 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
-
-/* link this file in with the server and any clients */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#include <rpc.h>
-#include <rpcndr.h>
-
-#ifdef _MIDL_USE_GUIDDEF_
-
-#ifndef INITGUID
-#define INITGUID
-#include <guiddef.h>
-#undef INITGUID
-#else
-#include <guiddef.h>
-#endif
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
-
-#else // !_MIDL_USE_GUIDDEF_
-
-#ifndef __IID_DEFINED__
-#define __IID_DEFINED__
-
-typedef struct _IID
-{
- unsigned long x;
- unsigned short s1;
- unsigned short s2;
- unsigned char c[8];
-} IID;
-
-#endif // __IID_DEFINED__
-
-#ifndef CLSID_DEFINED
-#define CLSID_DEFINED
-typedef IID CLSID;
-#endif // CLSID_DEFINED
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-
-#endif !_MIDL_USE_GUIDDEF_
-
-MIDL_DEFINE_GUID(IID, LIBID_VEHandlerLib,0x856CA1B0,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
-
-
-MIDL_DEFINE_GUID(CLSID, CLSID_VEHandlerClass,0x856CA1B1,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
-
-
-MIDL_DEFINE_GUID(IID, IID_IVEHandler,0x856CA1B2,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
-
-#undef MIDL_DEFINE_GUID
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
diff --git a/src/pal/prebuilt/idl/tlbimpexp_i.cpp b/src/pal/prebuilt/idl/tlbimpexp_i.cpp
deleted file mode 100644
index 0eb2791fa3..0000000000
--- a/src/pal/prebuilt/idl/tlbimpexp_i.cpp
+++ /dev/null
@@ -1,82 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
-
-/* link this file in with the server and any clients */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-#include <rpc.h>
-#include <rpcndr.h>
-
-#ifdef _MIDL_USE_GUIDDEF_
-
-#ifndef INITGUID
-#define INITGUID
-#include <guiddef.h>
-#undef INITGUID
-#else
-#include <guiddef.h>
-#endif
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
-
-#else // !_MIDL_USE_GUIDDEF_
-
-#ifndef __IID_DEFINED__
-#define __IID_DEFINED__
-
-typedef struct _IID
-{
- unsigned long x;
- unsigned short s1;
- unsigned short s2;
- unsigned char c[8];
-} IID;
-
-#endif // __IID_DEFINED__
-
-#ifndef CLSID_DEFINED
-#define CLSID_DEFINED
-typedef IID CLSID;
-#endif // CLSID_DEFINED
-
-#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
- const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
-
-#endif !_MIDL_USE_GUIDDEF_
-
-MIDL_DEFINE_GUID(IID, LIBID_TlbImpLib,0x20BC1825,0x06F0,0x11d2,0x8C,0xF4,0x00,0xA0,0xC9,0xB0,0xA0,0x63);
-
-
-MIDL_DEFINE_GUID(IID, IID_ITypeLibImporterNotifySink,0xF1C3BF76,0xC3E4,0x11D3,0x88,0xE7,0x00,0x90,0x27,0x54,0xC4,0x3A);
-
-
-MIDL_DEFINE_GUID(IID, IID_ITypeLibExporterNotifySink,0xF1C3BF77,0xC3E4,0x11D3,0x88,0xE7,0x00,0x90,0x27,0x54,0xC4,0x3A);
-
-
-MIDL_DEFINE_GUID(IID, IID_ITypeLibExporterNameProvider,0xFA1F3615,0xACB9,0x486d,0x9E,0xAC,0x1B,0xEF,0x87,0xE3,0x6B,0x09);
-
-#undef MIDL_DEFINE_GUID
-
-#ifdef __cplusplus
-}
-#endif
-
-
-
diff --git a/src/pal/prebuilt/inc/corprof.h b/src/pal/prebuilt/inc/corprof.h
index befa45a942..5a4f8c37d6 100644
--- a/src/pal/prebuilt/inc/corprof.h
+++ b/src/pal/prebuilt/inc/corprof.h
@@ -191,6 +191,13 @@ typedef interface ICorProfilerInfo8 ICorProfilerInfo8;
#endif /* __ICorProfilerInfo8_FWD_DEFINED__ */
+#ifndef __ICorProfilerInfo9_FWD_DEFINED__
+#define __ICorProfilerInfo9_FWD_DEFINED__
+typedef interface ICorProfilerInfo9 ICorProfilerInfo9;
+
+#endif /* __ICorProfilerInfo9_FWD_DEFINED__ */
+
+
#ifndef __ICorProfilerMethodEnum_FWD_DEFINED__
#define __ICorProfilerMethodEnum_FWD_DEFINED__
typedef interface ICorProfilerMethodEnum ICorProfilerMethodEnum;
@@ -514,9 +521,10 @@ enum __MIDL___MIDL_itf_corprof_0000_0000_0006
COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES = 0x1,
COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED = 0x2,
COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS = 0x4,
+ COR_PRF_HIGH_DISABLE_TIERED_COMPILATION = 0x8,
COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0,
COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = ( COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED | COR_PRF_HIGH_MONITOR_DYNAMIC_FUNCTION_UNLOADS ) ,
- COR_PRF_HIGH_MONITOR_IMMUTABLE = 0
+ COR_PRF_HIGH_MONITOR_IMMUTABLE = ( COR_PRF_HIGH_DISABLE_TIERED_COMPILATION )
} COR_PRF_HIGH_MONITOR;
typedef /* [public] */
@@ -14206,6 +14214,937 @@ EXTERN_C const IID IID_ICorProfilerInfo8;
#endif /* __ICorProfilerInfo8_INTERFACE_DEFINED__ */
+#ifndef __ICorProfilerInfo9_INTERFACE_DEFINED__
+#define __ICorProfilerInfo9_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo9 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo9;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("008170db-f8cc-4796-9a51-dc8aa0b47012")
+ ICorProfilerInfo9 : public ICorProfilerInfo8
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetNativeCodeStartAddresses(
+ FunctionID functionID,
+ ReJITID reJitId,
+ ULONG32 cCodeStartAddresses,
+ ULONG32 *pcCodeStartAddresses,
+ UINT_PTR codeStartAddresses[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILToNativeMapping3(
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cMap,
+ ULONG32 *pcMap,
+ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeInfo4(
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cCodeInfos,
+ ULONG32 *pcCodeInfos,
+ COR_PRF_CODE_INFO codeInfos[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo9Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo9 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumThreads )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeCurrentThread )(
+ ICorProfilerInfo9 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestReJIT )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRevert )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo3 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITIDs )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions2 )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask2 )(
+ ICorProfilerInfo9 * This,
+ /* [out] */ DWORD *pdwEventsLow,
+ /* [out] */ DWORD *pdwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask2 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ DWORD dwEventsLow,
+ /* [in] */ DWORD dwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumNgenModuleMethodsInliningThisMethod )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID inlinersModuleId,
+ /* [in] */ ModuleID inlineeModuleId,
+ /* [in] */ mdMethodDef inlineeMethodId,
+ /* [out] */ BOOL *incompleteData,
+ /* [out] */ ICorProfilerMethodEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyMetaData )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInMemorySymbolsLength )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ DWORD *pCountSymbolBytes);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadInMemorySymbols )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD symbolsReadOffset,
+ /* [out] */ BYTE *pSymbolBytes,
+ /* [in] */ DWORD countSymbolBytes,
+ /* [out] */ DWORD *pCountSymbolBytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *IsFunctionDynamic )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *isDynamic);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP3 )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *functionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDynamicFunctionInfo )(
+ ICorProfilerInfo9 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ModuleID *moduleId,
+ /* [out] */ PCCOR_SIGNATURE *ppvSig,
+ /* [out] */ ULONG *pbSig,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [out] */ WCHAR wszName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNativeCodeStartAddresses )(
+ ICorProfilerInfo9 * This,
+ FunctionID functionID,
+ ReJITID reJitId,
+ ULONG32 cCodeStartAddresses,
+ ULONG32 *pcCodeStartAddresses,
+ UINT_PTR codeStartAddresses[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping3 )(
+ ICorProfilerInfo9 * This,
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cMap,
+ ULONG32 *pcMap,
+ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo4 )(
+ ICorProfilerInfo9 * This,
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cCodeInfos,
+ ULONG32 *pcCodeInfos,
+ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ END_INTERFACE
+ } ICorProfilerInfo9Vtbl;
+
+ interface ICorProfilerInfo9
+ {
+ CONST_VTBL struct ICorProfilerInfo9Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo9_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo9_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo9_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo9_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo9_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo9_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo9_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo9_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo9_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo9_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo9_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo9_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo9_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo9_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo9_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo9_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo9_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo9_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo9_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo9_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo9_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo9_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo9_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo9_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo9_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo9_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo9_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo9_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo9_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo9_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo9_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo9_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo9_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo9_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo9_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo9_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo9_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo9_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo9_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo9_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo9_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo9_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo9_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo9_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo9_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo9_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo9_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo9_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo9_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo9_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo9_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo9_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo9_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo9_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo9_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo9_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo9_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo9_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo9_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo9_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo9_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo9_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo9_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo9_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo9_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo9_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo9_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo9_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo9_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo9_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo9_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+
+#define ICorProfilerInfo9_EnumThreads(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumThreads(This,ppEnum) )
+
+#define ICorProfilerInfo9_InitializeCurrentThread(This) \
+ ( (This)->lpVtbl -> InitializeCurrentThread(This) )
+
+#define ICorProfilerInfo9_RequestReJIT(This,cFunctions,moduleIds,methodIds) \
+ ( (This)->lpVtbl -> RequestReJIT(This,cFunctions,moduleIds,methodIds) )
+
+#define ICorProfilerInfo9_RequestRevert(This,cFunctions,moduleIds,methodIds,status) \
+ ( (This)->lpVtbl -> RequestRevert(This,cFunctions,moduleIds,methodIds,status) )
+
+#define ICorProfilerInfo9_GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo9_GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) )
+
+#define ICorProfilerInfo9_GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) \
+ ( (This)->lpVtbl -> GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) )
+
+#define ICorProfilerInfo9_GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) )
+
+#define ICorProfilerInfo9_EnumJITedFunctions2(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions2(This,ppEnum) )
+
+#define ICorProfilerInfo9_GetObjectSize2(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize2(This,objectId,pcSize) )
+
+
+#define ICorProfilerInfo9_GetEventMask2(This,pdwEventsLow,pdwEventsHigh) \
+ ( (This)->lpVtbl -> GetEventMask2(This,pdwEventsLow,pdwEventsHigh) )
+
+#define ICorProfilerInfo9_SetEventMask2(This,dwEventsLow,dwEventsHigh) \
+ ( (This)->lpVtbl -> SetEventMask2(This,dwEventsLow,dwEventsHigh) )
+
+
+#define ICorProfilerInfo9_EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) \
+ ( (This)->lpVtbl -> EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) )
+
+
+#define ICorProfilerInfo9_ApplyMetaData(This,moduleId) \
+ ( (This)->lpVtbl -> ApplyMetaData(This,moduleId) )
+
+#define ICorProfilerInfo9_GetInMemorySymbolsLength(This,moduleId,pCountSymbolBytes) \
+ ( (This)->lpVtbl -> GetInMemorySymbolsLength(This,moduleId,pCountSymbolBytes) )
+
+#define ICorProfilerInfo9_ReadInMemorySymbols(This,moduleId,symbolsReadOffset,pSymbolBytes,countSymbolBytes,pCountSymbolBytesRead) \
+ ( (This)->lpVtbl -> ReadInMemorySymbols(This,moduleId,symbolsReadOffset,pSymbolBytes,countSymbolBytes,pCountSymbolBytesRead) )
+
+
+#define ICorProfilerInfo9_IsFunctionDynamic(This,functionId,isDynamic) \
+ ( (This)->lpVtbl -> IsFunctionDynamic(This,functionId,isDynamic) )
+
+#define ICorProfilerInfo9_GetFunctionFromIP3(This,ip,functionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP3(This,ip,functionId,pReJitId) )
+
+#define ICorProfilerInfo9_GetDynamicFunctionInfo(This,functionId,moduleId,ppvSig,pbSig,cchName,pcchName,wszName) \
+ ( (This)->lpVtbl -> GetDynamicFunctionInfo(This,functionId,moduleId,ppvSig,pbSig,cchName,pcchName,wszName) )
+
+
+#define ICorProfilerInfo9_GetNativeCodeStartAddresses(This,functionID,reJitId,cCodeStartAddresses,pcCodeStartAddresses,codeStartAddresses) \
+ ( (This)->lpVtbl -> GetNativeCodeStartAddresses(This,functionID,reJitId,cCodeStartAddresses,pcCodeStartAddresses,codeStartAddresses) )
+
+#define ICorProfilerInfo9_GetILToNativeMapping3(This,pNativeCodeStartAddress,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping3(This,pNativeCodeStartAddress,cMap,pcMap,map) )
+
+#define ICorProfilerInfo9_GetCodeInfo4(This,pNativeCodeStartAddress,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo4(This,pNativeCodeStartAddress,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo9_INTERFACE_DEFINED__ */
+
+
#ifndef __ICorProfilerMethodEnum_INTERFACE_DEFINED__
#define __ICorProfilerMethodEnum_INTERFACE_DEFINED__
diff --git a/src/pal/prebuilt/inc/ivalidator.h b/src/pal/prebuilt/inc/ivalidator.h
deleted file mode 100644
index 320022dc40..0000000000
--- a/src/pal/prebuilt/inc/ivalidator.h
+++ /dev/null
@@ -1,334 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-/* verify that the <rpcndr.h> version is high enough to compile this file*/
-#ifndef __REQUIRED_RPCNDR_H_VERSION__
-#define __REQUIRED_RPCNDR_H_VERSION__ 475
-#endif
-
-#include "rpc.h"
-#include "rpcndr.h"
-
-#ifndef __RPCNDR_H_VERSION__
-#error this stub requires an updated version of <rpcndr.h>
-#endif // __RPCNDR_H_VERSION__
-
-#ifndef COM_NO_WINDOWS_H
-#include "windows.h"
-#include "ole2.h"
-#endif /*COM_NO_WINDOWS_H*/
-
-#ifndef __IValidator_h__
-#define __IValidator_h__
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-#pragma once
-#endif
-
-/* Forward Declarations */
-
-#ifndef __IValidator_FWD_DEFINED__
-#define __IValidator_FWD_DEFINED__
-typedef interface IValidator IValidator;
-
-#endif /* __IValidator_FWD_DEFINED__ */
-
-
-#ifndef __ICLRValidator_FWD_DEFINED__
-#define __ICLRValidator_FWD_DEFINED__
-typedef interface ICLRValidator ICLRValidator;
-
-#endif /* __ICLRValidator_FWD_DEFINED__ */
-
-
-/* header files for imported files */
-#include "ivehandler.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-/* interface __MIDL_itf_IValidator_0000_0000 */
-/* [local] */
-
-#pragma warning(push)
-#pragma warning(disable:28718)
-
-
-
-enum ValidatorFlags
- {
- VALIDATOR_EXTRA_VERBOSE = 0x1,
- VALIDATOR_SHOW_SOURCE_LINES = 0x2,
- VALIDATOR_CHECK_ILONLY = 0x4,
- VALIDATOR_CHECK_PEFORMAT_ONLY = 0x8,
- VALIDATOR_NOCHECK_PEFORMAT = 0x10,
- VALIDATOR_TRANSPARENT_ONLY = 0x20
- } ;
-
-
-extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0000_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0000_v0_0_s_ifspec;
-
-#ifndef __IValidator_INTERFACE_DEFINED__
-#define __IValidator_INTERFACE_DEFINED__
-
-/* interface IValidator */
-/* [unique][uuid][object] */
-
-
-EXTERN_C const IID IID_IValidator;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FAC")
- IValidator : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE Validate(
- /* [in] */ IVEHandler *veh,
- /* [in] */ IUnknown *pAppDomain,
- /* [in] */ unsigned long ulFlags,
- /* [in] */ unsigned long ulMaxError,
- /* [in] */ unsigned long token,
- /* [in] */ LPWSTR fileName,
- /* [size_is][in] */ BYTE *pe,
- /* [in] */ unsigned long ulSize) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
- /* [in] */ HRESULT hVECode,
- /* [in] */ VEContext Context,
- /* [out][in] */ LPWSTR msg,
- /* [in] */ unsigned long ulMaxLength,
- /* [in] */ SAFEARRAY * psa) = 0;
-
- };
-
-
-#else /* C style interface */
-
- typedef struct IValidatorVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
- IValidator * This,
- /* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
- _COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
- IValidator * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
- IValidator * This);
-
- HRESULT ( STDMETHODCALLTYPE *Validate )(
- IValidator * This,
- /* [in] */ IVEHandler *veh,
- /* [in] */ IUnknown *pAppDomain,
- /* [in] */ unsigned long ulFlags,
- /* [in] */ unsigned long ulMaxError,
- /* [in] */ unsigned long token,
- /* [in] */ LPWSTR fileName,
- /* [size_is][in] */ BYTE *pe,
- /* [in] */ unsigned long ulSize);
-
- HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
- IValidator * This,
- /* [in] */ HRESULT hVECode,
- /* [in] */ VEContext Context,
- /* [out][in] */ LPWSTR msg,
- /* [in] */ unsigned long ulMaxLength,
- /* [in] */ SAFEARRAY * psa);
-
- END_INTERFACE
- } IValidatorVtbl;
-
- interface IValidator
- {
- CONST_VTBL struct IValidatorVtbl *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define IValidator_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
-
-#define IValidator_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
-
-#define IValidator_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
-
-
-#define IValidator_Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
- ( (This)->lpVtbl -> Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize) )
-
-#define IValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
- ( (This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) )
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-
-#endif /* __IValidator_INTERFACE_DEFINED__ */
-
-
-#ifndef __ICLRValidator_INTERFACE_DEFINED__
-#define __ICLRValidator_INTERFACE_DEFINED__
-
-/* interface ICLRValidator */
-/* [unique][uuid][object] */
-
-
-EXTERN_C const IID IID_ICLRValidator;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FDD")
- ICLRValidator : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE Validate(
- /* [in] */ IVEHandler *veh,
- /* [in] */ unsigned long ulAppDomainId,
- /* [in] */ unsigned long ulFlags,
- /* [in] */ unsigned long ulMaxError,
- /* [in] */ unsigned long token,
- /* [in] */ LPWSTR fileName,
- /* [size_is][in] */ BYTE *pe,
- /* [in] */ unsigned long ulSize) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
- /* [in] */ HRESULT hVECode,
- /* [in] */ VEContext Context,
- /* [out][in] */ LPWSTR msg,
- /* [in] */ unsigned long ulMaxLength,
- /* [in] */ SAFEARRAY * psa) = 0;
-
- };
-
-
-#else /* C style interface */
-
- typedef struct ICLRValidatorVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
- ICLRValidator * This,
- /* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
- _COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
- ICLRValidator * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
- ICLRValidator * This);
-
- HRESULT ( STDMETHODCALLTYPE *Validate )(
- ICLRValidator * This,
- /* [in] */ IVEHandler *veh,
- /* [in] */ unsigned long ulAppDomainId,
- /* [in] */ unsigned long ulFlags,
- /* [in] */ unsigned long ulMaxError,
- /* [in] */ unsigned long token,
- /* [in] */ LPWSTR fileName,
- /* [size_is][in] */ BYTE *pe,
- /* [in] */ unsigned long ulSize);
-
- HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
- ICLRValidator * This,
- /* [in] */ HRESULT hVECode,
- /* [in] */ VEContext Context,
- /* [out][in] */ LPWSTR msg,
- /* [in] */ unsigned long ulMaxLength,
- /* [in] */ SAFEARRAY * psa);
-
- END_INTERFACE
- } ICLRValidatorVtbl;
-
- interface ICLRValidator
- {
- CONST_VTBL struct ICLRValidatorVtbl *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define ICLRValidator_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
-
-#define ICLRValidator_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
-
-#define ICLRValidator_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
-
-
-#define ICLRValidator_Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
- ( (This)->lpVtbl -> Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize) )
-
-#define ICLRValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
- ( (This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) )
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-
-#endif /* __ICLRValidator_INTERFACE_DEFINED__ */
-
-
-/* interface __MIDL_itf_IValidator_0000_0002 */
-/* [local] */
-
-#pragma warning(pop)
-
-
-extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0002_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0002_v0_0_s_ifspec;
-
-/* Additional Prototypes for ALL interfaces */
-
-unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
-unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
-unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
-void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
-
-/* end of Additional Prototypes */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
diff --git a/src/pal/prebuilt/inc/ivehandler.h b/src/pal/prebuilt/inc/ivehandler.h
deleted file mode 100644
index bdd8cb521b..0000000000
--- a/src/pal/prebuilt/inc/ivehandler.h
+++ /dev/null
@@ -1,220 +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.
-
-
-
-/* this ALWAYS GENERATED file contains the definitions for the interfaces */
-
-
- /* File created by MIDL compiler version 8.00.0603 */
-/* @@MIDL_FILE_HEADING( ) */
-
-#pragma warning( disable: 4049 ) /* more than 64k source lines */
-
-
-/* verify that the <rpcndr.h> version is high enough to compile this file*/
-#ifndef __REQUIRED_RPCNDR_H_VERSION__
-#define __REQUIRED_RPCNDR_H_VERSION__ 475
-#endif
-
-#include "rpc.h"
-#include "rpcndr.h"
-
-#ifndef __RPCNDR_H_VERSION__
-#error this stub requires an updated version of <rpcndr.h>
-#endif // __RPCNDR_H_VERSION__
-
-#ifndef COM_NO_WINDOWS_H
-#include "windows.h"
-#include "ole2.h"
-#endif /*COM_NO_WINDOWS_H*/
-
-#ifndef __IVEHandler_h__
-#define __IVEHandler_h__
-
-#if defined(_MSC_VER) && (_MSC_VER >= 1020)
-#pragma once
-#endif
-
-/* Forward Declarations */
-
-#ifndef __VEHandlerClass_FWD_DEFINED__
-#define __VEHandlerClass_FWD_DEFINED__
-
-#ifdef __cplusplus
-typedef class VEHandlerClass VEHandlerClass;
-#else
-typedef struct VEHandlerClass VEHandlerClass;
-#endif /* __cplusplus */
-
-#endif /* __VEHandlerClass_FWD_DEFINED__ */
-
-
-#ifndef __IVEHandler_FWD_DEFINED__
-#define __IVEHandler_FWD_DEFINED__
-typedef interface IVEHandler IVEHandler;
-
-#endif /* __IVEHandler_FWD_DEFINED__ */
-
-
-/* header files for imported files */
-#include "unknwn.h"
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-/* interface __MIDL_itf_IVEHandler_0000_0000 */
-/* [local] */
-
-typedef struct tag_VerError
- {
- unsigned long flags;
- unsigned long opcode;
- unsigned long uOffset;
- unsigned long Token;
- unsigned long item1_flags;
- int *item1_data;
- unsigned long item2_flags;
- int *item2_data;
- } _VerError;
-
-typedef _VerError VEContext;
-
-
-
-
-extern RPC_IF_HANDLE __MIDL_itf_IVEHandler_0000_0000_v0_0_c_ifspec;
-extern RPC_IF_HANDLE __MIDL_itf_IVEHandler_0000_0000_v0_0_s_ifspec;
-
-
-#ifndef __VEHandlerLib_LIBRARY_DEFINED__
-#define __VEHandlerLib_LIBRARY_DEFINED__
-
-/* library VEHandlerLib */
-/* [helpstring][version][uuid] */
-
-
-EXTERN_C const IID LIBID_VEHandlerLib;
-
-EXTERN_C const CLSID CLSID_VEHandlerClass;
-
-#ifdef __cplusplus
-
-class DECLSPEC_UUID("856CA1B1-7DAB-11d3-ACEC-00C04F86C309")
-VEHandlerClass;
-#endif
-#endif /* __VEHandlerLib_LIBRARY_DEFINED__ */
-
-#ifndef __IVEHandler_INTERFACE_DEFINED__
-#define __IVEHandler_INTERFACE_DEFINED__
-
-/* interface IVEHandler */
-/* [unique][uuid][object] */
-
-
-EXTERN_C const IID IID_IVEHandler;
-
-#if defined(__cplusplus) && !defined(CINTERFACE)
-
- MIDL_INTERFACE("856CA1B2-7DAB-11d3-ACEC-00C04F86C309")
- IVEHandler : public IUnknown
- {
- public:
- virtual HRESULT STDMETHODCALLTYPE VEHandler(
- /* [in] */ HRESULT VECode,
- /* [in] */ VEContext Context,
- /* [in] */ SAFEARRAY * psa) = 0;
-
- virtual HRESULT STDMETHODCALLTYPE SetReporterFtn(
- /* [in] */ __int64 lFnPtr) = 0;
-
- };
-
-
-#else /* C style interface */
-
- typedef struct IVEHandlerVtbl
- {
- BEGIN_INTERFACE
-
- HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
- IVEHandler * This,
- /* [in] */ REFIID riid,
- /* [annotation][iid_is][out] */
- _COM_Outptr_ void **ppvObject);
-
- ULONG ( STDMETHODCALLTYPE *AddRef )(
- IVEHandler * This);
-
- ULONG ( STDMETHODCALLTYPE *Release )(
- IVEHandler * This);
-
- HRESULT ( STDMETHODCALLTYPE *VEHandler )(
- IVEHandler * This,
- /* [in] */ HRESULT VECode,
- /* [in] */ VEContext Context,
- /* [in] */ SAFEARRAY * psa);
-
- HRESULT ( STDMETHODCALLTYPE *SetReporterFtn )(
- IVEHandler * This,
- /* [in] */ __int64 lFnPtr);
-
- END_INTERFACE
- } IVEHandlerVtbl;
-
- interface IVEHandler
- {
- CONST_VTBL struct IVEHandlerVtbl *lpVtbl;
- };
-
-
-
-#ifdef COBJMACROS
-
-
-#define IVEHandler_QueryInterface(This,riid,ppvObject) \
- ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
-
-#define IVEHandler_AddRef(This) \
- ( (This)->lpVtbl -> AddRef(This) )
-
-#define IVEHandler_Release(This) \
- ( (This)->lpVtbl -> Release(This) )
-
-
-#define IVEHandler_VEHandler(This,VECode,Context,psa) \
- ( (This)->lpVtbl -> VEHandler(This,VECode,Context,psa) )
-
-#define IVEHandler_SetReporterFtn(This,lFnPtr) \
- ( (This)->lpVtbl -> SetReporterFtn(This,lFnPtr) )
-
-#endif /* COBJMACROS */
-
-
-#endif /* C style interface */
-
-
-
-
-#endif /* __IVEHandler_INTERFACE_DEFINED__ */
-
-
-/* Additional Prototypes for ALL interfaces */
-
-unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
-unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
-unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
-void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
-
-/* end of Additional Prototypes */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
diff --git a/src/pal/prebuilt/inc/mscoree.h b/src/pal/prebuilt/inc/mscoree.h
index 45b8864d69..b62ab58b63 100644
--- a/src/pal/prebuilt/inc/mscoree.h
+++ b/src/pal/prebuilt/inc/mscoree.h
@@ -220,7 +220,6 @@ typedef interface ICLRAppDomainResourceMonitor ICLRAppDomainResourceMonitor;
/* header files for imported files */
#include "unknwn.h"
#include "gchost.h"
-#include "ivalidator.h"
#ifdef __cplusplus
extern "C"{
diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt
index 370866ca9e..3bfc348c13 100644
--- a/src/pal/src/CMakeLists.txt
+++ b/src/pal/src/CMakeLists.txt
@@ -372,12 +372,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
)
endif(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
-if(HAVE_NUMA_H)
- target_link_libraries(coreclrpal
- numa
- )
-endif(HAVE_NUMA_H)
-
add_subdirectory(examples)
if(FEATURE_EVENT_TRACE)
diff --git a/src/pal/src/cruntime/mbstring.cpp b/src/pal/src/cruntime/mbstring.cpp
index ace2aa56c6..828e4a3240 100644
--- a/src/pal/src/cruntime/mbstring.cpp
+++ b/src/pal/src/cruntime/mbstring.cpp
@@ -31,6 +31,7 @@ Implementation Notes:
#include "pal/palinternal.h"
#include "pal/dbgmsg.h"
+#include <algorithm>
SET_DEFAULT_DEBUG_CHANNEL(CRT);
@@ -125,7 +126,7 @@ _mbsninc(
ret = (unsigned char *) string;
if (GetCPInfo(CP_ACP, &cpinfo) && cpinfo.MaxCharSize == 1)
{
- ret += min(count, strlen((const char*)string));
+ ret += std::min(count, strlen((const char*)string));
}
else
{
diff --git a/src/pal/src/cruntime/printf.cpp b/src/pal/src/cruntime/printf.cpp
index 72c7e11bea..6ae6263b74 100644
--- a/src/pal/src/cruntime/printf.cpp
+++ b/src/pal/src/cruntime/printf.cpp
@@ -47,83 +47,6 @@ static int SscanfFloatCheckExponent(LPCSTR buff, LPCSTR floatFmt,
/*******************************************************************************
Function:
- Internal_AddPaddingA
-
-Parameters:
- Out
- - buffer to place padding and given string (In)
- Count
- - maximum chars to be copied so as not to overrun given buffer
- In
- - string to place into (Out) accompanied with padding
- Padding
- - number of padding chars to add
- Flags
- - padding style flags (PRINTF_FORMAT_FLAGS)
-*******************************************************************************/
-BOOL Internal_AddPaddingA(LPSTR *Out, INT Count, LPSTR In,
- INT Padding, INT Flags)
-{
- LPSTR OutOriginal = *Out;
- INT PaddingOriginal = Padding;
- INT LengthInStr;
- LengthInStr = strlen(In);
-
-
- if (Padding < 0)
- {
- /* this is used at the bottom to determine if the buffer ran out */
- PaddingOriginal = 0;
- }
- if (Flags & PFF_MINUS) /* pad on right */
- {
- if (strncpy_s(*Out, Count, In, min(LengthInStr + 1, Count)) != SAFECRT_SUCCESS)
- {
- return FALSE;
- }
-
- *Out += min(LengthInStr, Count);
- }
- if (Padding > 0)
- {
- if (Flags & PFF_ZERO) /* '0', pad with zeros */
- {
- while (Padding-- && Count > *Out - OutOriginal)
- {
- *(*Out)++ = '0';
- }
- }
- else /* pad left with spaces */
- {
- while (Padding-- && Count > *Out - OutOriginal)
- {
- *(*Out)++ = ' ';
- }
- }
- }
- if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
- {
- if (strncpy_s(*Out, Count, In,
- min(LengthInStr + 1, Count - (*Out - OutOriginal))) != SAFECRT_SUCCESS)
- {
- return FALSE;
- }
-
- *Out += min(LengthInStr, Count - (*Out - OutOriginal));
- }
-
- if (LengthInStr + PaddingOriginal > Count)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-/*******************************************************************************
-Function:
PAL_printf_arg_remover
Parameters:
diff --git a/src/pal/src/cruntime/printfcpp.cpp b/src/pal/src/cruntime/printfcpp.cpp
index 0b9072102b..662561b87b 100644
--- a/src/pal/src/cruntime/printfcpp.cpp
+++ b/src/pal/src/cruntime/printfcpp.cpp
@@ -776,83 +776,6 @@ BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, L
/*******************************************************************************
Function:
- Internal_AddPaddingW
-
-Parameters:
- Out
- - buffer to place padding and given string (In)
- Count
- - maximum chars to be copied so as not to overrun given buffer
- In
- - string to place into (Out) accompanied with padding
- Padding
- - number of padding chars to add
- Flags
- - padding style flags (PRINTF_FORMAT_FLAGS)
-*******************************************************************************/
-
-BOOL Internal_AddPaddingW(LPWSTR *Out, INT Count, LPWSTR In, INT Padding, INT Flags)
-{
- LPWSTR OutOriginal = *Out;
- INT PaddingOriginal = Padding;
- INT LengthInStr;
- LengthInStr = PAL_wcslen(In);
-
-
- if (Padding < 0)
- {
- /* this is used at the bottom to determine if the buffer ran out */
- PaddingOriginal = 0;
- }
- if (Flags & PFF_MINUS) /* pad on right */
- {
- if (wcsncpy_s(*Out, Count, In, min(LengthInStr + 1, Count - 1)) != SAFECRT_SUCCESS)
- {
- return FALSE;
- }
-
- *Out += min(LengthInStr, Count - 1);
- }
- if (Padding > 0)
- {
- if (Flags & PFF_ZERO) /* '0', pad with zeros */
- {
- while (Padding-- && Count > *Out - OutOriginal)
- {
- *(*Out)++ = '0';
- }
- }
- else /* pad left with spaces */
- {
- while (Padding-- && Count > *Out - OutOriginal)
- {
- *(*Out)++ = ' ';
- }
- }
- }
- if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
- {
- if (wcsncpy_s(*Out, Count - (*Out - OutOriginal), In,
- min(LengthInStr, Count - (*Out - OutOriginal) - 1)) != SAFECRT_SUCCESS)
- {
- return FALSE;
- }
-
- *Out += min(LengthInStr, Count - (*Out - OutOriginal) - 1);
- }
-
- if (LengthInStr + PaddingOriginal > Count - 1)
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-/*******************************************************************************
-Function:
Internal_AddPaddingVfprintf
Parameters:
diff --git a/src/pal/src/cruntime/wchar.cpp b/src/pal/src/cruntime/wchar.cpp
index 5b466960a6..c93a3d5edf 100644
--- a/src/pal/src/cruntime/wchar.cpp
+++ b/src/pal/src/cruntime/wchar.cpp
@@ -41,6 +41,7 @@ Abstract:
#endif
#include <errno.h>
+#include <algorithm>
SET_DEFAULT_DEBUG_CHANNEL(CRT);
@@ -1237,7 +1238,7 @@ PAL_wcsncpy( wchar_16 * strDest, const wchar_16 *strSource, size_t count )
strDest, strSource, strSource, (unsigned long) count);
memset( strDest, 0, length );
- length = min( count, PAL_wcslen( strSource ) ) * sizeof( wchar_16 );
+ length = std::min( count, PAL_wcslen( strSource ) ) * sizeof( wchar_16 );
memcpy( strDest, strSource, length );
LOGEXIT("wcsncpy returning (wchar_16*): %p\n", strDest);
diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
index 2d1c18218a..9f5f074f18 100644
--- a/src/pal/src/exception/seh.cpp
+++ b/src/pal/src/exception/seh.cpp
@@ -39,37 +39,7 @@ Abstract:
#include <unistd.h>
#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);
- }
-}
+#include <utility>
using namespace CorUnix;
diff --git a/src/pal/src/include/pal/cruntime.h b/src/pal/src/include/pal/cruntime.h
index 65bf33c952..3b3fa7b3f8 100644
--- a/src/pal/src/include/pal/cruntime.h
+++ b/src/pal/src/include/pal/cruntime.h
@@ -98,24 +98,6 @@ typedef enum
/*******************************************************************************
Function:
- Internal_AddPaddingA
-
-Parameters:
- Out
- - buffer to place padding and given string (In)
- Count
- - maximum chars to be copied so as not to overrun given buffer
- In
- - string to place into (Out) accompanied with padding
- Padding
- - number of padding chars to add
- Flags
- - padding style flags (PRINTF_FORMAT_FLAGS)
-*******************************************************************************/
-BOOL Internal_AddPaddingA(LPSTR *Out, INT Count, LPSTR In, INT Padding, INT Flags);
-
-/*******************************************************************************
-Function:
PAL_printf_arg_remover
Parameters:
diff --git a/src/pal/src/include/pal/malloc.hpp b/src/pal/src/include/pal/malloc.hpp
index c7333419a7..9faf4273d9 100644
--- a/src/pal/src/include/pal/malloc.hpp
+++ b/src/pal/src/include/pal/malloc.hpp
@@ -25,6 +25,7 @@ Abstract:
#include <stdarg.h>
#include <stdlib.h>
+#include <new>
extern "C"
{
@@ -54,9 +55,6 @@ extern "C"
);
}
-inline void* operator new(size_t, void* p) throw () { return p; }
-inline void* operator new[](size_t, void* p) throw () { return p; }
-
namespace CorUnix{
void *
diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h
index 12312a3018..abebcb545e 100644
--- a/src/pal/src/include/pal/palinternal.h
+++ b/src/pal/src/include/pal/palinternal.h
@@ -153,6 +153,11 @@ function_name() to call the system's implementation
#define _ENABLE_DEBUG_MESSAGES_ 0
#endif
+/* Include type_traits before including the pal.h. On newer glibcxx versions,
+ the type_traits fail to compile if we redefine the wchar_t before including
+ the header */
+#include <type_traits>
+
#ifdef PAL_PERF
#include "pal_perf.h"
#endif
@@ -534,6 +539,9 @@ function_name() to call the system's implementation
#undef ctime
+#undef min
+#undef max
+
#undef SCHAR_MIN
#undef SCHAR_MAX
#undef UCHAR_MAX
diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp
index 37c1677f38..996292e2c4 100644
--- a/src/pal/src/init/pal.cpp
+++ b/src/pal/src/init/pal.cpp
@@ -83,6 +83,8 @@ int CacheLineSize;
#include <kvm.h>
#endif
+#include <algorithm>
+
using namespace CorUnix;
//
@@ -218,7 +220,7 @@ InitializeDefaultStackSize()
if (errno == 0)
{
- g_defaultStackSize = max(size, PTHREAD_STACK_MIN);
+ g_defaultStackSize = std::max(size, (long int)PTHREAD_STACK_MIN);
}
}
diff --git a/src/pal/src/misc/cgroup.cpp b/src/pal/src/misc/cgroup.cpp
index ec0a0bd5fb..7a3a9261a1 100644
--- a/src/pal/src/misc/cgroup.cpp
+++ b/src/pal/src/misc/cgroup.cpp
@@ -17,6 +17,7 @@ SET_DEFAULT_DEBUG_CHANNEL(MISC);
#include "pal/palinternal.h"
#include <sys/resource.h>
#include "pal/virtual.h"
+#include <algorithm>
#define PROC_MOUNTINFO_FILENAME "/proc/self/mountinfo"
#define PROC_CGROUP_FILENAME "/proc/self/cgroup"
@@ -362,7 +363,7 @@ PAL_GetRestrictedPhysicalMemoryLimit()
{
rlimit_soft_limit = curr_rlimit.rlim_cur;
}
- physical_memory_limit = min(physical_memory_limit, rlimit_soft_limit);
+ physical_memory_limit = std::min(physical_memory_limit, rlimit_soft_limit);
// Ensure that limit is not greater than real memory size
long pages = sysconf(_SC_PHYS_PAGES);
@@ -371,8 +372,8 @@ PAL_GetRestrictedPhysicalMemoryLimit()
long pageSize = sysconf(_SC_PAGE_SIZE);
if (pageSize != -1)
{
- physical_memory_limit = min(physical_memory_limit,
- (size_t)pages * pageSize);
+ physical_memory_limit = std::min(physical_memory_limit,
+ (size_t)(pages * pageSize));
}
}
diff --git a/src/pal/src/misc/sysinfo.cpp b/src/pal/src/misc/sysinfo.cpp
index a06f4b75cb..bc55dadd4b 100644
--- a/src/pal/src/misc/sysinfo.cpp
+++ b/src/pal/src/misc/sysinfo.cpp
@@ -81,6 +81,7 @@ Revision History:
#include "pal/dbgmsg.h"
+#include <algorithm>
SET_DEFAULT_DEBUG_CHANNEL(MISC);
@@ -437,16 +438,16 @@ PAL_GetLogicalProcessorCacheSizeFromOS()
size_t cacheSize = 0;
#ifdef _SC_LEVEL1_DCACHE_SIZE
- cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE));
+ cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL1_DCACHE_SIZE));
#endif
#ifdef _SC_LEVEL2_CACHE_SIZE
- cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE));
+ cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL2_CACHE_SIZE));
#endif
#ifdef _SC_LEVEL3_CACHE_SIZE
- cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE));
+ cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL3_CACHE_SIZE));
#endif
#ifdef _SC_LEVEL4_CACHE_SIZE
- cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE));
+ cacheSize = std::max(cacheSize, (size_t)sysconf(_SC_LEVEL4_CACHE_SIZE));
#endif
#if defined(_ARM64_)
@@ -455,15 +456,15 @@ PAL_GetLogicalProcessorCacheSizeFromOS()
size_t size;
if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index0/size", &size))
- cacheSize = max(cacheSize, size);
+ cacheSize = std::max(cacheSize, size);
if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index1/size", &size))
- cacheSize = max(cacheSize, size);
+ cacheSize = std::max(cacheSize, size);
if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index2/size", &size))
- cacheSize = max(cacheSize, size);
+ cacheSize = std::max(cacheSize, size);
if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index3/size", &size))
- cacheSize = max(cacheSize, size);
+ cacheSize = std::max(cacheSize, size);
if(ReadMemoryValueFromFile("/sys/devices/system/cpu/cpu0/cache/index4/size", &size))
- cacheSize = max(cacheSize, size);
+ cacheSize = std::max(cacheSize, size);
}
if(cacheSize == 0)
@@ -488,7 +489,7 @@ PAL_GetLogicalProcessorCacheSizeFromOS()
// Assume L3$/CPU grows linearly from 256K to 1.5M/CPU as logicalCPUs grows from 2 to 12 CPUs
DWORD logicalCPUs = PAL_GetLogicalCpuCountFromOS();
- cacheSize = logicalCPUs*min(1536, max(256, logicalCPUs*128))*1024;
+ cacheSize = logicalCPUs*std::min(1536, std::max(256, (int)logicalCPUs*128))*1024;
}
#endif
diff --git a/src/pal/src/numa/numa.cpp b/src/pal/src/numa/numa.cpp
index 383fb0e3b0..6e4593d0b3 100644
--- a/src/pal/src/numa/numa.cpp
+++ b/src/pal/src/numa/numa.cpp
@@ -32,6 +32,8 @@ SET_DEFAULT_DEBUG_CHANNEL(NUMA);
#include <pthread.h>
#include <dlfcn.h>
+#include <algorithm>
+
#include "numashim.h"
using namespace CorUnix;
@@ -630,7 +632,7 @@ SetThreadAffinityMask(
if (st == 0)
{
- for (int i = 0; i < min(8 * sizeof(KAFFINITY), g_possibleCpuCount); i++)
+ for (int i = 0; i < std::min(8 * (int)sizeof(KAFFINITY), g_possibleCpuCount); i++)
{
if (CPU_ISSET(i, &prevCpuSet))
{
@@ -978,4 +980,4 @@ SetThreadIdealProcessorEx(
PERF_EXIT(SetThreadIdealProcessorEx);
return success;
-} \ No newline at end of file
+}
diff --git a/src/pal/src/numa/numashim.h b/src/pal/src/numa/numashim.h
index 428fc8822a..dd7f58d6de 100644
--- a/src/pal/src/numa/numashim.h
+++ b/src/pal/src/numa/numashim.h
@@ -13,6 +13,8 @@
#include <numa.h>
#include <numaif.h>
+#define numa_free_cpumask numa_bitmask_free
+
// List of all functions from the numa library that are used
#define FOR_ALL_NUMA_FUNCTIONS \
PER_FUNCTION_BLOCK(numa_available) \
diff --git a/src/pal/src/synchmgr/synchmanager.cpp b/src/pal/src/synchmgr/synchmanager.cpp
index 048ea3ee7d..349b3de135 100644
--- a/src/pal/src/synchmgr/synchmanager.cpp
+++ b/src/pal/src/synchmgr/synchmanager.cpp
@@ -39,6 +39,10 @@ SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do t
#include "pal/fakepoll.h"
#endif // HAVE_POLL
+#include <algorithm>
+
+const int CorUnix::CThreadSynchronizationInfo::PendingSignalingsArraySize;
+
// We use the synchronization manager's worker thread to handle
// process termination requests. It does so by calling the
// registered handler function.
@@ -4146,7 +4150,7 @@ namespace CorUnix
ERROR("Failed creating thread synchronization mutex [error=%d (%s)]\n", iRet, strerror(iRet));
if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
{
- poll(NULL, 0, min(100,10*iEagains));
+ poll(NULL, 0, std::min(100,10*iEagains));
goto Mutex_retry;
}
else if (ENOMEM == iRet)
@@ -4172,7 +4176,7 @@ namespace CorUnix
"[error=%d (%s)]\n", iRet, strerror(iRet));
if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
{
- poll(NULL, 0, min(100,10*iEagains));
+ poll(NULL, 0, std::min(100,10*iEagains));
goto Cond_retry;
}
else if (ENOMEM == iRet)
@@ -4361,7 +4365,7 @@ namespace CorUnix
if (0 < m_lPendingSignalingCount)
{
- LONG lArrayPendingSignalingCount = min(PendingSignalingsArraySize, m_lPendingSignalingCount);
+ LONG lArrayPendingSignalingCount = std::min(PendingSignalingsArraySize, m_lPendingSignalingCount);
LONG lIdx = 0;
PAL_ERROR palTempErr;
diff --git a/src/publish.proj b/src/publish.proj
index c6c2149ba3..81ac12df7c 100644
--- a/src/publish.proj
+++ b/src/publish.proj
@@ -1,41 +1,71 @@
<?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" />
- <Import Project="$(ToolsDir)PublishContent.targets" />
- <Import Project="$(ToolsDir)versioning.targets" />
- <!-- gathers the items to be published -->
- <Target Name="GatherItemsForPattern">
- <Error Condition="'$(PublishPattern)' == ''" Text="Please specify a value for PublishPattern using standard msbuild 'include' syntax." />
+ <Import Project="$(PackagesDir)/$(FeedTasksPackage.ToLower())/$(FeedTasksPackageVersion)/build/$(FeedTasksPackage).targets" />
+
+ <PropertyGroup>
+ <PackagesPattern Condition="'$(PackagesPattern)' == ''">$(PackagesBinDir)pkg\*.nupkg</PackagesPattern>
+ <TestNativeBinariesPattern Condition="'$(TestNativeBinariesPattern)' == ''">$(OutputPath)\bin\**</TestNativeBinariesPattern>
+ <SymbolsPackagesPattern Condition="'$(SymbolPackagesPattern)' == ''">$(PackagesBinDir)symbolpkg\*.nupkg</SymbolsPackagesPattern>
+ <PublishFlatContainer Condition="'$(PublishFlatContainer)' == ''">true</PublishFlatContainer>
+ </PropertyGroup>
+
+ <PropertyGroup>
+ <ContainerName>$(ContainerName.Replace(".","-"))</ContainerName>
+ <AccountName>$(CloudDropAccountName)</AccountName>
+ <AccountKey>$(CloudDropAccessToken)</AccountKey>
+ </PropertyGroup>
+
+ <Target Name="PublishPackages" Condition="'$(__PublishPackages)' == 'true' and ('$(OfficialPublish)' != 'true' or '$(__BuildType)' == 'Release')">
+ <PropertyGroup>
+ <RelativePath Condition="'$(RelativePath)' == ''">$(__BuildType)/pkg</RelativePath>
+ <ExpectedFeedUrl>https://$(AccountName).blob.core.windows.net/$(ContainerName)/$(RelativePath)/index.json</ExpectedFeedUrl>
+ </PropertyGroup>
<ItemGroup>
- <ForPublishing Include="$(PublishPattern)" />
+ <ItemsToPush Remove="*.nupkg" />
+ <ItemsToPush Include="$(PackagesPattern)" Exclude="$(SymbolsPackagesPattern)"/>
</ItemGroup>
- <!-- add relative blob path metadata -->
+ <PushToBlobFeed ExpectedFeedUrl="$(ExpectedFeedUrl)"
+ AccountKey="$(AccountKey)"
+ ItemsToPush="@(ItemsToPush)"
+ PublishFlatContainer="$(PublishFlatContainer)"
+ Overwrite="$(OverwriteOnPublish)"
+ IndexDirectory="$(__IntermediatesDir)"/>
+ </Target>
+
+ <Target Name="PublishSymbolPackages" Condition="'$(__PublishSymbols)' == 'true' and ('$(OfficialPublish)' != 'true' or '$(__BuildType)' == 'Release')">
+ <PropertyGroup>
+ <RelativePath Condition="'$(RelativePath)' == ''">$(__BuildType)/symbolpkg</RelativePath>
+ <ExpectedFeedUrl>https://$(AccountName).blob.core.windows.net/$(ContainerName)/$(RelativePath)/index.json</ExpectedFeedUrl>
+ </PropertyGroup>
<ItemGroup>
- <ForPublishing>
- <RelativeBlobPath Condition="'$(PublishTestNativeBins)' != 'true'">$(__BuildType)/%(RecursiveDir)%(Filename)%(Extension)</RelativeBlobPath>
- <RelativeBlobPath Condition="'$(PublishTestNativeBins)' == 'true'">$(__BuildType)/%(RecursiveDir)%(Filename)%(Extension)</RelativeBlobPath>
- </ForPublishing>
+ <ItemsToPush Remove="*.nupkg" />
+ <ItemsToPush Include="$(SymbolsPackagesPattern)"/>
</ItemGroup>
- <Error Condition="'@(ForPublishing)' == ''" Text="No items were found matching pattern '$(PublishPattern)'." />
+ <PushToBlobFeed ExpectedFeedUrl="$(ExpectedFeedUrl)"
+ AccountKey="$(AccountKey)"
+ ItemsToPush="@(ItemsToPush)"
+ PublishFlatContainer="$(PublishFlatContainer)"
+ Overwrite="$(OverwriteOnPublish)" />
</Target>
- <PropertyGroup>
- <PublishPattern Condition="'$(PublishPattern)' == '' and '$(PublishTestNativeBins)' != 'true'">$(PackagesBinDir)**\*.nupkg</PublishPattern>
- <PublishPattern Condition="'$(PublishPattern)' == '' and '$(PublishTestNativeBins)' == 'true'">$(OutputPath)\bin\**</PublishPattern>
- </PropertyGroup>
-
- <Target Name="CreateContainerName"
- DependsOnTargets="CreateVersionFileDuringBuild"
- Condition="'$(ContainerName)' == '' or '$(PublishTestNativeBins)' == 'true'">
+ <Target Name="PublishTestNativeBinaries" Condition="'$(PublishTestNativeBins)' == 'true' and '$(OfficialPublish)' != 'true'">
<PropertyGroup>
- <ContainerName Condition="'$(__Container)' == '' and '$(PublishTestNativeBins)' != 'true'">coreclr-$(PreReleaseLabel)-$(BuildNumberMajor)-$(BuildNumberMinor)</ContainerName>
- <ContainerName Condition="'$(__Container)' == '' and '$(PublishTestNativeBins)' == 'true'">coreclr-$(PreReleaseLabel)-$(BuildNumberMajor)-$(BuildNumberMinor)-$(__DistroRid)-$(__BuildArch)</ContainerName>
- <ContainerName Condition="'$(__Container)' != '' and '$(PublishTestNativeBins)' != 'true'">$(__Container)</ContainerName>
- <ContainerName Condition="'$(__Container)' != '' and '$(PublishTestNativeBins)' == 'true'">$(__Container)-$(__DistroRid)-$(__BuildArch)</ContainerName>
- <ContainerName>$(ContainerName.Replace(".","-"))</ContainerName>
+ <RelativePath Condition="'$(RelativePath)' == ''">$(__BuildType)/TestNativeBins</RelativePath>
+ <ExpectedFeedUrl>https://$(AccountName).blob.core.windows.net/$(ContainerName)/$(RelativePath)/index.json</ExpectedFeedUrl>
</PropertyGroup>
+ <ItemGroup>
+ <ItemsToPush Remove="*.nupkg" />
+ <ItemsToPush Include="$(TestNativeBinariesPattern)"/>
+ </ItemGroup>
+ <PushToBlobFeed ExpectedFeedUrl="$(ExpectedFeedUrl)"
+ AccountKey="$(AccountKey)"
+ ItemsToPush="@(ItemsToPush)"
+ PublishFlatContainer="$(PublishFlatContainer)"
+ Overwrite="$(OverwriteOnPublish)" />
</Target>
- <Target Name="Build" DependsOnTargets="CreateContainerName;UploadToAzure" />
+
+ <Target Name="Build" DependsOnTargets="PublishPackages;PublishSymbolPackages;PublishTestNativeBinaries"/>
</Project> \ No newline at end of file
diff --git a/src/strongname/api/common.h b/src/strongname/api/common.h
index 92fb5b49d5..7cea2ec795 100644
--- a/src/strongname/api/common.h
+++ b/src/strongname/api/common.h
@@ -72,10 +72,6 @@
#include "lazycow.h"
-#include "compatibilityflags.h"
-extern BOOL GetCompatibilityFlag(CompatibilityFlag flag);
-extern DWORD* GetGlobalCompatibilityFlags();
-
#include "strongname.h"
#include "stdmacros.h"
diff --git a/src/syncAzure.proj b/src/syncAzure.proj
index 14baa2622e..c5360d77f5 100644
--- a/src/syncAzure.proj
+++ b/src/syncAzure.proj
@@ -3,13 +3,9 @@
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
- <ContainerNamePrefix Condition="'$(ContainerNamePrefix)' == ''">coreclr-$(PreReleaseLabel)</ContainerNamePrefix>
- <ContainerName Condition="'$(__Container)' == '' and '$(ContainerNamePrefix)' != '' and '$(BuildNumberMajor)' != '' and '$(BuildNumberMinor)' != ''">$(ContainerNamePrefix)-$(BuildNumberMajor)-$(BuildNumberMinor)</ContainerName>
- <ContainerName Condition="'$(__Container)' != ''">$(__Container)</ContainerName>
<ContainerName>$(ContainerName.Replace(".","-"))</ContainerName>
<BlobNamePrefix>$(__BlobNamePrefix)</BlobNamePrefix>
- <DownloadDirectory Condition="'$(PublishTestNativeBins)' != 'true'">$(PackagesDir)AzureTransfer</DownloadDirectory>
- <DownloadDirectory Condition="'$(PublishTestNativeBins)' == 'true'">$(PackagesDir)TestNativeBins\$(RuntimeId)</DownloadDirectory>
+ <DownloadDirectory Condition="'$(DownloadDirectory)' == ''">$(PackagesDir)AzureTransfer</DownloadDirectory>
</PropertyGroup>
<Import Project="$(ToolsDir)SyncCloudContent.targets" />
@@ -17,10 +13,10 @@
<Target Name="ValidateRequiredProperties">
<Error Condition="'$(CloudDropAccountName)' == ''" Text="Missing property CloudDropAccountName." />
<Error Condition="'$(CloudDropAccessToken)' == ''" Text="Missing property CloudDropAccessToken." />
- <Error Condition="'$(__Container)' == '' and '$(PublishTestNativeBins)' == 'true'" Text="Missing property Container." />
+ <Error Condition="'$(ContainerName)' == '' and '$(PublishTestNativeBins)' == 'true'" Text="Missing property Container." />
<Error Condition="'$(RuntimeId)' == '' and '$(PublishTestNativeBins)' == 'true'" Text="Missing property RuntimeId." />
</Target>
<!-- We don't want to run sync on test native binaries for Windows, since those don't get published -->
- <Target Name="Build" DependsOnTargets="ValidateRequiredProperties;DownloadBlobsFromAzureTargets" Condition="'$(PublishTestNativeBins)' != 'true' or !$(RuntimeId.ToLower().StartsWith('win'))"/>
+ <Target Name="Build" DependsOnTargets="ValidateRequiredProperties;DownloadBlobsFromAzureTargets" Condition="!$(RuntimeId.ToLower().StartsWith('win'))"/>
</Project> \ No newline at end of file
diff --git a/src/tools/metainfo/mdinfo.cpp b/src/tools/metainfo/mdinfo.cpp
index 753321fb5c..5458a76d28 100644
--- a/src/tools/metainfo/mdinfo.cpp
+++ b/src/tools/metainfo/mdinfo.cpp
@@ -38,7 +38,6 @@ extern HRESULT _FillVariant(
// Validator declarations.
extern DWORD g_ValModuleType;
-#include <ivehandler.h>
// Tables for mapping element type to text
const char *g_szMapElementType[] =
@@ -312,7 +311,6 @@ void MDInfo::Init(
strPassBackFn inPBFn, // Callback to write text.
DUMP_FILTER DumpFilter) // Flags to control the dump.
{
- m_VEHandlerReporterPtr = 0;
m_pbFn = inPBFn;
m_DumpFilter = DumpFilter;
m_pTables = NULL;
@@ -335,228 +333,6 @@ MDInfo::~MDInfo()
} // MDInfo::~MDInfo()
//=====================================================================================================================
-//#define EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
-#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
-
-HINSTANCE GetModuleInst()
-{
- return NULL;
-} // HINSTANCE GetModuleInst()
-
-typedef HRESULT (*REPORTFCTN)(LPCWSTR, VEContext, HRESULT);
-HRESULT DefaultReporter( // Return status.
- LPCWSTR szMsg, // Error message.
- VEContext Context, // Error context (offset,token)
- HRESULT hrRpt) // Original HRESULT
-{
- if(szMsg)
- {
- printf("%S", szMsg);
- // include token and offset from Context
- if(Context.Token) printf(" [token:0x%08X]",Context.Token);
- if(Context.uOffset) printf(" [at:0x%X]",Context.uOffset);
- printf(" [hr:0x%08X]\n",hrRpt);
- fflush(stdout);
- }
- return S_OK;
-} // HRESULT DefaultReporter()
-
-
-#ifdef FEATURE_METADATA_VALIDATOR
-class MDVEHandlerClass : public IVEHandler
-{
-public:
- LONG m_refCount;
- REPORTFCTN m_fnReport;
-
- MDVEHandlerClass() { m_refCount=0; m_fnReport=DefaultReporter; };
- virtual ~MDVEHandlerClass() { };
-
- //-----------------------------------------------------------
- // IUnknown support
- //-----------------------------------------------------------
- HRESULT STDMETHODCALLTYPE QueryInterface(REFIID id, void** pInterface)
- {
- if (id == IID_IVEHandler)
- *pInterface = (IVEHandler*)this;
- /*
- else if (id == IID_IUnknown)
- *pInterface = (IUnknown*)(IVEHandler*)this;
- */
- else
- {
- *pInterface = NULL;
- return E_NOINTERFACE;
- }
-
- AddRef();
- return S_OK;
- }
- ULONG STDMETHODCALLTYPE AddRef()
- {
- return InterlockedIncrement(&m_refCount);
- }
-
- ULONG STDMETHODCALLTYPE Release()
- {
- LONG refCount = InterlockedDecrement(&m_refCount);
- if (refCount == 0) delete this;
- return (refCount);
- }
- //-----------------------------------------------------------
- // IVEHandler support
- //-----------------------------------------------------------
- HRESULT STDMETHODCALLTYPE SetReporterFtn(__int64 lFnPtr)
- {
- m_fnReport = lFnPtr ? reinterpret_cast<REPORTFCTN>(lFnPtr)
- : DefaultReporter;
- return S_OK;
- };
-
-//*****************************************************************************
-// The Verification Event Handler itself. Declared in VEHandler.h as virtual, may be overridden
-//*****************************************************************************
- HRESULT STDMETHODCALLTYPE VEHandler(HRESULT hrRpt, VEContext Context, SAFEARRAY *psa)
- {
- WCHAR rcBuf[1024]; // Resource string.
- WCHAR rcMsg[1024]; // Error message.
- BYTE *marker; // User text.
- HRESULT hr;
- ULONG32 k;
- WCHAR *pWsz[1024]; // is more than 1024 string arguments likely?
-
- // Return warnings without text.
- if (!FAILED(hrRpt))
- return (hrRpt);
- memset(pWsz,0,sizeof(pWsz));
-
- ULONG32 nVars;
- // Convert safearray of variants into va_list
- if(psa && (nVars = psa->rgsabound[0].cElements))
- {
- WCHAR *pwsz;
- VARIANT *pVar;
- ULONG32 i,l;
- BYTE *pval;
-
- _ASSERTE(psa->fFeatures & FADF_VARIANT);
- _ASSERTE(psa->cDims == 1);
- marker = new BYTE[nVars*sizeof(double)]; // double being the largest variant element
- for(i=0,pVar=(VARIANT *)(psa->pvData),pval=marker; i < nVars; pVar++,i++)
- {
- switch(V_VT(pVar))
- {
- case VT_I1:
- *(int *)pval = V_I1(pVar);
- pval += sizeof(int);
- break;
-
- case VT_UI1:
- *(int *)pval = V_UI1(pVar);
- pval += sizeof(int);
- break;
-
-
- case VT_I2:
- *(int *)pval = V_I2(pVar);
- pval += sizeof(int);
- break;
-
- case VT_UI2:
- *(int *)pval = V_UI2(pVar);
- pval += sizeof(int);
- break;
-
- case VT_I8:
- case VT_UI8:
- *(INT64 *)pval = V_I8(pVar);
- pval += sizeof(INT64);
- break;
-
-
- case VT_BYREF|VT_I1:
- case VT_BYREF|VT_UI1: // it's ASCII string, convert it to UNICODE
- {
- PBYTE pb = V_UI1REF(pVar);
- l = (ULONG32)strlen((char *)pb)+1;
- pwsz = new WCHAR[l];
- WszMultiByteToWideChar(CP_ACP,0,(char*)pb,-1,pwsz,l);
- for(k=0; pWsz[k]; k++);
- pWsz[k] = pwsz;
-
- *(WCHAR **)pval = pwsz;
- pval += sizeof(WCHAR *);
- break;
- }
-
- default:
- *(int *)pval = V_I4(pVar);
- pval += sizeof(int);
- break;
- }
- }
- }
- else
- marker = NULL;
-
- // If this is one of our errors, then grab the error from the rc file.
- if (HRESULT_FACILITY(hrRpt) == FACILITY_URT)
- {
- hr = UtilLoadStringRC(LOWORD(hrRpt), rcBuf, NumItems(rcBuf), true);
- if (hr == S_OK)
- {
- // Format the error.
- vswprintf_s(rcMsg, NumItems(rcMsg), rcBuf, (va_list) marker);
- rcMsg[NumItems(rcMsg) - 1] = 0;
- }
- }
- // Otherwise it isn't one of ours, so we need to see if the system can
- // find the text for it.
- else
- {
- if (WszFormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
- 0, hrRpt, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- rcMsg, NumItems(rcMsg), 0))
- {
- hr = S_OK;
-
- // System messages contain a trailing \r\n, which we don't want normally.
- int iLen = lstrlenW(rcMsg);
- if (iLen > 3 && rcMsg[iLen - 2] == '\r' && rcMsg[iLen - 1] == '\n')
- rcMsg[iLen - 2] = '\0';
- }
- else
- hr = HRESULT_FROM_WIN32(GetLastError());
- }
- if(marker) delete [] marker;
-
- // If we failed to find the message anywhere, then issue a hard coded message.
- if (FAILED(hr))
- {
- swprintf_s(rcMsg, NumItems(rcMsg), W("COM+ Runtime Internal error: 0x%08x"), hrRpt);
- //DEBUG_STMT(DbgWriteEx(rcMsg));
- }
-
- // delete WCHAR buffers allocated above (if any)
- for(k=0; pWsz[k]; k++)
- {
- if(pWsz[k])
- {
- delete [] pWsz[k];
- pWsz[k] = NULL;
- }
- }
-
- return (m_fnReport(rcMsg, Context,hrRpt) == S_OK ? S_OK : E_FAIL);
- };
-
- static HRESULT STDMETHODCALLTYPE CreateObject(REFIID id, void **object)
- { return E_NOTIMPL; }
-};
-#endif // FEATURE_METADATA_VALIDATOR
-
-#endif
-//=====================================================================================================================
// DisplayMD() function
//
// Displays the meta data content of a file
@@ -596,84 +372,6 @@ void MDInfo::DisplayMD()
if (m_DumpFilter & dumpUnsat)
DisplayUnsatInfo();
WriteLine("===========================================================");
-#ifdef FEATURE_METADATA_VALIDATOR
- if (m_DumpFilter & dumpValidate)
- {
- IMetaDataValidate *pValidate = 0;
-#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
- MDVEHandlerClass *pVEHandler = 0;
-#else
- IVEHandler *pVEHandler = 0;
-#endif
- const char *szErrStr = 0;
- HRESULT hr = S_OK;
-
- // Get a pointer to the Validator interface.
- hr = m_pImport->QueryInterface(IID_IMetaDataValidate, (void **) &pValidate);
- if (FAILED(hr))
- {
- szErrStr = "QueryInterface failed for IMetaDataValidate.";
- goto ErrExit;
- }
-
- // Get a pointer to the VEHandler interface.
-#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
- if((pVEHandler = new MDVEHandlerClass())) hr = S_OK;
- else hr = E_FAIL;
-#else
- hr = CoCreateInstance(CLSID_VEHandlerClass,
- NULL,
- CLSCTX_INPROC_SERVER,
- IID_IVEHandler,
- (void **)&pVEHandler);
-#endif
- if (FAILED(hr))
- {
-#ifndef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
- szErrStr = "Failed to create VEHandler.";
-#else
- szErrStr = "CoCreateInstance(VEHandler) failed.";
-#endif
- goto ErrExit;
- }
-
- if(m_VEHandlerReporterPtr) pVEHandler->SetReporterFtn((__int64)m_VEHandlerReporterPtr);
-
- hr = pValidate->ValidatorInit(g_ValModuleType, pVEHandler);
- if (FAILED(hr))
- {
- szErrStr = "ValidatorInit failed.";
- goto ErrExit;
- }
-
- hr = pValidate->ValidateMetaData();
- if (FAILED(hr))
- {
- szErrStr = "ValidateMetaData failed to run successfully.";
- goto ErrExit;
- }
- if (hr == S_OK)
- WriteLine("No warnings or errors found.");
- else if (hr == VLDTR_S_WRN)
- WriteLine("Warnings found.");
- else if (hr == VLDTR_S_ERR)
- WriteLine("Errors found.");
- else if (hr == VLDTR_S_WRNERR)
- WriteLine("Warnings and Errors found.");
- else
- VWriteLine("Validator returned unexpected success code, hr=0x%08x.", hr);
-ErrExit:
- if (pValidate)
- pValidate->Release();
-#ifdef EXTERNAL_VE_HANDLER_FOR_MD_VALIDATION
- if (pVEHandler)
- pVEHandler->Release();
-#endif
- if (szErrStr)
- Error(szErrStr, hr);
- }
-#endif // FEATURE_METADATA_VALIDATOR
- WriteLine("===========================================================");
} // MDVEHandlerClass()
int MDInfo::WriteLine(__in_z __in const char *str)
diff --git a/src/tools/metainfo/mdinfo.h b/src/tools/metainfo/mdinfo.h
index 06c0a76b63..acca606f32 100644
--- a/src/tools/metainfo/mdinfo.h
+++ b/src/tools/metainfo/mdinfo.h
@@ -164,7 +164,6 @@ public:
void DumpRawCol(ULONG ixTbl, ULONG ixCol, ULONG rid, bool bStats);
ULONG DumpRawColStats(ULONG ixTbl, ULONG ixCol, ULONG cRows);
const char *DumpRawNameOfType(ULONG ulType);
- void SetVEHandlerReporter(__int64 VEHandlerReporterPtr) { m_VEHandlerReporterPtr = VEHandlerReporterPtr; };
static void Error(const char *szError, HRESULT hr = S_OK);
private:
@@ -186,7 +185,6 @@ private:
IMetaDataImport2 *m_pImport;
IMetaDataAssemblyImport *m_pAssemblyImport;
strPassBackFn m_pbFn;
- __int64 m_VEHandlerReporterPtr;
IMetaDataTables *m_pTables;
IMetaDataTables2 *m_pTables2;
diff --git a/src/utilcode/CMakeLists.txt b/src/utilcode/CMakeLists.txt
index dfe830d5c0..9c61314848 100644
--- a/src/utilcode/CMakeLists.txt
+++ b/src/utilcode/CMakeLists.txt
@@ -81,11 +81,6 @@ if(WIN32)
)
endif()
- if(NOT DEFINED FEATURE_IMPLICIT_TLS)
- list(APPEND UTILCODE_SOURCES
- tls.cpp
- )
- endif(NOT DEFINED FEATURE_IMPLICIT_TLS)
endif(WIN32)
set(UTILCODE_SOURCES
@@ -93,14 +88,6 @@ set(UTILCODE_SOURCES
perflog.cpp
)
-if(WIN32)
- if(NOT DEFINED FEATURE_IMPLICIT_TLS)
- list(APPEND UTILCODE_SOURCES
- tls.cpp
- )
- endif(NOT DEFINED FEATURE_IMPLICIT_TLS)
-endif()
-
set(UTILCODE_DAC_SOURCES
${UTILCODE_COMMON_SOURCES}
hostimpl.cpp
diff --git a/src/utilcode/sxshelpers.cpp b/src/utilcode/sxshelpers.cpp
deleted file mode 100644
index 214c5c7066..0000000000
--- a/src/utilcode/sxshelpers.cpp
+++ /dev/null
@@ -1,1508 +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.
-//*****************************************************************************
-//
-// sxshelpers.cpp
-//
-// Some helping classes and methods for SxS in mscoree and mscorwks
-//
-
-//*****************************************************************************
-
-#include "stdafx.h"
-#include "utilcode.h"
-#include "sxshelpers.h"
-
-#define SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE (0x00000001)
-#define SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS (0x00000002)
-
-typedef struct _SXS_GUID_INFORMATION_CLR
-{
- DWORD cbSize;
- DWORD dwFlags;
- PCWSTR pcwszRuntimeVersion;
- PCWSTR pcwszTypeName;
- PCWSTR pcwszAssemblyIdentity;
-} SXS_GUID_INFORMATION_CLR, *PSXS_GUID_INFORMATION_CLR;
-typedef const SXS_GUID_INFORMATION_CLR *PCSXS_GUID_INFORMATION_CLR;
-
-#define SXS_LOOKUP_CLR_GUID_USE_ACTCTX (0x00000001)
-#define SXS_LOOKUP_CLR_GUID_FIND_SURROGATE (0x00010000)
-#define SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS (0x00020000)
-#define SXS_LOOKUP_CLR_GUID_FIND_ANY (SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS | SXS_LOOKUP_CLR_GUID_FIND_SURROGATE)
-
-#define SXS_DLL_NAME_W (W("sxs.dll"))
-#define SXS_LOOKUP_CLR_GUID ("SxsLookupClrGuid")
-
-typedef BOOL (WINAPI* PFN_SXS_LOOKUP_CLR_GUID)(
- IN DWORD dwFlags,
- IN LPGUID pClsid,
- IN HANDLE hActCtx,
- IN OUT PVOID pvOutputBuffer,
- IN SIZE_T cbOutputBuffer,
- OUT PSIZE_T pcbOutputBuffer
- );
-
-// forward declaration
-BOOL TranslateWin32AssemblyIdentityToFusionDisplayName(__deref_out_z LPWSTR *ppwzFusionDisplayName, PCWSTR lpWin32AssemblyIdentity);
-
-// The initial size of the buffer passed to SxsLookupClrGuid.
-#define INIT_GUID_LOOKUP_BUFFER_SIZE 512
-
-// Function pointer to the function to lookup a CLR type by GUID in the unmanaged
-// fusion activation context.
-PFN_SXS_LOOKUP_CLR_GUID g_pfnLookupGuid = NULL;
-Volatile<BOOL> g_fSxSInfoInitialized = FALSE;
-
-HMODULE g_hmSxsDll = NULL;
-
-// And Here are the functions for getting shim info from
-// Win32 activation context
-
-// FindShimInfoFromWin32
-//
-// This method is used in ComInterop. If a COM client calls
-// CoCreateInstance on a managed COM server, we will use this method
-// trying to find required info of the managed COM server from Win32 subsystem.
-// If this fails, we will fall back to query the registry.
-//
-// Parameters:
-// rclsid: [in] The CLSID of the managed COM server
-// bLoadRecord: [in] Set to TRUE if we are looking for a record
-// *ppwzRuntimeVersion: [out] Runtime version
-// *ppwzClassName: [out] Class name
-// *ppwzAssemblyString: [out] Assembly display name
-// *pfRegFreePIA: [out] TRUE if the entry is <clrSurrogate>
-// Return:
-// FAILED(hr) if cannot find shim info from Win32
-// SUCCEEDED(HR) if shim info is found from Win32
-
-HRESULT
-FindShimInfoFromWin32(
- REFCLSID rClsid,
- BOOL bLoadRecord,
- __deref_out_z __deref_opt_out_opt LPWSTR *ppwszRuntimeVersion,
- __deref_out_z __deref_opt_out_opt LPWSTR *ppwszSupportedRuntimeVersions,
- __deref_out_z __deref_opt_out_opt LPWSTR *ppwszClassName,
- __deref_out_z __deref_opt_out_opt LPWSTR *ppwszAssemblyString,
- BOOL *pfRegFreePIA
- )
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- CQuickBytes rDataBuffer;
- SIZE_T cbWritten;
- HRESULT hr = S_OK;
- PCSXS_GUID_INFORMATION_CLR pFoundInfo = NULL;
- SIZE_T cch;
- GUID MyGuid = rClsid;
- DWORD dwFlags = bLoadRecord ? SXS_LOOKUP_CLR_GUID_FIND_SURROGATE : SXS_LOOKUP_CLR_GUID_FIND_ANY;
-
- if (!ppwszRuntimeVersion && !ppwszClassName && !ppwszAssemblyString)
- IfFailGo(E_INVALIDARG);
-
- if (ppwszRuntimeVersion)
- *ppwszRuntimeVersion = NULL;
-
- if (ppwszSupportedRuntimeVersions)
- *ppwszSupportedRuntimeVersions = NULL;
-
- if (ppwszClassName)
- *ppwszClassName = NULL;
-
- if (ppwszAssemblyString)
- *ppwszAssemblyString = NULL;
-
- if (pfRegFreePIA)
- *pfRegFreePIA = FALSE;
-
- // If we haven't initialized the SxS info yet, then do so now.
- if (!g_fSxSInfoInitialized)
- {
- if (g_hmSxsDll == NULL)
- g_hmSxsDll = WszLoadLibrary(SXS_DLL_NAME_W);
-
- if (g_hmSxsDll != NULL)
- {
- // Lookup the SxsLookupClrGuid function in the SxS DLL.
- g_pfnLookupGuid = (PFN_SXS_LOOKUP_CLR_GUID)GetProcAddress(g_hmSxsDll, SXS_LOOKUP_CLR_GUID);
- }
-
- // The SxS info has been initialized.
- g_fSxSInfoInitialized = TRUE;
- }
-
- // If we don't have the proc address of SxsLookupClrGuid, then return a failure.
- if (g_pfnLookupGuid == NULL)
- IfFailGo(E_FAIL);
-
- // Resize the CQuickBytes to the initial buffer size.
- IfFailGo(rDataBuffer.ReSizeNoThrow(INIT_GUID_LOOKUP_BUFFER_SIZE));
-
- if (!g_pfnLookupGuid(dwFlags, &MyGuid, INVALID_HANDLE_VALUE, rDataBuffer.Ptr(), rDataBuffer.Size(), &cbWritten))
- {
- const DWORD dwLastError = ::GetLastError();
-
- // Failed b/c we need more space? Expand and try again.
- if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
- {
- IfFailGo(rDataBuffer.ReSizeNoThrow(cbWritten));
-
- // Still failed even with enough space? Bummer.
- if (!g_pfnLookupGuid(dwFlags, &MyGuid, INVALID_HANDLE_VALUE, rDataBuffer.Ptr(), rDataBuffer.Size(), &cbWritten))
- IfFailGo(E_FAIL);
- }
- // All other failures are real failures - probably the section isn't present
- // or some other problem.
- else
- {
- IfFailGo(E_FAIL);
- }
- }
-
- pFoundInfo = (PCSXS_GUID_INFORMATION_CLR)rDataBuffer.Ptr();
-
- if (pFoundInfo->dwFlags == SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE && ppwszRuntimeVersion)
- {
- // Surrogate does not have runtime version information !!!
- IfFailGo(E_FAIL);
- }
-
- //
- // This is special - translate the win32 assembly name into a managed
- // assembly identity.
- //
- if (ppwszAssemblyString && pFoundInfo->pcwszAssemblyIdentity)
- {
- if (!TranslateWin32AssemblyIdentityToFusionDisplayName(ppwszAssemblyString, pFoundInfo->pcwszAssemblyIdentity))
- IfFailGo(E_FAIL);
- }
-
- //
- // For each field, allocate the outbound pointer and call through.
- //
- if (ppwszClassName && pFoundInfo->pcwszTypeName)
- {
- cch = wcslen(pFoundInfo->pcwszTypeName);
-
- if (cch > 0)
- {
- IfNullGo(*ppwszClassName = new (nothrow) WCHAR[cch + 1]);
- wcscpy_s(*ppwszClassName, cch+1, pFoundInfo->pcwszTypeName);
- }
- else
- IfFailGo(E_FAIL);
- }
-
- if (ppwszRuntimeVersion)
- {
- if (pFoundInfo->pcwszRuntimeVersion && (cch = wcslen(pFoundInfo->pcwszRuntimeVersion)) > 0)
- {
- IfNullGo(*ppwszRuntimeVersion = new (nothrow) WCHAR[cch + 1]);
- wcscpy_s(*ppwszRuntimeVersion, cch+1, pFoundInfo->pcwszRuntimeVersion);
- }
- else
- {
- // Sxs.dll returns empty string even when the runtimeVersion attribute is missing so
- // we cannot tell whether it's not there or is empty. We'll return 1.0 in both cases.
- //
- // The goal is to emulate pre-4.0 behavior where this function wasn't called with
- // non-NULL ppwszRuntimeVersion on the COM activation path at all so shim loaded the
- // latest runtime on the machine.
- IfNullGo(*ppwszRuntimeVersion = DuplicateString(V1_VERSION_NUM));
- }
- }
-
- if (pfRegFreePIA)
- {
- *pfRegFreePIA = (pFoundInfo->dwFlags == SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE);
- }
-
-ErrExit:
- //
- // Deallocate in case of failure
- //
- if (FAILED(hr))
- {
- if (ppwszRuntimeVersion && *ppwszRuntimeVersion)
- {
- delete [] *ppwszRuntimeVersion;
- *ppwszRuntimeVersion = NULL;
- }
- if (ppwszAssemblyString && *ppwszAssemblyString)
- {
- delete [] *ppwszAssemblyString;
- *ppwszAssemblyString = NULL;
- }
- if (ppwszClassName && *ppwszClassName)
- {
- delete [] *ppwszClassName;
- *ppwszClassName = NULL;
- }
- }
-
- return hr;
-}
-
-// TranslateWin32AssemblyIdentityToFusionDisplayName
-//
-// Culture info is missing in the assemblyIdentity returned from win32,
-// So Need to do a little more work here to get the correct fusion display name
-//
-// replace "language=" in assemblyIdentity to "culture=" if any.
-// If "language=" is not present in assemblyIdentity, add "culture=neutral"
-// to it.
-//
-// Also check other attributes as well.
-//
-// Parameters:
-// ppwzFusionDisplayName: the corrected output of assembly displayname
-// lpWin32AssemblyIdentity: input assemblyIdentity returned from win32
-//
-// returns:
-// TRUE if the conversion is done.
-// FALSE otherwise
-
-BOOL TranslateWin32AssemblyIdentityToFusionDisplayName(__deref_out_z LPWSTR *ppwzFusionDisplayName, PCWSTR lpWin32AssemblyIdentity)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- size_t size = 0;
- LPWSTR lpAssemblyIdentityCopy = NULL;
- LPWSTR lpVersionKey = W("version=");
- LPWSTR lpPublicKeyTokenKey = W("publickeytoken=");
- LPWSTR lpCultureKey = W("culture=");
- LPWSTR lpNeutral = W("neutral");
- LPWSTR lpLanguageKey = W("language=");
- LPWSTR lpMatch = NULL;
- LPWSTR lpwzFusionDisplayName = NULL;
-
- if (ppwzFusionDisplayName == NULL) return FALSE;
- *ppwzFusionDisplayName = NULL;
-
- if (lpWin32AssemblyIdentity == NULL) return FALSE;
-
- size = wcslen(lpWin32AssemblyIdentity);
- if (size == 0) return FALSE;
-
- // make a local copy
- lpAssemblyIdentityCopy = new (nothrow) WCHAR[size+1];
- if (!lpAssemblyIdentityCopy)
- return FALSE;
-
- wcscpy_s(lpAssemblyIdentityCopy, size+1, lpWin32AssemblyIdentity);
-
- // convert to lower case
- _wcslwr_s(lpAssemblyIdentityCopy, size+1);
-
- // check if "version" key is presented
- if (!wcsstr(lpAssemblyIdentityCopy, lpVersionKey))
- {
- // version is not presented, append it
- size += wcslen(lpVersionKey)+8; // length of ","+"0.0.0.0"
- lpwzFusionDisplayName = new (nothrow) WCHAR[size+1];
- if (!lpwzFusionDisplayName)
- {
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return FALSE;
- }
-
- //copy old one
- wcscpy_s(lpwzFusionDisplayName, size+1, lpAssemblyIdentityCopy);
- wcscat_s(lpwzFusionDisplayName, size+1, W(","));
- wcscat_s(lpwzFusionDisplayName, size+1, lpVersionKey);
- wcscat_s(lpwzFusionDisplayName, size+1, W("0.0.0.0"));
-
- // delete the old copy
- delete[] lpAssemblyIdentityCopy;
-
- // lpAssemblyIdentityCopy has the new copy
- lpAssemblyIdentityCopy = lpwzFusionDisplayName;
- lpwzFusionDisplayName = NULL;
- }
-
- // check if "publickeytoken" key is presented
- if (!wcsstr(lpAssemblyIdentityCopy, lpPublicKeyTokenKey))
- {
- // publickeytoken is not presented, append it
- size += wcslen(lpPublicKeyTokenKey)+5; //length of ","+"null"
- lpwzFusionDisplayName = new (nothrow) WCHAR[size+1];
- if (!lpwzFusionDisplayName)
- {
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return FALSE;
- }
-
- // copy the old one
- wcscpy_s(lpwzFusionDisplayName, size+1, lpAssemblyIdentityCopy);
- wcscat_s(lpwzFusionDisplayName, size+1, W(","));
- wcscat_s(lpwzFusionDisplayName, size+1, lpPublicKeyTokenKey);
- wcscat_s(lpwzFusionDisplayName, size+1, W("null"));
-
- // delete the old copy
- delete[] lpAssemblyIdentityCopy;
-
- // lpAssemblyIdentityCopy has the new copy
- lpAssemblyIdentityCopy = lpwzFusionDisplayName;
- lpwzFusionDisplayName = NULL;
- }
-
- if (wcsstr(lpAssemblyIdentityCopy, lpCultureKey))
- {
- // culture info is already included in the assemblyIdentity
- // nothing need to be done
- lpwzFusionDisplayName = lpAssemblyIdentityCopy;
- *ppwzFusionDisplayName = lpwzFusionDisplayName;
- return TRUE;
- }
-
- if ((lpMatch = wcsstr(lpAssemblyIdentityCopy, lpLanguageKey)) !=NULL )
- {
- // language info is included in the assembly identity
- // need to replace it with culture
-
- // final size
- size += wcslen(lpCultureKey)-wcslen(lpLanguageKey);
- lpwzFusionDisplayName = new (nothrow) WCHAR[size + 1];
- if (!lpwzFusionDisplayName)
- {
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return FALSE;
- }
- wcsncpy_s(lpwzFusionDisplayName, size+1, lpAssemblyIdentityCopy, lpMatch-lpAssemblyIdentityCopy);
- lpwzFusionDisplayName[lpMatch-lpAssemblyIdentityCopy] = W('\0');
- wcscat_s(lpwzFusionDisplayName, size+1, lpCultureKey);
- wcscat_s(lpwzFusionDisplayName, size+1, lpMatch+wcslen(lpLanguageKey));
- *ppwzFusionDisplayName = lpwzFusionDisplayName;
-
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return TRUE;
- }
- else
- {
- // neither culture or language key is presented
- // let us attach culture info key to the identity
- size += wcslen(lpCultureKey)+wcslen(lpNeutral)+1;
- lpwzFusionDisplayName = new (nothrow) WCHAR[size + 1];
- if (!lpwzFusionDisplayName)
- {
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return FALSE;
- }
-
- wcscpy_s(lpwzFusionDisplayName, size+1, lpAssemblyIdentityCopy);
- wcscat_s(lpwzFusionDisplayName, size+1, W(","));
- wcscat_s(lpwzFusionDisplayName, size+1, lpCultureKey);
- wcscat_s(lpwzFusionDisplayName, size+1, lpNeutral);
- *ppwzFusionDisplayName = lpwzFusionDisplayName;
-
- // clean up
- delete[] lpAssemblyIdentityCopy;
- return TRUE;
- }
-}
-
-//****************************************************************************
-// AssemblyVersion
-//
-// class to handle assembly version
-// Since only functions in this file will use it,
-// we declare it in the cpp file so other people won't use it.
-//
-//****************************************************************************
-
-// Extract version info from pwzVersion, expecting "a.b.c.d",
-// where a,b,c and d are all digits.
-HRESULT AssemblyVersion::Init(__in_z LPCWSTR pcwzVersion, BOOL bStartsWithV)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
- LPWSTR pwzVersionCopy = NULL;
- LPWSTR pwzTokens = NULL;
- LPWSTR pwzToken = NULL;
- size_t size = 0;
- int iVersion = 0;
-
- if ((pcwzVersion == NULL) || (*pcwzVersion == W('\0')))
- IfFailGo(E_INVALIDARG);
-
- // If fStartsWithV is true, then the version string should start with a v.
- // Verify this and if it is the case, start tokenizing at the character after the v.
- if (bStartsWithV)
- {
- if (*pcwzVersion == W('v') || *pcwzVersion == W('V'))
- pcwzVersion++;
- else
- IfFailGo(E_INVALIDARG);
- }
-
- IfFailGo(ValidateVersion(pcwzVersion));
-
- size = wcslen(pcwzVersion);
-
- IfNullGo(pwzVersionCopy = new (nothrow) WCHAR[size + 1]);
-
- wcscpy_s(pwzVersionCopy, size+1, pcwzVersion);
- pwzTokens = pwzVersionCopy;
-
- // parse major version
- pwzToken = wcstok_s(pwzTokens, W("."),&pwzTokens);
- if (pwzToken != NULL)
- {
- iVersion = _wtoi(pwzToken);
- if (iVersion > 0xffff)
- IfFailGo(E_INVALIDARG);
- _major = (WORD)iVersion;
- }
-
- // parse minor version
- pwzToken = wcstok_s(pwzTokens, W("."),&pwzTokens);
- if (pwzToken != NULL)
- {
- iVersion = _wtoi(pwzToken);
- if (iVersion > 0xffff)
- IfFailGo(E_INVALIDARG);
- _minor = (WORD)iVersion;
- }
-
- // parse build version
- pwzToken = wcstok_s(pwzTokens, W("."),&pwzTokens);
- if (pwzToken != NULL)
- {
- iVersion = _wtoi(pwzToken);
- if (iVersion > 0xffff)
- IfFailGo(E_INVALIDARG);
- _build = (WORD)iVersion;
- }
-
- // parse revision version
- pwzToken = wcstok_s(pwzTokens, W("."),&pwzTokens);
- if (pwzToken != NULL)
- {
- iVersion = _wtoi(pwzToken);
- if (iVersion > 0xffff)
- IfFailGo(E_INVALIDARG);
- _revision = (WORD)iVersion;
- }
-
-ErrExit:
- if (pwzVersionCopy)
- delete[] pwzVersionCopy;
- return hr;
-}
-
-// pcwzVersion must be in format of a.b.c.d, where a, b, c, d are numbers
-HRESULT AssemblyVersion::ValidateVersion(LPCWSTR pcwzVersion)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- LPCWSTR pwCh = pcwzVersion;
- INT dots = 0; // number of dots
- BOOL bIsDot = FALSE; // is previous char a dot?
-
- // first char cannot be .
- if (*pwCh == W('.'))
- return E_INVALIDARG;
-
- for(;*pwCh != W('\0');pwCh++)
- {
- if (*pwCh == W('.'))
- {
- if (bIsDot) // ..
- return E_INVALIDARG;
- else
- {
- dots++;
- bIsDot = TRUE;
- }
- }
- /*
- // We can't do this sort of validation, because then our v1.2.x86chk version numbers will be invalid
- else if (!iswdigit(*pwCh))
- return E_INVALIDARG;
- */
- else
- bIsDot = FALSE;
- }
-
- if (dots > 3)
- return E_INVALIDARG;
-
- return S_OK;
-}
-
-BOOL operator==(const AssemblyVersion& version1,
- const AssemblyVersion& version2)
-{
- LIMITED_METHOD_CONTRACT;
-
- return ((version1._major == version2._major)
- && (version1._minor == version2._minor)
- && (version1._build == version2._build)
- && (version1._revision == version2._revision));
-}
-
-BOOL operator>=(const AssemblyVersion& version1,
- const AssemblyVersion& version2)
-{
- LIMITED_METHOD_CONTRACT;
-
- ULONGLONG ulVersion1;
- ULONGLONG ulVersion2;
-
- ulVersion1 = version1._major;
- ulVersion1 = (ulVersion1<<16)|version1._minor;
- ulVersion1 = (ulVersion1<<16)|version1._build;
- ulVersion1 = (ulVersion1<<16)|version1._revision;
-
- ulVersion2 = version2._major;
- ulVersion2 = (ulVersion2<<16)|version2._minor;
- ulVersion2 = (ulVersion2<<16)|version2._build;
- ulVersion2 = (ulVersion2<<16)|version2._revision;
-
- return (ulVersion1 >= ulVersion2);
-}
-
-enum RegistryBasePath
-{
- RegistryBasePath_Record,
- RegistryBasePath_CLSID_InprocServer32,
- RegistryBasePath_CLSID_LocalServer32_32Key,
- RegistryBasePath_CLSID_LocalServer32_64Key,
-};
-
-// Find which subkey has the highest verion
-// If return S_OK, *ppwzHighestVersion has the highest version string.
-// *pbIsTopKey indicates if top key is the one with highest version.
-// If return S_FALSE, cannot find any version. *ppwzHighestVersion is set
-// to NULL, and *pbIsTopKey is TRUE.
-// If failed, *ppwzHighestVersion will be set to NULL, and *pbIsTopKey is
-// undefined.
-// Note: If succeeded, this function will allocate memory for *ppwzVersion.
-// Caller is responsible to release them
-HRESULT FindHighestVersion(REFCLSID rclsid, RegistryBasePath basePath, AssemblyVersion *prvHighestAllowed,
- __deref_out_z LPWSTR *ppwzHighestVersion, BOOL *pbIsTopKey, BOOL *pbIsUnmanagedObject)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
- WCHAR szID[64];
- WCHAR clsidKeyname[128];
- WCHAR wzSubKeyName[32];
- DWORD cwSubKeySize;
- DWORD dwIndex; // subkey index
- HKEY hKeyCLSID = NULL;
- HKEY hSubKey = NULL;
- DWORD type;
- DWORD size;
- BOOL bIsTopKey = FALSE; // Does top key have the highest version?
- BOOL bGotVersion = FALSE; // Do we get anything out of registry?
- LONG lResult;
- LPWSTR wzAssemblyString = NULL;
- DWORD numSubKeys = 0;
- AssemblyVersion avHighest; WCHAR wzHighest[32];
- AssemblyVersion avCurrent; WCHAR wzCurrent[32];
-
- _ASSERTE(pbIsUnmanagedObject != NULL);
- *pbIsUnmanagedObject = FALSE;
-
- if ((ppwzHighestVersion == NULL) || (pbIsTopKey == NULL))
- IfFailGo(E_INVALIDARG);
-
- *ppwzHighestVersion = NULL;
- *pbIsTopKey = FALSE;
-
- if (!GuidToLPWSTR(rclsid, szID, NumItems(szID)))
- IfFailGo(E_INVALIDARG);
-
- if (basePath == RegistryBasePath_Record)
- {
- wcscpy_s(clsidKeyname, 128, W("Record\\"));
- wcscat_s(clsidKeyname, 128, szID);
- }
- else
- {
- wcscpy_s(clsidKeyname, 128, W("CLSID\\"));
- wcscat_s(clsidKeyname, 128, szID);
- if (basePath == RegistryBasePath_CLSID_InprocServer32)
- {
- wcscat_s(clsidKeyname, 128, W("\\InprocServer32"));
- }
- else
- {
- _ASSERTE(basePath == RegistryBasePath_CLSID_LocalServer32_32Key || basePath == RegistryBasePath_CLSID_LocalServer32_64Key);
- wcscat_s(clsidKeyname, 128, W("\\LocalServer32"));
- }
- }
-
- // Open HKCR\CLSID\<clsid> , or HKCR\Record\<RecordId>
- REGSAM accessFlags = KEY_ENUMERATE_SUB_KEYS | KEY_READ;
- if (basePath == RegistryBasePath_CLSID_LocalServer32_32Key)
- {
- // open the WoW key
- accessFlags |= KEY_WOW64_32KEY;
- }
- else if (basePath == RegistryBasePath_CLSID_LocalServer32_64Key)
- {
- // open the 64-bit key
- accessFlags |= KEY_WOW64_64KEY;
- }
-
- IfFailWin32Go(WszRegOpenKeyEx(
- HKEY_CLASSES_ROOT,
- clsidKeyname,
- 0,
- accessFlags,
- &hKeyCLSID));
-
-
- //
- // Start by looking for a version subkey.
- //
-
- IfFailWin32Go(WszRegQueryInfoKey(hKeyCLSID, NULL, NULL, NULL,
- &numSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL));
-
- for ( dwIndex = 0; dwIndex < numSubKeys; dwIndex++)
- {
- cwSubKeySize = NumItems(wzSubKeyName);
-
- IfFailWin32Go(WszRegEnumKeyEx(hKeyCLSID, //HKCR\CLSID\<clsid>\InprocServer32
- dwIndex, // which subkey
- wzSubKeyName, // subkey name
- &cwSubKeySize, // size of subkey name
- NULL, // lpReserved
- NULL, // lpClass
- NULL, // lpcbClass
- NULL)); // lpftLastWriteTime
-
- hr = avCurrent.Init(wzSubKeyName, FALSE);
- if (FAILED(hr))
- {
- // not valid version subkey, ignore
- continue;
- }
- wcscpy_s(wzCurrent, COUNTOF(wzCurrent), wzSubKeyName);
-
- IfFailWin32Go(WszRegOpenKeyEx(
- hKeyCLSID,
- wzSubKeyName,
- 0,
- accessFlags,
- &hSubKey));
-
- // Check if this is a non-interop scenario
- lResult = WszRegQueryValueEx(
- hSubKey,
- SBSVERSIONVALUE,
- NULL,
- &type,
- NULL,
- &size);
- if (lResult == ERROR_SUCCESS)
- {
- *pbIsUnmanagedObject = TRUE;
- }
- // This is an interop assembly
- else
- {
- lResult = WszRegQueryValueEx(
- hSubKey,
- W("Assembly"),
- NULL,
- &type,
- NULL,
- &size);
- if (!((lResult == ERROR_SUCCESS)&&(type == REG_SZ)&&(size > 0)))
- {
- // do not have value "Assembly"
- RegCloseKey(hSubKey);
- hSubKey = NULL;
- continue;
- }
-
- lResult = WszRegQueryValueEx(
- hSubKey,
- W("Class"),
- NULL,
- &type,
- NULL,
- &size);
- if (!((lResult == ERROR_SUCCESS)&&(type == REG_SZ)&&(size > 0)))
- {
- // do not have value "Class"
- RegCloseKey(hSubKey);
- hSubKey = NULL;
- continue;
- }
-
- lResult = WszRegQueryValueEx(
- hSubKey,
- W("RuntimeVersion"),
- NULL,
- &type,
- NULL,
- &size);
- if (!((lResult == ERROR_SUCCESS)&&(type == REG_SZ)&&(size > 0)))
- {
- // We didn't find a RuntimeVersion value. This is fine for Records since
- // in V1.1, Records didn't have a RuntimeVersion value. However if we aren't
- // dealing with a Record, then this version subkey is invalid.
- if (basePath != RegistryBasePath_Record)
- {
- // do not have value "RuntimeVersion"
- RegCloseKey(hSubKey);
- hSubKey = NULL;
- continue;
- }
- }
- else
- {
- // If a highest allowed runtime version was specified, make sure that the component
- // was built with a runtime version lower or equal to the highest.
- if (prvHighestAllowed)
- {
- NewArrayHolder<WCHAR> wzRuntimeVersionString =
- new (nothrow) WCHAR[(size/sizeof(WCHAR)) + 1];
- IfNullGo(wzRuntimeVersionString);
- // RegQueryValueEx() does not guarantee NULL-terminated strings
- wzRuntimeVersionString[size/sizeof(WCHAR)] = W('\0');
- IfFailWin32Go(WszRegQueryValueEx(
- hSubKey,
- W("RuntimeVersion"),
- NULL,
- &type,
- (LPBYTE)(WCHAR*)wzRuntimeVersionString,
- &size));
-
- AssemblyVersion rvCurrent;
- rvCurrent.Init(wzRuntimeVersionString, TRUE);
-
- // We only care about major and minor version number.
- rvCurrent.SetBuild(0);
- rvCurrent.SetRevision(0);
-
- if ((*prvHighestAllowed) < rvCurrent)
- {
- // This version of the component was built with a runtime version higher
- // than maximum allowed one so we don't want to consider it.
- RegCloseKey(hSubKey);
- hSubKey = NULL;
- continue;
- }
- }
- }
- }
-
- // ok. Now I believe this is a valid subkey
- RegCloseKey(hSubKey);
- hSubKey = NULL;
-
- if (bGotVersion)
- {
- if (avCurrent >= avHighest)
- {
- avHighest = avCurrent;
- wcscpy_s(wzHighest, COUNTOF(wzHighest), wzCurrent);
- }
- }
- else
- {
- avHighest = avCurrent;
- wcscpy_s(wzHighest, COUNTOF(wzHighest), wzCurrent);
- }
-
- bGotVersion = TRUE;
- }
-
-
- //
- // If there are no subkeys, then look at the top level key.
- //
-
- if (!bGotVersion)
- {
- // make sure value Class exists
- // If not dealing with record, also make sure RuntimeVersion exists.
- if ((WszRegQueryValueEx(hKeyCLSID, W("Class"), NULL, &type, NULL, &size) == ERROR_SUCCESS) && (type == REG_SZ) && (size > 0))
- {
- // If there is no RuntimeVersion value, we will assume the component was built against
- // the V1.0 CLR.
- BOOL bSupportedVersion = TRUE;
-
- lResult = WszRegQueryValueEx(
- hKeyCLSID,
- W("RuntimeVersion"),
- NULL,
- &type,
- NULL,
- &size);
- if ((lResult == ERROR_SUCCESS) && (type == REG_SZ) && (size > 0))
- {
- // If a highest allowed runtime version was specified, make sure that the component
- // was built with a runtime version lower or equal to the highest.
- if (prvHighestAllowed)
- {
- NewArrayHolder<WCHAR> wzRuntimeVersionString =
- new (nothrow) WCHAR[(size/sizeof(WCHAR)) + 1];
- IfNullGo(wzRuntimeVersionString);
- // RegQueryValueEx() does not guarantee NULL-terminated strings
- wzRuntimeVersionString[size/sizeof(WCHAR)] = W('\0');
- IfFailWin32Go(WszRegQueryValueEx(
- hKeyCLSID,
- W("RuntimeVersion"),
- NULL,
- &type,
- (LPBYTE)(WCHAR*)wzRuntimeVersionString,
- &size));
-
- AssemblyVersion rvCurrent;
- rvCurrent.Init(wzRuntimeVersionString, TRUE);
-
- // We only care about major and minor version number.
- rvCurrent.SetBuild(0);
- rvCurrent.SetRevision(0);
-
- if ((*prvHighestAllowed) < rvCurrent)
- {
- // This version of the component was built with a runtime version higher
- // than maximum allowed one so we don't want to consider it.
- bSupportedVersion = FALSE;
- }
- }
- }
-
- if (bSupportedVersion)
- {
- // Get the size of assembly display name
- lResult = WszRegQueryValueEx(
- hKeyCLSID,
- W("Assembly"),
- NULL,
- &type,
- NULL,
- &size);
-
- if ((lResult == ERROR_SUCCESS) && (type == REG_SZ) && (size > 0))
- {
- IfNullGo(wzAssemblyString = new (nothrow) WCHAR[size + 1]);
- IfFailWin32Go(WszRegQueryValueEx(
- hKeyCLSID,
- W("Assembly"),
- NULL,
- &type,
- (LPBYTE)wzAssemblyString,
- &size));
-
- // Now we have the assembly display name.
- // Extract the version out.
-
- // first lowercase display name
- _wcslwr_s(wzAssemblyString,size+1);
-
- // locate "version="
- LPWSTR pwzVersion = wcsstr(wzAssemblyString, W("version="));
- if (pwzVersion) {
- // point to the character after "version="
- pwzVersion += 8; // length of W("version=")
-
- // Now find the next W(',')
- LPWSTR pwzEnd = pwzVersion;
-
- while((*pwzEnd != W(',')) && (*pwzEnd != W('\0')))
- pwzEnd++;
-
- // terminate version string
- *pwzEnd = W('\0');
-
- // trim version string
- while(iswspace(*pwzVersion))
- pwzVersion++;
-
- pwzEnd--;
- while(iswspace(*pwzEnd)&&(pwzEnd > pwzVersion))
- {
- *pwzEnd = W('\0');
- pwzEnd--;
- }
-
- // Make sure the version is valid.
- if(SUCCEEDED(avHighest.Init(pwzVersion, FALSE)))
- {
- // This is the first version found, so it is the highest version
- wcscpy_s(wzHighest, COUNTOF(wzHighest), pwzVersion);
- bIsTopKey = TRUE;
- bGotVersion = TRUE;
- }
- }
- }
- }
- } // end of handling of key HKCR\CLSID\<clsid>\InprocServer32
- }
-
- if (bGotVersion)
- {
- // Now we have the highest version. Copy it out
- size_t cchHighest = wcslen(wzHighest) + 1;
- *ppwzHighestVersion = new (nothrow) WCHAR[cchHighest];
- wcscpy_s(*ppwzHighestVersion, cchHighest, wzHighest);
-
- *pbIsTopKey = bIsTopKey;
-
- // return S_OK to indicate we successfully found the highest version.
- hr = S_OK;
- }
- else
- {
- // return E_CLASSNOTREG to indicate that we didn't find anything
- hr = REGDB_E_CLASSNOTREG;
- }
-
-ErrExit:
- if (hKeyCLSID)
- RegCloseKey(hKeyCLSID);
- if (hSubKey)
- RegCloseKey(hSubKey);
- if (wzAssemblyString)
- delete[] wzAssemblyString;
-
- return hr;
-}
-
-// If the value exists and is retrieved successfully, returns S_OK
-// If the value does not exist, returns S_FALSE
-// If some other error occurs, returns error-specific HRESULT
-static
-HRESULT ReadRegistryStringValue(
- HKEYHolder &hKey,
- LPCWSTR wszName,
- __deref_out_z __deref_out_opt LPWSTR *pwszValue)
-{
- HRESULT hr = S_OK;
-
- _ASSERTE(pwszValue != NULL);
- *pwszValue = NULL;
-
- // extract the string value.
- DWORD dwSize;
- DWORD dwType;
- NewArrayHolder<WCHAR> wszValue(NULL);
- hr = HRESULT_FROM_WIN32(WszRegQueryValueEx(hKey, wszName, NULL, &dwType, NULL, &dwSize));
-
- // If the function succeeds, the return value is ERROR_SUCCESS.
- // If the wszName registry value does not exist, the function returns ERROR_FILE_NOT_FOUND.
- if (hr == HRESULT_FROM_WIN32(ERROR_SUCCESS))
- {
- // The value is not a string
- if (dwType != REG_SZ)
- return E_INVALIDARG;
-
- if(!ClrSafeInt<DWORD>::addition(dwSize, 1, dwSize))
- IfFailWin32Ret(ERROR_ARITHMETIC_OVERFLOW);
-
- IfNullRet(wszValue = new (nothrow) WCHAR[dwSize]);
- IfFailWin32Ret(WszRegQueryValueEx(hKey, wszName, NULL, NULL, (LPBYTE)static_cast<LPCWSTR>(wszValue), &dwSize));
- hr = S_OK;
- }
- else if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
- {
- return S_FALSE;
- }
-
- _ASSERTE(hr == S_OK);
- wszValue.SuppressRelease();
- *pwszValue = wszValue;
- return hr;
-}
-
-// FindRuntimeVersionFromRegistry
-//
-// Find the runtimeVersion corresponding to the highest version
-HRESULT FindRuntimeVersionFromRegistry(
- REFCLSID rclsid,
- __deref_out_z __deref_out_opt LPWSTR *ppwzRuntimeVersion,
- __deref_out_z __deref_out_opt LPWSTR *ppwzSupportedVersions)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
- HKEYHolder userKey;
- WCHAR szID[64];
- WCHAR keyname[256];
- DWORD size;
- DWORD type;
- NewArrayHolder<WCHAR> pwzVersion = NULL;
- BOOL bIsTopKey;
- BOOL bIsUnmanagedObject = FALSE;
- NewArrayHolder<WCHAR> pwzRuntimeVersion = NULL;
- NewArrayHolder<WCHAR> pwzSupportedRuntimeVersions = NULL;
-
- if (ppwzRuntimeVersion == NULL)
- IfFailRet(E_INVALIDARG);
-
- // Initialize the string passed in to NULL.
- *ppwzRuntimeVersion = NULL;
-
- if (ppwzSupportedVersions != NULL)
- *ppwzSupportedVersions = NULL;
-
- // Convert the GUID to its string representation.
- if (GuidToLPWSTR(rclsid, szID, NumItems(szID)) == 0)
- IfFailRet(E_INVALIDARG);
-
- // retrieve the highest version.
- IfFailRet(FindHighestVersion(rclsid, RegistryBasePath_CLSID_InprocServer32, NULL, &pwzVersion, &bIsTopKey, &bIsUnmanagedObject));
-
- if (!bIsUnmanagedObject)
- {
- // if highest version is in top key,
- // we will look at HKCR\CLSID\<clsid>\InprocServer32 or HKCR\Record\<RecordId>
- // Otherwise we will look at HKCR\CLSID\<clsid>\InprocServer32\<version> or HKCR\Record\<RecordId>\<Version>
- wcscpy_s(keyname, 256, W("CLSID\\"));
- wcscat_s(keyname, 256, szID);
- wcscat_s(keyname, 256, W("\\InprocServer32"));
- if (!bIsTopKey)
- {
- wcscat_s(keyname, 256, W("\\"));
- wcscat_s(keyname, 256, pwzVersion);
- }
-
- // open the registry key
- IfFailWin32Ret(WszRegOpenKeyEx(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &userKey));
-
- // extract the runtime version.
- IfFailRet(ReadRegistryStringValue(userKey, W("RuntimeVersion"), &pwzRuntimeVersion));
- if (hr == S_FALSE)
- {
- IfNullRet(pwzRuntimeVersion = DuplicateString(V1_VERSION_NUM));
- }
-
- // extract the supported runtime versions
- if (ppwzSupportedVersions != NULL)
- IfFailRet(ReadRegistryStringValue(userKey, W("SupportedRuntimeVersions"), &pwzSupportedRuntimeVersions));
- }
-
- else
- {
- // We need to prepend the 'v' to the version string
- IfNullRet(pwzRuntimeVersion = new (nothrow) WCHAR[wcslen(pwzVersion)+1+1]); // +1 for the v, +1 for the null
- *pwzRuntimeVersion = W('v');
- wcscpy_s(pwzRuntimeVersion+1, wcslen(pwzVersion)+1, pwzVersion);
- }
-
- _ASSERTE(SUCCEEDED(hr));
-
- // now we have the data, copy it out
- pwzRuntimeVersion.SuppressRelease();
- *ppwzRuntimeVersion = pwzRuntimeVersion;
-
- if (ppwzSupportedVersions != NULL)
- {
- pwzSupportedRuntimeVersions.SuppressRelease();
- *ppwzSupportedVersions = pwzSupportedRuntimeVersions;
- }
-
- return hr;
-}
-
-// FindShimInfoFromRegistry
-//
-HRESULT FindShimInfoFromRegistryWorker(
- REFCLSID rclsid,
- RegistryBasePath basePath,
- WORD wHighestRuntimeMajorVersion,
- WORD wHighestRuntimeMinorVersion,
- __deref_out_z LPWSTR *ppwzClassName,
- __deref_out_z LPWSTR *ppwzAssemblyString,
- __deref_out_z LPWSTR *ppwzCodeBase)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
- HKEY userKey = NULL;
- WCHAR szID[64];
- WCHAR keyname[256];
- DWORD size;
- DWORD type;
- LPWSTR pwzVersion = NULL;
- BOOL bIsTopKey;
- NewArrayHolder<WCHAR> wzClassName = NULL;
- NewArrayHolder<WCHAR> wzAssemblyString = NULL;
- NewArrayHolder<WCHAR> wzCodeBase = NULL;
- LONG lResult;
- AssemblyVersion highestRuntimeVersion;
-
- // at least one should be specified.
- // codebase is optional
- if ((ppwzClassName == NULL) && (ppwzAssemblyString == NULL))
- IfFailGo(E_INVALIDARG);
-
- // Initialize the strings passed in to NULL.
- if (ppwzClassName)
- *ppwzClassName = NULL;
- if (ppwzAssemblyString)
- *ppwzAssemblyString = NULL;
- if (ppwzCodeBase)
- *ppwzCodeBase = NULL;
-
- // Convert the GUID to its string representation.
- if (GuidToLPWSTR(rclsid, szID, NumItems(szID)) == 0)
- IfFailGo(E_INVALIDARG);
-
- // retrieve the highest version.
- BOOL bIsUnmanaged = FALSE;
-
- // Initialize the highest runtime version based on the passed in major and minor version numbers.
- highestRuntimeVersion.Init(wHighestRuntimeMajorVersion, wHighestRuntimeMinorVersion, 0, 0);
-
- IfFailGo(FindHighestVersion(rclsid, basePath, &highestRuntimeVersion, &pwzVersion, &bIsTopKey, &bIsUnmanaged));
-
- // if highest version is in top key,
- // we will look at HKCR\CLSID\<clsid>\{Inproc,Local}Server32 or HKCR\Record\<RecordId>
- // Otherwise we will look at HKCR\CLSID\<clsid>\{Inproc,Local}Server32\<version> or HKCR\Record\<RecordId>\<Version>
- if (basePath == RegistryBasePath_Record)
- {
- wcscpy_s(keyname, 256, W("Record\\"));
- wcscat_s(keyname, 256, szID);
- }
- else
- {
- wcscpy_s(keyname, 256, W("CLSID\\"));
- wcscat_s(keyname, 256, szID);
- if (basePath == RegistryBasePath_CLSID_InprocServer32)
- {
- wcscat_s(keyname, 256, W("\\InprocServer32"));
- }
- else
- {
- _ASSERTE(basePath == RegistryBasePath_CLSID_LocalServer32_32Key || basePath == RegistryBasePath_CLSID_LocalServer32_64Key);
- wcscat_s(keyname, 256, W("\\LocalServer32"));
- }
- }
- if (!bIsTopKey)
- {
- wcscat_s(keyname, 256, W("\\"));
- wcscat_s(keyname, 256, pwzVersion);
- }
-
- // open the registry
- REGSAM accessFlags = KEY_READ;
- if (basePath == RegistryBasePath_CLSID_LocalServer32_32Key)
- {
- // open the WoW key
- accessFlags |= KEY_WOW64_32KEY;
- }
- else if (basePath == RegistryBasePath_CLSID_LocalServer32_64Key)
- {
- // open the 64-bit key
- accessFlags |= KEY_WOW64_64KEY;
- }
-
- IfFailWin32Go(WszRegOpenKeyEx(HKEY_CLASSES_ROOT, keyname, 0, accessFlags, &userKey));
-
- // get the class name
- IfFailWin32Go(WszRegQueryValueEx(userKey, W("Class"), NULL, &type, NULL, &size));
- IfNullGo(wzClassName = new (nothrow) WCHAR[size + 1]);
- IfFailWin32Go(WszRegQueryValueEx(userKey, W("Class"), NULL, NULL, (LPBYTE)wzClassName.GetValue(), &size));
-
- // get the assembly string
- IfFailWin32Go(WszRegQueryValueEx(userKey, W("Assembly"), NULL, &type, NULL, &size));
- IfNullGo(wzAssemblyString = new (nothrow) WCHAR[size + 1]);
- IfFailWin32Go(WszRegQueryValueEx(userKey, W("Assembly"), NULL, NULL, (LPBYTE)wzAssemblyString.GetValue(), &size));
-
- // get the code base if requested
- if (ppwzCodeBase)
- {
- // get the codebase, however not finding it does not constitute
- // a fatal error.
- lResult = WszRegQueryValueEx(userKey, W("CodeBase"), NULL, &type, NULL, &size);
- if ((lResult == ERROR_SUCCESS) && (type == REG_SZ) && (size > 0))
- {
- IfNullGo(wzCodeBase = new (nothrow) WCHAR[size + 1]);
- IfFailWin32Go(WszRegQueryValueEx(userKey, W("CodeBase"), NULL, NULL, (LPBYTE)wzCodeBase.GetValue(), &size));
- }
- }
-
- // now we got everything. Copy them out
- if (ppwzClassName)
- *ppwzClassName = wzClassName.Extract();
-
- if (ppwzAssemblyString)
- *ppwzAssemblyString = wzAssemblyString.Extract();
-
- if (ppwzCodeBase)
- *ppwzCodeBase = wzCodeBase.Extract();
-
- hr = S_OK;
-
-ErrExit:
- if (userKey)
- RegCloseKey(userKey);
-
- if (pwzVersion)
- delete[] pwzVersion;
-
- return hr;
-}
-
-// Find shim info corresponding to the highest version
-HRESULT FindShimInfoFromRegistry(
- REFCLSID rclsid,
- BOOL bLoadRecord,
- WORD wHighestRuntimeMajorVersion,
- WORD wHighestRuntimeMinorVersion,
- __deref_out_z LPWSTR *ppwzClassName,
- __deref_out_z LPWSTR *ppwzAssemblyString,
- __deref_out_z LPWSTR *ppwzCodeBase)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- if (bLoadRecord)
- {
- return FindShimInfoFromRegistryWorker(rclsid,
- RegistryBasePath_Record,
- wHighestRuntimeMajorVersion,
- wHighestRuntimeMinorVersion,
- ppwzClassName,
- ppwzAssemblyString,
- ppwzCodeBase);
- }
-
- // try InprocServer32 first
- HRESULT hr = FindShimInfoFromRegistryWorker(rclsid,
- RegistryBasePath_CLSID_InprocServer32,
- wHighestRuntimeMajorVersion,
- wHighestRuntimeMinorVersion,
- ppwzClassName,
- ppwzAssemblyString,
- ppwzCodeBase);
-
- // if it fails try both 64-bit and WoW LocalServer32
- if (FAILED(hr))
- {
- // prefer the bitness of the process, use the other bitness as a fallback
- hr = FindShimInfoFromRegistryWorker(rclsid,
-#ifdef _WIN64
- RegistryBasePath_CLSID_LocalServer32_64Key,
-#else // _WIN64
- RegistryBasePath_CLSID_LocalServer32_32Key,
-#endif // _WIN64
- wHighestRuntimeMajorVersion,
- wHighestRuntimeMinorVersion,
- ppwzClassName,
- ppwzAssemblyString,
- ppwzCodeBase);
-
- if (FAILED(hr)
-#ifndef _WIN64
- && RunningInWow64()
-#endif // !_WIN64
- )
- {
- hr = FindShimInfoFromRegistryWorker(rclsid,
-#ifdef _WIN64
- RegistryBasePath_CLSID_LocalServer32_32Key,
-#else // _WIN64
- RegistryBasePath_CLSID_LocalServer32_64Key,
-#endif // _WIN64
- wHighestRuntimeMajorVersion,
- wHighestRuntimeMinorVersion,
- ppwzClassName,
- ppwzAssemblyString,
- ppwzCodeBase);
- }
- }
- return hr;
-}
-
-
-// ----------------------------------------------------------------------------------------------------------
-//
-// Gets config file name from Win32 manifest file. Strips the last extension (.manifest) from the manifest
-// file name. Doesn't strip the last extension if it is '.exe'.
-//
-// Note: Config file name could be already set in activation context by COM+ (out-of-process COM) - they
-// pick up CLR version information from registry.
-//
-// Arguments:
-// wszBuffer - [in, out] The buffer to fill the configuration file name (can be NULL)
-// cBuffer - [in] Size of the buffer in wide characters
-// pcNameSize - [out] Size of the name filled in the buffer (in wide characters including terminating null).
-// Can be NULL.
-//
-// Return value:
-// S_OK - Success. Buffer (wszBuffer) and config file name size (pcNameSize) are filled.
-// HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER) - Buffer is too small for filling config file name.
-// Sets pcNameSize (if not NULL) to the size of config file name including null terminator.
-//
-HRESULT GetConfigFileFromWin32Manifest(__out_ecount(cBuffer) WCHAR *wszBuffer,
- SIZE_T cBuffer,
- SIZE_T *pcNameSize)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
-
- HANDLE hActCtx = NULL;
- SIZE_T cbInfo = 0;
- SIZE_T cConfigFileName = 0;
-
- // Get detailed information about activation activation context
- if (!WszQueryActCtxW(0, // Flags
- hActCtx, // Activation context being queried
- NULL, // Specific to the information class
- ActivationContextDetailedInformation,
- // Information class - detailed information
- NULL, // [out] Buffer
- 0, // [in] Buffer size
- &cbInfo)) // [out] Written/required sized in buffer
- {
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- {
- CQuickBytes qbInfo;
- ACTIVATION_CONTEXT_DETAILED_INFORMATION *pInfo = NULL;
-
- pInfo = (ACTIVATION_CONTEXT_DETAILED_INFORMATION *)qbInfo.AllocNoThrow(cbInfo);
- IfNullGo(pInfo);
-
- if (WszQueryActCtxW(0, // Flags
- hActCtx, // Activation context being queried
- NULL, // Specific to the information class
- ActivationContextDetailedInformation,
- // Information class - detailed information
- pInfo, // [out] Buffer
- cbInfo, // [in] Buffer size
- &cbInfo) && // [out] Written size in the buffer
- pInfo->ulAppDirPathType == ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE)
- { // Application manifest was loaded from Win32 file (not an URL, AssemblyRef etc.)
- WCHAR *wszConfigFileName = NULL;
- CQuickWSTR qwszConfigFileName;
-
- if (pInfo->lpRootConfigurationPath != NULL)
- { // Configuration file name is provided, use it
- wszConfigFileName = (WCHAR *)pInfo->lpRootConfigurationPath;
- }
- else if (pInfo->lpRootManifestPath != NULL)
- { // Manifest file name is provided, use it
- SIZE_T cManifestFileName = wcslen(pInfo->lpRootManifestPath);
- if (cManifestFileName != 0)
- { // Manifest file does exist
- WCHAR wszConfigFileExtension[] = W(".config");
- SIZE_T cConfigFileExtension = sizeof(wszConfigFileExtension) / sizeof(WCHAR);
- // Allocate space for manifest file name + .config + terminating null
- // (included in .config extension)
- SIZE_T cConfigFileNameAllocated = cManifestFileName + cConfigFileExtension;
- wszConfigFileName = qwszConfigFileName.AllocNoThrow(cConfigFileNameAllocated);
- IfNullGo(wszConfigFileName);
- // Use manifest file name as the template for config file name
- wcscpy_s(wszConfigFileName, cConfigFileNameAllocated, pInfo->lpRootManifestPath);
-
- // Find the last extension in the manifest file name (or NULL if not found)
- LPWSTR wszLastExtension = wcsrchr(wszConfigFileName, W('.'));
- // Is the manifest file in an external separate file?
- if ((wszLastExtension != NULL) && (_wcsicmp(wszLastExtension, W(".exe")) != 0))
- { // It is an external manifest file (with .manifest or similar extension)
- // Excluded are files without an extension and with .exe extension (embeded
- // manifest in executable resources)
-
- // Strip the last extension in the manifest file name
- *wszLastExtension = 0;
- }
- // Manifest file name has stripped last extension (.manifest)
-
- // Append the .config extension behind the manifest file name
- wcscat_s(wszConfigFileName,
- cConfigFileNameAllocated,
- wszConfigFileExtension);
- }
- }
-
- // Do we have a configuration file name?
- if (wszConfigFileName != NULL)
- { // We have a configuration file name
- // Get the real configuration file name length (including terminating null)
- cConfigFileName = wcslen(wszConfigFileName) + 1;
- // Check the output buffer - is its size sufficient?
- if ((wszBuffer == NULL) || (cConfigFileName > cBuffer))
- { // Insufficient output buffer (too small or not passed)
- IfFailGo(HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
- }
- else
- { // Fill output buffer
- wcscpy_s(wszBuffer, cConfigFileName, wszConfigFileName);
- }
- }
- }
- }
- }
-
-ErrExit:
- // Should we return config file name size?
- if (pcNameSize != NULL)
- { // We should return name size
- // Return either copied size or potentially copied size
- *pcNameSize = cConfigFileName;
- }
- return hr;
-}
-
-HRESULT GetApplicationPathFromWin32Manifest(__out_ecount(dwBuffer) WCHAR* buffer, SIZE_T dwBuffer, SIZE_T* pSize)
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_FAULT;
-
- HRESULT hr = S_OK;
-
- // Get the basic activation context first.
- ACTIVATION_CONTEXT_DETAILED_INFORMATION* pInfo = NULL;
- SIZE_T length = 0;
-
- HANDLE hActCtx = NULL;
- SIZE_T nCount = 0;
-
- if (!WszQueryActCtxW(0, hActCtx, NULL, ActivationContextDetailedInformation,
- NULL, nCount, &nCount))
- {
-
- if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- {
-
- pInfo = (ACTIVATION_CONTEXT_DETAILED_INFORMATION*) alloca(nCount);
-
- if (WszQueryActCtxW(0, hActCtx, NULL, ActivationContextDetailedInformation,
- pInfo, nCount, &nCount) &&
- pInfo->ulAppDirPathType == ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE)
- {
-
- if(pInfo->lpAppDirPath) {
- length = wcslen(pInfo->lpAppDirPath) + 1;
- if(length > dwBuffer || buffer == NULL) {
- hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
- }
- else {
- wcscpy_s(buffer, dwBuffer, pInfo->lpAppDirPath);
- }
- }
-
- }
- }
- }
- if(pSize) *pSize = length;
- return hr;
-}
diff --git a/src/utilcode/tls.cpp b/src/utilcode/tls.cpp
deleted file mode 100644
index cb6934fd0b..0000000000
--- a/src/utilcode/tls.cpp
+++ /dev/null
@@ -1,271 +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.
-/* TLS.CPP:
- *
-
- *
- * Encapsulates TLS access for maximum performance.
- *
- */
-
-#include "stdafx.h"
-
-#include "unsafe.h"
-#include "tls.h"
-#include "contract.h"
-#include "corerror.h"
-#include "ex.h"
-#include "clrhost.h"
-
-#ifndef SELF_NO_HOST
-#include "clrconfig.h"
-#endif
-
-#include "clrnt.h"
-
-#ifndef SELF_NO_HOST
-
-//---------------------------------------------------------------------------
-// Win95 and WinNT store the TLS in different places relative to the
-// fs:[0]. This api reveals which. Can also return TLSACCESS_GENERIC if
-// no info is available about the Thread location (you have to use the TlsGetValue
-// api.) This is intended for use by stub generators that want to inline TLS
-// access.
-//---------------------------------------------------------------------------
-TLSACCESSMODE GetTLSAccessMode(DWORD tlsIndex)
-{
- // Static contracts because this is used by contract infrastructure
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- TLSACCESSMODE tlsAccessMode = TLSACCESS_GENERIC;
-
-#ifdef _DEBUG
- // Debug builds allow user to throw a switch to force use of the generic
- // (non-optimized) Thread/AppDomain getters. Even if the user doesn't throw
- // the switch, force tests to go down the generic getter code path about 1% of the
- // time so it's exercised a couple dozen times during each devbvt run.
- if ((CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_UseGenericTlsGetters) != 0) || DbgRandomOnExe(.01))
- return TLSACCESS_GENERIC;
-#endif
-
- if (tlsIndex < TLS_MINIMUM_AVAILABLE)
- {
- tlsAccessMode = TLSACCESS_WNT;
- }
- else
- if (tlsIndex < (TLS_MINIMUM_AVAILABLE + TLS_EXPANSION_SLOTS))
- {
- // Expansion slots are lazily created at the first call to
- // TlsGetValue on a thread, and the code we generate
- // assumes that the expansion slots will exist.
- //
- // <TODO> On newer flavors of NT we could use the vectored
- // exception handler to take the AV, call TlsGetValue, and
- // resume execution at the start of the getter. </TODO>
- tlsAccessMode = TLSACCESS_GENERIC;//TLSACCESS_WNT_HIGH;
- }
- else
- {
- //
- // If the app verifier is enabled, TLS indices
- // are faked to help detect invalid handle use.
- //
- }
-
- return tlsAccessMode;
-}
-
-//---------------------------------------------------------------------------
-// Creates a platform-optimized version of TlsGetValue compiled
-// for a particular index. Can return NULL.
-//---------------------------------------------------------------------------
-// A target for the optimized getter can be passed in, this is
-// useful so that code can avoid an indirect call for the GetThread
-// and GetAppDomain calls for instance. If NULL is passed then
-// we will allocate from the executeable heap.
-POPTIMIZEDTLSGETTER MakeOptimizedTlsGetter(DWORD tlsIndex, LPVOID pBuffer, SIZE_T cbBuffer, POPTIMIZEDTLSGETTER pGenericImpl, BOOL fForceGeneric)
-{
- // Static contracts because this is used by contract infrastructure
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- ARM_ONLY(pBuffer = ThumbCodeToDataPointer<BYTE*>(pBuffer));
-
- // Buffer that should be big enough to encode the TLS getter on any reasonable platform
- TADDR patch[4 INDEBUG(+4 /* last error trashing */)];
-
- PBYTE pPatch = (PBYTE)&patch;
-
- TLSACCESSMODE mode = fForceGeneric ? TLSACCESS_GENERIC : GetTLSAccessMode(tlsIndex);
-
-#if defined(_DEBUG)
- if (mode != TLSACCESS_GENERIC)
- {
- //
- // Trash last error in debug builds
- //
-
-#ifdef _TARGET_X86_
- *((DWORD*) (pPatch + 0)) = 0x05c764; // mov dword ptr fs:[offsetof(TEB, LastErrorValue)], LAST_ERROR_TRASH_VALUE
- *((DWORD*) (pPatch + 3)) = offsetof(TEB, LastErrorValue);
- *((DWORD*) (pPatch + 7)) = LAST_ERROR_TRASH_VALUE;
- pPatch += 11;
-#endif // _TARGET_X86_
-
-#ifdef _TARGET_AMD64_
- // iDNA doesn't like writing directly to gs:[nn]
- *((UINT64*)(pPatch + 0)) = 0x25048b4865; // mov rax, gs:[offsetof(TEB, NtTib.Self)]
- *((DWORD*) (pPatch + 5)) = offsetof(TEB, NtTib.Self);
- *((WORD*) (pPatch + 9)) = 0x80c7; // mov dword ptr [rax + offsetof(TEB, LastErrorValue)], LAST_ERROR_TRASH_VALUE
- *((DWORD*) (pPatch + 11)) = offsetof(TEB, LastErrorValue);
- *((DWORD*) (pPatch + 15)) = LAST_ERROR_TRASH_VALUE;
- pPatch += 19;
-#endif
- }
-#endif // _DEBUG
-
- switch (mode)
- {
-#ifdef _TARGET_X86_
- case TLSACCESS_WNT:
- *((WORD*) (pPatch + 0)) = 0xa164; // mov eax, fs:[IMM32]
- *((DWORD*) (pPatch + 2)) = offsetof(TEB, TlsSlots) + tlsIndex * sizeof(void*);
- *((BYTE*) (pPatch + 6)) = 0xc3; // retn
- pPatch += 7;
- break;
-
- case TLSACCESS_GENERIC:
- if (pGenericImpl == NULL)
- return NULL;
-
- _ASSERTE(pBuffer != NULL);
- *((BYTE*) (pPatch + 0)) = 0xE9; // jmp pGenericImpl
- TADDR rel32 = ((TADDR)pGenericImpl - ((TADDR)pBuffer + 1 + sizeof(INT32)));
- *((INT32*) (pPatch + 1)) = (INT32)rel32;
- pPatch += 5;
- break;
-#endif // _TARGET_X86_
-
-#ifdef _TARGET_AMD64_
- case TLSACCESS_WNT:
- *((UINT64*)(pPatch + 0)) = 0x25048b4865; // mov rax, gs:[IMM32]
- *((DWORD*) (pPatch + 5)) = offsetof(TEB, TlsSlots) + (tlsIndex * sizeof(void*));
- *((BYTE*) (pPatch + 9)) = 0xc3; // return
- pPatch += 10;
- break;
-
- case TLSACCESS_GENERIC:
- if (pGenericImpl == NULL)
- return NULL;
-
- _ASSERTE(pBuffer != NULL);
- *((BYTE*) (pPatch + 0)) = 0xE9; // jmp pGenericImpl
- TADDR rel32 = ((TADDR)pGenericImpl - ((TADDR)pBuffer + 1 + sizeof(INT32)));
- _ASSERTE((INT64)(INT32)rel32 == (INT64)rel32);
- *((INT32*) (pPatch + 1)) = (INT32)rel32;
- pPatch += 5;
-
- *pPatch++ = 0xCC; // Make sure there is full 8 bytes worth of data
- *pPatch++ = 0xCC;
- *pPatch++ = 0xCC;
- break;
-
-#endif // _TARGET_AMD64_
-
-#ifdef _TARGET_ARM_
- case TLSACCESS_WNT:
- {
- WORD slotOffset = (WORD)(offsetof(TEB, TlsSlots) + tlsIndex * sizeof(void*));
- _ASSERTE(slotOffset < 4096);
-
- WORD *pInstr = (WORD*)pPatch;
-
- *pInstr++ = 0xee1d; // mrc p15, 0, r0, c13, c0, 2
- *pInstr++ = 0x0f50;
- *pInstr++ = 0xf8d0; // ldr r0, [r0, #slotOffset]
- *pInstr++ = slotOffset;
- *pInstr++ = 0x4770; // bx lr
-
- pPatch = (PBYTE)pInstr;
- }
- break;
-
- case TLSACCESS_GENERIC:
- {
- if (pGenericImpl == NULL)
- return NULL;
-
- _ASSERTE(pBuffer != NULL);
-
- *(DWORD *)pPatch = 0x9000F000; // b pGenericImpl
- PutThumb2BlRel24((WORD*)pPatch, (TADDR)pGenericImpl - ((TADDR)pBuffer + 4 + THUMB_CODE));
-
- pPatch += 4;
- }
- break;
-#endif // _TARGET_ARM_
- }
-
- SIZE_T cbCode = (TADDR)pPatch - (TADDR)&patch;
- _ASSERTE(cbCode <= sizeof(patch));
-
- if (pBuffer != NULL)
- {
- _ASSERTE_ALL_BUILDS("clr/src/utilcode/tls.cpp", cbCode <= cbBuffer);
-
- // We assume that the first instruction of the buffer is a short jump to dummy helper
- // that can be atomically overwritten to avoid races with other threads executing the code.
- // It is the same basic technique as hot patching.
-
- // Assert on all builds to make sure that retail optimizations are not affecting the alignment.
- _ASSERTE_ALL_BUILDS("clr/src/utilcode/tls.cpp", IS_ALIGNED((void*)pBuffer, sizeof(TADDR)));
-
- // Size of short jump that gets patched last.
- if (cbCode > sizeof(TADDR))
- {
- memcpy((BYTE *)pBuffer + sizeof(TADDR), &patch[1], cbCode - sizeof(TADDR));
- FlushInstructionCache(GetCurrentProcess(), (BYTE *)pBuffer + sizeof(TADDR), cbCode - sizeof(TADDR));
- }
-
- // Make sure that the the dummy implementation still works.
- _ASSERTE(((POPTIMIZEDTLSGETTER)ARM_ONLY(DataPointerToThumbCode<BYTE*>)(pBuffer))() == NULL);
-
- // It is important for this write to happen atomically
- VolatileStore<TADDR>((TADDR *)pBuffer, patch[0]);
-
- FlushInstructionCache(GetCurrentProcess(), (BYTE *)pBuffer, sizeof(TADDR));
- }
- else
- {
- pBuffer = (BYTE*) new (executable, nothrow) BYTE[cbCode];
- if (pBuffer == NULL)
- return NULL;
-
- memcpy(pBuffer, &patch, cbCode);
-
- FlushInstructionCache(GetCurrentProcess(), pBuffer, cbCode);
- }
-
- return (POPTIMIZEDTLSGETTER)ARM_ONLY(DataPointerToThumbCode<BYTE*>)(pBuffer);
-}
-
-
-//---------------------------------------------------------------------------
-// Frees a function created by MakeOptimizedTlsGetter().
-//---------------------------------------------------------------------------
-VOID FreeOptimizedTlsGetter(POPTIMIZEDTLSGETTER pOptimizedTlsGetter)
-{
- // Static contracts because this is used by contract infrastructure
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- BYTE* pGetter = (BYTE*)pOptimizedTlsGetter;
-#ifdef _TARGET_ARM_
- pGetter = ThumbCodeToDataPointer<BYTE*>(pGetter);
-#endif
- DeleteExecutable(pGetter);
-}
-
-#endif // !SELF_NO_HOST
diff --git a/src/utilcode/util.cpp b/src/utilcode/util.cpp
index 8b2ee6f8ca..97b90ed06f 100644
--- a/src/utilcode/util.cpp
+++ b/src/utilcode/util.cpp
@@ -3035,348 +3035,7 @@ LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs)
Volatile<PVOID> ForbidCallsIntoHostOnThisThread::s_pvOwningFiber = NULL;
-#ifdef ENABLE_CONTRACTS_IMPL
-
-enum SOViolationType {
- SO_Violation_Intolerant = 0,
- SO_Violation_NotMainline = 1,
- SO_Violation_Backout = 2,
-};
-
-struct HashedSOViolations {
- ULONG m_hash;
- HashedSOViolations* m_pNext;
- HashedSOViolations(ULONG hash, HashedSOViolations *pNext) : m_hash(hash), m_pNext(pNext) {}
-};
-
-static HashedSOViolations *s_pHashedSOViolations = NULL;
-
-void SOViolation(const char *szFunction, const char *szFile, int lineNum, SOViolationType violation);
-
-
-//
-// SOTolerantViolation is used to report an SO-intolerant function that is not running behind a probe.
-//
-void SOTolerantViolation(const char *szFunction, const char *szFile, int lineNum)
-{
- return SOViolation(szFunction, szFile, lineNum, SO_Violation_Intolerant);
-}
-
-//
-// SONotMainlineViolation is used to report any code with SO_NOT_MAINLINE being run in a test environment
-// with COMPlus_NO_SO_NOT_MAINLINE enabled
-//
-void SONotMainlineViolation(const char *szFunction, const char *szFile, int lineNum)
-{
- return SOViolation(szFunction, szFile, lineNum, SO_Violation_NotMainline);
-}
-
-//
-// SONotMainlineViolation is used to report any code with SO_NOT_MAINLINE being run in a test environment
-// with COMPlus_NO_SO_NOT_MAINLINE enabled
-//
-void SOBackoutViolation(const char *szFunction, const char *szFile, int lineNum)
-{
- return SOViolation(szFunction, szFile, lineNum, SO_Violation_Backout);
-}
-
-//
-// Code common to SO violations
-//
-// The default is to throw up an ASSERT. But the function can also dump violations to a file and
-// ensure that only unique violations are tracked.
-//
-void SOViolation(const char *szFunction, const char *szFile, int lineNum, SOViolationType violationType)
-{
- // This function is called from places that don't allow a throw. But this is debug-only
- // code that should eventually never be called once all the violations are gone.
- CONTRACT_VIOLATION(ThrowsViolation|FaultViolation|TakesLockViolation);
-
- static BOOL fDumpToFileInitialized = FALSE;
- static BOOL fDumpToFile = FALSE;
-
-#pragma warning(disable:4640) // Suppress warning: construction of local static object is not thread-safe
- static SString hashFN;
- static SString fnameFN;
- static SString detailsFN;
-#pragma warning(default:4640)
-
- static int dumpLock = -1;
-
- static CHAR szExprWithStack[10480];
- static DWORD stackTraceLength = 20;
-
- if (fDumpToFileInitialized == FALSE)
- {
- stackTraceLength = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SODumpViolationsStackTraceLength, stackTraceLength);
- // Limit the length or we'll overflow our buffer
- if (stackTraceLength > cfrMaxAssertStackLevels)
- {
- stackTraceLength = cfrMaxAssertStackLevels;
- }
- NewArrayHolder<WCHAR> dumpDir(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SODumpViolationsDir));
- if (dumpDir == NULL)
- {
- fDumpToFileInitialized = TRUE;
- }
- else
- {
- fDumpToFile = TRUE;
- hashFN.Append(SString(dumpDir.GetValue()));
- hashFN.Append(W("\\SOViolationHashes.txt"));
- fnameFN.Append(SString(dumpDir.GetValue()));
- fnameFN.Append(W("\\SOViolationFunctionNames.txt"));
- detailsFN.Append(SString(dumpDir.GetValue()));
- detailsFN.Append(W("\\SOViolationDetails.txt"));
- }
- }
-
- char buff[1024];
-
- if (violationType == SO_Violation_NotMainline)
- {
- sprintf_s(buff,
- _countof(buff),
- "CONTRACT VIOLATION by %s at \"%s\" @ %d\n\n"
- "SO-not-mainline function being called with not-mainline checking enabled.\n"
- "\nPlease open a bug against the feature owner.\n"
- "\nNOTE: You can disable this ASSERT by setting COMPlus_SOEnableDefaultRWValidation=0.\n"
- " or by turning of not-mainline checking by by setting COMPlus_NO_SO_NOT_MAINLINE=0.\n"
- "\nFor details about this feature, see, in a CLR enlistment,\n"
- "src\\ndp\\clr\\doc\\OtherDevDocs\\untriaged\\clrdev_web\\SO Guide for CLR Developers.doc\n",
- szFunction, szFile, lineNum);
- }
- else if (violationType == SO_Violation_Backout)
- {
- sprintf_s(buff,
- _countof(buff),
- "SO Backout Marker overrun.\n\n"
- "A dtor or handler path exceeded the backout code stack consumption limit.\n"
- "\nPlease open a bug against the feature owner.\n"
- "\nNOTE: You can disable this ASSERT by setting COMPlus_SOEnableBackoutStackValidation=0.\n"
- "\nFor details about this feature, see, in a CLR enlistment,\n"
- "src\\ndp\\clr\\doc\\OtherDevDocs\\untriaged\\clrdev_web\\SO Guide for CLR Developers.doc\n");
- }
- else
- {
- sprintf_s(buff,
- _countof(buff),
- "CONTRACT VIOLATION by %s at \"%s\" @ %d\n\n"
- "SO-intolerant function called outside an SO probe.\n"
- "\nPlease open a bug against the feature owner.\n"
- "\nNOTE: You can disable this ASSERT by setting COMPlus_SOEnableDefaultRWValidation=0.\n"
- "\nFor details about this feature, see, in a CLR enlistment,\n"
- "src\\ndp\\clr\\doc\\OtherDevDocs\\untriaged\\clrdev_web\\SO Guide for CLR Developers.doc\n",
- szFunction, szFile, lineNum);
- }
-
- // At this point, we've checked if we should dump to file or not and so can either
- // do the assert or fall through and dump to a file.
- if (! fDumpToFile)
- {
- DbgAssertDialog((char *)szFile, lineNum, buff);
- return;
- }
-
- // If we are dumping violations to a file, we want to avoid duplicates so that we can run multiple tests
- // and find unique violations and not end up with massively long files.
- // We keep three files:
- // 1) a list of the hashed strings for each unique filename/function
- // 2) a list of the actual filename/function for unique violations and
- // 3) a detailed assert dump for the violation itself
- //
- // First thing to do is read in the hashes file if this is our first violation. We read the filenames into a linked
- // list with their hashes.
- //
- // Then we want to search through the list for that violation
-
- // If it's new, then we insert the violation at the front of our list and append it to the violation files
- // Otherwise, if we've already seen this violation, we can ignore it.
-
-
- HANDLE hashesDumpFileHandle = INVALID_HANDLE_VALUE;
-
- StackScratchBuffer buffer;
- // First see if we've initialized yet
- if (fDumpToFileInitialized == FALSE)
- {
- LONG lAlreadyOwned = InterlockedExchange((LPLONG)&dumpLock, 1);
- if (lAlreadyOwned == 1)
- {
- // somebody else has gotten here first. So just skip this violation.
- return;
- }
-
- // This is our first time through, so read in the existing file and create a linked list of hashed names from it.
- hashesDumpFileHandle = CreateFileA(
- hashFN.GetANSI(buffer),
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH,
- NULL);
-
- // If we successfully opened the file, pull out each hash number and add it to a linked list of known violations.
- // Otherwise, if we couldn't open the file, assume that there were no preexisting violations. The worse thing
- // that will happen in this case is that we might report some dups.
- if (hashesDumpFileHandle != INVALID_HANDLE_VALUE)
- {
- DWORD dwFileSize = GetFileSize( hashesDumpFileHandle, NULL );
-
- NewArrayHolder<char> pBuffer(new char[dwFileSize]);
- DWORD cbBuffer = dwFileSize;
- DWORD cbRead;
- DWORD result = ReadFile( hashesDumpFileHandle, pBuffer.GetValue(), cbBuffer, &cbRead, NULL );
-
- CloseHandle( hashesDumpFileHandle );
- hashesDumpFileHandle = INVALID_HANDLE_VALUE;
-
- // If we couldn't read the file, assume that there were no preexisting violations. Worse thing
- // that will happen is we might report some dups.
- if (result && cbRead == cbBuffer)
- {
- char *pBuf = pBuffer.GetValue();
- COUNT_T count = 0;
- LOG((LF_EH, LL_INFO100000, "SOTolerantViolation: Reading known violations\n"));
- while (count < cbRead)
- {
- char *pHashStart = pBuf + count;
- char *pHashEnd = strstr(pHashStart, "\r\n");
- COUNT_T len = static_cast<COUNT_T>(pHashEnd-pHashStart);
- SString hashString(SString::Ascii, pHashStart, len);
- ULONG hashValue = wcstoul(hashString.GetUnicode(), NULL, 16);
- HashedSOViolations *pHashedSOViolations = new HashedSOViolations(hashValue, s_pHashedSOViolations);
- s_pHashedSOViolations = pHashedSOViolations;
- count += (len + 2);
- LOG((LF_ALWAYS, LL_ALWAYS, " %8.8x\n", pHashedSOViolations->m_hash));
- }
- }
- }
- fDumpToFileInitialized = TRUE;
- dumpLock = -1;
- }
-
-
- SString violation;
- violation.Append(SString(SString::Ascii, szFile));
- violation.Append(W(" "));
- violation.Append(SString(SString::Ascii, szFunction));
- HashedSOViolations *cur = s_pHashedSOViolations;
-
- // look for the violation in the list
- while (cur != NULL)
- {
- if (cur->m_hash == violation.Hash())
- {
- return;
- }
- cur = cur->m_pNext;
- }
-
- LONG lAlreadyOwned = InterlockedExchange((LPLONG)&dumpLock, 1);
- if (lAlreadyOwned == 1)
- {
- // somebody else has gotten here first. So just skip this violation.
- return;
- }
-
- HANDLE functionsDumpFileHandle = INVALID_HANDLE_VALUE;
- HANDLE detailsDumpFileHandle = INVALID_HANDLE_VALUE;
-
- // This is a new violation
- // Append new violations to the output files
- functionsDumpFileHandle = CreateFileA(
- fnameFN.GetANSI(buffer), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, NULL);
-
- if (functionsDumpFileHandle != INVALID_HANDLE_VALUE)
- {
- // First write it to the filename dump
- SetFilePointer(functionsDumpFileHandle, NULL, NULL, FILE_END);
-
- DWORD written;
- char *szExpr = &szExprWithStack[0];
- sprintf_s(szExpr, _countof(szExprWithStack), "%s %8.8x\r\n", violation.GetANSI(buffer), violation.Hash());
- WriteFile(functionsDumpFileHandle, szExpr, static_cast<DWORD>(strlen(szExpr)), &written, NULL);
- CloseHandle(functionsDumpFileHandle);
-
- // Now write it to the hashes dump. Once we've got it in the filename dump, we don't
- // care if these others fail. We can live w/o detailed info or with dups.
- hashesDumpFileHandle = CreateFileA(
- hashFN.GetANSI(buffer), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, NULL);
-
- if (hashesDumpFileHandle != INVALID_HANDLE_VALUE)
- {
- SetFilePointer(hashesDumpFileHandle, NULL, NULL, FILE_END);
-
- DWORD written;
- sprintf_s(szExpr, _countof(szExprWithStack), "%8.8x", violation.Hash());
- strcat_s(szExpr, _countof(szExprWithStack), "\r\n");
- WriteFile(hashesDumpFileHandle, szExpr, static_cast<DWORD>(strlen(szExpr)), &written, NULL);
- CloseHandle(hashesDumpFileHandle);
- hashesDumpFileHandle = INVALID_HANDLE_VALUE;
- }
-
- // Now write it to the details dump
- strcpy_s(szExpr, _countof(szExprWithStack), buff);
- strcat_s(szExpr, _countof(szExprWithStack), "\n\n");
-#ifndef FEATURE_PAL
- GetStringFromStackLevels(1, stackTraceLength, szExprWithStack + strlen(szExprWithStack));
- strcat_s(szExpr, _countof(szExprWithStack), "\n\n");
-#endif // FEATURE_PAL
- char exeName[300];
- GetModuleFileNameA(NULL, exeName, sizeof(exeName)/sizeof(WCHAR));
- strcat_s(szExpr, _countof(szExprWithStack), exeName);
- strcat_s(szExpr, _countof(szExprWithStack), "\n\n\n");
-
- detailsDumpFileHandle = CreateFileA(
- detailsFN.GetANSI(buffer), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_WRITE_THROUGH, NULL);
-
- if (detailsDumpFileHandle != INVALID_HANDLE_VALUE)
- {
- SetFilePointer(detailsDumpFileHandle, NULL, NULL, FILE_END);
- WriteFile(detailsDumpFileHandle, szExpr, static_cast<DWORD>(strlen(szExpr)), &written, NULL);
- CloseHandle(detailsDumpFileHandle);
- detailsDumpFileHandle = INVALID_HANDLE_VALUE;
- }
-
- // add the new violation to our list
- HashedSOViolations *pHashedSOViolations = new HashedSOViolations(violation.Hash(), s_pHashedSOViolations);
- s_pHashedSOViolations = pHashedSOViolations;
- LOG((LF_ALWAYS, LL_ALWAYS, "SOTolerantViolation: Adding new violation %8.8x %s\n", pHashedSOViolations->m_hash, violation.GetANSI(buffer)));
- dumpLock = -1;
- }
-}
-
-void SoTolerantViolationHelper(const char *szFunction,
- const char *szFile,
- int lineNum)
-{
- // Keep this function separate to avoid overhead of EH in the normal case where we don't assert
- // Enter SO-tolerant mode for scope of this call so that we don't get contract asserts
- // in anything called downstream of CONTRACT_ASSERT. If we unwind out of here, our dtor
- // will reset our state to what it was on entry.
- CONTRACT_VIOLATION(SOToleranceViolation);
-
- SOTolerantViolation(szFunction, szFile, lineNum);
-
-}
-
-void CloseSOTolerantViolationFile()
-{
- // We used to have a file to close. Now we just cleanup the memory.
- HashedSOViolations *ptr = s_pHashedSOViolations;
- while (ptr != NULL)
- {
- s_pHashedSOViolations = s_pHashedSOViolations->m_pNext;
- delete ptr;
- ptr = s_pHashedSOViolations;
- }
-}
-#endif //ENABLE_CONTRACTS_IMPL
+//======================================================================
BOOL FileExists(LPCWSTR filename)
{
@@ -3392,7 +3051,6 @@ BOOL FileExists(LPCWSTR filename)
return TRUE;
}
-
//======================================================================
// This function returns true, if it can determine that the instruction pointer
// refers to a code address that belongs in the range of the given image.
diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt
index f8790cf85d..aefc77113c 100644
--- a/src/vm/CMakeLists.txt
+++ b/src/vm/CMakeLists.txt
@@ -10,15 +10,11 @@ add_definitions(-D_UNICODE)
if(CMAKE_CONFIGURATION_TYPES) # multi-configuration generator?
foreach (Config DEBUG CHECKED)
- if(NOT FEATURE_STANDALONE_GC_ONLY)
- set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:${Config}>:WRITE_BARRIER_CHECK=1>)
- endif(NOT FEATURE_STANDALONE_GC_ONLY)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:${Config}>:WRITE_BARRIER_CHECK=1>)
endforeach (Config)
else()
if(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
- if(NOT FEATURE_STANDALONE_GC_ONLY)
- add_definitions(-DWRITE_BARRIER_CHECK=1)
- endif(NOT FEATURE_STANDALONE_GC_ONLY)
+ add_definitions(-DWRITE_BARRIER_CHECK=1)
endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED)
endif(CMAKE_CONFIGURATION_TYPES)
@@ -120,6 +116,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
versionresilienthashcode.cpp
virtualcallstub.cpp
win32threadpool.cpp
+ yieldprocessornormalized.cpp
zapsig.cpp
)
@@ -200,6 +197,7 @@ set(VM_SOURCES_WKS
gccover.cpp
gcenv.ee.static.cpp
gcenv.ee.common.cpp
+ gcenv.os.cpp
gchelpers.cpp
genmeth.cpp
hosting.cpp
@@ -270,6 +268,7 @@ set(GC_SOURCES_WKS
../gc/gchandletable.cpp
../gc/gceesvr.cpp
../gc/gceewks.cpp
+ ../gc/gcload.cpp
../gc/softwarewritewatch.cpp
../gc/handletablecache.cpp)
@@ -285,12 +284,6 @@ if(FEATURE_STANDALONE_GC)
)
endif(FEATURE_STANDALONE_GC)
-if(NOT FEATURE_STANDALONE_GC)
- list(APPEND VM_SOURCES_WKS
- gcenv.os.cpp
- )
-endif(NOT FEATURE_STANDALONE_GC)
-
if(WIN32)
set(VM_SOURCES_DAC_AND_WKS_WIN32
@@ -351,7 +344,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/InstantiatingStub.asm
${ARCH_SOURCES_DIR}/JitHelpers_Fast.asm
${ARCH_SOURCES_DIR}/JitHelpers_FastWriteBarriers.asm
- ${ARCH_SOURCES_DIR}/JitHelpers_InlineGetAppDomain.asm
${ARCH_SOURCES_DIR}/JitHelpers_InlineGetThread.asm
${ARCH_SOURCES_DIR}/JitHelpers_SingleAppDomain.asm
${ARCH_SOURCES_DIR}/JitHelpers_Slow.asm
@@ -359,7 +351,6 @@ if(CLR_CMAKE_TARGET_ARCH_AMD64)
${ARCH_SOURCES_DIR}/RedirectedHandledJITCase.asm
${ARCH_SOURCES_DIR}/ThePreStubAMD64.asm
${ARCH_SOURCES_DIR}/ExternalMethodFixupThunk.asm
- ${ARCH_SOURCES_DIR}/TlsGetters.asm # Condition="'$(FeatureImplicitTls)' != 'true'
${ARCH_SOURCES_DIR}/UMThunkStub.asm
${ARCH_SOURCES_DIR}/VirtualCallStubAMD64.asm
)
@@ -513,15 +504,9 @@ list(APPEND VM_SOURCES_DAC
${VM_SOURCES_DAC_AND_WKS_ARCH}
)
-# The default option for FEATURE_STANDALONE_GC builds a standalone
-# and non-standalone GC, linking the non-standalone GC into coreclr.dll.
-# For testing purposes, FEATURE_STANDALONE_GC_ONLY instead only builds and
-# links the non-standalone GC into coreclr.dll.
-if (NOT FEATURE_STANDALONE_GC_ONLY)
- list(APPEND VM_SOURCES_WKS
- ${GC_SOURCES_WKS}
- )
-endif(NOT FEATURE_STANDALONE_GC_ONLY)
+list(APPEND VM_SOURCES_WKS
+ ${GC_SOURCES_WKS}
+)
# The DAC does need GC sources in order to link correctly, even if
# it's not used.
diff --git a/src/vm/amd64/AsmMacros.inc b/src/vm/amd64/AsmMacros.inc
index f95a291929..58fd8d130f 100644
--- a/src/vm/amd64/AsmMacros.inc
+++ b/src/vm/amd64/AsmMacros.inc
@@ -188,29 +188,25 @@ Section ends
;
-; Macro to Call GetThread() correctly whether it is indirect or direct
-;
-CALL_GETTHREAD macro
-ifndef GetThread
-extern GetThread:proc
-endif
- call GetThread
- endm
+; Inlined version of GetThread
+; Trashes rax and r11
+;
+INLINE_GETTHREAD macro Reg
+
+ EXTERN _tls_index : DWORD
+ EXTERN gCurrentThreadInfo:DWORD
+
+ mov r11d, [_tls_index]
+ mov rax, gs:[OFFSET__TEB__ThreadLocalStoragePointer]
+ mov rax, [rax + r11 * 8]
+ mov r11d, SECTIONREL gCurrentThreadInfo
+ mov Reg, [rax + r11]
-CALL_GETAPPDOMAIN macro
-ifndef GetAppDomain
-extern GetAppDomain:proc
-endif
- call GetAppDomain
endm
-;
; if you change this code there will be corresponding code in JITInterfaceGen.cpp which will need to be changed
;
-; DEFAULT_TARGET needs to always be futher away than the fixed up target will be
-
-
JIT_HELPER_MONITOR_THUNK macro THUNK_NAME, Section
Section segment para 'CODE'
align 16
diff --git a/src/vm/amd64/InstantiatingStub.asm b/src/vm/amd64/InstantiatingStub.asm
index dff1b6f5a6..8601e4ae44 100644
--- a/src/vm/amd64/InstantiatingStub.asm
+++ b/src/vm/amd64/InstantiatingStub.asm
@@ -90,13 +90,11 @@ NESTED_ENTRY InstantiatingMethodStubWorker, _TEXT
;
; link the StubHelperFrame
;
- CALL_GETTHREAD
- mov rdx, [rax + OFFSETOF__Thread__m_pFrame]
+ INLINE_GETTHREAD r12
+ mov rdx, [r12 + OFFSETOF__Thread__m_pFrame]
mov [rbp + OFFSETOF_FRAME + OFFSETOF__Frame__m_Next], rdx
lea rcx, [rbp + OFFSETOF_FRAME]
- mov [rax + OFFSETOF__Thread__m_pFrame], rcx
-
- mov r12, rax ; store the Thread pointer
+ mov [r12 + OFFSETOF__Thread__m_pFrame], rcx
add rsp, SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES
diff --git a/src/vm/amd64/JitHelpers_Fast.asm b/src/vm/amd64/JitHelpers_Fast.asm
index f004be549e..5e0d79f74f 100644
--- a/src/vm/amd64/JitHelpers_Fast.asm
+++ b/src/vm/amd64/JitHelpers_Fast.asm
@@ -583,58 +583,6 @@ endif
nop
LEAF_END_MARKED JIT_WriteBarrier, _TEXT
-ifndef FEATURE_IMPLICIT_TLS
-LEAF_ENTRY GetThread, _TEXT
- ; the default implementation will just jump to one that returns null until
- ; MakeOptimizedTlsGetter is run which will overwrite this with the actual
- ; implementation.
- jmp short GetTLSDummy
-
- ;
- ; insert enough NOPS to be able to insert the largest optimized TLS getter
- ; that we might need, it is important that the TLS getter doesn't overwrite
- ; into the dummy getter.
- ;
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-
-LEAF_END GetThread, _TEXT
-
-LEAF_ENTRY GetAppDomain, _TEXT
- ; the default implementation will just jump to one that returns null until
- ; MakeOptimizedTlsGetter is run which will overwrite this with the actual
- ; implementation.
- jmp short GetTLSDummy
-
- ;
- ; insert enough NOPS to be able to insert the largest optimized TLS getter
- ; that we might need, it is important that the TLS getter doesn't overwrite
- ; into the dummy getter.
- ;
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-
-LEAF_END GetAppDomain, _TEXT
-
-LEAF_ENTRY GetTLSDummy, _TEXT
- xor rax, rax
- ret
-LEAF_END GetTLSDummy, _TEXT
-
-LEAF_ENTRY ClrFlsGetBlock, _TEXT
- ; the default implementation will just jump to one that returns null until
- ; MakeOptimizedTlsGetter is run which will overwrite this with the actual
- ; implementation.
- jmp short GetTLSDummy
-
- ;
- ; insert enough NOPS to be able to insert the largest optimized TLS getter
- ; that we might need, it is important that the TLS getter doesn't overwrite
- ; into the dummy getter.
- ;
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-
-LEAF_END ClrFlsGetBlock, _TEXT
-endif
-
; Mark start of the code region that we patch at runtime
LEAF_ENTRY JIT_PatchedCodeLast, _TEXT
ret
@@ -986,12 +934,11 @@ if 0 ne 0
;
; link the TailCallFrame
;
- CALL_GETTHREAD
- mov r14, rax
- mov r15, [rax + OFFSETOF__Thread__m_pFrame]
+ INLINE_GETTHREAD r14
+ mov r15, [r14 + OFFSETOF__Thread__m_pFrame]
mov [r13 + OFFSETOF_FRAME + OFFSETOF__Frame__m_Next], r15
lea r10, [r13 + OFFSETOF_FRAME]
- mov [rax + OFFSETOF__Thread__m_pFrame], r10
+ mov [r14 + OFFSETOF__Thread__m_pFrame], r10
endif
; the pretend call would be here
diff --git a/src/vm/amd64/JitHelpers_InlineGetAppDomain.asm b/src/vm/amd64/JitHelpers_InlineGetAppDomain.asm
deleted file mode 100644
index 187decf14d..0000000000
--- a/src/vm/amd64/JitHelpers_InlineGetAppDomain.asm
+++ /dev/null
@@ -1,123 +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.
-
-; ==++==
-;
-
-;
-; ==--==
-; ***********************************************************************
-; File: JitHelpers_InlineGetAppDomain.asm, see history in jithelp.asm
-;
-; Notes: These routinues will be patched at runtime with the location in
-; the TLS to find the AppDomain* and are the fastest implementation
-; of their specific functionality.
-; ***********************************************************************
-
-include AsmMacros.inc
-include asmconstants.inc
-
-; Min amount of stack space that a nested function should allocate.
-MIN_SIZE equ 28h
-
-; Macro to create a patchable inline GetAppdomain, if we decide to create patchable
-; high TLS inline versions then just change this macro to make sure to create enough
-; space in the asm to patch the high TLS getter instructions.
-PATCHABLE_INLINE_GETAPPDOMAIN macro Reg, PatchLabel
-PATCH_LABEL PatchLabel
- mov Reg, gs:[OFFSET__TEB__TlsSlots]
- endm
-
-extern JIT_GetSharedNonGCStaticBase_Helper:proc
-extern JIT_GetSharedGCStaticBase_Helper:proc
-
-LEAF_ENTRY JIT_GetSharedNonGCStaticBase_InlineGetAppDomain, _TEXT
- ; Check if rcx (moduleDomainID) is not a moduleID
- mov rax, rcx
- test rax, 1
- jz HaveLocalModule
-
- PATCHABLE_INLINE_GETAPPDOMAIN rax, JIT_GetSharedNonGCStaticBase__PatchTLSLabel
-
- ; Get the LocalModule, rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- mov rax, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- ; If class is not initialized, bail to C++ helper
- test byte ptr [rax + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
- jz CallHelper
- REPRET
-
- align 16
- CallHelper:
- ; Tail call JIT_GetSharedNonGCStaticBase_Helper
- mov rcx, rax
- jmp JIT_GetSharedNonGCStaticBase_Helper
-LEAF_END JIT_GetSharedNonGCStaticBase_InlineGetAppDomain, _TEXT
-
-LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_InlineGetAppDomain, _TEXT
- ; Check if rcx (moduleDomainID) is not a moduleID
- mov rax, rcx
- test rax, 1
- jz HaveLocalModule
-
- PATCHABLE_INLINE_GETAPPDOMAIN rax, JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel
-
- ; Get the LocalModule, rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- mov rax, [rax + rcx * 4 - 4]
- ret
-
- align 16
- HaveLocalModule:
- REPRET
-LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_InlineGetAppDomain, _TEXT
-
-LEAF_ENTRY JIT_GetSharedGCStaticBase_InlineGetAppDomain, _TEXT
- ; Check if rcx (moduleDomainID) is not a moduleID
- mov rax, rcx
- test rax, 1
- jz HaveLocalModule
-
- PATCHABLE_INLINE_GETAPPDOMAIN rax, JIT_GetSharedGCStaticBase__PatchTLSLabel
-
- ; Get the LocalModule, rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- mov rax, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- ; If class is not initialized, bail to C++ helper
- test byte ptr [rax + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
- jz CallHelper
-
- mov rax, [rax + OFFSETOF__DomainLocalModule__m_pGCStatics]
- ret
-
- align 16
- CallHelper:
- ; Tail call Jit_GetSharedGCStaticBase_Helper
- mov rcx, rax
- jmp JIT_GetSharedGCStaticBase_Helper
-LEAF_END JIT_GetSharedGCStaticBase_InlineGetAppDomain, _TEXT
-
-LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_InlineGetAppDomain, _TEXT
- ; Check if rcx (moduleDomainID) is not a moduleID
- mov rax, rcx
- test rax, 1
- jz HaveLocalModule
-
- PATCHABLE_INLINE_GETAPPDOMAIN rax, JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel
-
- ; Get the LocalModule, rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- mov rax, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- mov rax, [rax + OFFSETOF__DomainLocalModule__m_pGCStatics]
- ret
-LEAF_END JIT_GetSharedGCStaticBaseNoCtor_InlineGetAppDomain, _TEXT
-
- end
-
diff --git a/src/vm/amd64/JitHelpers_InlineGetThread.asm b/src/vm/amd64/JitHelpers_InlineGetThread.asm
index 40d63bf729..d9f58cc30f 100644
--- a/src/vm/amd64/JitHelpers_InlineGetThread.asm
+++ b/src/vm/amd64/JitHelpers_InlineGetThread.asm
@@ -2,11 +2,6 @@
; The .NET Foundation licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
-; ==++==
-;
-
-;
-; ==--==
; ***********************************************************************
; File: JitHelpers_InlineGetThread.asm, see history in jithelp.asm
;
@@ -21,15 +16,6 @@ include asmconstants.inc
; Min amount of stack space that a nested function should allocate.
MIN_SIZE equ 28h
-; Macro to create a patchable inline GetAppdomain, if we decide to create patchable
-; high TLS inline versions then just change this macro to make sure to create enough
-; space in the asm to patch the high TLS getter instructions.
-PATCHABLE_INLINE_GETTHREAD macro Reg, PatchLabel
-PATCH_LABEL PatchLabel
- mov Reg, gs:[OFFSET__TEB__TlsSlots]
- endm
-
-
JIT_NEW equ ?JIT_New@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@@Z
Object__DEBUG_SetAppDomain equ ?DEBUG_SetAppDomain@Object@@QEAAXPEAVAppDomain@@@Z
CopyValueClassUnchecked equ ?CopyValueClassUnchecked@@YAXPEAX0PEAVMethodTable@@@Z
@@ -49,11 +35,6 @@ extern JIT_NewArr1:proc
extern JIT_InternalThrow:proc
-ifdef _DEBUG
-extern DEBUG_TrialAllocSetAppDomain:proc
-extern DEBUG_TrialAllocSetAppDomain_NoScratchArea:proc
-endif
-
; IN: rcx: MethodTable*
; OUT: rax: new object
LEAF_ENTRY JIT_TrialAllocSFastMP_InlineGetThread, _TEXT
@@ -61,7 +42,7 @@ LEAF_ENTRY JIT_TrialAllocSFastMP_InlineGetThread, _TEXT
; m_BaseSize is guaranteed to be a multiple of 8.
- PATCHABLE_INLINE_GETTHREAD r11, JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset
+ INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
@@ -73,10 +54,6 @@ LEAF_ENTRY JIT_TrialAllocSFastMP_InlineGetThread, _TEXT
mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], rdx
mov [rax], rcx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
AllocFailed:
@@ -95,7 +72,7 @@ NESTED_ENTRY JIT_BoxFastMP_InlineGetThread, _TEXT
; m_BaseSize is guaranteed to be a multiple of 8.
- PATCHABLE_INLINE_GETTHREAD r11, JIT_BoxFastMPIGT__PatchTLSLabel
+ INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
@@ -107,10 +84,6 @@ NESTED_ENTRY JIT_BoxFastMP_InlineGetThread, _TEXT
mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
mov [rax], rcx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
; Check whether the object contains pointers
test dword ptr [rcx + OFFSETOF__MethodTable__m_dwFlags], MethodTable__enum_flag_ContainsPointers
jnz ContainsPointers
@@ -169,7 +142,7 @@ LEAF_ENTRY AllocateStringFastMP_InlineGetThread, _TEXT
lea edx, [edx + ecx*2 + 7]
and edx, -8
- PATCHABLE_INLINE_GETTHREAD r11, AllocateStringFastMP_InlineGetThread__PatchTLSOffset
+ INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
@@ -183,10 +156,6 @@ LEAF_ENTRY AllocateStringFastMP_InlineGetThread, _TEXT
mov [rax + OFFSETOF__StringObject__m_StringLength], ecx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
OversizedString:
@@ -226,7 +195,7 @@ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT
and r8d, -8
- PATCHABLE_INLINE_GETTHREAD r11, JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset
+ INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
@@ -241,10 +210,6 @@ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT
mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
OversizedArray:
@@ -279,7 +244,7 @@ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT
; No need for rounding in this case - element size is 8, and m_BaseSize is guaranteed
; to be a multiple of 8.
- PATCHABLE_INLINE_GETTHREAD r11, JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset
+ INLINE_GETTHREAD r11
mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
@@ -293,10 +258,6 @@ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT
mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
OversizedArray:
diff --git a/src/vm/amd64/JitHelpers_Slow.asm b/src/vm/amd64/JitHelpers_Slow.asm
index f86d429e33..0e26ae6dfd 100644
--- a/src/vm/amd64/JitHelpers_Slow.asm
+++ b/src/vm/amd64/JitHelpers_Slow.asm
@@ -42,7 +42,6 @@ EXTERN g_GCShadowEnd:QWORD
endif
JIT_NEW equ ?JIT_New@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@@Z
-Object__DEBUG_SetAppDomain equ ?DEBUG_SetAppDomain@Object@@QEAAXPEAVAppDomain@@@Z
CopyValueClassUnchecked equ ?CopyValueClassUnchecked@@YAXPEAX0PEAVMethodTable@@@Z
JIT_Box equ ?JIT_Box@@YAPEAVObject@@PEAUCORINFO_CLASS_STRUCT_@@PEAX@Z
g_pStringClass equ ?g_pStringClass@@3PEAVMethodTable@@EA
@@ -162,290 +161,6 @@ endif
LEAF_END_MARKED JIT_WriteBarrier_Debug, _TEXT
endif
-NESTED_ENTRY JIT_TrialAllocSFastMP, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- CALL_GETTHREAD
- mov r11, rax
-
- mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
-
- ; m_BaseSize is guaranteed to be a multiple of 8.
-
- mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
- mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
-
- add r8, rax
-
- cmp r8, r10
- ja AllocFailed
-
- mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
- mov [rax], rcx
-
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain
-endif ; _DEBUG
-
- ; epilog
- add rsp, MIN_SIZE
- ret
-
- AllocFailed:
- add rsp, MIN_SIZE
- jmp JIT_NEW
-NESTED_END JIT_TrialAllocSFastMP, _TEXT
-
-
-; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
-NESTED_ENTRY JIT_BoxFastMP, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- mov rax, [rcx + OFFSETOF__MethodTable__m_pWriteableData]
-
- ; Check whether the class has not been initialized
- test dword ptr [rax + OFFSETOF__MethodTableWriteableData__m_dwFlags], MethodTableWriteableData__enum_flag_Unrestored
- jnz ClassNotInited
-
- CALL_GETTHREAD
- mov r11, rax
-
- mov r8d, [rcx + OFFSET__MethodTable__m_BaseSize]
-
- ; m_BaseSize is guaranteed to be a multiple of 8.
-
- mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
- mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
-
- add r8, rax
-
- cmp r8, r10
- ja AllocFailed
-
- mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
- mov [rax], rcx
-
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain
-endif ; _DEBUG
-
- ; Check whether the object contains pointers
- test dword ptr [rcx + OFFSETOF__MethodTable__m_dwFlags], MethodTable__enum_flag_ContainsPointers
- jnz ContainsPointers
-
- ; We have no pointers - emit a simple inline copy loop
-
- mov ecx, [rcx + OFFSET__MethodTable__m_BaseSize]
- sub ecx, 18h ; sizeof(ObjHeader) + sizeof(Object) + last slot
-
- CopyLoop:
- mov r8, [rdx+rcx]
- mov [rax+rcx+8], r8
-
- sub ecx, 8
- jge CopyLoop
-
- add rsp, MIN_SIZE
- ret
-
- ContainsPointers:
- ; Do call to CopyValueClassUnchecked(object, data, pMT)
-
- mov [rsp+20h], rax
-
- mov r8, rcx
- lea rcx, [rax + 8]
- call CopyValueClassUnchecked
-
- mov rax, [rsp+20h]
-
- add rsp, MIN_SIZE
- ret
-
- ClassNotInited:
- AllocFailed:
- add rsp, MIN_SIZE
- jmp JIT_Box
-NESTED_END JIT_BoxFastMP, _TEXT
-
-
-NESTED_ENTRY AllocateStringFastMP, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; Instead of doing elaborate overflow checks, we just limit the number of elements
- ; to (LARGE_OBJECT_SIZE - 256)/sizeof(WCHAR) or less.
- ; This will avoid all overflow problems, as well as making sure
- ; big string objects are correctly allocated in the big object heap.
-
- cmp ecx, (ASM_LARGE_OBJECT_SIZE - 256)/2
- jae OversizedString
-
- CALL_GETTHREAD
- mov r11, rax
-
- mov rdx, [g_pStringClass]
- mov r8d, [rdx + OFFSET__MethodTable__m_BaseSize]
-
- ; Calculate the final size to allocate.
- ; We need to calculate baseSize + cnt*2, then round that up by adding 7 and anding ~7.
-
- lea r8d, [r8d + ecx*2 + 7]
- and r8d, -8
-
- mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
- mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
-
- add r8, rax
-
- cmp r8, r10
- ja AllocFailed
-
- mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
- mov [rax], rdx
-
- mov [rax + OFFSETOF__StringObject__m_StringLength], ecx
-
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain
-endif ; _DEBUG
-
- add rsp, MIN_SIZE
- ret
-
- OversizedString:
- AllocFailed:
- add rsp, MIN_SIZE
- jmp FramedAllocateString
-NESTED_END AllocateStringFastMP, _TEXT
-
-; HCIMPL2(Object*, JIT_NewArr1VC_MP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
-NESTED_ENTRY JIT_NewArr1VC_MP, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; We were passed a (shared) method table in RCX, which contains the element type.
-
- ; The element count is in RDX
-
- ; NOTE: if this code is ported for CORINFO_HELP_NEWSFAST_ALIGN8, it will need
- ; to emulate the double-specific behavior of JIT_TrialAlloc::GenAllocArray.
-
- ; Do a conservative check here. This is to avoid overflow while doing the calculations. We don't
- ; have to worry about "large" objects, since the allocation quantum is never big enough for
- ; LARGE_OBJECT_SIZE.
-
- ; For Value Classes, this needs to be 2^16 - slack (2^32 / max component size),
- ; The slack includes the size for the array header and round-up ; for alignment. Use 256 for the
- ; slack value out of laziness.
-
- ; In both cases we do a final overflow check after adding to the alloc_ptr.
-
- CALL_GETTHREAD
- mov r11, rax
-
- cmp rdx, (65535 - 256)
- jae OversizedArray
-
- movzx r8d, word ptr [rcx + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
- imul r8d, edx ; signed mul, but won't overflow due to length restriction above
- add r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
-
- ; round the size to a multiple of 8
-
- add r8d, 7
- and r8d, -8
-
- mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
- mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
-
- add r8, rax
- jc AllocFailed
-
- cmp r8, r10
- ja AllocFailed
-
- mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
- mov [rax], rcx
-
- mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain
-endif ; _DEBUG
-
- add rsp, MIN_SIZE
- ret
-
- OversizedArray:
- AllocFailed:
- add rsp, MIN_SIZE
- jmp JIT_NewArr1
-NESTED_END JIT_NewArr1VC_MP, _TEXT
-
-
-; HCIMPL2(Object*, JIT_NewArr1OBJ_MP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
-NESTED_ENTRY JIT_NewArr1OBJ_MP, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; We were passed a (shared) method table in RCX, which contains the element type.
-
- ; The element count is in RDX
-
- ; NOTE: if this code is ported for CORINFO_HELP_NEWSFAST_ALIGN8, it will need
- ; to emulate the double-specific behavior of JIT_TrialAlloc::GenAllocArray.
-
- ; Verifies that LARGE_OBJECT_SIZE fits in 32-bit. This allows us to do array size
- ; arithmetic using 32-bit registers.
- .erre ASM_LARGE_OBJECT_SIZE lt 100000000h
-
- cmp rdx, (ASM_LARGE_OBJECT_SIZE - 256)/8
- jae OversizedArray
-
- CALL_GETTHREAD
- mov r11, rax
-
- ; In this case we know the element size is sizeof(void *), or 8 for x64
- ; This helps us in two ways - we can shift instead of multiplying, and
- ; there's no need to align the size either
-
- mov r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
- lea r8d, [r8d + edx * 8]
-
- ; No need for rounding in this case - element size is 8, and m_BaseSize is guaranteed
- ; to be a multiple of 8.
-
- mov r10, [r11 + OFFSET__Thread__m_alloc_context__alloc_limit]
- mov rax, [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr]
-
- add r8, rax
-
- cmp r8, r10
- ja AllocFailed
-
- mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
- mov [rax], rcx
-
- mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain
-endif ; _DEBUG
-
- add rsp, MIN_SIZE
- ret
-
- OversizedArray:
- AllocFailed:
- add rsp, MIN_SIZE
- jmp JIT_NewArr1
-NESTED_END JIT_NewArr1OBJ_MP, _TEXT
-
-
-
extern g_global_alloc_lock:dword
extern g_global_alloc_context:qword
@@ -471,10 +186,6 @@ LEAF_ENTRY JIT_TrialAllocSFastSP, _TEXT
mov [rax], rcx
mov [g_global_alloc_lock], -1
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
AllocFailed:
@@ -511,10 +222,6 @@ NESTED_ENTRY JIT_BoxFastUP, _TEXT
mov [rax], rcx
mov [g_global_alloc_lock], -1
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
; Check whether the object contains pointers
test dword ptr [rcx + OFFSETOF__MethodTable__m_dwFlags], MethodTable__enum_flag_ContainsPointers
jnz ContainsPointers
@@ -594,10 +301,6 @@ LEAF_ENTRY AllocateStringFastUP, _TEXT
mov [rax + OFFSETOF__StringObject__m_StringLength], ecx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
AllocFailed:
@@ -655,10 +358,6 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT
mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
AllocFailed:
@@ -711,10 +410,6 @@ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT
mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
-ifdef _DEBUG
- call DEBUG_TrialAllocSetAppDomain_NoScratchArea
-endif ; _DEBUG
-
ret
AllocFailed:
@@ -725,181 +420,5 @@ endif ; _DEBUG
LEAF_END JIT_NewArr1OBJ_UP, _TEXT
-NESTED_ENTRY JIT_GetSharedNonGCStaticBase_Slow, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; Check if rcx (moduleDomainID) is not a moduleID
- test rcx, 1
- jz HaveLocalModule
-
- CALL_GETAPPDOMAIN
-
- ; Get the LocalModule
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- ; rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rcx, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- ; If class is not initialized, bail to C++ helper
- test [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
- jz CallHelper
-
- mov rax, rcx
- add rsp, MIN_SIZE
- ret
-
- align 16
- CallHelper:
- ; Tail call Jit_GetSharedNonGCStaticBase_Helper
- add rsp, MIN_SIZE
- jmp JIT_GetSharedNonGCStaticBase_Helper
-NESTED_END JIT_GetSharedNonGCStaticBase_Slow, _TEXT
-
-NESTED_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_Slow, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; Check if rcx (moduleDomainID) is not a moduleID
- test rcx, 1
- jz HaveLocalModule
-
- CALL_GETAPPDOMAIN
-
- ; Get the LocalModule
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- ; rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rax, [rax + rcx * 4 - 4]
-
- add rsp, MIN_SIZE
- ret
-
- align 16
- HaveLocalModule:
- mov rax, rcx
- add rsp, MIN_SIZE
- ret
-NESTED_END JIT_GetSharedNonGCStaticBaseNoCtor_Slow, _TEXT
-
-NESTED_ENTRY JIT_GetSharedGCStaticBase_Slow, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; Check if rcx (moduleDomainID) is not a moduleID
- test rcx, 1
- jz HaveLocalModule
-
- CALL_GETAPPDOMAIN
-
- ; Get the LocalModule
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- ; rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rcx, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- ; If class is not initialized, bail to C++ helper
- test [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1
- jz CallHelper
-
- mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics]
-
- add rsp, MIN_SIZE
- ret
-
- align 16
- CallHelper:
- ; Tail call Jit_GetSharedGCStaticBase_Helper
- add rsp, MIN_SIZE
- jmp JIT_GetSharedGCStaticBase_Helper
-NESTED_END JIT_GetSharedGCStaticBase_Slow, _TEXT
-
-NESTED_ENTRY JIT_GetSharedGCStaticBaseNoCtor_Slow, _TEXT
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- ; Check if rcx (moduleDomainID) is not a moduleID
- test rcx, 1
- jz HaveLocalModule
-
- CALL_GETAPPDOMAIN
-
- ; Get the LocalModule
- mov rax, [rax + OFFSETOF__AppDomain__m_sDomainLocalBlock + OFFSETOF__DomainLocalBlock__m_pModuleSlots]
- ; rcx will always be odd, so: rcx * 4 - 4 <=> (rcx >> 1) * 8
- mov rcx, [rax + rcx * 4 - 4]
-
- HaveLocalModule:
- mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics]
-
- add rsp, MIN_SIZE
- ret
-NESTED_END JIT_GetSharedGCStaticBaseNoCtor_Slow, _TEXT
-
-
-ifdef _DEBUG
-
-extern Object__DEBUG_SetAppDomain:proc
-
-;
-; IN: rax: new object needing the AppDomain ID set..
-; OUT: rax, returns original value at entry
-;
-; all integer register state is preserved
-;
-DEBUG_TrialAllocSetAppDomain_STACK_SIZE equ MIN_SIZE + 10h
-NESTED_ENTRY DEBUG_TrialAllocSetAppDomain, _TEXT
- push_vol_reg rax
- push_vol_reg rcx
- push_vol_reg rdx
- push_vol_reg r8
- push_vol_reg r9
- push_vol_reg r10
- push_vol_reg r11
- push_nonvol_reg rbx
- alloc_stack MIN_SIZE
- END_PROLOGUE
-
- mov rbx, rax
-
- ; get the app domain ptr
- CALL_GETAPPDOMAIN
-
- ; set the sync block app domain ID
- mov rcx, rbx
- mov rdx, rax
- call Object__DEBUG_SetAppDomain
-
- ; epilog
- add rsp, MIN_SIZE
- pop rbx
- pop r11
- pop r10
- pop r9
- pop r8
- pop rdx
- pop rcx
- pop rax
- ret
-NESTED_END DEBUG_TrialAllocSetAppDomain, _TEXT
-
-NESTED_ENTRY DEBUG_TrialAllocSetAppDomain_NoScratchArea, _TEXT
-
- push_nonvol_reg rbp
- set_frame rbp, 0
- END_PROLOGUE
-
- sub rsp, 20h
- and rsp, -16
-
- call DEBUG_TrialAllocSetAppDomain
-
- lea rsp, [rbp+0]
- pop rbp
- ret
-NESTED_END DEBUG_TrialAllocSetAppDomain_NoScratchArea, _TEXT
-
-endif
-
-
end
diff --git a/src/vm/amd64/RedirectedHandledJITCase.asm b/src/vm/amd64/RedirectedHandledJITCase.asm
index a6d3496357..5ab69475e2 100644
--- a/src/vm/amd64/RedirectedHandledJITCase.asm
+++ b/src/vm/amd64/RedirectedHandledJITCase.asm
@@ -195,9 +195,8 @@ NESTED_ENTRY RedirectForThrowControl2, _TEXT
END_PROLOGUE
; Fetch rip from a CONTEXT, and store it as our return address.
- CALL_GETTHREAD
+ INLINE_GETTHREAD rcx
- mov rcx, rax
call Thread__GetAbortContext
mov rax, [rax + OFFSETOF__CONTEXT__Rip]
diff --git a/src/vm/amd64/TlsGetters.asm b/src/vm/amd64/TlsGetters.asm
deleted file mode 100644
index 7b5a30844b..0000000000
--- a/src/vm/amd64/TlsGetters.asm
+++ /dev/null
@@ -1,120 +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.
-
-; ==++==
-;
-
-;
-; ==--==
-; ***********************************************************************
-; File: TlsGetters.asm, see history in jithelp.asm
-;
-; Notes: These TlsGetters (GetAppDomain(), GetThread()) are implemented
-; in a generic fashion, but might be patched at runtime to contain
-; a much faster implementation which goes straight to the TLS for
-; the Thread* or AppDomain*.
-;
-; Note that the macro takes special care to not have these become
-; non-unwindable after the patching has overwritten the prologue of
-; the generic getter.
-; ***********************************************************************
-
-include AsmMacros.inc
-include asmconstants.inc
-
-; Min amount of stack space that a nested function should allocate.
-MIN_SIZE equ 28h
-
-
-; These generic TLS getters are used for GetThread() and GetAppDomain(), they do a little
-; extra work to ensure that certain registers are preserved, those include the following
-; volatile registers
-;
-; rcx
-; rdx
-; r8
-; r9
-; r10
-; r11
-;
-; The return value is in rax as usual
-;
-; They DO NOT save scratch flowing point registers, if you need those you need to save them.
-
-ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-GetThreadGenericFullCheck equ ?GetThreadGenericFullCheck@@YAPEAVThread@@XZ
-extern GetThreadGenericFullCheck:proc
-endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-; Creates a generic TLS getter using the value from TLS slot gTLSIndex. Set GenerateGetThread
-; when using this macro to generate GetThread, as that will cause special code to be generated which
-; enables additional debug-only checking, such as enforcement of EE_THREAD_NOT_REQUIRED contracts
-GenerateOptimizedTLSGetter macro name, GenerateGetThread
-
-extern g&name&TLSIndex:dword
-extern __imp_TlsGetValue:qword
-
-SIZEOF_PUSHED_ARGS equ 10h
-
-NESTED_ENTRY Get&name&Generic, _TEXT
- push_vol_reg r10
- push_vol_reg r11
- alloc_stack MIN_SIZE
-
- ; save argument registers in shadow space
- save_reg_postrsp rcx, MIN_SIZE + 8h + SIZEOF_PUSHED_ARGS
- save_reg_postrsp rdx, MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS
- save_reg_postrsp r8, MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS
- save_reg_postrsp r9, MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS
- END_PROLOGUE
-
-ifdef _DEBUG
- cmp dword ptr [g&name&TLSIndex], -1
- jnz @F
- int 3
-@@:
-endif ; _DEBUG
-
-CALL_GET_THREAD_GENERIC_FULL_CHECK=0
-
-ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-if GenerateGetThread
-
-; Generating the GetThread() tlsgetter, and GetThreadGenericFullCheck is
-; defined in C (in threads.cpp). So we'll want to delegate directly to
-; GetThreadGenericFullCheck, which may choose to do additional checking, such
-; as enforcing EE_THREAD_NOT_REQUIRED contracts
-CALL_GET_THREAD_GENERIC_FULL_CHECK=1
-
-endif ; GenerateGetThread
-endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-if CALL_GET_THREAD_GENERIC_FULL_CHECK
- call GetThreadGenericFullCheck
-else
- ; Not generating the GetThread() tlsgetter (or there is no GetThreadGenericFullCheck
- ; to call), so do nothing special--just look up the value stored at TLS slot gTLSIndex
- mov ecx, [g&name&TLSIndex]
- call [__imp_TlsGetValue]
-endif
-
- ; restore arguments from shadow space
- mov rcx, [rsp + MIN_SIZE + 8h + SIZEOF_PUSHED_ARGS]
- mov rdx, [rsp + MIN_SIZE + 10h + SIZEOF_PUSHED_ARGS]
- mov r8, [rsp + MIN_SIZE + 18h + SIZEOF_PUSHED_ARGS]
- mov r9, [rsp + MIN_SIZE + 20h + SIZEOF_PUSHED_ARGS]
-
- ; epilog
- add rsp, MIN_SIZE
- pop r11
- pop r10
- ret
-NESTED_END Get&name&Generic, _TEXT
-
- endm
-
-GenerateOptimizedTLSGetter Thread, 1
-GenerateOptimizedTLSGetter AppDomain, 0
-
- end
diff --git a/src/vm/amd64/UMThunkStub.asm b/src/vm/amd64/UMThunkStub.asm
index dd6d4ebc3c..8b44e67a7e 100644
--- a/src/vm/amd64/UMThunkStub.asm
+++ b/src/vm/amd64/UMThunkStub.asm
@@ -166,14 +166,12 @@ UMThunkStubAMD64_FIXED_STACK_ALLOC_SIZE = UMThunkStubAMD64_STACK_FRAME_SIZE - (U
;
; Call GetThread()
;
- CALL_GETTHREAD ; will not trash r10
- test rax, rax
+ INLINE_GETTHREAD r12 ; will not trash r10
+ test r12, r12
jz DoThreadSetup
HaveThread:
- mov r12, rax ; r12 <- Thread*
-
;FailFast if a native callable method invoked via ldftn and calli.
cmp dword ptr [r12 + OFFSETOF__Thread__m_fPreemptiveGCDisabled], 1
jz InvalidTransition
@@ -250,6 +248,8 @@ DoThreadSetup:
movdqa xmm1, xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 10h]
movdqa xmm2, xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 20h]
movdqa xmm3, xmmword ptr [rbp + UMThunkStubAMD64_XMM_SAVE_OFFSET + 30h]
+
+ mov r12, rax
jmp HaveThread
diff --git a/src/vm/amd64/asmconstants.h b/src/vm/amd64/asmconstants.h
index 1fef80f66d..b6a3c712e7 100644
--- a/src/vm/amd64/asmconstants.h
+++ b/src/vm/amd64/asmconstants.h
@@ -535,22 +535,9 @@ ASMCONSTANTS_C_ASSERT(MethodDescClassification__mdcClassification == mdcClassifi
ASMCONSTANTS_C_ASSERT(MethodDescClassification__mcInstantiated == mcInstantiated);
#ifndef FEATURE_PAL
-
-#define OFFSET__TEB__TlsSlots 0x1480
-ASMCONSTANTS_C_ASSERT(OFFSET__TEB__TlsSlots == offsetof(TEB, TlsSlots));
-
-#define OFFSETOF__TEB__LastErrorValue 0x68
-ASMCONSTANTS_C_ASSERT(OFFSETOF__TEB__LastErrorValue == offsetof(TEB, LastErrorValue));
-
-#endif // !FEATURE_PAL
-
-#ifdef _DEBUG
-#define TLS_GETTER_MAX_SIZE_ASM 0x30
-#else
-#define TLS_GETTER_MAX_SIZE_ASM 0x18
+#define OFFSET__TEB__ThreadLocalStoragePointer 0x58
+ASMCONSTANTS_C_ASSERT(OFFSET__TEB__ThreadLocalStoragePointer == offsetof(TEB, ThreadLocalStoragePointer));
#endif
-ASMCONSTANTS_C_ASSERT(TLS_GETTER_MAX_SIZE_ASM == TLS_GETTER_MAX_SIZE)
-
// If you change these constants, you need to update code in
// RedirectHandledJITCase.asm and ExcepAMD64.cpp.
diff --git a/src/vm/amd64/cgencpu.h b/src/vm/amd64/cgencpu.h
index 98e9770858..b83437039b 100644
--- a/src/vm/amd64/cgencpu.h
+++ b/src/vm/amd64/cgencpu.h
@@ -104,13 +104,6 @@ EXTERN_C void FastCallFinalizeWorker(Object *obj, PCODE funcPtr);
#define X86RegFromAMD64Reg(extended_reg) \
((X86Reg)(((int)extended_reg) & X86_REGISTER_MASK))
-// Max size of optimized TLS helpers
-#ifdef _DEBUG
-// Debug build needs extra space for last error trashing
-#define TLS_GETTER_MAX_SIZE 0x30
-#else
-#define TLS_GETTER_MAX_SIZE 0x18
-#endif
//=======================================================================
// IMPORTANT: This value is used to figure out how much to allocate
@@ -538,26 +531,22 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
return TRUE;
}
-#ifndef FEATURE_IMPLICIT_TLS
//
// JIT HELPER ALIASING FOR PORTABILITY.
//
// Create alias for optimized implementations of helpers provided on this platform
//
-#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_InlineGetAppDomain
-#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_InlineGetAppDomain
-#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_InlineGetAppDomain
-#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_InlineGetAppDomain
-#endif // FEATURE_IMPLICIT_TLS
+#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
+#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
#ifndef FEATURE_PAL
-
#define JIT_ChkCastClass JIT_ChkCastClass
#define JIT_ChkCastClassSpecial JIT_ChkCastClassSpecial
#define JIT_IsInstanceOfClass JIT_IsInstanceOfClass
#define JIT_ChkCastInterface JIT_ChkCastInterface
#define JIT_IsInstanceOfInterface JIT_IsInstanceOfInterface
-
#endif // FEATURE_PAL
#define JIT_Stelem_Ref JIT_Stelem_Ref
diff --git a/src/vm/amd64/jitinterfaceamd64.cpp b/src/vm/amd64/jitinterfaceamd64.cpp
index 6a19e274e0..bffec814b1 100644
--- a/src/vm/amd64/jitinterfaceamd64.cpp
+++ b/src/vm/amd64/jitinterfaceamd64.cpp
@@ -278,14 +278,14 @@ PBYTE WriteBarrierManager::CalculatePatchLocation(LPVOID base, LPVOID label, int
return ((LPBYTE)GetEEFuncEntryPoint(JIT_WriteBarrier) + ((LPBYTE)GetEEFuncEntryPoint(label) - (LPBYTE)GetEEFuncEntryPoint(base) + offset));
}
-void WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended)
+int WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended)
{
GCX_MAYBE_COOP_NO_THREAD_BROKEN((!isRuntimeSuspended && GetThread() != NULL));
- BOOL bEESuspendedHere = FALSE;
- if(!isRuntimeSuspended && m_currentWriteBarrier != WRITE_BARRIER_UNINITIALIZED)
+ int stompWBCompleteActions = SWB_PASS;
+ if (!isRuntimeSuspended && m_currentWriteBarrier != WRITE_BARRIER_UNINITIALIZED)
{
ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_GC_PREP);
- bEESuspendedHere = TRUE;
+ stompWBCompleteActions |= SWB_EE_RESTART;
}
_ASSERTE(m_currentWriteBarrier != newWriteBarrier);
@@ -409,13 +409,10 @@ void WriteBarrierManager::ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier,
UNREACHABLE_MSG("unexpected write barrier type!");
}
- UpdateEphemeralBounds(true);
- UpdateWriteWatchAndCardTableLocations(true, false);
+ stompWBCompleteActions |= UpdateEphemeralBounds(true);
+ stompWBCompleteActions |= UpdateWriteWatchAndCardTableLocations(true, false);
- if(bEESuspendedHere)
- {
- ThreadSuspend::RestartEE(FALSE, TRUE);
- }
+ return stompWBCompleteActions;
}
#undef CALC_PATCH_LOCATION
@@ -521,21 +518,20 @@ bool WriteBarrierManager::NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, W
return m_currentWriteBarrier != writeBarrierType;
}
-void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended)
+int WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended)
{
- bool needToFlushCache = false;
-
WriteBarrierType newType;
if (NeedDifferentWriteBarrier(false, &newType))
{
- ChangeWriteBarrierTo(newType, isRuntimeSuspended);
- return;
+ return ChangeWriteBarrierTo(newType, isRuntimeSuspended);
}
+ int stompWBCompleteActions = SWB_PASS;
+
#ifdef _DEBUG
// Using debug-only write barrier?
if (m_currentWriteBarrier == WRITE_BARRIER_UNINITIALIZED)
- return;
+ return stompWBCompleteActions;
#endif
switch (m_currentWriteBarrier)
@@ -549,7 +545,7 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended)
if (*(UINT64*)m_pUpperBoundImmediate != (size_t)g_ephemeral_high)
{
*(UINT64*)m_pUpperBoundImmediate = (size_t)g_ephemeral_high;
- needToFlushCache = true;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
}
}
//
@@ -564,7 +560,7 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended)
if (*(UINT64*)m_pLowerBoundImmediate != (size_t)g_ephemeral_low)
{
*(UINT64*)m_pLowerBoundImmediate = (size_t)g_ephemeral_low;
- needToFlushCache = true;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
}
break;
}
@@ -583,13 +579,10 @@ void WriteBarrierManager::UpdateEphemeralBounds(bool isRuntimeSuspended)
UNREACHABLE_MSG("unexpected m_currentWriteBarrier in UpdateEphemeralBounds");
}
- if (needToFlushCache)
- {
- FlushInstructionCache(GetCurrentProcess(), (PVOID)JIT_WriteBarrier, GetCurrentWriteBarrierSize());
- }
+ return stompWBCompleteActions;
}
-void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+int WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
{
// If we are told that we require an upper bounds check (GC did some heap reshuffling),
// we need to switch to the WriteBarrier_PostGrow function for good.
@@ -597,17 +590,16 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu
WriteBarrierType newType;
if (NeedDifferentWriteBarrier(bReqUpperBoundsCheck, &newType))
{
- ChangeWriteBarrierTo(newType, isRuntimeSuspended);
- return;
+ return ChangeWriteBarrierTo(newType, isRuntimeSuspended);
}
+
+ int stompWBCompleteActions = SWB_PASS;
#ifdef _DEBUG
// Using debug-only write barrier?
if (m_currentWriteBarrier == WRITE_BARRIER_UNINITIALIZED)
- return;
+ return stompWBCompleteActions;
#endif
-
- bool fFlushCache = false;
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
switch (m_currentWriteBarrier)
@@ -620,7 +612,7 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu
if (*(UINT64*)m_pWriteWatchTableImmediate != (size_t)g_sw_ww_table)
{
*(UINT64*)m_pWriteWatchTableImmediate = (size_t)g_sw_ww_table;
- fFlushCache = true;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
}
break;
@@ -632,32 +624,29 @@ void WriteBarrierManager::UpdateWriteWatchAndCardTableLocations(bool isRuntimeSu
if (*(UINT64*)m_pCardTableImmediate != (size_t)g_card_table)
{
*(UINT64*)m_pCardTableImmediate = (size_t)g_card_table;
- fFlushCache = true;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
}
#ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES
if (*(UINT64*)m_pCardBundleTableImmediate != (size_t)g_card_bundle_table)
{
*(UINT64*)m_pCardBundleTableImmediate = (size_t)g_card_bundle_table;
- fFlushCache = true;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
}
#endif
- if (fFlushCache)
- {
- FlushInstructionCache(GetCurrentProcess(), (LPVOID)JIT_WriteBarrier, GetCurrentWriteBarrierSize());
- }
+ return stompWBCompleteActions;
}
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
-void WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
+int WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
{
WriteBarrierType newWriteBarrierType;
switch (m_currentWriteBarrier)
{
case WRITE_BARRIER_UNINITIALIZED:
// Using the debug-only write barrier
- return;
+ return SWB_PASS;
case WRITE_BARRIER_PREGROW64:
newWriteBarrierType = WRITE_BARRIER_WRITE_WATCH_PREGROW64;
@@ -677,17 +666,17 @@ void WriteBarrierManager::SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
UNREACHABLE();
}
- ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended);
+ return ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended);
}
-void WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
+int WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
{
WriteBarrierType newWriteBarrierType;
switch (m_currentWriteBarrier)
{
case WRITE_BARRIER_UNINITIALIZED:
// Using the debug-only write barrier
- return;
+ return SWB_PASS;
case WRITE_BARRIER_WRITE_WATCH_PREGROW64:
newWriteBarrierType = WRITE_BARRIER_PREGROW64;
@@ -707,42 +696,47 @@ void WriteBarrierManager::SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
UNREACHABLE();
}
- ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended);
+ return ChangeWriteBarrierTo(newWriteBarrierType, isRuntimeSuspended);
}
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
// This function bashes the super fast amd64 version of the JIT_WriteBarrier
// helper. It should be called by the GC whenever the ephermeral region
// bounds get changed, but still remain on the top of the GC Heap.
-void StompWriteBarrierEphemeral(bool isRuntimeSuspended)
+int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
{
WRAPPER_NO_CONTRACT;
- g_WriteBarrierManager.UpdateEphemeralBounds(isRuntimeSuspended);
+ return g_WriteBarrierManager.UpdateEphemeralBounds(isRuntimeSuspended);
}
// This function bashes the super fast amd64 versions of the JIT_WriteBarrier
// helpers. It should be called by the GC whenever the ephermeral region gets moved
// from being at the top of the GC Heap, and/or when the cards table gets moved.
-void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
{
WRAPPER_NO_CONTRACT;
- g_WriteBarrierManager.UpdateWriteWatchAndCardTableLocations(isRuntimeSuspended, bReqUpperBoundsCheck);
+ return g_WriteBarrierManager.UpdateWriteWatchAndCardTableLocations(isRuntimeSuspended, bReqUpperBoundsCheck);
+}
+
+void FlushWriteBarrierInstructionCache()
+{
+ FlushInstructionCache(GetCurrentProcess(), (PVOID)JIT_WriteBarrier, g_WriteBarrierManager.GetCurrentWriteBarrierSize());
}
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
-void SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
+int SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
{
WRAPPER_NO_CONTRACT;
- g_WriteBarrierManager.SwitchToWriteWatchBarrier(isRuntimeSuspended);
+ return g_WriteBarrierManager.SwitchToWriteWatchBarrier(isRuntimeSuspended);
}
-void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
+int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
{
WRAPPER_NO_CONTRACT;
- g_WriteBarrierManager.SwitchToNonWriteWatchBarrier(isRuntimeSuspended);
+ return g_WriteBarrierManager.SwitchToNonWriteWatchBarrier(isRuntimeSuspended);
}
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 7b0da7f5a2..6ec129cd3c 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -46,7 +46,6 @@
#ifdef FEATURE_COMINTEROP
#include "comtoclrcall.h"
-#include "sxshelpers.h"
#include "runtimecallablewrapper.h"
#include "mngstdinterfaces.h"
#include "olevariant.h"
@@ -64,8 +63,6 @@
#include "nativeoverlapped.h"
-#include "compatibilityflags.h"
-
#ifndef FEATURE_PAL
#include "dwreport.h"
#endif // !FEATURE_PAL
@@ -2062,8 +2059,6 @@ BOOL AppDomain::GetPreferComInsteadOfManagedRemoting()
return (GetComOrRemotingFlag() == COMorRemoting_COM);
}
-STDAPI GetXMLObjectEx(IXMLParser **ppv);
-
COMorRemotingFlag AppDomain::GetPreferComInsteadOfManagedRemotingFromConfigFile()
{
CONTRACTL
@@ -2406,10 +2401,6 @@ void SystemDomain::Init()
_ASSERTE(curCtx->GetDomain() != NULL);
#endif
-#ifdef _DEBUG
- g_fVerifierOff = g_pConfig->IsVerifierOff();
-#endif
-
#ifdef FEATURE_PREJIT
if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapDisable) != 0)
g_fAllowNativeImages = false;
@@ -10942,22 +10933,6 @@ PTR_MethodTable BaseDomain::LookupType(UINT32 id) {
return pMT;
}
-#ifndef DACCESS_COMPILE
-
-
-//------------------------------------------------------------------------
-BOOL GetCompatibilityFlag(CompatibilityFlag flag)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- } CONTRACTL_END;
-
- return FALSE;
-}
-#endif // !DACCESS_COMPILE
-
//---------------------------------------------------------------------------------------
//
BOOL
@@ -11915,19 +11890,3 @@ void ZapperSetBindingPaths(ICorCompilationDomain *pDomain, SString &trustedPlatf
}
#endif
-
-#if !defined(CROSSGEN_COMPILE)
-bool IsSingleAppDomain()
-{
- STARTUP_FLAGS flags = CorHost2::GetStartupFlags();
- if(flags & STARTUP_SINGLE_APPDOMAIN)
- return TRUE;
- else
- return FALSE;
-}
-#else
-bool IsSingleAppDomain()
-{
- return FALSE;
-}
-#endif
diff --git a/src/vm/appdomainconfigfactory.hpp b/src/vm/appdomainconfigfactory.hpp
deleted file mode 100644
index b443797c0d..0000000000
--- a/src/vm/appdomainconfigfactory.hpp
+++ /dev/null
@@ -1,240 +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.
-
-
-#ifndef APPDOMAINCONFIGFACTORY_H
-#define APPDOMAINCONFIGFACTORY_H
-
-#include <xmlparser.h>
-#include <objbase.h>
-#include "unknwn.h"
-#include "../xmlparser/_reference.h"
-#include "../xmlparser/_unknown.h"
-
-#include "appdomain.hpp"
-
-#define ISWHITE(ch) ((ch) >= 0x09 && (ch) <= 0x0D || (ch) == 0x20)
-
-#define CONST_STRING_AND_LEN(str) str, NumItems(str)-1
-
-
-extern int EEXMLStringCompare(const WCHAR *pStr1,
- DWORD cchStr1,
- const WCHAR *pStr2,
- DWORD cchStr2);
-
-
-enum APPDOMAINPARSESTATE
-{
- APPDOMAINPARSESTATE_INITIALIZED,
- APPDOMAINPARSESTATE_RUNTIME,
- APPDOMAINPARSESTATE_PREFERCOMINSTEADOFREMOTING,
- APPDOMAINPARSESTATE_ENABLED,
- APPDOMAINPARSESTATE_LEGACYMODE
-};
-
-
-
-class AppDomainConfigFactory : public _unknown<IXMLNodeFactory, &IID_IXMLNodeFactory>
-{
-
-public:
- AppDomainConfigFactory() : m_dwDepth(0), comorRemotingFlag(COMorRemoting_NotInitialized), m_appdomainParseState(APPDOMAINPARSESTATE_INITIALIZED)
- {
- LIMITED_METHOD_CONTRACT;
- }
-
- ~AppDomainConfigFactory()
- {
- LIMITED_METHOD_CONTRACT;
- }
-
- HRESULT STDMETHODCALLTYPE NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt)
- {
- LIMITED_METHOD_CONTRACT;
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo)
- {
- LIMITED_METHOD_CONTRACT;
-
- m_dwDepth++;
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmptyNode,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo)
- {
- LIMITED_METHOD_CONTRACT;
-
- if (!fEmptyNode)
- m_dwDepth--;
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE Error(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
- {
- LIMITED_METHOD_CONTRACT;
- /*
- UNUSED(pSource);
- UNUSED(hrErrorCode);
- UNUSED(cNumRecs);
- UNUSED(apNodeInfo);
- */
- return hrErrorCode;
- }
-
- HRESULT STDMETHODCALLTYPE CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
- {
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- if(m_dwDepth > 2)
- {
- return S_OK;
- }
-
- HRESULT hr = S_OK;
- DWORD dwStringSize = 0;
- WCHAR* pszString = NULL;
- DWORD i;
- BOOL fRuntimeKey = FALSE;
- BOOL fVersion = FALSE;
-
- for( i = 0; i < cNumRecs; i++) {
-
- if(apNodeInfo[i]->dwType == XML_ELEMENT ||
- apNodeInfo[i]->dwType == XML_ATTRIBUTE ||
- apNodeInfo[i]->dwType == XML_PCDATA) {
-
- dwStringSize = apNodeInfo[i]->ulLen;
- pszString = (WCHAR*) apNodeInfo[i]->pwcText;
- // Trim the value
-
- // we should never decrement lgth if it's 0, because it's unsigned
-
- for(;*pszString && ISWHITE(*pszString) && dwStringSize>0; pszString++, dwStringSize--);
- while( dwStringSize > 0 && ISWHITE(pszString[dwStringSize-1]))
- dwStringSize--;
-
- if (m_appdomainParseState == APPDOMAINPARSESTATE_INITIALIZED)
- {
- //look forward to <runtime>
- if (m_dwDepth == 1 &&
- apNodeInfo[i]->dwType == XML_ELEMENT &&
- EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("runtime"))) == 0)
- {
- m_appdomainParseState = APPDOMAINPARSESTATE_RUNTIME;
- }
- return S_OK;
- }
- else if (m_appdomainParseState == APPDOMAINPARSESTATE_RUNTIME)
- {
- // look forward to <PreferComInsteadOfManagedRemoting enabled="true"/>
- if (m_dwDepth == 2 &&
- apNodeInfo[i]->dwType == XML_ELEMENT &&
- EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("PreferComInsteadOfManagedRemoting"))) == 0)
- {
- m_appdomainParseState = APPDOMAINPARSESTATE_PREFERCOMINSTEADOFREMOTING;
- continue;
- }
- // if we ended parsing <Runtime>, we abort it
- if (m_dwDepth <= 1)
- pSource->Abort(NULL);
- return S_OK;
- }
- else if (m_appdomainParseState == APPDOMAINPARSESTATE_PREFERCOMINSTEADOFREMOTING)
- {
- // require enabled="true"/> or legacyMode="true"/>
- if (m_dwDepth == 2 &&
- apNodeInfo[i]->dwType == XML_ATTRIBUTE)
- {
- if (EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("enabled"))) == 0)
- {
- m_appdomainParseState = APPDOMAINPARSESTATE_ENABLED;
- }
- if (EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("legacyMode"))) == 0)
- {
- m_appdomainParseState = APPDOMAINPARSESTATE_LEGACYMODE;
- }
- }
-
- // ignore unrecognized attributes (forward compat)
- continue;
- }
- else if (m_appdomainParseState == APPDOMAINPARSESTATE_ENABLED || m_appdomainParseState == APPDOMAINPARSESTATE_LEGACYMODE)
- {
- // require "true" /> or "false" />
- if (m_dwDepth == 2 &&
- apNodeInfo[i]->dwType == XML_PCDATA)
- {
- if (EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("true"))) == 0)
- {
- if (m_appdomainParseState == APPDOMAINPARSESTATE_LEGACYMODE)
- {
- // LegacyMode does not override the "master switch"
- if (comorRemotingFlag != COMorRemoting_COM)
- comorRemotingFlag = COMorRemoting_LegacyMode;
- }
- else
- {
- comorRemotingFlag = COMorRemoting_COM;
- }
- }
- else if (EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("false"))) == 0)
- {
- if (m_appdomainParseState == APPDOMAINPARSESTATE_ENABLED)
- {
- // we do report that the "master switch" is explictly false
- if (comorRemotingFlag == COMorRemoting_NotInitialized)
- comorRemotingFlag = COMorRemoting_Remoting;
- }
- }
-
- m_appdomainParseState = APPDOMAINPARSESTATE_PREFERCOMINSTEADOFREMOTING;
- continue;
- }
- pSource->Abort(NULL);
- return S_OK;
- }
- }
- }
- return hr;
- }
-
- COMorRemotingFlag GetCOMorRemotingFlag()
- {
- LIMITED_METHOD_CONTRACT;
- return comorRemotingFlag;
- }
-
-private:
- DWORD m_dwDepth;
- COMorRemotingFlag comorRemotingFlag;
- APPDOMAINPARSESTATE m_appdomainParseState;
-
-};
-
-#endif APPDOMAINCONFIGFACTORY_H
diff --git a/src/vm/arm/asmconstants.h b/src/vm/arm/asmconstants.h
index 704fa28556..ab3d16b9a9 100644
--- a/src/vm/arm/asmconstants.h
+++ b/src/vm/arm/asmconstants.h
@@ -256,9 +256,6 @@ ASMCONSTANTS_C_ASSERT(VASigCookie__pNDirectILStub == offsetof(VASigCookie, pNDir
#define CONTEXT_Pc 0x040
ASMCONSTANTS_C_ASSERT(CONTEXT_Pc == offsetof(T_CONTEXT,Pc))
-#define TLS_GETTER_MAX_SIZE_ASM 0x10
-ASMCONSTANTS_C_ASSERT(TLS_GETTER_MAX_SIZE_ASM == TLS_GETTER_MAX_SIZE)
-
#define CallDescrData__pSrc 0x00
#define CallDescrData__numStackSlots 0x04
#define CallDescrData__pArgumentRegisters 0x08
diff --git a/src/vm/arm/asmhelpers.S b/src/vm/arm/asmhelpers.S
index 36933f5ea6..40faf9c3bc 100644
--- a/src/vm/arm/asmhelpers.S
+++ b/src/vm/arm/asmhelpers.S
@@ -662,11 +662,11 @@ NESTED_ENTRY ProfileEnterNaked, _TEXT, NoHandler
PROLOG_PUSH "{r4, r5, r7, r11, lr}"
PROLOG_STACK_SAVE_OFFSET r7, #8
- // fields of PLATFORM_SPECIFIC_DATA, in reverse order
+ // fields of PROFILE_PLATFORM_SPECIFIC_DATA, in reverse order
// UINT32 r0; // Keep r0 & r1 contiguous to make returning 64-bit results easier
// UINT32 r1;
- // void *R11;
+ // void *r11;
// void *Pc;
// union // Float arg registers as 32-bit (s0-s15) and 64-bit (d0-d7)
// {
@@ -705,11 +705,11 @@ NESTED_ENTRY ProfileLeaveNaked, _TEXT, NoHandler
PROLOG_PUSH "{r1, r2, r4, r5, r7, r11, lr}"
PROLOG_STACK_SAVE_OFFSET r7, #16
- // fields of PLATFORM_SPECIFIC_DATA, in reverse order
+ // fields of PROFILE_PLATFORM_SPECIFIC_DATA, in reverse order
// UINT32 r0; // Keep r0 & r1 contiguous to make returning 64-bit results easier
// UINT32 r1;
- // void *R11;
+ // void *r11;
// void *Pc;
// union // Float arg registers as 32-bit (s0-s15) and 64-bit (d0-d7)
// {
@@ -734,13 +734,56 @@ NESTED_ENTRY ProfileLeaveNaked, _TEXT, NoHandler
push { lr }
push { r11 }
push { r1 }
- push { r2 }
+ push { r0 }
mov r1, sp
bl C_FUNC(ProfileLeave)
EPILOG_STACK_RESTORE_OFFSET r7, #16
EPILOG_POP "{r1, r2, r4, r5, r7, r11, pc}"
NESTED_END ProfileLeaveNaked, _TEXT
+//
+// EXTERN_C void ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID);
+//
+NESTED_ENTRY ProfileTailcallNaked, _TEXT, NoHandler
+ PROLOG_PUSH "{r1, r2, r4, r5, r7, r11, lr}"
+ PROLOG_STACK_SAVE_OFFSET r7, #16
+
+ // fields of PROFILE_PLATFORM_SPECIFIC_DATA, in reverse order
+
+ // UINT32 r0; // Keep r0 & r1 contiguous to make returning 64-bit results easier
+ // UINT32 r1;
+ // void *r11;
+ // void *Pc;
+ // union // Float arg registers as 32-bit (s0-s15) and 64-bit (d0-d7)
+ // {
+ // UINT32 s[16];
+ // UINT64 d[8];
+ // };
+ // FunctionID functionId;
+ // void *probeSp; // stack pointer of managed function
+ // void *profiledSp; // location of arguments on stack
+ // LPVOID hiddenArg;
+ // UINT32 flags;
+ movw r4, #2
+ push { /* flags */ r4 }
+ movw r4, #0
+ push { /* hiddenArg */ r4 }
+ add r5, r11, #8
+ push { /* profiledSp */ r5 }
+ add r5, sp, #40
+ push { /* probeSp */ r5 }
+ push { /* functionId */ r0 }
+ vpush.64 { d0 - d7 }
+ push { lr }
+ push { r11 }
+ push { r1 }
+ push { r0 }
+ mov r1, sp
+ bl C_FUNC(ProfileTailcall)
+ EPILOG_STACK_RESTORE_OFFSET r7, #16
+ EPILOG_POP "{r1, r2, r4, r5, r7, r11, pc}"
+NESTED_END ProfileTailcallNaked, _TEXT
+
// EXTERN_C int __fastcall HelperMethodFrameRestoreState(
// INDEBUG_COMMA(HelperMethodFrame *pFrame)
// MachState *pState
diff --git a/src/vm/arm/asmhelpers.asm b/src/vm/arm/asmhelpers.asm
index e5fd41a513..4d21d07462 100644
--- a/src/vm/arm/asmhelpers.asm
+++ b/src/vm/arm/asmhelpers.asm
@@ -1481,7 +1481,6 @@ stackProbe_loop
NESTED_END
-#ifdef FEATURE_CORECLR
;
; JIT Static access helpers for single appdomain case
;
@@ -1543,7 +1542,6 @@ CallCppHelper3
bx lr
LEAF_END
-#endif
; ------------------------------------------------------------------
; __declspec(naked) void F_CALL_CONV JIT_Stelem_Ref(PtrArray* array, unsigned idx, Object* val)
diff --git a/src/vm/arm/cgencpu.h b/src/vm/arm/cgencpu.h
index 2a369d8f02..8da2b2b3cc 100644
--- a/src/vm/arm/cgencpu.h
+++ b/src/vm/arm/cgencpu.h
@@ -83,9 +83,6 @@ EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
#define CALLDESCR_ARGREGS 1 // CallDescrWorker has ArgumentRegister parameter
#define CALLDESCR_FPARGREGS 1 // CallDescrWorker has FloatArgumentRegisters parameter
-// Max size of optimized TLS helpers
-#define TLS_GETTER_MAX_SIZE 0x10
-
// Given a return address retrieved during stackwalk,
// this is the offset by which it should be decremented to arrive at the callsite.
#define STACKWALK_CONTROLPC_ADJUST_OFFSET 2
@@ -552,7 +549,7 @@ public:
ThumbEmitJumpRegister(thumbRegLr);
}
- void ThumbEmitGetThread(TLSACCESSMODE mode, ThumbReg dest);
+ void ThumbEmitGetThread(ThumbReg dest);
void ThumbEmitNop()
{
@@ -1056,19 +1053,15 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
#endif
}
-#ifndef FEATURE_IMPLICIT_TLS
//
// JIT HELPER ALIASING FOR PORTABILITY.
//
// Create alias for optimized implementations of helpers provided on this platform
//
-// optimized static helpers
-#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_InlineGetAppDomain
-#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_InlineGetAppDomain
-#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_InlineGetAppDomain
-#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_InlineGetAppDomain
-
-#endif
+#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
+#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
#ifndef FEATURE_PAL
#define JIT_Stelem_Ref JIT_Stelem_Ref
diff --git a/src/vm/arm/patchedcode.S b/src/vm/arm/patchedcode.S
index 9335fe65fc..43adca25c8 100644
--- a/src/vm/arm/patchedcode.S
+++ b/src/vm/arm/patchedcode.S
@@ -20,22 +20,6 @@
LEAF_END JIT_PatchedCodeStart, _TEXT
// ------------------------------------------------------------------
-// Optimized TLS getters
-
- LEAF_ENTRY GetTLSDummy, _TEXT
- mov r0, #0
- bx lr
- LEAF_END GetTLSDummy, _TEXT
-
- .align 4
- LEAF_ENTRY ClrFlsGetBlock, _TEXT
- // This will be overwritten at runtime with optimized ClrFlsGetBlock implementation
- b C_FUNC(GetTLSDummy)
- // Just allocate space that will be filled in at runtime
- .space (TLS_GETTER_MAX_SIZE_ASM - 2)
- LEAF_END ClrFlsGetBlock, _TEXT
-
-// ------------------------------------------------------------------
// GC write barrier support.
//
// GC Write barriers are defined in asmhelpers.asm. The following functions are used to define
diff --git a/src/vm/arm/patchedcode.asm b/src/vm/arm/patchedcode.asm
index 9fdd60961d..c7e2322e38 100644
--- a/src/vm/arm/patchedcode.asm
+++ b/src/vm/arm/patchedcode.asm
@@ -13,52 +13,6 @@
#include "asmmacros.h"
- SETALIAS JIT_Box,?JIT_Box@@YAPAVObject@@PAUCORINFO_CLASS_STRUCT_@@PAX@Z
- SETALIAS JIT_New, ?JIT_New@@YAPAVObject@@PAUCORINFO_CLASS_STRUCT_@@@Z
- SETALIAS JIT_Box, ?JIT_Box@@YAPAVObject@@PAUCORINFO_CLASS_STRUCT_@@PAX@Z
- SETALIAS FramedAllocateString, ?FramedAllocateString@@YAPAVStringObject@@K@Z
- SETALIAS g_pStringClass, ?g_pStringClass@@3PAVMethodTable@@A
- SETALIAS JIT_NewArr1, ?JIT_NewArr1@@YAPAVObject@@PAUCORINFO_CLASS_STRUCT_@@H@Z
- SETALIAS CopyValueClassUnchecked, ?CopyValueClassUnchecked@@YAXPAX0PAVMethodTable@@@Z
-
- IMPORT $JIT_New
- IMPORT $JIT_Box
- IMPORT $FramedAllocateString
- IMPORT $g_pStringClass
- IMPORT $JIT_NewArr1
- IMPORT $CopyValueClassUnchecked
- IMPORT SetAppDomainInObject
-
-
- IMPORT JIT_GetSharedNonGCStaticBase_Helper
- IMPORT JIT_GetSharedGCStaticBase_Helper
-
-
- EXPORT JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset
- EXPORT JIT_BoxFastMP_InlineGetThread__PatchTLSOffset
- EXPORT AllocateStringFastMP_InlineGetThread__PatchTLSOffset
- EXPORT JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset
- EXPORT JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset
-
- EXPORT JIT_GetSharedNonGCStaticBase__PatchTLSLabel
- EXPORT JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel
- EXPORT JIT_GetSharedGCStaticBase__PatchTLSLabel
- EXPORT JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel
-
- MACRO
- PATCHABLE_INLINE_GETTHREAD $reg, $label
-$label
- mrc p15, 0, $reg, c13, c0, 2
- ldr $reg, [$reg, #0xe10]
- MEND
-
-
- MACRO
- PATCHABLE_INLINE_GETAPPDOMAIN $reg, $label
-$label
- mrc p15, 0, $reg, c13, c0, 2
- ldr $reg, [$reg, #0xe10]
- MEND
TEXTAREA
@@ -70,38 +24,6 @@ $label
LEAF_END
; ------------------------------------------------------------------
-; Optimized TLS getters
-
- ALIGN 4
- LEAF_ENTRY GetThread
- ; This will be overwritten at runtime with optimized GetThread implementation
- b GetTLSDummy
- ; Just allocate space that will be filled in at runtime
- SPACE (TLS_GETTER_MAX_SIZE_ASM - 2)
- LEAF_END
-
- ALIGN 4
- LEAF_ENTRY GetAppDomain
- ; This will be overwritten at runtime with optimized GetThread implementation
- b GetTLSDummy
- ; Just allocate space that will be filled in at runtime
- SPACE (TLS_GETTER_MAX_SIZE_ASM - 2)
- LEAF_END
-
- LEAF_ENTRY GetTLSDummy
- mov r0, #0
- bx lr
- LEAF_END
-
- ALIGN 4
- LEAF_ENTRY ClrFlsGetBlock
- ; This will be overwritten at runtime with optimized ClrFlsGetBlock implementation
- b GetTLSDummy
- ; Just allocate space that will be filled in at runtime
- SPACE (TLS_GETTER_MAX_SIZE_ASM - 2)
- LEAF_END
-
-; ------------------------------------------------------------------
; GC write barrier support.
;
; GC Write barriers are defined in asmhelpers.asm. The following functions are used to define
@@ -134,443 +56,6 @@ $label
bx lr
LEAF_END
-; JIT Allocation helpers when TLS Index for Thread is low enough for fast helpers
-
-;---------------------------------------------------------------------------
-; IN: r0: MethodTable*
-;; OUT: r0: new object
-
- LEAF_ENTRY JIT_TrialAllocSFastMP_InlineGetThread
-
- ;get object size
- ldr r1, [r0, #MethodTable__m_BaseSize]
-
- ; m_BaseSize is guaranteed to be a multiple of 4.
-
- ;getThread
- PATCHABLE_INLINE_GETTHREAD r12, JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset
-
- ;load current allocation pointers
- ldr r2, [r12, #Thread__m_alloc_context__alloc_limit]
- ldr r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;add object size to current pointer
- add r1, r3
-
- ;if beyond the limit call c++ method
- cmp r1, r2
- bhi AllocFailed
-
- ;r1 is the new alloc_ptr and r3 has object address
- ;update the alloc_ptr in Thread
- str r1, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;write methodTable in object
- str r0, [r3]
-
- ;return object in r0
- mov r0, r3
-
-#ifdef _DEBUG
- ; Tail call to a helper that will set the current AppDomain index into the object header and then
- ; return the object pointer back to our original caller.
- b SetAppDomainInObject
-#else
- ;return
- bx lr
-#endif
-
-AllocFailed
- b $JIT_New
- LEAF_END
-
-
-;---------------------------------------------------------------------------
-; HCIMPL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* unboxedData)
-; IN: r0: MethodTable*
-; IN: r1: data pointer
-;; OUT: r0: new object
-
- LEAF_ENTRY JIT_BoxFastMP_InlineGetThread
-
- ldr r2, [r0, #MethodTable__m_pWriteableData]
-
- ;Check whether the class has been initialized
- ldr r2, [r2, #MethodTableWriteableData__m_dwFlags]
- cmp r2, #MethodTableWriteableData__enum_flag_Unrestored
- bne ClassNotInited
-
- ; Check whether the object contains pointers
- ldr r3, [r0, #MethodTable__m_dwFlags]
- cmp r3, #MethodTable__enum_flag_ContainsPointers
- bne ContainsPointers
-
- ldr r2, [r0, #MethodTable__m_BaseSize]
-
- ;m_BaseSize is guranteed to be a multiple of 4
-
- ;GetThread
- PATCHABLE_INLINE_GETTHREAD r12, JIT_BoxFastMP_InlineGetThread__PatchTLSOffset
-
- ldr r3, [r12, #Thread__m_alloc_context__alloc_ptr]
- add r3, r2
-
- ldr r2, [r12, #Thread__m_alloc_context__alloc_limit]
-
- cmp r3, r2
- bhi AllocFailed2
-
- ldr r2, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;advance alloc_ptr in Thread
- str r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;write methodtable* in the object
- str r0, [r2]
-
- ;copy the contents of value type in the object
-
- ldr r3, [r0, #MethodTable__m_BaseSize]
- sub r3, #0xc
-
- ;r3 = no of bytes to copy
-
- ;move address of object to return register
- mov r0, r2
-
- ;advance r2 to skip methodtable location
- add r2, #4
-
-CopyLoop
- ldr r12, [r1, r3]
- str r12, [r2, r3]
- sub r3, #4
- bne CopyLoop
-
-#ifdef _DEBUG
- ; Tail call to a helper that will set the current AppDomain index into the object header and then
- ; return the object pointer back to our original caller.
- b SetAppDomainInObject
-#else
- ;return
- bx lr
-#endif
-
-ContainsPointers
-ClassNotInited
-AllocFailed2
- b $JIT_Box
- LEAF_END
-
-
-;---------------------------------------------------------------------------
-; IN: r0: number of characters to allocate
-;; OUT: r0: address of newly allocated string
-
- LEAF_ENTRY AllocateStringFastMP_InlineGetThread
-
- ; Instead of doing elaborate overflow checks, we just limit the number of elements to
- ; MAX_FAST_ALLOCATE_STRING_SIZE. This is picked (in asmconstants.h) to avoid any possibility of
- ; overflow and to ensure we never try to allocate anything here that really should go on the large
- ; object heap instead. Additionally the size has been selected so that it will encode into an
- ; immediate in a single cmp instruction.
-
- cmp r0, #MAX_FAST_ALLOCATE_STRING_SIZE
- bhs OversizedString
-
- ; Calculate total string size: Align(base size + (characters * 2), 4).
- mov r1, #(SIZEOF__BaseStringObject + 3) ; r1 == string base size + 3 for alignment round up
- add r1, r1, r0, lsl #1 ; r1 += characters * 2
- bic r1, r1, #3 ; r1 &= ~3; round size to multiple of 4
-
- ;GetThread
- PATCHABLE_INLINE_GETTHREAD r12, AllocateStringFastMP_InlineGetThread__PatchTLSOffset
- ldr r2, [r12, #Thread__m_alloc_context__alloc_limit]
- ldr r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- add r1, r3
- cmp r1, r2
- bhi AllocFailed3
-
- ;can allocate
-
- ;advance alloc_ptr
- str r1, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ; Write MethodTable pointer into new object.
- ldr r1, =$g_pStringClass
- ldr r1, [r1]
- str r1, [r3]
-
- ; Write string length into new object.
- str r0, [r3, #StringObject__m_StringLength]
-
- ;prepare to return new object address
- mov r0, r3
-
-#ifdef _DEBUG
- ; Tail call to a helper that will set the current AppDomain index into the object header and then
- ; return the object pointer back to our original caller.
- b SetAppDomainInObject
-#else
- ;return
- bx lr
-#endif
-
-
-OversizedString
-AllocFailed3
- b $FramedAllocateString
-
- LEAF_END
-
-
-; HCIMPL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
-;---------------------------------------------------------------------------
-; IN: r0: a (shared) array method table, which contains the element type.
-; IN: r1: number of array elements
-;; OUT: r0: address of newly allocated object
-
- LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread
-
- ; Do a conservative check here for number of elements.
- ; This is to avoid overflow while doing the calculations. We don't
- ; have to worry about "large" objects, since the allocation quantum is never big enough for
- ; LARGE_OBJECT_SIZE.
-
- ; For Value Classes, this needs to be < (max_value_in_4byte - size_of_base_array)/(max_size_of_each_element)
- ; This evaluates to (2^32-1 - 0xc)/2^16
-
- ; Additionally the constant has been chosen such that it can be encoded in a
- ; single Thumb2 CMP instruction.
-
- cmp r1, #MAX_FAST_ALLOCATE_ARRAY_VC_SIZE
- bhs OverSizedArray3
-
- ;get element size - stored in low 16bits of m_dwFlags
- ldrh r12, [r0, #MethodTable__m_dwFlags]
-
- ; getting size of object to allocate
-
- ; multiply number of elements with size of each element
- mul r2, r12, r1
-
- ; add the base array size and 3 to align total bytes at 4 byte boundary
- add r2, r2, #SIZEOF__ArrayOfValueType + 3
- bic r2, #3
-
- ;GetThread
- PATCHABLE_INLINE_GETTHREAD r12, JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset
- ldr r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- add r3, r2
-
- ldr r2, [r12, #Thread__m_alloc_context__alloc_limit]
-
- cmp r3, r2
- bhi AllocFailed6
-
- ; can allocate
-
- ;r2 = address of new object
- ldr r2, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;update pointer in allocation context
- str r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;store number of elements
- str r1, [r2, #ArrayBase__m_NumComponents]
-
- ;store methodtable
- str r0, [r2]
-
- ;copy return value
- mov r0, r2
-
-#ifdef _DEBUG
- ; Tail call to a helper that will set the current AppDomain index into the object header and then
- ; return the object pointer back to our original caller.
- b SetAppDomainInObject
-#else
- ;return
- bx lr
-#endif
-
-
-
-AllocFailed6
-OverSizedArray3
- b $JIT_NewArr1
-
- LEAF_END
-
-
-
-; HCIMPL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
-;---------------------------------------------------------------------------
-; IN: r0: a (shared) array method table, which contains the element type.
-; IN: r1: number of array elements
-;; OUT: r0: address of newly allocated object
-
- LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread
-
- cmp r1, #MAX_FAST_ALLOCATE_ARRAY_OBJECTREF_SIZE
- bhs OverSizedArray
-
- mov r2, #SIZEOF__ArrayOfObjectRef
- add r2, r2, r1, lsl #2
-
- ;r2 will be a multiple of 4
-
-
- ;GetThread
- PATCHABLE_INLINE_GETTHREAD r12, JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset
- ldr r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- add r3, r2
-
- ldr r2, [r12, #Thread__m_alloc_context__alloc_limit]
-
- cmp r3, r2
- bhi AllocFailed4
-
- ;can allocate
-
- ;r2 = address of new object
- ldr r2, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;update pointer in allocation context
- str r3, [r12, #Thread__m_alloc_context__alloc_ptr]
-
- ;store number of elements
- str r1, [r2, #ArrayBase__m_NumComponents]
-
- ;store methodtable
- str r0, [r2]
-
- ;copy return value
- mov r0, r2
-
-#ifdef _DEBUG
- ; Tail call to a helper that will set the current AppDomain index into the object header and then
- ; return the object pointer back to our original caller.
- b SetAppDomainInObject
-#else
- ;return
- bx lr
-#endif
-
-OverSizedArray
-AllocFailed4
- b $JIT_NewArr1
- LEAF_END
-
-;
-; JIT Static access helpers when TLS Index for AppDomain is low enough for fast helpers
-;
-
-; ------------------------------------------------------------------
-; void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
-
- LEAF_ENTRY JIT_GetSharedNonGCStaticBase_InlineGetAppDomain
- ; Check if r0 (moduleDomainID) is not a moduleID
- tst r0, #1
- beq HaveLocalModule1
-
- PATCHABLE_INLINE_GETAPPDOMAIN r2, JIT_GetSharedNonGCStaticBase__PatchTLSLabel
-
- ; Get the LocalModule, r0 will always be odd, so: r0 * 2 - 2 <=> (r0 >> 1) * 4
- ldr r2, [r2 , #AppDomain__m_sDomainLocalBlock + DomainLocalBlock__m_pModuleSlots]
- add r2, r2, r0, LSL #1
- ldr r0, [r2, #-2]
-
-HaveLocalModule1
- ; If class is not initialized, bail to C++ helper
- add r2, r0, #DomainLocalModule__m_pDataBlob
- ldrb r2, [r2, r1]
- tst r2, #1
- beq CallHelper1
-
- bx lr
-
-CallHelper1
- ; Tail call JIT_GetSharedNonGCStaticBase_Helper
- b JIT_GetSharedNonGCStaticBase_Helper
- LEAF_END
-
-
-; ------------------------------------------------------------------
-; void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
-
- LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_InlineGetAppDomain
- ; Check if r0 (moduleDomainID) is not a moduleID
- tst r0, #1
- beq HaveLocalModule2
-
- PATCHABLE_INLINE_GETAPPDOMAIN r2, JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel
-
- ; Get the LocalModule, r0 will always be odd, so: r0 * 2 - 2 <=> (r0 >> 1) * 4
- ldr r2, [r2 , #AppDomain__m_sDomainLocalBlock + DomainLocalBlock__m_pModuleSlots]
- add r2, r2, r0, LSL #1
- ldr r0, [r2, #-2]
-
-
-HaveLocalModule2
- bx lr
- LEAF_END
-
-
-; ------------------------------------------------------------------
-; void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID)
-
- LEAF_ENTRY JIT_GetSharedGCStaticBase_InlineGetAppDomain
- ; Check if r0 (moduleDomainID) is not a moduleID
- tst r0, #1
- beq HaveLocalModule3
-
- PATCHABLE_INLINE_GETAPPDOMAIN r2, JIT_GetSharedGCStaticBase__PatchTLSLabel
-
- ; Get the LocalModule, r0 will always be odd, so: r0 * 2 - 2 <=> (r0 >> 1) * 4
- ldr r2, [r2 , #AppDomain__m_sDomainLocalBlock + DomainLocalBlock__m_pModuleSlots]
- add r2, r2, r0, LSL #1
- ldr r0, [r2, #-2]
-
-HaveLocalModule3
- ; If class is not initialized, bail to C++ helper
- add r2, r0, #DomainLocalModule__m_pDataBlob
- ldrb r2, [r2, r1]
- tst r2, #1
- beq CallHelper3
-
- ldr r0, [r0, #DomainLocalModule__m_pGCStatics]
- bx lr
-
-CallHelper3
- ; Tail call Jit_GetSharedGCStaticBase_Helper
- b JIT_GetSharedGCStaticBase_Helper
- LEAF_END
-
-
-; ------------------------------------------------------------------
-; void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID)
-
- LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_InlineGetAppDomain
- ; Check if r0 (moduleDomainID) is not a moduleID
- tst r0, #1
- beq HaveLocalModule4
-
- PATCHABLE_INLINE_GETAPPDOMAIN r2, JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel
-
- ; Get the LocalModule, r0 will always be odd, so: r0 * 2 - 2 <=> (r0 >> 1) * 4
- ldr r2, [r2 , #AppDomain__m_sDomainLocalBlock + DomainLocalBlock__m_pModuleSlots]
- add r2, r2, r0, LSL #1
- ldr r0, [r2, #-2]
-
-HaveLocalModule4
- ldr r0, [r0, #DomainLocalModule__m_pGCStatics]
- bx lr
- LEAF_END
-
; ------------------------------------------------------------------
; End of the writeable code region
LEAF_ENTRY JIT_PatchedCodeLast
diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
index 4bc1b2c1ea..f2500c302e 100644
--- a/src/vm/arm/stubs.cpp
+++ b/src/vm/arm/stubs.cpp
@@ -442,15 +442,9 @@ void UpdateGCWriteBarriers(bool postGrow = false)
pDesc++;
}
-
- // We've changed code so we must flush the instruction cache.
- BYTE *pbAlteredRange;
- DWORD cbAlteredRange;
- ComputeWriteBarrierRange(&pbAlteredRange, &cbAlteredRange);
- FlushInstructionCache(GetCurrentProcess(), pbAlteredRange, cbAlteredRange);
}
-void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
{
// The runtime is not always suspended when this is called (unlike StompWriteBarrierEphemeral) but we have
// no way to update the barrier code atomically on ARM since each 32-bit value we change is loaded over
@@ -462,26 +456,36 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
// suspend/resuming the EE under GC stress will trigger a GC and if we're holding the
// GC lock due to allocating a LOH segment it will cause a deadlock so disable it here.
GCStressPolicy::InhibitHolder iholder;
+ int stompWBCompleteActions = SWB_ICACHE_FLUSH;
- bool fSuspended = false;
if (!isRuntimeSuspended)
{
ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_OTHER);
- fSuspended = true;
+ stompWBCompleteActions |= SWB_EE_RESTART;
}
UpdateGCWriteBarriers(bReqUpperBoundsCheck);
- if (fSuspended)
- ThreadSuspend::RestartEE(FALSE, TRUE);
+ return stompWBCompleteActions;
}
-void StompWriteBarrierEphemeral(bool isRuntimeSuspended)
+int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
{
UNREFERENCED_PARAMETER(isRuntimeSuspended);
_ASSERTE(isRuntimeSuspended);
UpdateGCWriteBarriers();
+ return SWB_ICACHE_FLUSH;
+}
+
+void FlushWriteBarrierInstructionCache()
+{
+ // We've changed code so we must flush the instruction cache.
+ BYTE *pbAlteredRange;
+ DWORD cbAlteredRange;
+ ComputeWriteBarrierRange(&pbAlteredRange, &cbAlteredRange);
+ FlushInstructionCache(GetCurrentProcess(), pbAlteredRange, cbAlteredRange);
}
+
#endif // CROSSGEN_COMPILE
#endif // !DACCESS_COMPILE
@@ -1399,30 +1403,21 @@ Stub *GenerateInitPInvokeFrameHelper()
ThumbReg regThread = ThumbReg(5);
ThumbReg regScratch = ThumbReg(6);
-#ifdef FEATURE_IMPLICIT_TLS
- TLSACCESSMODE mode = TLSACCESS_GENERIC;
-#else
- TLSACCESSMODE mode = GetTLSAccessMode(GetThreadTLSIndex());
-#endif
+#ifdef FEATURE_PAL
+ // Erect frame to perform call to GetThread
+ psl->ThumbEmitProlog(1, sizeof(ArgumentRegisters), FALSE); // Save r4 for aligned stack
+ // Save argument registers around the GetThread call. Don't bother with using ldm/stm since this inefficient path anyway.
+ for (int reg = 0; reg < 4; reg++)
+ psl->ThumbEmitStoreRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r[reg]));
+#endif
- if (mode == TLSACCESS_GENERIC)
- {
- // Erect frame to perform call to GetThread
- psl->ThumbEmitProlog(1, sizeof(ArgumentRegisters), FALSE); // Save r4 for aligned stack
-
- // Save argument registers around the GetThread call. Don't bother with using ldm/stm since this inefficient path anyway.
- for (int reg = 0; reg < 4; reg++)
- psl->ThumbEmitStoreRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r[reg]));
- }
-
- psl->ThumbEmitGetThread(mode, regThread);
+ psl->ThumbEmitGetThread(regThread);
- if (mode == TLSACCESS_GENERIC)
- {
- for (int reg = 0; reg < 4; reg++)
- psl->ThumbEmitLoadRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r[reg]));
- }
+#ifdef FEATURE_PAL
+ for (int reg = 0; reg < 4; reg++)
+ psl->ThumbEmitLoadRegIndirect(ThumbReg(reg), thumbRegSp, offsetof(ArgumentRegisters, r[reg]));
+#endif
// mov [regFrame + FrameInfo.offsetOfGSCookie], GetProcessGSCookie()
psl->ThumbEmitMovConstant(regScratch, GetProcessGSCookie());
@@ -1444,82 +1439,36 @@ Stub *GenerateInitPInvokeFrameHelper()
psl->ThumbEmitMovConstant(regScratch, 0);
psl->ThumbEmitStoreRegIndirect(regScratch, regFrame, FrameInfo.offsetOfReturnAddress - negSpace);
- if (mode == TLSACCESS_GENERIC)
- {
- DWORD cbSavedRegs = sizeof(ArgumentRegisters) + 2 * 4; // r0-r3, r4, lr
- psl->ThumbEmitAdd(regScratch, thumbRegSp, cbSavedRegs);
- psl->ThumbEmitStoreRegIndirect(regScratch, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
- }
- else
- {
- // str SP, [regFrame + FrameInfo.offsetOfCallSiteSP]
- psl->ThumbEmitStoreRegIndirect(thumbRegSp, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
- }
+#ifdef FEATURE_PAL
+ DWORD cbSavedRegs = sizeof(ArgumentRegisters) + 2 * 4; // r0-r3, r4, lr
+ psl->ThumbEmitAdd(regScratch, thumbRegSp, cbSavedRegs);
+ psl->ThumbEmitStoreRegIndirect(regScratch, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
+#else
+ // str SP, [regFrame + FrameInfo.offsetOfCallSiteSP]
+ psl->ThumbEmitStoreRegIndirect(thumbRegSp, regFrame, FrameInfo.offsetOfCallSiteSP - negSpace);
+#endif
// mov [regThread + offsetof(Thread, m_pFrame)], regFrame
psl->ThumbEmitStoreRegIndirect(regFrame, regThread, offsetof(Thread, m_pFrame));
// leave current Thread in R4
- if (mode == TLSACCESS_GENERIC)
- {
- psl->ThumbEmitEpilog();
- }
- else
- {
- // Return. The return address has been restored into LR at this point.
- // bx lr
- psl->ThumbEmitJumpRegister(thumbRegLr);
- }
+#ifdef FEATURE_PAL
+ psl->ThumbEmitEpilog();
+#else
+ // Return. The return address has been restored into LR at this point.
+ // bx lr
+ psl->ThumbEmitJumpRegister(thumbRegLr);
+#endif
// A single process-wide stub that will never unload
RETURN psl->Link(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap());
}
-void StubLinkerCPU::ThumbEmitGetThread(TLSACCESSMODE mode, ThumbReg dest)
+void StubLinkerCPU::ThumbEmitGetThread(ThumbReg dest)
{
-#ifndef FEATURE_IMPLICIT_TLS
- DWORD idxThread = GetThreadTLSIndex();
+#ifdef FEATURE_PAL
- if (mode != TLSACCESS_GENERIC)
- {
- // mrc p15, 0, dest, c13, c0, 2
- Emit16(0xee1d);
- Emit16((WORD)(0x0f50 | (dest << 12)));
-
- if (mode == TLSACCESS_WNT)
- {
- // ldr dest, [dest, #(WINNT_TLS_OFFSET + (idxThread * sizeof(void*)))]
- ThumbEmitLoadRegIndirect(dest, dest, offsetof(TEB, TlsSlots) + (idxThread * sizeof(void*)));
- }
- else
- {
- _ASSERTE(mode == TLSACCESS_WNT_HIGH);
-
- // ldr dest, [dest, #WINNT5_TLSEXPANSIONPTR_OFFSET]
- ThumbEmitLoadRegIndirect(dest, dest, offsetof(TEB, TlsExpansionSlots));
-
- // ldr dest, [dest + #(idxThread * 4)]
- ThumbEmitLoadRegIndirect(dest, dest, (idxThread - TLS_MINIMUM_AVAILABLE) * sizeof(void*));
- }
- }
- else
- {
- ThumbEmitMovConstant(ThumbReg(0), idxThread);
-
-#pragma push_macro("TlsGetValue")
-#undef TlsGetValue
- ThumbEmitMovConstant(ThumbReg(1), (TADDR)TlsGetValue);
-#pragma pop_macro("TlsGetValue")
-
- ThumbEmitCallRegister(ThumbReg(1));
-
- if (dest != ThumbReg(0))
- {
- ThumbEmitMovRegReg(dest, ThumbReg(0));
- }
- }
-#else
ThumbEmitMovConstant(ThumbReg(0), (TADDR)GetThread);
ThumbEmitCallRegister(ThumbReg(0));
@@ -1528,7 +1477,20 @@ void StubLinkerCPU::ThumbEmitGetThread(TLSACCESSMODE mode, ThumbReg dest)
{
ThumbEmitMovRegReg(dest, ThumbReg(0));
}
-#endif
+
+#else // FEATURE_PAL
+
+ // mrc p15, 0, dest, c13, c0, 2
+ Emit16(0xee1d);
+ Emit16((WORD)(0x0f50 | (dest << 12)));
+
+ ThumbEmitLoadRegIndirect(dest, dest, offsetof(TEB, ThreadLocalStoragePointer));
+
+ ThumbEmitLoadRegIndirect(dest, dest, sizeof(void *) * (g_TlsIndex & 0xFFFF));
+
+ ThumbEmitLoadRegIndirect(dest, dest, (g_TlsIndex & 0x7FFF0000) >> 16);
+
+#endif // FEATURE_PAL
}
#endif // CROSSGEN_COMPILE
@@ -2533,110 +2495,12 @@ void UMEntryThunkCode::Poison()
#ifndef CROSSGEN_COMPILE
-
-EXTERN_C DWORD gThreadTLSIndex;
-EXTERN_C DWORD gAppDomainTLSIndex;
-
-
-EXTERN_C Object* JIT_TrialAllocSFastMP_InlineGetThread(CORINFO_CLASS_HANDLE typeHnd_);
-EXTERN_C Object* JIT_BoxFastMP_InlineGetThread (CORINFO_CLASS_HANDLE type, void* unboxedData);
-EXTERN_C Object* AllocateStringFastMP_InlineGetThread (CLR_I4 cch);
-EXTERN_C Object* JIT_NewArr1OBJ_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
-EXTERN_C Object* JIT_NewArr1VC_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
-
-EXTERN_C void JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_BoxFastMP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void AllocateStringFastMP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset();
-
extern "C" void STDCALL JIT_PatchedCodeStart();
extern "C" void STDCALL JIT_PatchedCodeLast();
-#ifndef FEATURE_IMPLICIT_TLS
-static const LPVOID InlineGetThreadLocations[] = {
- (PVOID)JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_BoxFastMP_InlineGetThread__PatchTLSOffset,
- (PVOID)AllocateStringFastMP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset,
-};
-#endif
-
-//EXTERN_C Object* JIT_TrialAllocSFastMP(CORINFO_CLASS_HANDLE typeHnd_);
-Object* JIT_TrialAllocSFastMP(CORINFO_CLASS_HANDLE typeHnd_);
-EXTERN_C Object* JIT_NewArr1OBJ_MP(CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
-EXTERN_C Object* AllocateStringFastMP(CLR_I4 cch);
-EXTERN_C Object* JIT_NewArr1VC_MP(CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
-EXTERN_C Object* JIT_BoxFastMP(CORINFO_CLASS_HANDLE type, void* unboxedData);
-
-
-EXTERN_C void JIT_GetSharedNonGCStaticBase__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedGCStaticBase__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel();
-
-EXTERN_C void JIT_GetSharedNonGCStaticBase_SingleAppDomain();
-EXTERN_C void JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain();
-EXTERN_C void JIT_GetSharedGCStaticBase_SingleAppDomain();
-EXTERN_C void JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain();
-
-
-static const LPVOID InlineGetAppDomainLocations[] = {
- (PVOID)JIT_GetSharedNonGCStaticBase__PatchTLSLabel,
- (PVOID)JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel,
- (PVOID)JIT_GetSharedGCStaticBase__PatchTLSLabel,
- (PVOID)JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel
-};
-
-#ifndef FEATURE_IMPLICIT_TLS
-void FixupInlineGetters(DWORD tlsSlot, const LPVOID * pLocations, int nLocations)
-{
- STANDARD_VM_CONTRACT;
-
- for (int i=0; i<nLocations; i++)
- {
- BYTE * pInlineGetter = (BYTE *)PCODEToPINSTR(GetEEFuncEntryPoint(pLocations[i]));
-
- DWORD offset = (tlsSlot * sizeof(LPVOID) + offsetof(TEB, TlsSlots));
-
- // ldr r??, [r??, #offset]
- _ASSERTE_ALL_BUILDS("clr/src/VM/arm/stubs.cpp",
- pInlineGetter[0] == 0x1d &&
- pInlineGetter[1] == 0xee &&
- pInlineGetter[2] == 0x50 &&
- pInlineGetter[5] == 0xf8 &&
- "Initialization failure while stomping instructions for the TLS slot offset: "
- "the instruction at the given offset did not match what we expect");
-
- *((WORD*)(pInlineGetter + 6)) &= 0xf000;
-
- _ASSERTE(offset <=4095);
- *((WORD*)(pInlineGetter + 6)) |= (WORD)offset;
- }
-}
-#endif
-
void InitJITHelpers1()
{
STANDARD_VM_CONTRACT;
-
-#ifndef FEATURE_IMPLICIT_TLS
-
- if (gThreadTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- FixupInlineGetters(gThreadTLSIndex, InlineGetThreadLocations, COUNTOF(InlineGetThreadLocations));
- }
-
- if (gAppDomainTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- FixupInlineGetters(gAppDomainTLSIndex, InlineGetAppDomainLocations, COUNTOF(InlineGetAppDomainLocations));
- }
-
- if(gThreadTLSIndex < TLS_MINIMUM_AVAILABLE || gAppDomainTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- FlushInstructionCache(GetCurrentProcess(), JIT_PatchedCodeStart, (BYTE*)JIT_PatchedCodeLast - (BYTE*)JIT_PatchedCodeStart);
- }
#if CHECK_APP_DOMAIN_LEAKS
if(g_pConfig->AppDomainLeaks())
@@ -2651,54 +2515,14 @@ void InitJITHelpers1()
#endif // _DEBUG
))
{
-
_ASSERTE(GCHeapUtilities::UseThreadAllocationContexts());
- // If the TLS for Thread is low enough use the super-fast helpers
- if (gThreadTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastMP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastMP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_InlineGetThread);
- ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP_InlineGetThread), ECall::FastAllocateString);
- }
- else
- {
-/*
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastMP);
- SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastMP);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP);
+ SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
- ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP), ECall::FastAllocateString);
-*/
- }
+ ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
}
-
-
- if(IsSingleAppDomain())
- {
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain);
- }
- else
- if (gAppDomainTLSIndex >= TLS_MINIMUM_AVAILABLE)
- {
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_Portable);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_Portable);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_Portable);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_Portable);
- }
-#endif
-}
-
-extern "C" Object *SetAppDomainInObject(Object *pObject)
-{
- pObject->SetAppDomain();
- return pObject;
}
// +64 stack-based arguments here
@@ -3037,19 +2861,13 @@ void StubLinkerCPU::EmitStubLinkFrame(TADDR pFrameVptr, int offsetOfFrame, int o
// str r6, [r4 + #offsetof(MulticastFrame, m_Next)]
// str r4, [r5 + #offsetof(Thread, m_pFrame)]
-#ifdef FEATURE_IMPLICIT_TLS
- TLSACCESSMODE mode = TLSACCESS_GENERIC;
-#else
- TLSACCESSMODE mode = GetTLSAccessMode(GetThreadTLSIndex());
+ ThumbEmitGetThread(ThumbReg(5));
+#ifdef FEATURE_PAL
+ // reload argument registers that could have been corrupted by the call
+ for (int reg = 0; reg < 4; reg++)
+ ThumbEmitLoadRegIndirect(ThumbReg(reg), ThumbReg(4),
+ offsetOfTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters() + offsetof(ArgumentRegisters, r[reg]));
#endif
- ThumbEmitGetThread(mode, ThumbReg(5));
- if (mode == TLSACCESS_GENERIC)
- {
- // reload argument registers that could have been corrupted by the call
- for (int reg = 0; reg < 4; reg++)
- ThumbEmitLoadRegIndirect(ThumbReg(reg), ThumbReg(4),
- offsetOfTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters() + offsetof(ArgumentRegisters, r[reg]));
- }
ThumbEmitLoadRegIndirect(ThumbReg(6), ThumbReg(5), Thread::GetOffsetOfCurrentFrame());
ThumbEmitStoreRegIndirect(ThumbReg(6), ThumbReg(4), Frame::GetOffsetOfNextLink());
@@ -3782,16 +3600,121 @@ PCODE DynamicHelpers::CreateDictionaryLookupHelper(LoaderAllocator * pAllocator,
pArgs->module = (CORINFO_MODULE_HANDLE)pModule;
// It's available only via the run-time helper function,
- // since optimization cases are not yet implemented.
- assert(pLookup->indirections == CORINFO_USEHELPER);
- BEGIN_DYNAMIC_HELPER_EMIT(18);
+ if (pLookup->indirections == CORINFO_USEHELPER)
+ {
+ BEGIN_DYNAMIC_HELPER_EMIT(18);
- EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
- END_DYNAMIC_HELPER_EMIT();
+ END_DYNAMIC_HELPER_EMIT();
+ }
+ else
+ {
+ int indirectionsSize = 0;
+ for (WORD i = 0; i < pLookup->indirections; i++)
+ {
+ if ((i == 0 && pLookup->indirectFirstOffset) || (i == 1 && pLookup->indirectSecondOffset))
+ {
+ indirectionsSize += (pLookup->offsets[i] >= 0xFFF ? 10 : 2);
+ indirectionsSize += 4;
+ }
+ else
+ {
+ indirectionsSize += (pLookup->offsets[i] >= 0xFFF ? 10 : 4);
+ }
+ }
+
+ int codeSize = indirectionsSize + (pLookup->testForNull ? 26 : 2);
+
+ BEGIN_DYNAMIC_HELPER_EMIT(codeSize);
- // @TODO : Additional implementation is required for optimization cases.
+ if (pLookup->testForNull)
+ {
+ // mov r3, r0
+ *(WORD *)p = 0x4603;
+ p += 2;
+ }
+
+ for (WORD i = 0; i < pLookup->indirections; i++)
+ {
+ if ((i == 0 && pLookup->indirectFirstOffset) || (i == 1 && pLookup->indirectSecondOffset))
+ {
+ if (pLookup->offsets[i] >= 0xFF)
+ {
+ // mov r2, offset
+ MovRegImm(p, 2, pLookup->offsets[i]);
+ p += 8;
+
+ // add r0, r2
+ *(WORD *)p = 0x4410;
+ p += 2;
+ }
+ else
+ {
+ // add r0, <offset>
+ *(WORD *)p = (WORD)((WORD)0x3000 | (WORD)((0x00FF) & pLookup->offsets[i]));
+ p += 2;
+ }
+
+ // r0 is pointer + offset[0]
+ // ldr r2, [r0]
+ *(WORD *)p = 0x6802;
+ p += 2;
+
+ // r2 is offset1
+ // add r0, r2
+ *(WORD *)p = 0x4410;
+ p += 2;
+ }
+ else
+ {
+ if (pLookup->offsets[i] >= 0xFFF)
+ {
+ // mov r2, offset
+ MovRegImm(p, 2, pLookup->offsets[i]);
+ p += 8;
+
+ // ldr r0, [r0, r2]
+ *(WORD *)p = 0x5880;
+ p += 2;
+ }
+ else
+ {
+ // ldr r0, [r0 + offset]
+ *(WORD *)p = 0xF8D0;
+ p += 2;
+ *(WORD *)p = (WORD)(0xFFF & pLookup->offsets[i]);
+ p += 2;
+ }
+ }
+ }
+
+ // No null test required
+ if (!pLookup->testForNull)
+ {
+ // mov pc, lr
+ *(WORD *)p = 0x46F7;
+ p += 2;
+ }
+ else
+ {
+ // cbz r0, nullvaluelabel
+ *(WORD *)p = 0xB100;
+ p += 2;
+ // mov pc, lr
+ *(WORD *)p = 0x46F7;
+ p += 2;
+ // nullvaluelabel:
+ // mov r0, r3
+ *(WORD *)p = 0x4618;
+ p += 2;
+
+ EmitHelperWithArg(p, pAllocator, (TADDR)pArgs, helperAddress);
+ }
+
+ END_DYNAMIC_HELPER_EMIT();
+ }
}
#endif // FEATURE_READYTORUN
diff --git a/src/vm/arm/unixstubs.cpp b/src/vm/arm/unixstubs.cpp
index 62f60473ab..b1462fab3a 100644
--- a/src/vm/arm/unixstubs.cpp
+++ b/src/vm/arm/unixstubs.cpp
@@ -15,9 +15,4 @@ extern "C"
{
PORTABILITY_ASSERT("Implement for PAL");
}
-
- void ProfileTailcallNaked(FunctionIDOrClientID functionIDOrClientID)
- {
- PORTABILITY_ASSERT("Implement for PAL");
- }
};
diff --git a/src/vm/arm64/cgencpu.h b/src/vm/arm64/cgencpu.h
index 8abe4de6ab..a168cdc162 100644
--- a/src/vm/arm64/cgencpu.h
+++ b/src/vm/arm64/cgencpu.h
@@ -84,7 +84,11 @@ typedef INT64 StackElemType;
//
// Create alias for optimized implementations of helpers provided on this platform
//
-// optimized static helpers
+#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain
+#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain
+#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain
+
#define JIT_Stelem_Ref JIT_Stelem_Ref
//**********************************************************************
@@ -435,10 +439,8 @@ public:
void EmitUnboxMethodStub(MethodDesc* pRealMD);
void EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall);
void EmitCallLabel(CodeLabel *target, BOOL fTailCall, BOOL fIndirect);
- void EmitSecureDelegateInvoke(UINT_PTR hash);
- static UINT_PTR HashMulticastInvoke(MetaSig* pSig);
+
void EmitShuffleThunk(struct ShuffleEntry *pShuffleEntryArray);
- void EmitGetThreadInlined(IntReg Xt);
#ifdef _DEBUG
void EmitNop() { Emit32(0xD503201F); }
diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp
index 7e7c2e8088..3c56c382ea 100644
--- a/src/vm/arm64/stubs.cpp
+++ b/src/vm/arm64/stubs.cpp
@@ -16,10 +16,6 @@
#include "jitinterface.h"
#include "ecall.h"
-EXTERN_C void JIT_GetSharedNonGCStaticBase_SingleAppDomain();
-EXTERN_C void JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain();
-EXTERN_C void JIT_GetSharedGCStaticBase_SingleAppDomain();
-EXTERN_C void JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain();
EXTERN_C void JIT_UpdateWriteBarrierState(bool skipEphemeralCheck);
@@ -1114,14 +1110,6 @@ void InitJITHelpers1()
}
#endif
- if(IsSingleAppDomain())
- {
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain);
- }
-
JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap());
}
#ifndef FEATURE_PAL // TODO-ARM64-WINDOWS #13592
@@ -1348,26 +1336,35 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv)
return EXCEPTION_CONTINUE_SEARCH;
}
+void FlushWriteBarrierInstructionCache()
+{
+ // this wouldn't be called in arm64, just to comply with gchelpers.h
+}
+
#ifndef CROSSGEN_COMPILE
-void StompWriteBarrierEphemeral(bool isRuntimeSuspended)
+int StompWriteBarrierEphemeral(bool isRuntimeSuspended)
{
JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap());
+ return SWB_PASS;
}
-void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
{
JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap());
+ return SWB_PASS;
}
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
-void SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
+int SwitchToWriteWatchBarrier(bool isRuntimeSuspended)
{
JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap());
+ return SWB_PASS;
}
-void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
+int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended)
{
JIT_UpdateWriteBarrierState(GCHeapUtilities::IsServerHeap());
+ return SWB_PASS;
}
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
#endif // CROSSGEN_COMPILE
@@ -1837,33 +1834,6 @@ void StubLinkerCPU::EmitCallManagedMethod(MethodDesc *pMD, BOOL fTailCall)
#ifndef CROSSGEN_COMPILE
-EXTERN_C UINT32 _tls_index;
-void StubLinkerCPU::EmitGetThreadInlined(IntReg Xt)
-{
-#if defined(FEATURE_IMPLICIT_TLS) && !defined(FEATURE_PAL)
- // Trashes x8.
- IntReg X8 = IntReg(8);
- _ASSERTE(Xt != X8);
-
- // Load the _tls_index
- EmitLabelRef(NewExternalCodeLabel((LPVOID)&_tls_index), reinterpret_cast<LoadFromLabelInstructionFormat&>(gLoadFromLabelIF), X8);
-
- // Load Teb->ThreadLocalStoragePointer into x8
- EmitLoadStoreRegImm(eLOAD, Xt, IntReg(18), offsetof(_TEB, ThreadLocalStoragePointer));
-
- // index it with _tls_index, i.e Teb->ThreadLocalStoragePointer[_tls_index].
- // This will give us the TLS section for the module on this thread's context
- EmitLoadRegReg(Xt, Xt, X8, eLSL);
-
- // read the Thread* from TLS section
- EmitAddImm(Xt, Xt, OFFSETOF__TLS__tls_CurrentThread);
- EmitLoadStoreRegImm(eLOAD, Xt, Xt, 0);
-#else
- _ASSERTE(!"NYI:StubLinkerCPU::EmitGetThreadInlined");
-#endif
-
-}
-
void StubLinkerCPU::EmitUnboxMethodStub(MethodDesc *pMD)
{
_ASSERTE(!pMD->RequiresInstMethodDescArg());
diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp
index c64d9e9042..504bf799ac 100644
--- a/src/vm/ceeload.cpp
+++ b/src/vm/ceeload.cpp
@@ -3796,27 +3796,31 @@ ISymUnmanagedReader *Module::GetISymUnmanagedReader(void)
// We've got in-memory ILDB symbols, create the ILDB symbol binder
// Note that in this case, we must be very careful not to use diasymreader.dll
// at all - we don't trust it, and shouldn't run any code in it
- IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS,
- IID_ISymUnmanagedBinder,
- (void**)&pBinder));
+ IfFailThrow(IldbSymbolsCreateInstance(CLSID_CorSymBinder_SxS, IID_ISymUnmanagedBinder, (void**)&pBinder));
}
else
{
- // We're going to be working with PDB format symbols
- // Attempt to coCreate the symbol binder.
- // CoreCLR supports not having a symbol reader installed, so this is expected there.
+ // We're going to be working with Windows PDB format symbols. Attempt to CoCreate the symbol binder.
+ // CoreCLR supports not having a symbol reader installed, so CoCreate searches the PATH env var
+ // and then tries coreclr dll location.
// On desktop, the framework installer is supposed to install diasymreader.dll as well
// and so this shouldn't happen.
- hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS,
- NATIVE_SYMBOL_READER_DLL,
- IID_ISymUnmanagedBinder,
- (void**)&pBinder,
- NULL);
+ hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, NATIVE_SYMBOL_READER_DLL, IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
if (FAILED(hr))
{
- RETURN (NULL);
+ PathString symbolReaderPath;
+ hr = GetHModuleDirectory(GetModuleInst(), symbolReaderPath);
+ if (FAILED(hr))
+ {
+ RETURN (NULL);
+ }
+ symbolReaderPath.Append(NATIVE_SYMBOL_READER_DLL);
+ hr = FakeCoCreateInstanceEx(CLSID_CorSymBinder_SxS, symbolReaderPath.GetUnicode(), IID_ISymUnmanagedBinder, (void**)&pBinder, NULL);
+ if (FAILED(hr))
+ {
+ RETURN (NULL);
+ }
}
-
}
LOG((LF_CORDB, LL_INFO10, "M::GISUR: Created binder\n"));
@@ -10844,11 +10848,7 @@ void Module::LoadTokenTables()
pEEInfo->emptyString = (CORINFO_Object **)StringObject::GetEmptyStringRefPtr();
}
-#ifdef FEATURE_IMPLICIT_TLS
pEEInfo->threadTlsIndex = TLS_OUT_OF_INDEXES;
-#else
- pEEInfo->threadTlsIndex = GetThreadTLSIndex();
-#endif
pEEInfo->rvaStaticTlsIndex = NULL;
#endif // CROSSGEN_COMPILE
}
diff --git a/src/vm/ceeload.h b/src/vm/ceeload.h
index b70ea51feb..62facce0be 100644
--- a/src/vm/ceeload.h
+++ b/src/vm/ceeload.h
@@ -3101,8 +3101,10 @@ public:
static BOOL IsEncodedModuleIndex(SIZE_T ModuleID)
{
LIMITED_METHOD_DAC_CONTRACT;
-
- return (ModuleID&1)==1;
+
+ // We should never see encoded module index in CoreCLR
+ _ASSERTE((ModuleID&1)==0);
+ return FALSE;
}
static SIZE_T IndexToID(ModuleIndex index)
@@ -3553,6 +3555,10 @@ struct VASigCookieEx : public VASigCookie
const BYTE *m_pArgs; // pointer to first unfixed unmanaged arg
};
-bool IsSingleAppDomain();
+inline bool IsSingleAppDomain()
+{
+ // CoreCLR always runs as single AppDomain
+ return true;
+}
#endif // !CEELOAD_H_
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index 011caf0997..f3b72e01e2 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -175,7 +175,6 @@
#include "finalizerthread.h"
#include "threadsuspend.h"
#include "disassembler.h"
-#include "gcenv.ee.h"
#ifndef FEATURE_PAL
#include "dwreport.h"
@@ -234,6 +233,10 @@
#include "process.h"
#endif // !FEATURE_PAL
+#ifdef FEATURE_GDBJIT
+#include "gdbjit.h"
+#endif // FEATURE_GDBJIT
+
#ifdef FEATURE_IPCMAN
static HRESULT InitializeIPCManager(void);
static void PublishIPCManager(void);
@@ -685,6 +688,11 @@ void EEStartupHelper(COINITIEE fFlags)
EventPipe::Initialize();
#endif // FEATURE_PERFTRACING
+#ifdef FEATURE_GDBJIT
+ // Initialize gdbjit
+ NotifyGdb::Initialize();
+#endif // FEATURE_GDBJIT
+
#ifdef FEATURE_EVENT_TRACE
// Initialize event tracing early so we can trace CLR startup time events.
InitializeEventTracing();
@@ -2438,103 +2446,6 @@ BOOL ExecuteDLL_ReturnOrThrow(HRESULT hr, BOOL fFromThunk)
// Initialize the Garbage Collector
//
-// Prototype for the function that initialzes the garbage collector.
-// Should only be called once: here, during EE startup.
-// Returns true if the initialization was successful, false otherwise.
-//
-// When using a standalone GC, this function is loaded dynamically using
-// GetProcAddress.
-extern "C" bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, IGCHandleManager** gcHandleManager, GcDacVars* gcDacVars);
-
-#ifdef FEATURE_STANDALONE_GC
-
-void LoadGarbageCollector()
-{
- CONTRACTL {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- } CONTRACTL_END;
-
- TCHAR *standaloneGc = nullptr;
- CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCStandaloneLocation, &standaloneGc);
- HMODULE hMod;
- if (!standaloneGc)
- {
-#ifdef FEATURE_STANDALONE_GC_ONLY
- // if the user has set GCUseStandalone but has not given us a standalone location,
- // try and load the initialization symbol from the current module.
- hMod = GetModuleInst();
-#else
- ThrowHR(E_FAIL);
-#endif // FEATURE_STANDALONE_GC_ONLY
- }
- else
- {
- hMod = CLRLoadLibrary(standaloneGc);
- }
-
- if (!hMod)
- {
- ThrowHR(E_FAIL);
- }
-
- InitializeGarbageCollectorFunction igcf = (InitializeGarbageCollectorFunction)GetProcAddress(hMod, INITIALIZE_GC_FUNCTION_NAME);
- if (!igcf)
- {
- ThrowHR(E_FAIL);
- }
-
- // at this point we are committing to using the standalone GC
- // given to us.
- IGCToCLR* gcToClr = new (nothrow) standalone::GCToEEInterface();
- if (!gcToClr)
- {
- ThrowOutOfMemory();
- }
-
- IGCHandleManager *pGcHandleManager;
- IGCHeap *pGCHeap;
- if (!igcf(gcToClr, &pGCHeap, &pGcHandleManager, &g_gc_dac_vars))
- {
- ThrowOutOfMemory();
- }
-
- assert(pGCHeap != nullptr);
- assert(pGcHandleManager != nullptr);
- g_pGCHeap = pGCHeap;
- g_pGCHandleManager = pGcHandleManager;
- g_gcDacGlobals = &g_gc_dac_vars;
-}
-
-#endif // FEATURE_STANDALONE_GC
-
-#ifndef FEATURE_STANDALONE_GC_ONLY
-void LoadStaticGarbageCollector()
-{
- CONTRACTL{
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- } CONTRACTL_END;
-
- IGCHandleManager *pGcHandleManager;
- IGCHeap *pGCHeap;
-
- if (!InitializeGarbageCollector(nullptr, &pGCHeap, &pGcHandleManager, &g_gc_dac_vars))
- {
- ThrowOutOfMemory();
- }
-
- assert(pGCHeap != nullptr);
- assert(pGcHandleManager != nullptr);
- g_pGCHeap = pGCHeap;
- g_pGCHandleManager = pGcHandleManager;
- g_gcDacGlobals = &g_gc_dac_vars;
-}
-#endif // FEATURE_STANDALONE_GC_ONLY
-
-
void InitializeGarbageCollector()
{
CONTRACTL{
@@ -2557,21 +2468,10 @@ void InitializeGarbageCollector()
g_pFreeObjectMethodTable->SetBaseSize(ObjSizeOf (ArrayBase));
g_pFreeObjectMethodTable->SetComponentSize(1);
-#ifdef FEATURE_STANDALONE_GC
- if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCUseStandalone)
-#ifdef FEATURE_STANDALONE_GC_ONLY
- || true
-#endif // FEATURE_STANDALONE_GC_ONLY
- )
- {
- LoadGarbageCollector();
- }
- else
-#endif // FEATURE_STANDALONE_GC
+ hr = GCHeapUtilities::LoadAndInitialize();
+ if (hr != S_OK)
{
-#ifndef FEATURE_STANDALONE_GC_ONLY
- LoadStaticGarbageCollector();
-#endif // FEATURE_STANDALONE_GC_ONLY
+ ThrowHR(hr);
}
// Apparently the Windows linker removes global variables if they are never
@@ -2705,17 +2605,7 @@ BOOL STDMETHODCALLTYPE EEDllMain( // TRUE on success, FALSE on error.
, TRUE
#endif
);
-#ifdef FEATURE_IMPLICIT_TLS
Thread* thread = GetThread();
-#else
- // Don't use GetThread because perhaps we didn't initialize yet, or we
- // have already shutdown the EE. Note that there is a race here. We
- // might ask for TLS from a slot we just released. We are assuming that
- // nobody re-allocates that same slot while we are doing this. It just
- // isn't worth locking for such an obscure case.
- DWORD tlsVal = GetThreadTLSIndex();
- Thread *thread = (tlsVal != (DWORD)-1)?(Thread *) UnsafeTlsGetValue(tlsVal):NULL;
-#endif
if (thread)
{
#ifdef FEATURE_COMINTEROP
diff --git a/src/vm/ceemain.h b/src/vm/ceemain.h
index ccf763ac80..9a14af54ca 100644
--- a/src/vm/ceemain.h
+++ b/src/vm/ceemain.h
@@ -83,8 +83,6 @@ public:
// Setup FLS simulation block, including ClrDebugState and StressLog.
static void SetupTLSForThread(Thread *pThread);
- static DWORD GetTlsIndex () {return TlsIndex;}
-
static LPVOID* GetTlsData();
static BOOL SetTlsData (void** ppTlsInfo);
@@ -92,12 +90,6 @@ public:
// private implementation:
//***************************************************************************
private:
-
- // The debugger needs access to the TlsIndex so that we can read it from OOP.
- friend class EEDbgInterfaceImpl;
-
- SVAL_DECL (DWORD, TlsIndex);
-
static PTLS_CALLBACK_FUNCTION Callbacks[MAX_PREDEFINED_TLS_SLOT];
//***************************************************************************
diff --git a/src/vm/clsload.cpp b/src/vm/clsload.cpp
index 22b030caa0..abf96d0425 100644
--- a/src/vm/clsload.cpp
+++ b/src/vm/clsload.cpp
@@ -4928,7 +4928,7 @@ BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, Method
if (m_fThrowIfTargetIsInaccessible)
{
- ThrowAccessException(pContext, pTargetMT, NULL, FALSE);
+ ThrowAccessException(pContext, pTargetMT, NULL);
}
return FALSE;
@@ -4938,7 +4938,7 @@ BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, Method
{
if (m_fThrowIfTargetIsInaccessible)
{
- ThrowAccessException(pContext, pTargetMT, NULL, FALSE);
+ ThrowAccessException(pContext, pTargetMT, NULL);
}
return FALSE;
@@ -4948,8 +4948,6 @@ BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, Method
#ifndef CROSSGEN_COMPILE
- BOOL fAccessingFrameworkCode = FALSE;
-
// In CoreCLR kRestrictedMemberAccess means that one can access private/internal
// classes/members in app code.
if (m_accessCheckType != kMemberAccess && pTargetMT)
@@ -4966,7 +4964,7 @@ BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, Method
// No Access
if (m_fThrowIfTargetIsInaccessible)
{
- ThrowAccessException(pContext, pTargetMT, NULL, fAccessingFrameworkCode);
+ ThrowAccessException(pContext, pTargetMT, NULL);
}
#endif // CROSSGEN_COMPILE
@@ -4982,8 +4980,7 @@ BOOL AccessCheckOptions::DemandMemberAccess(AccessCheckContext *pContext, Method
void AccessCheckOptions::ThrowAccessException(
AccessCheckContext* pContext,
MethodTable* pFailureMT, /* = NULL */
- Exception* pInnerException, /* = NULL */
- BOOL fAccessingFrameworkCode /* = FALSE */) const
+ Exception* pInnerException /* = NULL */) const
{
CONTRACTL
{
@@ -5005,7 +5002,7 @@ void AccessCheckOptions::ThrowAccessException(
// If we know the specific type that caused the failure, display it.
// Else display the whole type that we are trying to access.
MethodTable * pMT = (pFailureMT != NULL) ? pFailureMT : m_pTargetMT;
- ThrowTypeAccessException(pContext, pMT, 0, pInnerException, fAccessingFrameworkCode);
+ ThrowTypeAccessException(pContext, pMT, 0, pInnerException);
}
else if (m_pTargetMethod != NULL)
{
@@ -5018,17 +5015,17 @@ void AccessCheckOptions::ThrowAccessException(
// throwing the standard MethodAccessException.
if (pCallerMD != NULL && m_pTargetMethod == pCallerMD && pFailureMT != NULL)
{
- ThrowTypeAccessException(pContext, pFailureMT, 0, pInnerException, fAccessingFrameworkCode);
+ ThrowTypeAccessException(pContext, pFailureMT, 0, pInnerException);
}
else
{
- ThrowMethodAccessException(pContext, m_pTargetMethod, 0, pInnerException, fAccessingFrameworkCode);
+ ThrowMethodAccessException(pContext, m_pTargetMethod, 0, pInnerException);
}
}
else
{
_ASSERTE(m_pTargetField != NULL);
- ThrowFieldAccessException(pContext, m_pTargetField, 0, pInnerException, fAccessingFrameworkCode);
+ ThrowFieldAccessException(pContext, m_pTargetField, 0, pInnerException);
}
}
@@ -5085,80 +5082,10 @@ BOOL AccessCheckOptions::FailOrThrow(AccessCheckContext *pContext) const
return FALSE;
}
-// Generate access exception context strings that are due to potential security misconfiguration
-void GetAccessExceptionAdditionalContextForSecurity(Assembly *pAccessingAssembly,
- Assembly *pTargetAssembly,
- BOOL fAccessingFrameworkCode,
- StringArrayList *pContextInformation)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pAccessingAssembly));
- PRECONDITION(CheckPointer(pTargetAssembly));
- PRECONDITION(CheckPointer(pContextInformation));
- }
- CONTRACTL_END;
-
- if (fAccessingFrameworkCode)
- {
- SString accessingFrameworkCodeError;
- EEException::GetResourceMessage(IDS_E_ACCESSING_PRIVATE_FRAMEWORK_CODE, accessingFrameworkCodeError);
-
- pContextInformation->Append(accessingFrameworkCodeError);
- }
-
-
-}
-
-// Generate additional context about the root cause of an access exception which may help in debugging it (for
-// instance v4 APTCA implying transparnecy, or conditional APTCA not being enabled). If no additional
-// context is available, then this returns SString.Empty.
-SString GetAdditionalAccessExceptionContext(Assembly *pAccessingAssembly,
- Assembly *pTargetAssembly,
- BOOL fAccessingFrameworkCode)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pAccessingAssembly));
- PRECONDITION(CheckPointer(pTargetAssembly));
- }
- CONTRACTL_END;
-
- StringArrayList contextComponents;
-
- // See if the exception may have been caused by security
- GetAccessExceptionAdditionalContextForSecurity(pAccessingAssembly,
- pTargetAssembly,
- fAccessingFrameworkCode,
- &contextComponents);
-
- // Append each component of additional context we found into the additional context string in its own
- // paragraph.
- SString additionalContext;
- for (DWORD i = 0; i < contextComponents.GetCount(); ++i)
- {
- SString contextComponent = contextComponents.Get(i);
- if (!contextComponent.IsEmpty())
- {
- additionalContext.Append(W("\n\n"));
- additionalContext.Append(contextComponent);
- }
- }
-
- return additionalContext;
-}
-
void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
FieldDesc *pFD,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5175,15 +5102,13 @@ void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
ThrowFieldAccessException(pCallerMD,
pFD,
messageID,
- pInnerException,
- fAccessingFrameworkCode);
+ pInnerException);
}
void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
FieldDesc *pFD,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5202,11 +5127,7 @@ void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
messageID = IDS_E_FIELDACCESS;
}
- SString strAdditionalContext = GetAdditionalAccessExceptionContext(pCallerMD->GetAssembly(),
- pFD->GetApproxEnclosingMethodTable()->GetAssembly(),
- fAccessingFrameworkCode);
-
- EX_THROW_WITH_INNER(EEFieldException, (pFD, pCallerMD, strAdditionalContext, messageID), pInnerException);
+ EX_THROW_WITH_INNER(EEFieldException, (pFD, pCallerMD, SString::Empty(), messageID), pInnerException);
}
else
{
@@ -5217,8 +5138,7 @@ void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc* pCallerMD,
void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
MethodDesc *pCalleeMD,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5235,15 +5155,13 @@ void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
ThrowMethodAccessException(pCallerMD,
pCalleeMD,
messageID,
- pInnerException,
- fAccessingFrameworkCode);
+ pInnerException);
}
void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
MethodDesc *pCalleeMD,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5262,11 +5180,7 @@ void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
messageID = IDS_E_METHODACCESS;
}
- SString strAdditionalContext = GetAdditionalAccessExceptionContext(pCallerMD->GetAssembly(),
- pCalleeMD->GetAssembly(),
- fAccessingFrameworkCode);
-
- EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD, pCallerMD, strAdditionalContext, messageID), pInnerException);
+ EX_THROW_WITH_INNER(EEMethodException, (pCalleeMD, pCallerMD, SString::Empty(), messageID), pInnerException);
}
else
{
@@ -5277,8 +5191,7 @@ void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc* pCallerMD,
void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
MethodTable *pMT,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5295,15 +5208,13 @@ void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
ThrowTypeAccessException(pCallerMD,
pMT,
messageID,
- pInnerException,
- fAccessingFrameworkCode);
+ pInnerException);
}
void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc* pCallerMD,
MethodTable *pMT,
UINT messageID /* = 0 */,
- Exception *pInnerException /* = NULL */,
- BOOL fAccessingFrameworkCode /* = FALSE */)
+ Exception *pInnerException /* = NULL */)
{
CONTRACTL
{
@@ -5322,11 +5233,7 @@ void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc* pCallerMD,
messageID = IDS_E_TYPEACCESS;
}
- SString strAdditionalContext = GetAdditionalAccessExceptionContext(pCallerMD->GetAssembly(),
- pMT->GetAssembly(),
- fAccessingFrameworkCode);
-
- EX_THROW_WITH_INNER(EETypeAccessException, (pMT, pCallerMD, strAdditionalContext, messageID), pInnerException);
+ EX_THROW_WITH_INNER(EETypeAccessException, (pMT, pCallerMD, SString::Empty(), messageID), pInnerException);
}
else
{
diff --git a/src/vm/clsload.hpp b/src/vm/clsload.hpp
index 5a9248e422..9689979123 100644
--- a/src/vm/clsload.hpp
+++ b/src/vm/clsload.hpp
@@ -474,8 +474,7 @@ private:
void ThrowAccessException(
AccessCheckContext* pContext,
MethodTable* pFailureMT = NULL,
- Exception* pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE) const;
+ Exception* pInnerException = NULL) const;
MethodTable * m_pTargetMT;
MethodDesc * m_pTargetMethod;
@@ -493,38 +492,32 @@ private:
void DECLSPEC_NORETURN ThrowFieldAccessException(MethodDesc *pCallerMD,
FieldDesc *pFD,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
void DECLSPEC_NORETURN ThrowMethodAccessException(MethodDesc *pCallerMD,
MethodDesc *pCalleeMD,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
void DECLSPEC_NORETURN ThrowTypeAccessException(MethodDesc *pCallerMD,
MethodTable *pMT,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
void DECLSPEC_NORETURN ThrowFieldAccessException(AccessCheckContext* pContext,
FieldDesc *pFD,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
void DECLSPEC_NORETURN ThrowMethodAccessException(AccessCheckContext* pContext,
MethodDesc *pCalleeMD,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
void DECLSPEC_NORETURN ThrowTypeAccessException(AccessCheckContext* pContext,
MethodTable *pMT,
UINT messageID = 0,
- Exception *pInnerException = NULL,
- BOOL fAccessingFrameworkCode = FALSE);
+ Exception *pInnerException = NULL);
//---------------------------------------------------------------------------------------
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 878119ca0d..a19ab8e0ae 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -6917,6 +6917,14 @@ BOOL ReadyToRunJitManager::JitCodeToMethodInfo(RangeSection * pRangeSection,
if (MethodIndex < 0)
return FALSE;
+ if (ppMethodDesc == NULL && pCodeInfo == NULL)
+ {
+ // Bail early if caller doesn't care about the MethodDesc or EECodeInfo.
+ // Avoiding the method desc lookups below also prevents deadlocks when this
+ // is called from IsManagedCode.
+ return TRUE;
+ }
+
#ifdef WIN64EXCEPTIONS
// Save the raw entry
PTR_RUNTIME_FUNCTION RawFunctionEntry = pRuntimeFunctions + MethodIndex;
diff --git a/src/vm/comdelegate.cpp b/src/vm/comdelegate.cpp
index 961a758750..3f3c55338f 100644
--- a/src/vm/comdelegate.cpp
+++ b/src/vm/comdelegate.cpp
@@ -1050,126 +1050,6 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis,
GCPROTECT_END();
}
-// On the CoreCLR, we don't allow non-fulltrust delegates to be marshaled out (or created: CorHost::CreateDelegate ensures that)
-// This helper function checks if we have a full-trust delegate with AllowReversePInvokeCallsAttribute targets.
-BOOL COMDelegate::IsFullTrustDelegate(DELEGATEREF pDelegate)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
-#ifdef FEATURE_WINDOWSPHONE
- // we always allow reverse p/invokes on the phone. The OS provides the sandbox.
- return TRUE;
-#else
- if (IsSecureDelegate(pDelegate))
- {
- // A secure delegate implies => creator and target are different, and creator is not fully-trusted
- return FALSE;
- }
- else
- {
- // Suffices to look at the target assembly and check if that is fully-trusted.
- // if creator is same as target, we're done.
- // if creator is not same as target, then the only interesting case is when it's not FT,
- // and that's captured by the SecureDelegate case above.
- // The target method yields the target assembly. Target method is not determinable for certain cases:
- // - Open Virtual Delegates
- // For those cases we play it safe and return FALSE from this function
- if (pDelegate->GetInvocationCount() != 0)
- {
- // From MulticastDelegate.cs (MulticastDelegate.Equals):
- // there are 4 kind of delegate kinds that fall into this bucket
- // 1- Multicast (_invocationList is Object[])
- // 2- Secure (_invocationList is Delegate)
- // 3- Unmanaged FntPtr (_invocationList == null)
- // 4- Open virtual (_invocationCount == MethodDesc of target)
- // (_invocationList == null, or _invocationList is a LoaderAllocator or DynamicResolver)
-
- OBJECTREF invocationList = pDelegate->GetInvocationList();
- if (invocationList != NULL)
- {
-
- MethodTable *pMT;
- pMT = invocationList->GetTrueMethodTable();
- // Has to be a multicast delegate, or inner open virtual delegate of collectible secure delegate
- // since we already checked for secure delegates above
- _ASSERTE(!pMT->IsDelegate());
-
- if (!pMT->IsArray())
- {
- // open Virtual delegate: conservatively return FALSE
- return FALSE;
- }
-
- // Given a multicast delegate we walk the list and make sure all targets are FullTrust.
- // Yes, this is a recursive call to IsFullTrustDelegate. But we should hit stackoverflow
- // only for the same cases where invoking that delegate would hit stackoverflow.
- PTRARRAYREF delegateArrayRef = (PTRARRAYREF) invocationList;
-
- int numDelegates = delegateArrayRef->GetNumComponents();
- for(int i = 0; i< numDelegates; i++)
- {
- DELEGATEREF innerDel = (DELEGATEREF)delegateArrayRef->GetAt(i);
- _ASSERTE(innerDel->GetMethodTable()->IsDelegate());
- if (!IsFullTrustDelegate(innerDel))
- {
- // If we find even one non full-trust target in the list, return FALSE
- return FALSE;
- }
- }
- // All targets in the multicast delegate are FullTrust, so this multicast delegate is
- // also FullTrust
- return TRUE;
- }
- else
- {
- if (pDelegate->GetInvocationCount() == DELEGATE_MARKER_UNMANAGEDFPTR)
- {
- // Delegate to unmanaged function pointer - FullTrust
- return TRUE;
- }
-
- //
- // open Virtual delegate: conservatively return FALSE
- return FALSE;
- }
- }
- // Regular delegate. Let's just look at the target Method
- MethodDesc* pMD = GetMethodDesc((OBJECTREF)pDelegate);
- if (pMD != NULL)
- {
- // The target must be decorated with AllowReversePInvokeCallsAttribute
- if (!IsMethodAllowedToSinkReversePInvoke(pMD)) return FALSE;
-
- return TRUE;
- }
- }
- // Default:
- return FALSE;
-#endif //FEATURE_WINDOWSPHONE
-}
-
-// Checks whether the method is decorated with AllowReversePInvokeCallsAttribute.
-BOOL COMDelegate::IsMethodAllowedToSinkReversePInvoke(MethodDesc *pMD)
-{
- WRAPPER_NO_CONTRACT;
-#ifdef FEATURE_WINDOWSPHONE
- // we always allow reverse p/invokes on the phone. The OS provides the sandbox.
- return TRUE;
-#else
- return (S_OK == pMD->GetMDImport()->GetCustomAttributeByName(
- pMD->GetMemberDef(),
- "System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute",
- NULL,
- NULL));
-#endif // FEATURE_WINDOWSPHONE
-}
-
// Marshals a managed method to an unmanaged callback provided the
// managed method is static and it's parameters require no marshalling.
PCODE COMDelegate::ConvertToCallback(MethodDesc* pMD)
@@ -1262,14 +1142,6 @@ LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj)
MethodTable* pMT = pDelegate->GetMethodTable();
DelegateEEClass* pClass = (DelegateEEClass*)(pMT->GetClass());
- // On the CoreCLR, we only allow marshaling out delegates that we can guarantee are full-trust delegates
- if (!IsFullTrustDelegate(pDelegate))
- {
- StackSString strDelegateType;
- TypeString::AppendType(strDelegateType, pMT, TypeString::FormatNamespace | TypeString::FormatAngleBrackets| TypeString::FormatSignature);
- COMPlusThrow(kSecurityException, IDS_E_DELEGATE_FULLTRUST_ARPIC_1, strDelegateType.GetUnicode());
- }
-
if (pMT->HasInstantiation())
COMPlusThrowArgumentException(W("delegate"), W("Argument_NeedNonGenericType"));
@@ -1450,12 +1322,6 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT)
if (pUMEntryThunk->GetDomainId() != GetAppDomain()->GetId())
COMPlusThrow(kNotSupportedException, W("NotSupported_DelegateMarshalToWrongDomain"));
- // On the CoreCLR, we only allow marshaling out delegates that we can guarantee are full-trust delegates
- if (!IsFullTrustDelegate((DELEGATEREF)pDelegate))
- {
- COMPlusThrow(kSecurityException, IDS_E_DELEGATE_FULLTRUST_ARPIC_2);
- }
-
GCPROTECT_END();
return pDelegate;
}
@@ -1558,12 +1424,6 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT)
GCPROTECT_END();
#endif // defined(_TARGET_X86_)
- // On the CoreCLR, we only allow marshaling out delegates that we can guarantee are full-trust delegates
- if (!IsFullTrustDelegate(delObj))
- {
- COMPlusThrow(kSecurityException, IDS_E_DELEGATE_FULLTRUST_ARPIC_2);
- }
-
return delObj;
}
diff --git a/src/vm/comdelegate.h b/src/vm/comdelegate.h
index f6ca775b60..1bfe8ac987 100644
--- a/src/vm/comdelegate.h
+++ b/src/vm/comdelegate.h
@@ -125,10 +125,7 @@ public:
static BOOL IsTrueMulticastDelegate(OBJECTREF delegate);
- static BOOL IsMethodAllowedToSinkReversePInvoke(MethodDesc *pMD);
-
private:
- static BOOL IsFullTrustDelegate(DELEGATEREF pDelegate);
static Stub* SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth);
public:
diff --git a/src/vm/common.h b/src/vm/common.h
index a52566d55e..54ebf362c9 100644
--- a/src/vm/common.h
+++ b/src/vm/common.h
@@ -97,9 +97,6 @@
//-----------------------------------------------------------------------------------------------------------
-#include "compatibilityflags.h"
-extern BOOL GetCompatibilityFlag(CompatibilityFlag flag);
-
#include "strongname.h"
#include "stdmacros.h"
@@ -316,6 +313,7 @@ namespace Loader
#include "pedecoder.h"
#include "sstring.h"
#include "slist.h"
+#include "yieldprocessornormalized.h"
#include "eeconfig.h"
@@ -475,34 +473,11 @@ extern DummyGlobalContract ___contract;
#include "syncblk.inl"
#include "threads.inl"
#include "eehash.inl"
-#include "mscorcfg.h"
#ifdef FEATURE_COMINTEROP
#include "WinRTRedirector.h"
#include "winrtredirector.inl"
#endif // FEATURE_COMINTEROP
-inline HRESULT CreateConfigStreamHelper(LPCWSTR filename, IStream** pOutStream)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END
-
- HRESULT hr =S_OK;
-
- EX_TRY
- {
- hr = CreateConfigStream( filename, pOutStream);
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
-
#if defined(COMMON_TURNED_FPO_ON)
#pragma optimize("", on) // Go back to command line default optimizations
#undef COMMON_TURNED_FPO_ON
diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp
index 196e2163a5..327f0f1ed2 100644
--- a/src/vm/compile.cpp
+++ b/src/vm/compile.cpp
@@ -2541,8 +2541,8 @@ private:
public:
NGenPdbWriter (LPCWSTR wszNativeImagePath, LPCWSTR wszPdbPath, DWORD dwExtraData, LPCWSTR wszManagedPDBSearchPath)
- : m_hModule(NULL),
- m_Create(NULL),
+ : m_Create(NULL),
+ m_hModule(NULL),
m_wszPdbPath(wszPdbPath),
m_dwExtraData(dwExtraData),
m_wszManagedPDBSearchPath(wszManagedPDBSearchPath)
@@ -2600,7 +2600,7 @@ public:
}
};
-#define UNKNOWN_SOURCE_FILE_PATH L"unknown"
+#define UNKNOWN_SOURCE_FILE_PATH W("unknown")
// ----------------------------------------------------------------------------
// Manages generating all PDB data for an EE Module. Directly responsible for writing the
@@ -2730,10 +2730,10 @@ public:
: m_Create(Create),
m_wszPdbPath(wszPdbPath),
m_pWriter(NULL),
- m_dwExtraData(dwExtraData),
- m_pBinder(pBinder),
m_pModule(pModule),
+ m_dwExtraData(dwExtraData),
m_wszManagedPDBSearchPath(wszManagedPDBSearchPath),
+ m_pBinder(pBinder),
m_ilPdbDocCount(0),
m_finalPdbDocCount(1)
{
@@ -2836,9 +2836,9 @@ public:
m_pMethodRegionInfo(pMethodRegionInfo),
m_pCodeInfo(pCodeInfo),
m_pDocNameToOffsetMap(pDocNameToOffsetMap),
+ m_isILPDBProvided(isILPDBProvided),
m_cIlNativeMap(0),
- m_cSeqPoints(0),
- m_isILPDBProvided(isILPDBProvided)
+ m_cSeqPoints(0)
{
LIMITED_METHOD_CONTRACT;
}
@@ -3094,7 +3094,7 @@ HRESULT NGenModulePdbWriter::WritePDBData()
// we copy the file to somethign with this convention before generating the PDB
// and delete it when we are done.
SString dllPath = pLoadedLayout->GetPath();
- if (!dllPath.EndsWithCaseInsensitive(L".ni.dll") && !dllPath.EndsWithCaseInsensitive(L".ni.exe"))
+ if (!dllPath.EndsWithCaseInsensitive(W(".ni.dll")) && !dllPath.EndsWithCaseInsensitive(W(".ni.exe")))
{
SString::Iterator fileNameStart = dllPath.End();
dllPath.FindBack(fileNameStart, DIRECTORY_SEPARATOR_STR_W);
@@ -3105,7 +3105,7 @@ HRESULT NGenModulePdbWriter::WritePDBData()
// m_tempSourceDllName = Convertion of INPUT.dll to INPUT.ni.dll where the PDB lives.
m_tempSourceDllName = m_wszPdbPath;
m_tempSourceDllName += SString(dllPath, fileNameStart, ext - fileNameStart);
- m_tempSourceDllName += L".ni";
+ m_tempSourceDllName += W(".ni");
m_tempSourceDllName += SString(dllPath, ext, dllPath.End() - ext);
CopyFileW(dllPath, m_tempSourceDllName, false);
dllPath = m_tempSourceDllName;
@@ -3268,10 +3268,10 @@ HRESULT NGenModulePdbWriter::WriteMethodPDBData(PEImageLayout * pLoadedLayout, U
fullName,
hotDesc,
TypeString::FormatNamespace | TypeString::FormatSignature);
- fullName.Append(L"$#");
+ fullName.Append(W("$#"));
if (!mAssemblyName.Equals(assemblyName))
fullName.Append(assemblyName);
- fullName.Append(L"#");
+ fullName.Append(W("#"));
fullName.Append(methodToken);
BSTRHolder hotNameHolder(SysAllocString(fullName.GetUnicode()));
hr = m_pWriter->AddSymbol(hotNameHolder,
@@ -3291,10 +3291,10 @@ HRESULT NGenModulePdbWriter::WriteMethodPDBData(PEImageLayout * pLoadedLayout, U
fullNameCold,
hotDesc,
TypeString::FormatNamespace | TypeString::FormatSignature);
- fullNameCold.Append(L"$#");
+ fullNameCold.Append(W("$#"));
if (!mAssemblyName.Equals(assemblyName))
fullNameCold.Append(assemblyName);
- fullNameCold.Append(L"#");
+ fullNameCold.Append(W("#"));
fullNameCold.Append(methodToken);
BSTRHolder coldNameHolder(SysAllocString(fullNameCold.GetUnicode()));
@@ -5205,21 +5205,13 @@ static void SpecializeEqualityComparer(SString& ss, Instantiation& inst)
if (et == ELEMENT_TYPE_I4 ||
et == ELEMENT_TYPE_U4 ||
et == ELEMENT_TYPE_U2 ||
- et == ELEMENT_TYPE_U1)
+ et == ELEMENT_TYPE_I2 ||
+ et == ELEMENT_TYPE_U1 ||
+ et == ELEMENT_TYPE_I1)
{
ss.Set(W("System.Collections.Generic.EnumEqualityComparer`1"));
return;
}
- else if (et == ELEMENT_TYPE_I2)
- {
- ss.Set(W("System.Collections.Generic.ShortEnumEqualityComparer`1"));
- return;
- }
- else if (et == ELEMENT_TYPE_I1)
- {
- ss.Set(W("System.Collections.Generic.SByteEnumEqualityComparer`1"));
- return;
- }
else if (et == ELEMENT_TYPE_I8 ||
et == ELEMENT_TYPE_U8)
{
diff --git a/src/vm/comsynchronizable.cpp b/src/vm/comsynchronizable.cpp
index 1d7541a74a..472ca34feb 100644
--- a/src/vm/comsynchronizable.cpp
+++ b/src/vm/comsynchronizable.cpp
@@ -1658,9 +1658,7 @@ FCIMPL1(void, ThreadNative::SpinWait, int iterations)
//
if (iterations <= 100000)
{
- YieldProcessorNormalizationInfo normalizationInfo;
- for (int i = 0; i < iterations; i++)
- YieldProcessorNormalized(normalizationInfo);
+ YieldProcessorNormalized(YieldProcessorNormalizationInfo(), iterations);
return;
}
@@ -1670,9 +1668,7 @@ FCIMPL1(void, ThreadNative::SpinWait, int iterations)
HELPER_METHOD_FRAME_BEGIN_NOPOLL();
GCX_PREEMP();
- YieldProcessorNormalizationInfo normalizationInfo;
- for (int i = 0; i < iterations; i++)
- YieldProcessorNormalized(normalizationInfo);
+ YieldProcessorNormalized(YieldProcessorNormalizationInfo(), iterations);
HELPER_METHOD_FRAME_END();
}
diff --git a/src/vm/comthreadpool.cpp b/src/vm/comthreadpool.cpp
index c49f83400c..6ab6b60013 100644
--- a/src/vm/comthreadpool.cpp
+++ b/src/vm/comthreadpool.cpp
@@ -100,9 +100,6 @@ DelegateInfo *DelegateInfo::MakeDelegateInfo(AppDomain *pAppDomain,
INJECT_FAULT(COMPlusThrowOM());
}
CONTRACTL_END;
-
- // If there were any DelegateInfos waiting to be released, they'll get flushed now
- ThreadpoolMgr::FlushQueueOfTimerInfos();
DelegateInfoHolder delegateInfo = (DelegateInfo*) ThreadpoolMgr::GetRecycledMemory(ThreadpoolMgr::MEMTYPE_DelegateInfo);
@@ -818,10 +815,12 @@ void AppDomainTimerCallback_Worker(LPVOID ptr)
LogCall(pMeth,"AppDomainTimerCallback");
#endif
- MethodDescCallSite(METHOD__TIMER_QUEUE__APPDOMAIN_TIMER_CALLBACK).Call(NULL);
+ ThreadpoolMgr::TimerInfoContext* pTimerInfoContext = (ThreadpoolMgr::TimerInfoContext*)ptr;
+ ARG_SLOT args[] = { PtrToArgSlot(pTimerInfoContext->TimerId) };
+ MethodDescCallSite(METHOD__TIMER_QUEUE__APPDOMAIN_TIMER_CALLBACK).Call(args);
}
-VOID WINAPI AppDomainTimerCallback(PVOID delegateInfo, BOOLEAN timerOrWaitFired)
+VOID WINAPI AppDomainTimerCallback(PVOID callbackState, BOOLEAN timerOrWaitFired)
{
Thread* pThread = GetThread();
if (pThread == NULL)
@@ -840,8 +839,6 @@ VOID WINAPI AppDomainTimerCallback(PVOID delegateInfo, BOOLEAN timerOrWaitFired)
MODE_ANY;
GC_TRIGGERS;
SO_INTOLERANT;
-
- PRECONDITION(CheckPointer(delegateInfo));
}
CONTRACTL_END;
@@ -850,13 +847,14 @@ VOID WINAPI AppDomainTimerCallback(PVOID delegateInfo, BOOLEAN timerOrWaitFired)
GCX_COOP();
- ManagedThreadBase::ThreadPool(((DelegateInfo*)delegateInfo)->m_appDomainId, AppDomainTimerCallback_Worker, NULL);
+ ThreadpoolMgr::TimerInfoContext* pTimerInfoContext = (ThreadpoolMgr::TimerInfoContext*)callbackState;
+ ManagedThreadBase::ThreadPool(pTimerInfoContext->AppDomainId, AppDomainTimerCallback_Worker, pTimerInfoContext);
// We should have released all locks.
_ASSERTE(g_fEEShutDown || pThread->m_dwLockCount == 0 || pThread->m_fRudeAborted);
}
-HANDLE QCALLTYPE AppDomainTimerNative::CreateAppDomainTimer(INT32 dueTime)
+HANDLE QCALLTYPE AppDomainTimerNative::CreateAppDomainTimer(INT32 dueTime, INT32 timerId)
{
QCALL_CONTRACT;
@@ -864,20 +862,20 @@ HANDLE QCALLTYPE AppDomainTimerNative::CreateAppDomainTimer(INT32 dueTime)
BEGIN_QCALL;
_ASSERTE(dueTime >= 0);
+ _ASSERTE(timerId >= 0);
AppDomain* pAppDomain = GetThread()->GetDomain();
ADID adid = pAppDomain->GetId();
- DelegateInfoHolder delegateInfo = DelegateInfo::MakeDelegateInfo(
- pAppDomain,
- NULL,
- NULL,
- NULL);
+ ThreadpoolMgr::TimerInfoContext* timerContext = new ThreadpoolMgr::TimerInfoContext();
+ timerContext->AppDomainId = adid;
+ timerContext->TimerId = timerId;
+ NewHolder<ThreadpoolMgr::TimerInfoContext> timerContextHolder(timerContext);
BOOL res = ThreadpoolMgr::CreateTimerQueueTimer(
&hTimer,
(WAITORTIMERCALLBACK)AppDomainTimerCallback,
- (PVOID)delegateInfo,
+ (PVOID)timerContext,
(ULONG)dueTime,
(ULONG)-1 /* this timer doesn't repeat */,
0 /* no flags */);
@@ -891,7 +889,7 @@ HANDLE QCALLTYPE AppDomainTimerNative::CreateAppDomainTimer(INT32 dueTime)
}
else
{
- delegateInfo.SuppressRelease();
+ timerContextHolder.SuppressRelease();
}
END_QCALL;
diff --git a/src/vm/comthreadpool.h b/src/vm/comthreadpool.h
index b949885eab..3e01717d7a 100644
--- a/src/vm/comthreadpool.h
+++ b/src/vm/comthreadpool.h
@@ -60,7 +60,7 @@ public:
class AppDomainTimerNative
{
public:
- static HANDLE QCALLTYPE CreateAppDomainTimer(INT32 dueTime);
+ static HANDLE QCALLTYPE CreateAppDomainTimer(INT32 dueTime, INT32 timerId);
static BOOL QCALLTYPE ChangeAppDomainTimer(HANDLE hTimer, INT32 dueTime);
static BOOL QCALLTYPE DeleteAppDomainTimer(HANDLE hTimer);
};
diff --git a/src/vm/comutilnative.cpp b/src/vm/comutilnative.cpp
index 5c5a1e9eaa..c6c3138e07 100644
--- a/src/vm/comutilnative.cpp
+++ b/src/vm/comutilnative.cpp
@@ -1957,7 +1957,7 @@ void QCALLTYPE COMInterlocked::MemoryBarrierProcessWide()
FlushProcessWriteBuffers();
}
-FCIMPL6(INT32, ManagedLoggingHelper::GetRegistryLoggingValues, CLR_BOOL* bLoggingEnabled, CLR_BOOL* bLogToConsole, INT32 *iLogLevel, CLR_BOOL* bPerfWarnings, CLR_BOOL* bCorrectnessWarnings, CLR_BOOL* bSafeHandleStackTraces)
+FCIMPL3(INT32, ManagedLoggingHelper::GetRegistryLoggingValues, CLR_BOOL* bLoggingEnabled, CLR_BOOL* bLogToConsole, INT32 *iLogLevel)
{
FCALL_CONTRACT;
@@ -1969,11 +1969,8 @@ FCIMPL6(INT32, ManagedLoggingHelper::GetRegistryLoggingValues, CLR_BOOL* bLoggin
*bLogToConsole = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_LogToConsole, 0)!=0);
*iLogLevel = (INT32)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_LogLevel, 0));
logFacility = (INT32)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ManagedLogFacility, 0));
- *bPerfWarnings = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_BCLPerfWarnings, 0)!=0);
- *bCorrectnessWarnings = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_BCLCorrectnessWarnings, 0)!=0);
- *bSafeHandleStackTraces = (bool)(g_pConfig->GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SafeHandleStackTraces, 0)!=0);
- HELPER_METHOD_FRAME_END(); \
+ HELPER_METHOD_FRAME_END();
return logFacility;
}
diff --git a/src/vm/comutilnative.h b/src/vm/comutilnative.h
index 07c57c1312..b9737cedb7 100644
--- a/src/vm/comutilnative.h
+++ b/src/vm/comutilnative.h
@@ -204,7 +204,7 @@ public:
class ManagedLoggingHelper {
public:
- static FCDECL6(INT32, GetRegistryLoggingValues, CLR_BOOL* bLoggingEnabled, CLR_BOOL* bLogToConsole, INT32 *bLogLevel, CLR_BOOL* bPerfWarnings, CLR_BOOL* bCorrectnessWarnings, CLR_BOOL* bSafeHandleStackTraces);
+ static FCDECL3(INT32, GetRegistryLoggingValues, CLR_BOOL* bLoggingEnabled, CLR_BOOL* bLogToConsole, INT32 *bLogLevel);
};
class ValueTypeHelper {
diff --git a/src/vm/corhost.cpp b/src/vm/corhost.cpp
index 74c42d3a85..7fe542e0c2 100644
--- a/src/vm/corhost.cpp
+++ b/src/vm/corhost.cpp
@@ -51,7 +51,6 @@
GVAL_IMPL_INIT(DWORD, g_fHostConfig, 0);
-#ifdef FEATURE_IMPLICIT_TLS
#ifndef __llvm__
EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
#else // !__llvm__
@@ -62,11 +61,6 @@ EXTERN_C UINT32 _tls_index;
#else // FEATURE_PAL
UINT32 _tls_index = 0;
#endif // FEATURE_PAL
-SVAL_IMPL_INIT(DWORD, CExecutionEngine, TlsIndex, _tls_index);
-#else
-SVAL_IMPL_INIT(DWORD, CExecutionEngine, TlsIndex, TLS_OUT_OF_INDEXES);
-#endif
-
#if defined(FEATURE_WINDOWSPHONE)
SVAL_IMPL_INIT(ECustomDumpFlavor, CCLRErrorReportingManager, g_ECustomDumpFlavor, DUMP_FLAVOR_Default);
@@ -570,13 +564,6 @@ HRESULT CorHost2::ExecuteInAppDomain(DWORD dwAppDomainId,
return HOST_E_CLRNOTAVAILABLE;
}
- if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN))
- {
- // Ensure that code is not loaded in the Default AppDomain
- if (dwAppDomainId == DefaultADID)
- return HOST_E_INVALIDOPERATION;
- }
-
// Moved this here since no point validating the pointer
// if the basic checks [above] fail
if( pCallback == NULL)
@@ -632,7 +619,7 @@ HRESULT CorHost2::_CreateAppDomain(
HRESULT hr=S_OK;
//cannot call the function more than once when single appDomain is allowed
- if (m_fAppDomainCreated && (m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN))
+ if (m_fAppDomainCreated)
{
return HOST_E_INVALIDOPERATION;
}
@@ -661,15 +648,7 @@ HRESULT CorHost2::_CreateAppDomain(
AppDomainCreationHolder<AppDomain> pDomain;
- // If StartupFlag specifies single appDomain then return the default domain instead of creating new one
- if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)
- {
- pDomain.Assign(SystemDomain::System()->DefaultDomain());
- }
- else
- {
- AppDomain::CreateUnmanagedObject(pDomain);
- }
+ pDomain.Assign(SystemDomain::System()->DefaultDomain());
ETW::LoaderLog::DomainLoad(pDomain, (LPWSTR)wszFriendlyName);
@@ -744,11 +723,7 @@ HRESULT CorHost2::_CreateAppDomain(
*pAppDomainID=pDomain->GetId().m_dwId;
- // If StartupFlag specifies single appDomain then set the flag that appdomain has already been created
- if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)
- {
- m_fAppDomainCreated = TRUE;
- }
+ m_fAppDomainCreated = TRUE;
}
#ifdef PROFILING_SUPPORTED
EX_HOOK
@@ -821,13 +796,6 @@ HRESULT CorHost2::_CreateDelegate(
if (!m_fStarted)
return HOST_E_INVALIDOPERATION;
- if(!(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN))
- {
- // Ensure that code is not loaded in the Default AppDomain
- if (appDomainID == DefaultADID)
- return HOST_E_INVALIDOPERATION;
- }
-
BEGIN_ENTRYPOINT_NOTHROW;
BEGIN_EXTERNAL_ENTRYPOINT(&hr);
@@ -869,10 +837,6 @@ HRESULT CorHost2::_CreateDelegate(
if (pMD==NULL || !pMD->IsStatic() || pMD->ContainsGenericVariables())
ThrowHR(COR_E_MISSINGMETHOD);
- // the target method must be decorated with AllowReversePInvokeCallsAttribute
- if (!COMDelegate::IsMethodAllowedToSinkReversePInvoke(pMD))
- ThrowHR(COR_E_SECURITY);
-
UMEntryThunk *pUMEntryThunk = GetAppDomain()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
*fnPtr = (INT_PTR)pUMEntryThunk->GetCode();
@@ -1190,57 +1154,52 @@ STDMETHODIMP CorHost2::UnloadAppDomain2(DWORD dwDomainId, BOOL fWaitUntilDone, i
if (!m_fStarted)
return HOST_E_INVALIDOPERATION;
- if(m_dwStartupFlags & STARTUP_SINGLE_APPDOMAIN)
+ if (!g_fEEStarted)
{
- if (!g_fEEStarted)
- {
- return HOST_E_CLRNOTAVAILABLE;
- }
+ return HOST_E_CLRNOTAVAILABLE;
+ }
- if(!m_fAppDomainCreated)
- {
- return HOST_E_INVALIDOPERATION;
- }
+ if(!m_fAppDomainCreated)
+ {
+ return HOST_E_INVALIDOPERATION;
+ }
- HRESULT hr=S_OK;
- BEGIN_ENTRYPOINT_NOTHROW;
+ HRESULT hr=S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
- if (!m_fFirstToLoadCLR)
+ if (!m_fFirstToLoadCLR)
+ {
+ _ASSERTE(!"Not reachable");
+ hr = HOST_E_CLRNOTAVAILABLE;
+ }
+ else
+ {
+ LONG refCount = m_RefCount;
+ if (refCount == 0)
{
- _ASSERTE(!"Not reachable");
hr = HOST_E_CLRNOTAVAILABLE;
}
else
+ if (1 == refCount)
{
- LONG refCount = m_RefCount;
- if (refCount == 0)
- {
- hr = HOST_E_CLRNOTAVAILABLE;
- }
- else
- if (1 == refCount)
- {
- // Stop coreclr on unload.
- m_fStarted = FALSE;
- EEShutDown(FALSE);
- }
- else
- {
- _ASSERTE(!"Not reachable");
- hr = S_FALSE;
- }
+ // Stop coreclr on unload.
+ m_fStarted = FALSE;
+ EEShutDown(FALSE);
}
- END_ENTRYPOINT_NOTHROW;
-
- if (pLatchedExitCode)
+ else
{
- *pLatchedExitCode = GetLatchedExitCode();
+ _ASSERTE(!"Not reachable");
+ hr = S_FALSE;
}
+ }
+ END_ENTRYPOINT_NOTHROW;
- return hr;
+ if (pLatchedExitCode)
+ {
+ *pLatchedExitCode = GetLatchedExitCode();
}
- return CorRuntimeHostBase::UnloadAppDomain2(dwDomainId, fWaitUntilDone, pLatchedExitCode);
+ return hr;
}
HRESULT CorRuntimeHostBase::UnloadAppDomain(DWORD dwDomainId, BOOL fWaitUntilDone)
@@ -3172,7 +3131,6 @@ VOID WINAPI FlsCallback(
#endif // HAS_FLS_SUPPORT
-#ifdef FEATURE_IMPLICIT_TLS
void** CExecutionEngine::GetTlsData()
{
LIMITED_METHOD_CONTRACT;
@@ -3187,28 +3145,6 @@ BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo)
gCurrentThreadInfo.m_EETlsData = ppTlsInfo;
return TRUE;
}
-#else
-void** CExecutionEngine::GetTlsData()
-{
- LIMITED_METHOD_CONTRACT;
-
- if (TlsIndex == TLS_OUT_OF_INDEXES)
- return NULL;
-
- void **ppTlsData = (void **)UnsafeTlsGetValue(TlsIndex);
- return ppTlsData;
-}
-BOOL CExecutionEngine::SetTlsData (void** ppTlsInfo)
-{
- LIMITED_METHOD_CONTRACT;
-
- if (TlsIndex == TLS_OUT_OF_INDEXES)
- return FALSE;
-
- return UnsafeTlsSetValue(TlsIndex, ppTlsInfo);
-}
-
-#endif // FEATURE_IMPLICIT_TLS
//---------------------------------------------------------------------------------------
//
@@ -3299,25 +3235,6 @@ void **CExecutionEngine::CheckThreadState(DWORD slot, BOOL force)
}
#endif // HAS_FLS_SUPPORT
-#ifndef FEATURE_IMPLICIT_TLS
- // Ensure we have a TLS Index
- if (TlsIndex == TLS_OUT_OF_INDEXES)
- {
- DWORD tryTlsIndex = UnsafeTlsAlloc();
- if (tryTlsIndex != TLS_OUT_OF_INDEXES)
- {
- if (FastInterlockCompareExchange((LONG*)&TlsIndex, tryTlsIndex, TLS_OUT_OF_INDEXES) != (LONG)TLS_OUT_OF_INDEXES)
- {
- UnsafeTlsFree(tryTlsIndex);
- }
- }
- if (TlsIndex == TLS_OUT_OF_INDEXES)
- {
- COMPlusThrowOM();
- }
- }
-#endif // FEATURE_IMPLICIT_TLS
-
void** pTlsData = CExecutionEngine::GetTlsData();
BOOL fInTls = (pTlsData != NULL);
diff --git a/src/vm/crossgencompile.cpp b/src/vm/crossgencompile.cpp
index c4b9d3dfc3..411029becd 100644
--- a/src/vm/crossgencompile.cpp
+++ b/src/vm/crossgencompile.cpp
@@ -72,27 +72,6 @@ BOOL Debug_IsLockedViaThreadSuspension()
}
#endif // _DEBUG
-#if defined(FEATURE_MERGE_JIT_AND_ENGINE) && defined(FEATURE_IMPLICIT_TLS)
-void* theJitTls;
-
-extern "C"
-{
-
-void* GetJitTls()
-{
- LIMITED_METHOD_CONTRACT
-
- return theJitTls;
-}
-void SetJitTls(void* v)
-{
- LIMITED_METHOD_CONTRACT
- theJitTls = v;
-}
-
-}
-#endif
-
//---------------------------------------------------------------------------------------
//
// All locks are nops because of there is always only one thread.
diff --git a/src/vm/dbginterface.h b/src/vm/dbginterface.h
index 6378b7022d..9d2c4c9bdf 100644
--- a/src/vm/dbginterface.h
+++ b/src/vm/dbginterface.h
@@ -279,7 +279,7 @@ public:
DWORD nativeOffset,
DWORD *ilOffset) = 0;
- virtual HRESULT GetILToNativeMapping(MethodDesc *pMD,
+ virtual HRESULT GetILToNativeMapping(UINT_PTR pNativeCodeStartAddress,
ULONG32 cMap,
ULONG32 *pcMap,
COR_DEBUG_IL_TO_NATIVE_MAP map[]) = 0;
diff --git a/src/vm/domainfile.cpp b/src/vm/domainfile.cpp
index e5736b7282..410884531e 100644
--- a/src/vm/domainfile.cpp
+++ b/src/vm/domainfile.cpp
@@ -1786,10 +1786,8 @@ void DomainAssembly::FindNativeImage()
ExternalLog(LL_ERROR, "Rejecting native image because mscorlib does not have native image");
GetFile()->ClearNativeImage();
-#ifdef FEATURE_WINDOWSPHONE
- // On Phone, always through exceptions when we throw the NI out
+ // Always throw exceptions when we throw the NI out
ThrowHR(CLR_E_BIND_SYS_ASM_NI_MISSING);
-#endif
}
else
if (!CheckZapSecurity(pNativeImage))
@@ -1802,11 +1800,8 @@ void DomainAssembly::FindNativeImage()
GetFile()->ClearNativeImage();
-#ifdef FEATURE_WINDOWSPHONE
- // On Phone, always through exceptions when we throw the NI out
+ // Always throw exceptions when we throw the NI out
ThrowHR(CLR_E_BIND_NI_SECURITY_FAILURE);
-#endif
-
}
else if (!CheckZapDependencyIdentities(pNativeImage))
{
@@ -1818,11 +1813,8 @@ void DomainAssembly::FindNativeImage()
GetFile()->ClearNativeImage();
-#ifdef FEATURE_WINDOWSPHONE
- // On Phone, always through exceptions when we throw the NI out
+ // Always throw exceptions when we throw the NI out
ThrowHR(CLR_E_BIND_NI_DEP_IDENTITY_MISMATCH);
-#endif
-
}
else
{
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 4720b5a11f..83b6539f42 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -112,8 +112,6 @@ FCFuncStart(gStringFuncs)
FCIntrinsic("get_Chars", COMString::GetCharAt, CORINFO_INTRINSIC_StringGetChar)
FCFuncElement("IsAscii", COMString::IsAscii)
FCFuncElement("CompareOrdinalHelper", COMString::CompareOrdinalEx)
- FCFuncElement("IndexOfCharArray", COMString::IndexOfCharArray)
- FCFuncElement("LastIndexOfAny", COMString::LastIndexOfCharArray)
FCFuncElementSig("ReplaceInternal", &gsig_IM_Str_Str_RetStr, COMString::ReplaceString)
#ifdef FEATURE_COMINTEROP
FCFuncElement("SetTrailByte", COMString::FCSetTrailByte)
diff --git a/src/vm/eeconfig.cpp b/src/vm/eeconfig.cpp
index 4c49d1457f..16d6d73c9f 100644
--- a/src/vm/eeconfig.cpp
+++ b/src/vm/eeconfig.cpp
@@ -225,7 +225,6 @@ HRESULT EEConfig::Init()
fLegacyApartmentInitPolicy = false;
fLegacyComHierarchyVisibility = false;
fLegacyComVTableLayout = false;
- fLegacyVirtualMethodCallVerification = false;
fNewComVTableLayout = false;
#ifdef FEATURE_CORRUPTING_EXCEPTIONS
diff --git a/src/vm/eeconfig.h b/src/vm/eeconfig.h
index c55ba06a0b..84e4ccf15b 100644
--- a/src/vm/eeconfig.h
+++ b/src/vm/eeconfig.h
@@ -315,7 +315,6 @@ public:
bool LegacyNullReferenceExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyNullReferenceExceptionPolicy; }
bool LegacyUnhandledExceptionPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyUnhandledExceptionPolicy; }
- bool LegacyVirtualMethodCallVerification(void) const {LIMITED_METHOD_CONTRACT; return fLegacyVirtualMethodCallVerification; }
bool LegacyApartmentInitPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyApartmentInitPolicy; }
bool LegacyComHierarchyVisibility(void) const {LIMITED_METHOD_CONTRACT; return fLegacyComHierarchyVisibility; }
@@ -862,7 +861,6 @@ private: //----------------------------------------------------------------
bool fLegacyNullReferenceExceptionPolicy; // Old AV's as NullRef behavior
bool fLegacyUnhandledExceptionPolicy; // Old unhandled exception policy (many are swallowed)
- bool fLegacyVirtualMethodCallVerification; // Old (pre-whidbey) policy for call (nonvirt) of virtual function
#ifdef FEATURE_CORRUPTING_EXCEPTIONS
bool fLegacyCorruptedStateExceptionsPolicy;
diff --git a/src/vm/eedbginterface.h b/src/vm/eedbginterface.h
index 8c8c44d3e2..241ef332e2 100644
--- a/src/vm/eedbginterface.h
+++ b/src/vm/eedbginterface.h
@@ -280,7 +280,6 @@ public:
virtual void GetRuntimeOffsets(SIZE_T *pTLSIndex,
SIZE_T *pTLSIsSpecialIndex,
SIZE_T *pTLSCantStopIndex,
- SIZE_T *pTLSIndexOfPredefs,
SIZE_T *pEEThreadStateOffset,
SIZE_T *pEEThreadStateNCOffset,
SIZE_T *pEEThreadPGCDisabledOffset,
diff --git a/src/vm/eedbginterfaceimpl.cpp b/src/vm/eedbginterfaceimpl.cpp
index ede82c7780..e9f59d25d2 100644
--- a/src/vm/eedbginterfaceimpl.cpp
+++ b/src/vm/eedbginterfaceimpl.cpp
@@ -1387,14 +1387,11 @@ void EEDbgInterfaceImpl::DisableTraceCall(Thread *thread)
thread->DecrementTraceCallCount();
}
-#ifdef FEATURE_IMPLICIT_TLS
EXTERN_C UINT32 _tls_index;
-#endif
void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
SIZE_T *pTLSIsSpecialIndex,
SIZE_T *pTLSCantStopIndex,
- SIZE_T* pTLSIndexOfPredefs,
SIZE_T *pEEThreadStateOffset,
SIZE_T *pEEThreadStateNCOffset,
SIZE_T *pEEThreadPGCDisabledOffset,
@@ -1417,7 +1414,6 @@ void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
PRECONDITION(CheckPointer(pTLSIndex));
PRECONDITION(CheckPointer(pTLSIsSpecialIndex));
PRECONDITION(CheckPointer(pEEThreadStateOffset));
- PRECONDITION(CheckPointer(pTLSIndexOfPredefs));
PRECONDITION(CheckPointer(pEEThreadStateNCOffset));
PRECONDITION(CheckPointer(pEEThreadPGCDisabledOffset));
PRECONDITION(CheckPointer(pEEThreadPGCDisabledValue));
@@ -1433,14 +1429,9 @@ void EEDbgInterfaceImpl::GetRuntimeOffsets(SIZE_T *pTLSIndex,
}
CONTRACTL_END;
-#ifdef FEATURE_IMPLICIT_TLS
- *pTLSIndex = _tls_index;
-#else
- *pTLSIndex = GetThreadTLSIndex();
-#endif
+ *pTLSIndex = g_TlsIndex;
*pTLSIsSpecialIndex = TlsIdx_ThreadType;
*pTLSCantStopIndex = TlsIdx_CantStopCount;
- *pTLSIndexOfPredefs = CExecutionEngine::TlsIndex;
*pEEThreadStateOffset = Thread::GetOffsetOfState();
*pEEThreadStateNCOffset = Thread::GetOffsetOfStateNC();
*pEEThreadPGCDisabledOffset = Thread::GetOffsetOfGCFlag();
diff --git a/src/vm/eedbginterfaceimpl.h b/src/vm/eedbginterfaceimpl.h
index 979c706fb2..7451246a21 100644
--- a/src/vm/eedbginterfaceimpl.h
+++ b/src/vm/eedbginterfaceimpl.h
@@ -272,7 +272,6 @@ public:
void GetRuntimeOffsets(SIZE_T *pTLSIndex,
SIZE_T *pTLSIsSpecialIndex,
SIZE_T *pTLSCantStopIndex,
- SIZE_T *pTLSIndexOfPredefs,
SIZE_T *pEEThreadStateOffset,
SIZE_T *pEEThreadStateNCOffset,
SIZE_T *pEEThreadPGCDisabledOffset,
diff --git a/src/vm/eetoprofinterfaceimpl.cpp b/src/vm/eetoprofinterfaceimpl.cpp
index 75f4a02af2..3f32b5a39d 100644
--- a/src/vm/eetoprofinterfaceimpl.cpp
+++ b/src/vm/eetoprofinterfaceimpl.cpp
@@ -2006,7 +2006,8 @@ HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable()
{
LIMITED_METHOD_CONTRACT;
- if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0)
+ if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) ||
+ ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0))
{
LOG((
LF_CORPROF,
@@ -2268,12 +2269,14 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad)
{
#ifdef _DEBUG
- if ((dwEventMask & dwImmutableEventFlags) !=
- (g_profControlBlock.dwEventMask & dwImmutableEventFlags))
+ if (((dwEventMask & dwImmutableEventFlags) !=
+ (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) ||
#else //!_DEBUG
- if ((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
- (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE))
+ if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) !=
+ (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) ||
#endif //_DEBUG
+ ((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) !=
+ (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE)))
{
// FUTURE: Should we have a dedicated HRESULT for setting immutable flag?
return E_FAIL;
@@ -2284,10 +2287,11 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask
// allowable after an attach
if (m_fLoadedViaAttach &&
#ifdef _DEBUG
- ((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0))
+ (((dwEventMask & (~dwAllowableAfterAttachEventFlags)) != 0) ||
#else //!_DEBUG
- ((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0))
+ (((dwEventMask & (~COR_PRF_ALLOWABLE_AFTER_ATTACH)) != 0) ||
#endif //_DEBUG
+ (dwEventMaskHigh & (~COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH))))
{
return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;
}
diff --git a/src/vm/excep.cpp b/src/vm/excep.cpp
index af2554e324..17ad686c81 100644
--- a/src/vm/excep.cpp
+++ b/src/vm/excep.cpp
@@ -3462,8 +3462,7 @@ DWORD MapWin32FaultToCOMPlusException(EXCEPTION_RECORD *pExceptionRecord)
{
// We have a config key, InsecurelyTreatAVsAsNullReference, that ensures we always translate to
// NullReferenceException instead of doing the new AV translation logic.
- if ((g_pConfig != NULL) && !g_pConfig->LegacyNullReferenceExceptionPolicy() &&
- !GetCompatibilityFlag(compatNullReferenceExceptionOnAV) )
+ if ((g_pConfig != NULL) && !g_pConfig->LegacyNullReferenceExceptionPolicy())
{
#if defined(FEATURE_HIJACK) && !defined(PLATFORM_UNIX)
// If we got the exception on a redirect function it means the original exception happened in managed code:
diff --git a/src/vm/excep.h b/src/vm/excep.h
index 4c752932fd..4261c3cff3 100644
--- a/src/vm/excep.h
+++ b/src/vm/excep.h
@@ -55,8 +55,7 @@ BOOL IsWin32IOError(SCODE scode);
inline bool SwallowUnhandledExceptions()
{
return (eHostDeterminedPolicy == GetEEPolicy()->GetUnhandledExceptionPolicy()) ||
- g_pConfig->LegacyUnhandledExceptionPolicy() ||
- GetCompatibilityFlag(compatSwallowUnhandledExceptions);
+ g_pConfig->LegacyUnhandledExceptionPolicy();
}
// Enums
diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp
index b135173c0f..959687b7b8 100644
--- a/src/vm/gcenv.ee.cpp
+++ b/src/vm/gcenv.ee.cpp
@@ -843,6 +843,9 @@ void GCToEEInterface::DiagWalkBGCSurvivors(void* gcContext)
void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
{
+ int stompWBCompleteActions = SWB_PASS;
+ bool is_runtime_suspended = false;
+
assert(args != nullptr);
switch (args->operation)
{
@@ -868,7 +871,7 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
}
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check);
+ stompWBCompleteActions |= ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check);
// We need to make sure that other threads executing checked write barriers
// will see the g_card_table update before g_lowest/highest_address updates.
@@ -884,30 +887,45 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
// "cross-modifying code": We need all _executing_ threads to invalidate
// their instruction cache, which FlushProcessWriteBuffers achieves by sending
// an IPI (inter-process interrupt).
- FlushProcessWriteBuffers();
+
+ if (stompWBCompleteActions & SWB_ICACHE_FLUSH)
+ {
+ // flushing icache on current processor (thread)
+ ::FlushWriteBarrierInstructionCache();
+ // asking other processors (threads) to invalidate their icache
+ FlushProcessWriteBuffers();
+ }
g_lowest_address = args->lowest_address;
VolatileStore(&g_highest_address, args->highest_address);
#if defined(_ARM64_)
// Need to reupdate for changes to g_highest_address g_lowest_address
- ::StompWriteBarrierResize(args->is_runtime_suspended, args->requires_upper_bounds_check);
+ is_runtime_suspended = (stompWBCompleteActions & SWB_EE_RESTART) || args->is_runtime_suspended;
+ stompWBCompleteActions |= ::StompWriteBarrierResize(is_runtime_suspended, args->requires_upper_bounds_check);
- if(!args->is_runtime_suspended)
+ is_runtime_suspended = (stompWBCompleteActions & SWB_EE_RESTART) || args->is_runtime_suspended;
+ if(!is_runtime_suspended)
{
// If runtime is not suspended, force updated state to be visible to all threads
MemoryBarrier();
}
#endif
- return;
+ if (stompWBCompleteActions & SWB_EE_RESTART)
+ {
+ assert(!args->is_runtime_suspended &&
+ "if runtime was suspended in patching routines then it was in running state at begining");
+ ThreadSuspend::RestartEE(FALSE, TRUE);
+ }
+ return; // unlike other branches we have already done cleanup so bailing out here
case WriteBarrierOp::StompEphemeral:
// StompEphemeral requires a new ephemeral low and a new ephemeral high
assert(args->ephemeral_low != nullptr);
assert(args->ephemeral_high != nullptr);
g_ephemeral_low = args->ephemeral_low;
g_ephemeral_high = args->ephemeral_high;
- ::StompWriteBarrierEphemeral(args->is_runtime_suspended);
- return;
+ stompWBCompleteActions |= ::StompWriteBarrierEphemeral(args->is_runtime_suspended);
+ break;
case WriteBarrierOp::Initialize:
// This operation should only be invoked once, upon initialization.
assert(g_card_table == nullptr);
@@ -927,12 +945,10 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
assert(g_card_bundle_table == nullptr);
g_card_bundle_table = args->card_bundle_table;
#endif
-
- FlushProcessWriteBuffers();
g_lowest_address = args->lowest_address;
- VolatileStore(&g_highest_address, args->highest_address);
- ::StompWriteBarrierResize(true, false);
+ g_highest_address = args->highest_address;
+ stompWBCompleteActions |= ::StompWriteBarrierResize(true, false);
// StompWriteBarrierResize does not necessarily bash g_ephemeral_low
// usages, so we must do so here. This is particularly true on x86,
@@ -940,32 +956,42 @@ void GCToEEInterface::StompWriteBarrier(WriteBarrierParameters* args)
// called with the parameters (true, false), as it is above.
g_ephemeral_low = args->ephemeral_low;
g_ephemeral_high = args->ephemeral_high;
- ::StompWriteBarrierEphemeral(true);
- return;
+ stompWBCompleteActions |= ::StompWriteBarrierEphemeral(true);
+ break;
case WriteBarrierOp::SwitchToWriteWatch:
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
assert(args->write_watch_table != nullptr);
assert(args->is_runtime_suspended && "the runtime must be suspended here!");
g_sw_ww_table = args->write_watch_table;
g_sw_ww_enabled_for_gc_heap = true;
- ::SwitchToWriteWatchBarrier(true);
+ stompWBCompleteActions |= ::SwitchToWriteWatchBarrier(true);
#else
assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP");
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- return;
+ break;
case WriteBarrierOp::SwitchToNonWriteWatch:
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
assert(args->is_runtime_suspended && "the runtime must be suspended here!");
g_sw_ww_table = 0;
g_sw_ww_enabled_for_gc_heap = false;
- ::SwitchToNonWriteWatchBarrier(true);
+ stompWBCompleteActions |= ::SwitchToNonWriteWatchBarrier(true);
#else
assert(!"should never be called without FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP");
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- return;
+ break;
default:
assert(!"unknown WriteBarrierOp enum");
}
+ if (stompWBCompleteActions & SWB_ICACHE_FLUSH)
+ {
+ ::FlushWriteBarrierInstructionCache();
+ }
+ if (stompWBCompleteActions & SWB_EE_RESTART)
+ {
+ assert(!args->is_runtime_suspended &&
+ "if runtime was suspended in patching routines then it was in running state at begining");
+ ThreadSuspend::RestartEE(FALSE, TRUE);
+ }
}
void GCToEEInterface::EnableFinalization(bool foundFinalizers)
@@ -1143,3 +1169,13 @@ void GCToEEInterface::FreeStringConfigValue(const char* value)
{
delete [] value;
}
+
+bool GCToEEInterface::IsGCThread()
+{
+ return !!::IsGCThread();
+}
+
+bool GCToEEInterface::IsGCSpecialThread()
+{
+ return !!::IsGCSpecialThread();
+}
diff --git a/src/vm/gcenv.ee.h b/src/vm/gcenv.ee.h
index c9000b2485..063fa2554e 100644
--- a/src/vm/gcenv.ee.h
+++ b/src/vm/gcenv.ee.h
@@ -58,6 +58,8 @@ public:
bool GetIntConfigValue(const char* key, int64_t* value);
bool GetStringConfigValue(const char* key, const char** value);
void FreeStringConfigValue(const char* value);
+ bool IsGCThread();
+ bool IsGCSpecialThread();
};
} // namespace standalone
diff --git a/src/vm/gcheaputilities.cpp b/src/vm/gcheaputilities.cpp
index 3a6a42fd9d..90836a0fd2 100644
--- a/src/vm/gcheaputilities.cpp
+++ b/src/vm/gcheaputilities.cpp
@@ -4,6 +4,7 @@
#include "common.h"
#include "gcheaputilities.h"
+#include "gcenv.ee.h"
#include "appdomain.hpp"
@@ -36,3 +37,200 @@ bool g_sw_ww_enabled_for_gc_heap = false;
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
gc_alloc_context g_global_alloc_context = {};
+
+enum GC_LOAD_STATUS {
+ GC_LOAD_STATUS_BEFORE_START,
+ GC_LOAD_STATUS_START,
+ GC_LOAD_STATUS_DONE_LOAD,
+ GC_LOAD_STATUS_GET_VERSIONINFO,
+ GC_LOAD_STATUS_CALL_VERSIONINFO,
+ GC_LOAD_STATUS_DONE_VERSION_CHECK,
+ GC_LOAD_STATUS_GET_INITIALIZE,
+ GC_LOAD_STATUS_LOAD_COMPLETE
+};
+
+// Load status of the GC. If GC loading fails, the value of this
+// global indicates where the failure occured.
+GC_LOAD_STATUS g_gc_load_status = GC_LOAD_STATUS_BEFORE_START;
+
+// The version of the GC that we have loaded.
+VersionInfo g_gc_version_info;
+
+// GC entrypoints for the the linked-in GC. These symbols are invoked
+// directly if we are not using a standalone GC.
+extern "C" void GC_VersionInfo(/* Out */ VersionInfo* info);
+extern "C" HRESULT GC_Initialize(
+ /* In */ IGCToCLR* clrToGC,
+ /* Out */ IGCHeap** gcHeap,
+ /* Out */ IGCHandleManager** gcHandleManager,
+ /* Out */ GcDacVars* gcDacVars
+);
+
+#ifndef DACCESS_COMPILE
+
+namespace
+{
+
+// Loads and initializes a standalone GC, given the path to the GC
+// that we should load. Returns S_OK on success and the failed HRESULT
+// on failure.
+//
+// See Documentation/design-docs/standalone-gc-loading.md for details
+// on the loading protocol in use here.
+HRESULT LoadAndInitializeGC(LPWSTR standaloneGcLocation)
+{
+ LIMITED_METHOD_CONTRACT;
+
+#ifndef FEATURE_STANDALONE_GC
+ LOG((LF_GC, LL_FATALERROR, "EE not built with the ability to load standalone GCs"));
+ return E_FAIL;
+#else
+ LOG((LF_GC, LL_INFO100, "Loading standalone GC from path %S\n", standaloneGcLocation));
+ HMODULE hMod = CLRLoadLibrary(standaloneGcLocation);
+ if (!hMod)
+ {
+ HRESULT err = GetLastError();
+ LOG((LF_GC, LL_FATALERROR, "Load of %S failed\n", standaloneGcLocation));
+ return err;
+ }
+
+ // a standalone GC dispatches virtually on GCToEEInterface, so we must instantiate
+ // a class for the GC to use.
+ IGCToCLR* gcToClr = new (nothrow) standalone::GCToEEInterface();
+ if (!gcToClr)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ g_gc_load_status = GC_LOAD_STATUS_DONE_LOAD;
+ GC_VersionInfoFunction versionInfo = (GC_VersionInfoFunction)GetProcAddress(hMod, "GC_VersionInfo");
+ if (!versionInfo)
+ {
+ HRESULT err = GetLastError();
+ LOG((LF_GC, LL_FATALERROR, "Load of `GC_VersionInfo` from standalone GC failed\n"));
+ return err;
+ }
+
+ g_gc_load_status = GC_LOAD_STATUS_GET_VERSIONINFO;
+ versionInfo(&g_gc_version_info);
+ g_gc_load_status = GC_LOAD_STATUS_CALL_VERSIONINFO;
+
+ if (g_gc_version_info.MajorVersion != GC_INTERFACE_MAJOR_VERSION)
+ {
+ LOG((LF_GC, LL_FATALERROR, "Loaded GC has incompatible major version number (expected %d, got %d)\n",
+ GC_INTERFACE_MAJOR_VERSION, g_gc_version_info.MajorVersion));
+ return E_FAIL;
+ }
+
+ if (g_gc_version_info.MinorVersion < GC_INTERFACE_MINOR_VERSION)
+ {
+ LOG((LF_GC, LL_INFO100, "Loaded GC has lower minor version number (%d) than EE was compiled against (%d)\n",
+ g_gc_version_info.MinorVersion, GC_INTERFACE_MINOR_VERSION));
+ }
+
+ LOG((LF_GC, LL_INFO100, "Loaded GC identifying itself with name `%s`\n", g_gc_version_info.Name));
+ g_gc_load_status = GC_LOAD_STATUS_DONE_VERSION_CHECK;
+ GC_InitializeFunction initFunc = (GC_InitializeFunction)GetProcAddress(hMod, "GC_Initialize");
+ if (!initFunc)
+ {
+ HRESULT err = GetLastError();
+ LOG((LF_GC, LL_FATALERROR, "Load of `GC_Initialize` from standalone GC failed\n"));
+ return err;
+ }
+
+ g_gc_load_status = GC_LOAD_STATUS_GET_INITIALIZE;
+ IGCHeap* heap;
+ IGCHandleManager* manager;
+ HRESULT initResult = initFunc(gcToClr, &heap, &manager, &g_gc_dac_vars);
+ if (initResult == S_OK)
+ {
+ g_pGCHeap = heap;
+ g_pGCHandleManager = manager;
+ g_gcDacGlobals = &g_gc_dac_vars;
+ g_gc_load_status = GC_LOAD_STATUS_LOAD_COMPLETE;
+ LOG((LF_GC, LL_INFO100, "GC load successful\n"));
+ }
+ else
+ {
+ LOG((LF_GC, LL_FATALERROR, "GC initialization failed with HR = 0x%X\n", initResult));
+ }
+
+ return initResult;
+#endif // FEATURE_STANDALONE_GC
+}
+
+// Initializes a non-standalone GC. The protocol for initializing a non-standalone GC
+// is similar to loading a standalone one, except that the GC_VersionInfo and
+// GC_Initialize symbols are linked to directory and thus don't need to be loaded.
+//
+// The major and minor versions are still checked in debug builds - it must be the case
+// that the GC and EE agree on a shared version number because they are built from
+// the same sources.
+HRESULT InitializeDefaultGC()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ LOG((LF_GC, LL_INFO100, "Standalone GC location not provided, using provided GC\n"));
+
+ g_gc_load_status = GC_LOAD_STATUS_DONE_LOAD;
+ VersionInfo info;
+ GC_VersionInfo(&g_gc_version_info);
+ g_gc_load_status = GC_LOAD_STATUS_CALL_VERSIONINFO;
+
+ // the default GC builds with the rest of the EE. By definition, it must have been
+ // built with the same interface version.
+ assert(g_gc_version_info.MajorVersion == GC_INTERFACE_MAJOR_VERSION);
+ assert(g_gc_version_info.MinorVersion == GC_INTERFACE_MINOR_VERSION);
+ g_gc_load_status = GC_LOAD_STATUS_DONE_VERSION_CHECK;
+
+ IGCHeap* heap;
+ IGCHandleManager* manager;
+ HRESULT initResult = GC_Initialize(nullptr, &heap, &manager, &g_gc_dac_vars);
+ if (initResult == S_OK)
+ {
+ g_pGCHeap = heap;
+ g_pGCHandleManager = manager;
+ g_gcDacGlobals = &g_gc_dac_vars;
+ g_gc_load_status = GC_LOAD_STATUS_LOAD_COMPLETE;
+ LOG((LF_GC, LL_INFO100, "GC load successful\n"));
+ }
+ else
+ {
+ LOG((LF_GC, LL_FATALERROR, "GC initialization failed with HR = 0x%X\n", initResult));
+ }
+
+
+ return initResult;
+}
+
+} // anonymous namespace
+
+// Loads (if necessary) and initializes the GC. If using a standalone GC,
+// it loads the library containing it and dynamically loads the GC entry point.
+// If using a non-standalone GC, it invokes the GC entry point directly.
+HRESULT GCHeapUtilities::LoadAndInitialize()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // we should only call this once on startup. Attempting to load a GC
+ // twice is an error.
+ assert(g_pGCHeap == nullptr);
+
+ // we should not have attempted to load a GC already. Attempting a
+ // load after the first load already failed is an error.
+ assert(g_gc_load_status == GC_LOAD_STATUS_BEFORE_START);
+ g_gc_load_status = GC_LOAD_STATUS_START;
+
+ LPWSTR standaloneGcLocation = nullptr;
+ CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCName, &standaloneGcLocation);
+ if (!standaloneGcLocation)
+ {
+ return InitializeDefaultGC();
+ }
+ else
+ {
+ return LoadAndInitializeGC(standaloneGcLocation);
+ }
+}
+
+#endif // DACCESS_COMPILE
diff --git a/src/vm/gcheaputilities.h b/src/vm/gcheaputilities.h
index e4812ce8c0..b4bd5164af 100644
--- a/src/vm/gcheaputilities.h
+++ b/src/vm/gcheaputilities.h
@@ -196,6 +196,11 @@ public:
}
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+#ifndef DACCESS_COMPILE
+ // Loads (if using a standalone GC) and initializes the GC.
+ static HRESULT LoadAndInitialize();
+#endif // DACCESS_COMPILE
+
private:
// This class should never be instantiated.
GCHeapUtilities() = delete;
diff --git a/src/vm/gchelpers.h b/src/vm/gchelpers.h
index 73933f691f..0e407c6e61 100644
--- a/src/vm/gchelpers.h
+++ b/src/vm/gchelpers.h
@@ -107,10 +107,11 @@ OBJECTREF AllocateObject(MethodTable *pMT
#endif
);
-extern void StompWriteBarrierEphemeral(bool isRuntimeSuspended);
-extern void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck);
-extern void SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
-extern void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
+extern int StompWriteBarrierEphemeral(bool isRuntimeSuspended);
+extern int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck);
+extern int SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
+extern int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
+extern void FlushWriteBarrierInstructionCache();
extern void ThrowOutOfMemoryDimensionsExceeded();
diff --git a/src/vm/gdbjit.cpp b/src/vm/gdbjit.cpp
index 9dbf9df1a2..22bf30a2bd 100644
--- a/src/vm/gdbjit.cpp
+++ b/src/vm/gdbjit.cpp
@@ -661,15 +661,57 @@ void __attribute__((noinline)) __jit_debug_register_code() { __asm__(""); };
/* Make sure to specify the version statically, because the
debugger may check the version before we can set it. */
struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
+static CrstStatic g_jitDescriptorCrst;
// END of GDB JIT interface
-/* Static data for .debug_str section */
-const char* DebugStrings[] = {
- "CoreCLR", "" /* module name */, "" /* module path */
-};
+class DebugStringsCU
+{
+public:
+ DebugStringsCU(const char *module, const char *path)
+ : m_producerName("CoreCLR"),
+ m_moduleName(module),
+ m_moduleDir(path),
+ m_producerOffset(0),
+ m_moduleNameOffset(0),
+ m_moduleDirOffset(0)
+ {
+ }
-const int DebugStringCount = sizeof(DebugStrings) / sizeof(DebugStrings[0]);
+ int GetProducerOffset() const { return m_producerOffset; }
+ int GetModuleNameOffset() const { return m_moduleNameOffset; }
+ int GetModuleDirOffset() const { return m_moduleDirOffset; }
+
+ void DumpStrings(char *ptr, int &offset)
+ {
+ m_producerOffset = offset;
+ DumpString(m_producerName, ptr, offset);
+
+ m_moduleNameOffset = offset;
+ DumpString(m_moduleName, ptr, offset);
+
+ m_moduleDirOffset = offset;
+ DumpString(m_moduleDir, ptr, offset);
+ }
+
+private:
+ const char* m_producerName;
+ const char* m_moduleName;
+ const char* m_moduleDir;
+
+ int m_producerOffset;
+ int m_moduleNameOffset;
+ int m_moduleDirOffset;
+
+ static void DumpString(const char *str, char *ptr, int &offset)
+ {
+ if (ptr != nullptr)
+ {
+ strcpy(ptr + offset, str);
+ }
+ offset += strlen(str) + 1;
+ }
+};
/* Static data for .debug_abbrev */
const unsigned char AbbrevTable[] = {
@@ -1785,48 +1827,23 @@ static int getNextPrologueIndex(int from, T &arr, int n)
return -1;
}
+static NewArrayHolder<WCHAR> g_wszModuleNames;
+static DWORD g_cBytesNeeded;
+
static inline bool isListedModule(const WCHAR *wszModuleFile)
{
- static NewArrayHolder<WCHAR> wszModuleNames = nullptr;
- static DWORD cBytesNeeded = 0;
-
- // Get names of interesting modules from environment
- if (wszModuleNames == nullptr && cBytesNeeded == 0)
- {
- DWORD cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0);
-
- if (cCharsNeeded == 0)
- {
- cBytesNeeded = 0xffffffff;
- return false;
- }
-
- WCHAR *wszModuleNamesBuf = new WCHAR[cCharsNeeded+1];
-
- cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNamesBuf, cCharsNeeded);
-
- if (cCharsNeeded == 0)
- {
- delete[] wszModuleNamesBuf;
- cBytesNeeded = 0xffffffff;
- return false;
- }
-
- wszModuleNames = wszModuleNamesBuf;
- cBytesNeeded = cCharsNeeded + 1;
- }
- else if (wszModuleNames == nullptr)
+ if (g_wszModuleNames == nullptr)
{
return false;
}
- _ASSERTE(wszModuleNames != nullptr && cBytesNeeded > 0);
+ _ASSERTE(g_cBytesNeeded > 0);
BOOL isUserDebug = FALSE;
- NewArrayHolder<WCHAR> wszModuleName = new WCHAR[cBytesNeeded];
- LPWSTR pComma = wcsstr(wszModuleNames, W(","));
- LPWSTR tmp = wszModuleNames;
+ NewArrayHolder<WCHAR> wszModuleName = new WCHAR[g_cBytesNeeded];
+ LPWSTR pComma = wcsstr(g_wszModuleNames, W(","));
+ LPWSTR tmp = g_wszModuleNames;
while (pComma != NULL)
{
@@ -1854,7 +1871,8 @@ static inline bool isListedModule(const WCHAR *wszModuleFile)
return isUserDebug;
}
-static NotifyGdb::AddrSet codeAddrs;
+static NotifyGdb::AddrSet g_codeAddrs;
+static CrstStatic g_codeAddrsCrst;
class Elf_SectionTracker
{
@@ -2440,6 +2458,38 @@ static void BuildDebugFrame(Elf_Builder &elfBuilder, PCODE pCode, TADDR codeSize
}
#endif // FEATURE_GDBJIT_FRAME
+void NotifyGdb::Initialize()
+{
+ g_jitDescriptorCrst.Init(CrstNotifyGdb);
+ g_codeAddrsCrst.Init(CrstNotifyGdb);
+
+ // Get names of interesting modules from environment
+ if (g_wszModuleNames == nullptr && g_cBytesNeeded == 0)
+ {
+ DWORD cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), NULL, 0);
+
+ if (cCharsNeeded == 0)
+ {
+ g_cBytesNeeded = 0xffffffff;
+ return;
+ }
+
+ WCHAR *wszModuleNamesBuf = new WCHAR[cCharsNeeded+1];
+
+ cCharsNeeded = GetEnvironmentVariableW(W("CORECLR_GDBJIT"), wszModuleNamesBuf, cCharsNeeded);
+
+ if (cCharsNeeded == 0)
+ {
+ delete[] wszModuleNamesBuf;
+ g_cBytesNeeded = 0xffffffff;
+ return;
+ }
+
+ g_wszModuleNames = wszModuleNamesBuf;
+ g_cBytesNeeded = cCharsNeeded + 1;
+ }
+}
+
/* Create ELF/DWARF debug info for jitted method */
void NotifyGdb::MethodPrepared(MethodDesc* methodDescPtr)
{
@@ -2547,21 +2597,25 @@ void NotifyGdb::OnMethodPrepared(MethodDesc* methodDescPtr)
jit_symbols->symfile_addr = symfile_addr;
jit_symbols->symfile_size = symfile_size;
- /* Link into list */
- jit_code_entry *head = __jit_debug_descriptor.first_entry;
- __jit_debug_descriptor.first_entry = jit_symbols;
- if (head != 0)
{
- jit_symbols->next_entry = head;
- head->prev_entry = jit_symbols;
- }
+ CrstHolder crst(&g_jitDescriptorCrst);
- jit_symbols.SuppressRelease();
+ /* Link into list */
+ jit_code_entry *head = __jit_debug_descriptor.first_entry;
+ __jit_debug_descriptor.first_entry = jit_symbols;
+ if (head != 0)
+ {
+ jit_symbols->next_entry = head;
+ head->prev_entry = jit_symbols;
+ }
- /* Notify the debugger */
- __jit_debug_descriptor.relevant_entry = jit_symbols;
- __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
- __jit_debug_register_code();
+ jit_symbols.SuppressRelease();
+
+ /* Notify the debugger */
+ __jit_debug_descriptor.relevant_entry = jit_symbols;
+ __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+ __jit_debug_register_code();
+ }
}
#ifdef FEATURE_GDBJIT_FRAME
@@ -2764,27 +2818,24 @@ bool NotifyGdb::EmitDebugInfo(Elf_Builder &elfBuilder, MethodDesc* methodDescPtr
if (dirLen != 0)
{
dirPath = new char[dirLen];
- memcpy(dirPath, DebugStrings[1], dirLen - 1);
+ memcpy(dirPath, cuPath, dirLen - 1);
dirPath[dirLen - 1] = '\0';
}
- DebugStrings[1] = fileName;
- DebugStrings[2] = dirPath ? (const char *)dirPath : "";
+
+ DebugStringsCU debugStringsCU(fileName, dirPath ? (const char *)dirPath : "");
/* Build .debug_str section */
- if (!BuildDebugStrings(dbgStr, pTypeMap, method))
+ if (!BuildDebugStrings(dbgStr, pTypeMap, method, debugStringsCU))
{
return false;
}
/* Build .debug_info section */
- if (!BuildDebugInfo(dbgInfo, pTypeMap, method))
+ if (!BuildDebugInfo(dbgInfo, pTypeMap, method, debugStringsCU))
{
return false;
}
- DebugStrings[1] = "";
- DebugStrings[2] = "";
-
for (int i = 0; i < method.GetCount(); ++i)
{
method[i]->lines = nullptr;
@@ -2877,6 +2928,8 @@ void NotifyGdb::MethodPitched(MethodDesc* methodDescPtr)
if (pCode == NULL)
return;
+ CrstHolder crst(&g_jitDescriptorCrst);
+
/* Find relevant entry */
for (jit_code_entry* jit_symbols = __jit_debug_descriptor.first_entry; jit_symbols != 0; jit_symbols = jit_symbols->next_entry)
{
@@ -3197,7 +3250,7 @@ static void fixLineMapping(SymbolsInfo* lines, unsigned nlines)
/* Build program for DWARF source line section */
bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines)
{
- static char cnv_buf[16];
+ char cnv_buf[16];
/* reserve memory assuming worst case: set address, advance line command, set proglogue/epilogue and copy for each line */
buf.MemSize =
@@ -3266,15 +3319,15 @@ bool NotifyGdb::BuildLineProg(MemBuf& buf, PCODE startAddr, TADDR codeSize, Symb
}
/* Build the DWARF .debug_str section */
-bool NotifyGdb::BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method)
+bool NotifyGdb::BuildDebugStrings(MemBuf& buf,
+ PTK_TypeInfoMap pTypeMap,
+ FunctionMemberPtrArrayHolder &method,
+ DebugStringsCU &debugStringsCU)
{
int totalLength = 0;
/* calculate total section size */
- for (int i = 0; i < DebugStringCount; ++i)
- {
- totalLength += strlen(DebugStrings[i]) + 1;
- }
+ debugStringsCU.DumpStrings(nullptr, totalLength);
for (int i = 0; i < method.GetCount(); ++i)
{
@@ -3297,11 +3350,8 @@ bool NotifyGdb::BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, Functio
/* copy strings */
char* bufPtr = buf.MemPtr;
int offset = 0;
- for (int i = 0; i < DebugStringCount; ++i)
- {
- strcpy(bufPtr + offset, DebugStrings[i]);
- offset += strlen(DebugStrings[i]) + 1;
- }
+
+ debugStringsCU.DumpStrings(bufPtr, offset);
for (int i = 0; i < method.GetCount(); ++i)
{
@@ -3332,7 +3382,10 @@ bool NotifyGdb::BuildDebugAbbrev(MemBuf& buf)
}
/* Build tge DWARF .debug_info section */
-bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method)
+bool NotifyGdb::BuildDebugInfo(MemBuf& buf,
+ PTK_TypeInfoMap pTypeMap,
+ FunctionMemberPtrArrayHolder &method,
+ DebugStringsCU &debugStringsCU)
{
int totalTypeVarSubSize = 0;
{
@@ -3366,9 +3419,9 @@ bool NotifyGdb::BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMe
reinterpret_cast<DebugInfoCU*>(buf.MemPtr + offset);
memcpy(buf.MemPtr + offset, &debugInfoCU, sizeof(DebugInfoCU));
offset += sizeof(DebugInfoCU);
- diCU->m_prod_off = 0;
- diCU->m_cu_name = strlen(DebugStrings[0]) + 1;
- diCU->m_cu_dir = diCU->m_cu_name + strlen(DebugStrings[1]) + 1;
+ diCU->m_prod_off = debugStringsCU.GetProducerOffset();
+ diCU->m_cu_name = debugStringsCU.GetModuleNameOffset();
+ diCU->m_cu_dir = debugStringsCU.GetModuleDirOffset();
{
auto iter = pTypeMap->Begin();
while (iter != pTypeMap->End())
@@ -3422,8 +3475,10 @@ bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
{
AddrSet tmpCodeAddrs;
- if (!codeAddrs.Contains(nativeCode))
- codeAddrs.Add(nativeCode);
+ CrstHolder crst(&g_codeAddrsCrst);
+
+ if (!g_codeAddrs.Contains(nativeCode))
+ g_codeAddrs.Add(nativeCode);
CalledMethod* pList = pCalledMethods;
@@ -3431,7 +3486,7 @@ bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
while (pList != NULL)
{
TADDR callAddr = (TADDR)pList->GetCallAddr();
- if (!tmpCodeAddrs.Contains(callAddr) && !codeAddrs.Contains(callAddr)) {
+ if (!tmpCodeAddrs.Contains(callAddr) && !g_codeAddrs.Contains(callAddr)) {
tmpCodeAddrs.Add(callAddr);
}
pList = pList->GetNext();
@@ -3445,7 +3500,7 @@ bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
while (i < symbolCount && pList != NULL)
{
TADDR callAddr = (TADDR)pList->GetCallAddr();
- if (!codeAddrs.Contains(callAddr))
+ if (!g_codeAddrs.Contains(callAddr))
{
MethodDesc* pMD = pList->GetMethodDesc();
LPCUTF8 methodName = pMD->GetName();
@@ -3455,7 +3510,7 @@ bool NotifyGdb::CollectCalledMethods(CalledMethod* pCalledMethods,
sprintf_s((char*)symbolNames[i].m_name, symbolNameLength, "__thunk_%s", methodName);
symbolNames[i].m_value = callAddr;
++i;
- codeAddrs.Add(callAddr);
+ g_codeAddrs.Add(callAddr);
}
pList = pList->GetNext();
}
diff --git a/src/vm/gdbjit.h b/src/vm/gdbjit.h
index 6cfe52c36d..abb8480ba9 100644
--- a/src/vm/gdbjit.h
+++ b/src/vm/gdbjit.h
@@ -336,11 +336,13 @@ public:
struct Elf_Symbol;
class Elf_Builder;
+class DebugStringsCU;
class NotifyGdb
{
public:
class FileTableBuilder;
+ static void Initialize();
static void MethodPrepared(MethodDesc* methodDescPtr);
static void MethodPitched(MethodDesc* methodDescPtr);
template <typename PARENT_TRAITS>
@@ -429,9 +431,11 @@ private:
NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount,
unsigned int thunkIndexBase);
static bool BuildStringTableSection(MemBuf& strTab, NewArrayHolder<Elf_Symbol> &symbolNames, int symbolCount);
- static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method);
+ static bool BuildDebugStrings(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method,
+ DebugStringsCU &debugStringsCU);
static bool BuildDebugAbbrev(MemBuf& buf);
- static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method);
+ static bool BuildDebugInfo(MemBuf& buf, PTK_TypeInfoMap pTypeMap, FunctionMemberPtrArrayHolder &method,
+ DebugStringsCU &debugStringsCU);
static bool BuildDebugPub(MemBuf& buf, const char* name, uint32_t size, uint32_t dieOffset);
static bool BuildLineTable(MemBuf& buf, PCODE startAddr, TADDR codeSize, SymbolsInfo* lines, unsigned nlines,
const char * &cuPath);
diff --git a/src/vm/hillclimbing.cpp b/src/vm/hillclimbing.cpp
index 598ef3e8cd..196708a5e2 100644
--- a/src/vm/hillclimbing.cpp
+++ b/src/vm/hillclimbing.cpp
@@ -335,7 +335,7 @@ int HillClimbing::Update(int currentThreadCount, double sampleDuration, int numC
// we'll simply stay at minThreads much longer, and only occasionally try a higher value.
//
if (ratio.r < 0.0 && newThreadCount == ThreadpoolMgr::MinLimitTotalWorkerThreads)
- *pNewSampleInterval = (int)(0.5 + m_currentSampleInterval * (10.0 * max(-ratio.r, 1.0)));
+ *pNewSampleInterval = (int)(0.5 + m_currentSampleInterval * (10.0 * min(-ratio.r, 1.0)));
else
*pNewSampleInterval = m_currentSampleInterval;
diff --git a/src/vm/i386/asmconstants.h b/src/vm/i386/asmconstants.h
index f7d5f709dc..aa420428f7 100644
--- a/src/vm/i386/asmconstants.h
+++ b/src/vm/i386/asmconstants.h
@@ -317,9 +317,6 @@ ASMCONSTANTS_C_ASSERT(ASM__VTABLE_SLOTS_PER_CHUNK == VTABLE_SLOTS_PER_CHUNK)
#define ASM__VTABLE_SLOTS_PER_CHUNK_LOG2 3
ASMCONSTANTS_C_ASSERT(ASM__VTABLE_SLOTS_PER_CHUNK_LOG2 == VTABLE_SLOTS_PER_CHUNK_LOG2)
-#define TLS_GETTER_MAX_SIZE_ASM DBG_FRE(0x20, 0x10)
-ASMCONSTANTS_C_ASSERT(TLS_GETTER_MAX_SIZE_ASM == TLS_GETTER_MAX_SIZE)
-
#define JIT_TailCall_StackOffsetToFlags 0x08
#define CallDescrData__pSrc 0x00
diff --git a/src/vm/i386/asmhelpers.asm b/src/vm/i386/asmhelpers.asm
index 9df33219ac..17d521fb92 100644
--- a/src/vm/i386/asmhelpers.asm
+++ b/src/vm/i386/asmhelpers.asm
@@ -47,23 +47,10 @@ endif ; FEATURE_COMINTEROP
EXTERN __alloca_probe:PROC
EXTERN _NDirectImportWorker@4:PROC
EXTERN _UMThunkStubRareDisableWorker@8:PROC
-ifndef FEATURE_IMPLICIT_TLS
-ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-; This is defined in C (threads.cpp) and enforces EE_THREAD_NOT_REQUIRED contracts
-GetThreadGenericFullCheck EQU ?GetThreadGenericFullCheck@@YGPAVThread@@XZ
-EXTERN GetThreadGenericFullCheck:PROC
-endif ; ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-EXTERN _gThreadTLSIndex:DWORD
-EXTERN _gAppDomainTLSIndex:DWORD
-endif ; FEATURE_IMPLICIT_TLS
EXTERN _VarargPInvokeStubWorker@12:PROC
EXTERN _GenericPInvokeCalliStubWorker@12:PROC
-EXTERN _GetThread@0:PROC
-EXTERN _GetAppDomain@0:PROC
-
ifdef MDA_SUPPORTED
EXTERN _PInvokeStackImbalanceWorker@8:PROC
endif
@@ -716,56 +703,6 @@ doRet:
FASTCALL_ENDFUNC HelperMethodFrameRestoreState
-ifndef FEATURE_IMPLICIT_TLS
-;---------------------------------------------------------------------------
-; Portable GetThread() function: used if no platform-specific optimizations apply.
-; This is in assembly code because we count on edx not getting trashed on calls
-; to this function.
-;---------------------------------------------------------------------------
-; Thread* __stdcall GetThreadGeneric(void);
-GetThreadGeneric PROC stdcall public USES ecx edx
-
-ifdef _DEBUG
- cmp dword ptr [_gThreadTLSIndex], -1
- jnz @F
- int 3
-@@:
-endif
-ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
- ; non-PAL, debug-only GetThreadGeneric should defer to GetThreadGenericFullCheck
- ; to do extra contract enforcement. (See GetThreadGenericFullCheck for details.)
- ; This code is intentionally not added to asmhelper.s, as this enforcement is only
- ; implemented for non-PAL builds.
- call GetThreadGenericFullCheck
-else
- push dword ptr [_gThreadTLSIndex]
- call dword ptr [__imp__TlsGetValue@4]
-endif
- ret
-GetThreadGeneric ENDP
-
-;---------------------------------------------------------------------------
-; Portable GetAppdomain() function: used if no platform-specific optimizations apply.
-; This is in assembly code because we count on edx not getting trashed on calls
-; to this function.
-;---------------------------------------------------------------------------
-; Appdomain* __stdcall GetAppDomainGeneric(void);
-GetAppDomainGeneric PROC stdcall public USES ecx edx
-
-ifdef _DEBUG
- cmp dword ptr [_gAppDomainTLSIndex], -1
- jnz @F
- int 3
-@@:
-endif
-
- push dword ptr [_gAppDomainTLSIndex]
- call dword ptr [__imp__TlsGetValue@4]
- ret
-GetAppDomainGeneric ENDP
-endif
-
-
ifdef FEATURE_HIJACK
; A JITted method's return address was hijacked to return to us here.
diff --git a/src/vm/i386/cgencpu.h b/src/vm/i386/cgencpu.h
index 5360b3eb0e..ffdfb82b14 100644
--- a/src/vm/i386/cgencpu.h
+++ b/src/vm/i386/cgencpu.h
@@ -108,14 +108,6 @@ BOOL Runtime_Test_For_SSE2();
#define ENREGISTERED_RETURNTYPE_INTEGER_MAXSIZE 4
#define CALLDESCR_ARGREGS 1 // CallDescrWorker has ArgumentRegister parameter
-// Max size of patched TLS helpers
-#ifdef _DEBUG
-// Debug build needs extra space for last error trashing
-#define TLS_GETTER_MAX_SIZE 0x20
-#else
-#define TLS_GETTER_MAX_SIZE 0x10
-#endif
-
//=======================================================================
// IMPORTANT: This value is used to figure out how much to allocate
// for a fixed array of FieldMarshaler's. That means it must be at least
@@ -558,6 +550,12 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
return TRUE;
}
+//
+// JIT HELPER ALIASING FOR PORTABILITY.
+//
+// Create alias for optimized implementations of helpers provided on this platform
+//
+
// optimized static helpers generated dynamically at runtime
// #define JIT_GetSharedGCStaticBase
// #define JIT_GetSharedNonGCStaticBase
@@ -573,4 +571,5 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode)
#define JIT_NewCrossContext JIT_NewCrossContext
#define JIT_Stelem_Ref JIT_Stelem_Ref
#endif // FEATURE_PAL
+
#endif // __cgenx86_h__
diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp
index 3b523c9c28..19d7bbeea3 100644
--- a/src/vm/i386/cgenx86.cpp
+++ b/src/vm/i386/cgenx86.cpp
@@ -1076,7 +1076,7 @@ Stub *GenerateInitPInvokeFrameHelper()
unsigned negSpace = FrameInfo.offsetOfFrameVptr;
// mov esi, GetThread()
- psl->X86EmitCurrentThreadFetch(kESI, (1<<kEDI)|(1<<kEBX)|(1<<kECX)|(1<<kEDX));
+ psl->X86EmitCurrentThreadFetch(kESI, (1 << kEDI) | (1 << kEBX) | (1 << kECX) | (1 << kEDX));
// mov [edi + FrameInfo.offsetOfGSCookie], GetProcessGSCookie()
psl->X86EmitOffsetModRM(0xc7, (X86Reg)0x0, kEDI, FrameInfo.offsetOfGSCookie - negSpace);
diff --git a/src/vm/i386/jithelp.asm b/src/vm/i386/jithelp.asm
index 85e824040a..5d64b18c94 100644
--- a/src/vm/i386/jithelp.asm
+++ b/src/vm/i386/jithelp.asm
@@ -2,11 +2,6 @@
; The .NET Foundation licenses this file to you under the MIT license.
; See the LICENSE file in the project root for more information.
-; ==++==
-;
-
-;
-; ==--==
; ***********************************************************************
; File: JIThelp.asm
;
@@ -70,13 +65,11 @@ endif
EXTERN _g_TailCallFrameVptr:DWORD
EXTERN @JIT_FailFast@0:PROC
EXTERN _s_gsCookie:DWORD
+EXTERN _GetThread@0:PROC
EXTERN @JITutil_IsInstanceOfInterface@8:PROC
EXTERN @JITutil_ChkCastInterface@8:PROC
EXTERN @JITutil_IsInstanceOfAny@8:PROC
EXTERN @JITutil_ChkCastAny@8:PROC
-ifdef FEATURE_IMPLICIT_TLS
-EXTERN _GetThread@0:PROC
-endif
ifdef WRITE_BARRIER_CHECK
; Those global variables are always defined, but should be 0 for Server GC
@@ -963,13 +956,15 @@ NewArgs equ 20
; extra space is incremented as we push things on the stack along the way
ExtraSpace = 0
- call _GetThread@0; eax = Thread*
- push eax ; Thread*
+ push 0 ; Thread*
; save ArgumentRegisters
push ecx
push edx
+ call _GetThread@0; eax = Thread*
+ mov [esp + 8], eax
+
ExtraSpace = 12 ; pThread, ecx, edx
ifdef FEATURE_HIJACK
@@ -1247,44 +1242,8 @@ _JIT_PatchedCodeStart@0 proc public
ret
_JIT_PatchedCodeStart@0 endp
-;
-; Optimized TLS getters
-;
-
- ALIGN 4
-
-ifndef FEATURE_IMPLICIT_TLS
-_GetThread@0 proc public
- ; This will be overwritten at runtime with optimized GetThread implementation
- jmp short _GetTLSDummy@0
- ; Just allocate space that will be filled in at runtime
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-_GetThread@0 endp
-
- ALIGN 4
-
-_GetAppDomain@0 proc public
- ; This will be overwritten at runtime with optimized GetAppDomain implementation
- jmp short _GetTLSDummy@0
- ; Just allocate space that will be filled in at runtime
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-_GetAppDomain@0 endp
-
-_GetTLSDummy@0 proc public
- xor eax,eax
- ret
-_GetTLSDummy@0 endp
-
ALIGN 4
-_ClrFlsGetBlock@0 proc public
- ; This will be overwritten at runtime with optimized ClrFlsGetBlock implementation
- jmp short _GetTLSDummy@0
- ; Just allocate space that will be filled in at runtime
- db (TLS_GETTER_MAX_SIZE_ASM - 2) DUP (0CCh)
-_ClrFlsGetBlock@0 endp
-endif
-
;**********************************************************************
; Write barriers generated at runtime
diff --git a/src/vm/i386/jitinterfacex86.cpp b/src/vm/i386/jitinterfacex86.cpp
index 66911e87f5..3994c2e216 100644
--- a/src/vm/i386/jitinterfacex86.cpp
+++ b/src/vm/i386/jitinterfacex86.cpp
@@ -539,7 +539,7 @@ void JIT_TrialAlloc::EmitCore(CPUSTUBLINKER *psl, CodeLabel *noLock, CodeLabel *
&& "EAX should contain size for allocation and it doesnt!!!");
// Fetch current thread into EDX, preserving EAX and ECX
- psl->X86EmitCurrentThreadFetch(kEDX, (1<<kEAX)|(1<<kECX));
+ psl->X86EmitCurrentThreadFetch(kEDX, (1 << kEAX) | (1 << kECX));
// Try the allocation.
@@ -1253,7 +1253,7 @@ FastPrimitiveArrayAllocatorFuncPtr fastPrimitiveArrayAllocator = UnframedAllocat
// "init" should be the address of a routine which takes an argument of
// the module domain ID, the class domain ID, and returns the static base pointer
-void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck, bool bGCStatic, bool bSingleAppDomain)
+void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck, bool bGCStatic)
{
STANDARD_VM_CONTRACT;
@@ -1267,35 +1267,6 @@ void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCto
psl->Emit8(0x89);
psl->Emit8(0xc8);
- if(!bSingleAppDomain)
- {
- // Check tag
- CodeLabel *cctorCheck = psl->NewCodeLabel();
-
-
- // test eax, 1
- psl->Emit8(0xa9);
- psl->Emit32(1);
-
- // jz cctorCheck
- psl->X86EmitCondJump(cctorCheck, X86CondCode::kJZ);
-
- // mov eax GetAppDomain()
- psl->X86EmitCurrentAppDomainFetch(kEAX, (1<<kECX)|(1<<kEDX));
-
- // mov eax [eax->m_sDomainLocalBlock.m_pModuleSlots]
- psl->X86EmitIndexRegLoad(kEAX, kEAX, (__int32) AppDomain::GetOffsetOfModuleSlotsPointer());
-
- // Note: weird address arithmetic effectively does:
- // shift over 1 to remove tag bit (which is always 1), then multiply by 4.
- // mov eax [eax + ecx*2 - 2]
- psl->X86EmitOp(0x8b, kEAX, kEAX, -2, kECX, 2);
-
- // cctorCheck:
- psl->EmitLabel(cctorCheck);
-
- }
-
if (bCCtorCheck)
{
// test [eax + edx + offsetof(DomainLocalModule, m_pDataBlob], ClassInitFlags::INITIALIZED_FLAG // Is class inited
@@ -1356,7 +1327,7 @@ void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCto
}
-void *GenFastGetSharedStaticBase(bool bCheckCCtor, bool bGCStatic, bool bSingleAppDomain)
+void *GenFastGetSharedStaticBase(bool bCheckCCtor, bool bGCStatic)
{
STANDARD_VM_CONTRACT;
@@ -1372,7 +1343,7 @@ void *GenFastGetSharedStaticBase(bool bCheckCCtor, bool bGCStatic, bool bSingleA
init = sl.NewExternalCodeLabel((LPVOID)JIT_GetSharedNonGCStaticBase);
}
- EmitFastGetSharedStaticBase(&sl, init, bCheckCCtor, bGCStatic, bSingleAppDomain);
+ EmitFastGetSharedStaticBase(&sl, init, bCheckCCtor, bGCStatic);
Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap());
@@ -1521,16 +1492,14 @@ void InitJITHelpers1()
//UnframedAllocateString;
}
- bool bSingleAppDomain = IsSingleAppDomain();
-
// Replace static helpers with faster assembly versions
- pMethodAddresses[6] = GenFastGetSharedStaticBase(true, true, bSingleAppDomain);
+ pMethodAddresses[6] = GenFastGetSharedStaticBase(true, true);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, pMethodAddresses[6]);
- pMethodAddresses[7] = GenFastGetSharedStaticBase(true, false, bSingleAppDomain);
+ pMethodAddresses[7] = GenFastGetSharedStaticBase(true, false);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, pMethodAddresses[7]);
- pMethodAddresses[8] = GenFastGetSharedStaticBase(false, true, bSingleAppDomain);
+ pMethodAddresses[8] = GenFastGetSharedStaticBase(false, true);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, pMethodAddresses[8]);
- pMethodAddresses[9] = GenFastGetSharedStaticBase(false, false, bSingleAppDomain);
+ pMethodAddresses[9] = GenFastGetSharedStaticBase(false, false);
SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, pMethodAddresses[9]);
ETW::MethodLog::StubsInitialized(pMethodAddresses, (PVOID *)pHelperNames, ETW_NUM_JIT_HELPERS);
@@ -1675,21 +1644,21 @@ void ValidateWriteBarrierHelpers()
// When a GC happens, the upper and lower bounds of the ephemeral
// generation change. This routine updates the WriteBarrier thunks
// with the new values.
-void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
+int StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
{
CONTRACTL {
NOTHROW;
GC_NOTRIGGER;
} CONTRACTL_END;
+ int stompWBCompleteActions = SWB_PASS;
+
#ifdef WRITE_BARRIER_CHECK
// Don't do the fancy optimization if we are checking write barrier
if (((BYTE *)JIT_WriteBarrierEAX)[0] == 0xE9) // we are using slow write barrier
- return;
+ return stompWBCompleteActions;
#endif // WRITE_BARRIER_CHECK
- BOOL flushICache = FALSE;
-
// Update the lower bound.
for (int iBarrier = 0; iBarrier < NUM_WRITE_BARRIERS; iBarrier++)
{
@@ -1703,7 +1672,7 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
//avoid trivial self modifying code
if (*pfunc != (size_t) g_ephemeral_low)
{
- flushICache = TRUE;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
*pfunc = (size_t) g_ephemeral_low;
}
if (!WriteBarrierIsPreGrow())
@@ -1716,15 +1685,13 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
//avoid trivial self modifying code
if (*pfunc != (size_t) g_ephemeral_high)
{
- flushICache = TRUE;
+ stompWBCompleteActions |= SWB_ICACHE_FLUSH;
*pfunc = (size_t) g_ephemeral_high;
}
}
}
- if (flushICache)
- FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup,
- (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup);
+ return stompWBCompleteActions;
}
/*********************************************************************/
@@ -1733,24 +1700,24 @@ void StompWriteBarrierEphemeral(bool /* isRuntimeSuspended */)
// to the PostGrow thunk that checks both upper and lower bounds.
// regardless we need to update the thunk with the
// card_table - lowest_address.
-void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
+int StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
{
CONTRACTL {
NOTHROW;
if (GetThread()) {GC_TRIGGERS;} else {GC_NOTRIGGER;}
} CONTRACTL_END;
+ int stompWBCompleteActions = SWB_PASS;
+
#ifdef WRITE_BARRIER_CHECK
// Don't do the fancy optimization if we are checking write barrier
if (((BYTE *)JIT_WriteBarrierEAX)[0] == 0xE9) // we are using slow write barrier
- return;
+ return stompWBCompleteActions;
#endif // WRITE_BARRIER_CHECK
bool bWriteBarrierIsPreGrow = WriteBarrierIsPreGrow();
bool bStompWriteBarrierEphemeral = false;
- BOOL bEESuspendedHere = FALSE;
-
for (int iBarrier = 0; iBarrier < NUM_WRITE_BARRIERS; iBarrier++)
{
BYTE * pBuf = (BYTE *)c_rgWriteBarriers[iBarrier];
@@ -1765,9 +1732,9 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
if (bReqUpperBoundsCheck)
{
GCX_MAYBE_COOP_NO_THREAD_BROKEN((GetThread()!=NULL));
- if( !isRuntimeSuspended && !bEESuspendedHere) {
+ if( !isRuntimeSuspended && !(stompWBCompleteActions & SWB_EE_RESTART) ) {
ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_GC_PREP);
- bEESuspendedHere = TRUE;
+ stompWBCompleteActions |= SWB_EE_RESTART;
}
pfunc = (size_t *) JIT_WriteBarrierReg_PostGrow;
@@ -1855,16 +1822,15 @@ void StompWriteBarrierResize(bool isRuntimeSuspended, bool bReqUpperBoundsCheck)
if (bStompWriteBarrierEphemeral)
{
- _ASSERTE(isRuntimeSuspended || bEESuspendedHere);
- StompWriteBarrierEphemeral(true);
- }
- else
- {
- FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup,
- (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup);
+ _ASSERTE(isRuntimeSuspended || (stompWBCompleteActions & SWB_EE_RESTART));
+ stompWBCompleteActions |= StompWriteBarrierEphemeral(true);
}
+ return stompWBCompleteActions;
+}
- if(bEESuspendedHere)
- ThreadSuspend::RestartEE(FALSE, TRUE);
+void FlushWriteBarrierInstructionCache()
+{
+ FlushInstructionCache(GetCurrentProcess(), (void *)JIT_PatchedWriteBarrierGroup,
+ (BYTE*)JIT_PatchedWriteBarrierGroup_End - (BYTE*)JIT_PatchedWriteBarrierGroup);
}
diff --git a/src/vm/i386/stublinkerx86.cpp b/src/vm/i386/stublinkerx86.cpp
index b77609822b..e07b6e1c37 100644
--- a/src/vm/i386/stublinkerx86.cpp
+++ b/src/vm/i386/stublinkerx86.cpp
@@ -2320,7 +2320,7 @@ static const X86Reg c_argRegs[] = {
#ifndef CROSSGEN_COMPILE
-#if defined(_DEBUG) && (defined(_TARGET_AMD64_) || defined(_TARGET_X86_)) && !defined(FEATURE_PAL)
+#if defined(_DEBUG) && !defined(FEATURE_PAL)
void StubLinkerCPU::EmitJITHelperLoggingThunk(PCODE pJitHelper, LPVOID helperFuncCount)
{
STANDARD_VM_CONTRACT;
@@ -2358,95 +2358,7 @@ void StubLinkerCPU::EmitJITHelperLoggingThunk(PCODE pJitHelper, LPVOID helperFun
#endif
X86EmitTailcallWithSinglePop(NewExternalCodeLabel(pJitHelper), kECX);
}
-#endif // _DEBUG && (_TARGET_AMD64_ || _TARGET_X86_) && !FEATURE_PAL
-
-#ifndef FEATURE_IMPLICIT_TLS
-//---------------------------------------------------------------
-// Emit code to store the current Thread structure in dstreg
-// preservedRegSet is a set of registers to be preserved
-// TRASHES EAX, EDX, ECX unless they are in preservedRegSet.
-// RESULTS dstreg = current Thread
-//---------------------------------------------------------------
-VOID StubLinkerCPU::X86EmitTLSFetch(DWORD idx, X86Reg dstreg, unsigned preservedRegSet)
-{
- CONTRACTL
- {
- STANDARD_VM_CHECK;
-
- // It doesn't make sense to have the destination register be preserved
- PRECONDITION((preservedRegSet & (1<<dstreg)) == 0);
- AMD64_ONLY(PRECONDITION(dstreg < 8)); // code below doesn't support high registers
- }
- CONTRACTL_END;
-
- TLSACCESSMODE mode = GetTLSAccessMode(idx);
-
-#ifdef _DEBUG
- {
- static BOOL f = TRUE;
- f = !f;
- if (f)
- {
- mode = TLSACCESS_GENERIC;
- }
- }
-#endif
-
- switch (mode)
- {
- case TLSACCESS_WNT:
- {
- unsigned __int32 tlsofs = offsetof(TEB, TlsSlots) + (idx * sizeof(void*));
-#ifdef _TARGET_AMD64_
- BYTE code[] = {0x65,0x48,0x8b,0x04,0x25}; // mov dstreg, qword ptr gs:[IMM32]
- static const int regByteIndex = 3;
-#elif defined(_TARGET_X86_)
- BYTE code[] = {0x64,0x8b,0x05}; // mov dstreg, dword ptr fs:[IMM32]
- static const int regByteIndex = 2;
-#endif
- code[regByteIndex] |= (dstreg << 3);
-
- EmitBytes(code, sizeof(code));
- Emit32(tlsofs);
- }
- break;
-
- case TLSACCESS_GENERIC:
-
- X86EmitPushRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
-
- X86EmitPushImm32(idx);
-#ifdef _TARGET_AMD64_
- X86EmitPopReg (kECX); // arg in reg
-#endif
-
- // call TLSGetValue
- X86EmitCall(NewExternalCodeLabel((LPVOID) TlsGetValue), sizeof(void*));
-
- // mov dstreg, eax
- X86EmitMovRegReg(dstreg, kEAX);
-
- X86EmitPopRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
-
- break;
-
- default:
- _ASSERTE(0);
- }
-
-#ifdef _DEBUG
- // Trash caller saved regs that we were not told to preserve, and that aren't the dstreg.
- preservedRegSet |= 1<<dstreg;
- if (!(preservedRegSet & (1<<kEAX)))
- X86EmitDebugTrashReg(kEAX);
- if (!(preservedRegSet & (1<<kEDX)))
- X86EmitDebugTrashReg(kEDX);
- if (!(preservedRegSet & (1<<kECX)))
- X86EmitDebugTrashReg(kECX);
-#endif
-
-}
-#endif // FEATURE_IMPLICIT_TLS
+#endif // _DEBUG && !FEATURE_PAL
VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedRegSet)
{
@@ -2454,84 +2366,54 @@ VOID StubLinkerCPU::X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedR
{
STANDARD_VM_CHECK;
- // It doesn't make sense to have the destination register be preserved
- PRECONDITION((preservedRegSet & (1<<dstreg)) == 0);
+ // It doesn't make sense to have the destination register be preserved
+ PRECONDITION((preservedRegSet & (1 << dstreg)) == 0);
AMD64_ONLY(PRECONDITION(dstreg < 8)); // code below doesn't support high registers
}
CONTRACTL_END;
-#ifdef FEATURE_IMPLICIT_TLS
+#ifdef FEATURE_PAL
- X86EmitPushRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
+ X86EmitPushRegs(preservedRegSet & ((1 << kEAX) | (1 << kEDX) | (1 << kECX)));
- //TODO: Inline the instruction instead of a call
// call GetThread
- X86EmitCall(NewExternalCodeLabel((LPVOID) GetThread), sizeof(void*));
+ X86EmitCall(NewExternalCodeLabel((LPVOID)GetThread), sizeof(void*));
// mov dstreg, eax
X86EmitMovRegReg(dstreg, kEAX);
- X86EmitPopRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
+ X86EmitPopRegs(preservedRegSet & ((1 << kEAX) | (1 << kEDX) | (1 << kECX)));
#ifdef _DEBUG
// Trash caller saved regs that we were not told to preserve, and that aren't the dstreg.
- preservedRegSet |= 1<<dstreg;
- if (!(preservedRegSet & (1<<kEAX)))
+ preservedRegSet |= 1 << dstreg;
+ if (!(preservedRegSet & (1 << kEAX)))
X86EmitDebugTrashReg(kEAX);
- if (!(preservedRegSet & (1<<kEDX)))
+ if (!(preservedRegSet & (1 << kEDX)))
X86EmitDebugTrashReg(kEDX);
- if (!(preservedRegSet & (1<<kECX)))
+ if (!(preservedRegSet & (1 << kECX)))
X86EmitDebugTrashReg(kECX);
#endif // _DEBUG
-#else // FEATURE_IMPLICIT_TLS
-
- X86EmitTLSFetch(GetThreadTLSIndex(), dstreg, preservedRegSet);
-
-#endif // FEATURE_IMPLICIT_TLS
-
-}
-
-VOID StubLinkerCPU::X86EmitCurrentAppDomainFetch(X86Reg dstreg, unsigned preservedRegSet)
-{
- CONTRACTL
- {
- STANDARD_VM_CHECK;
-
- // It doesn't make sense to have the destination register be preserved
- PRECONDITION((preservedRegSet & (1<<dstreg)) == 0);
- AMD64_ONLY(PRECONDITION(dstreg < 8)); // code below doesn't support high registers
- }
- CONTRACTL_END;
-
-#ifdef FEATURE_IMPLICIT_TLS
- X86EmitPushRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
+#else // FEATURE_PAL
- //TODO: Inline the instruction instead of a call
- // call GetThread
- X86EmitCall(NewExternalCodeLabel((LPVOID) GetAppDomain), sizeof(void*));
-
- // mov dstreg, eax
- X86EmitMovRegReg(dstreg, kEAX);
-
- X86EmitPopRegs(preservedRegSet & ((1<<kEAX)|(1<<kEDX)|(1<<kECX)));
-
-#ifdef _DEBUG
- // Trash caller saved regs that we were not told to preserve, and that aren't the dstreg.
- preservedRegSet |= 1<<dstreg;
- if (!(preservedRegSet & (1<<kEAX)))
- X86EmitDebugTrashReg(kEAX);
- if (!(preservedRegSet & (1<<kEDX)))
- X86EmitDebugTrashReg(kEDX);
- if (!(preservedRegSet & (1<<kECX)))
- X86EmitDebugTrashReg(kECX);
+#ifdef _TARGET_AMD64_
+ BYTE code[] = { 0x65,0x48,0x8b,0x04,0x25 }; // mov dstreg, qword ptr gs:[IMM32]
+ static const int regByteIndex = 3;
+#elif defined(_TARGET_X86_)
+ BYTE code[] = { 0x64,0x8b,0x05 }; // mov dstreg, dword ptr fs:[IMM32]
+ static const int regByteIndex = 2;
#endif
+ code[regByteIndex] |= (dstreg << 3);
-#else // FEATURE_IMPLICIT_TLS
+ EmitBytes(code, sizeof(code));
+ Emit32(offsetof(TEB, ThreadLocalStoragePointer));
- X86EmitTLSFetch(GetAppDomainTLSIndex(), dstreg, preservedRegSet);
+ X86EmitIndexRegLoad(dstreg, dstreg, sizeof(void *) * (g_TlsIndex & 0xFFFF));
-#endif // FEATURE_IMPLICIT_TLS
+ X86EmitIndexRegLoad(dstreg, dstreg, (g_TlsIndex & 0x7FFF0000) >> 16);
+
+#endif // FEATURE_PAL
}
#if defined(_TARGET_X86_)
@@ -2861,56 +2743,7 @@ VOID StubLinkerCPU::EmitSetup(CodeLabel *pForwardRef)
{
STANDARD_VM_CONTRACT;
-#ifdef FEATURE_IMPLICIT_TLS
- DWORD idx = 0;
- TLSACCESSMODE mode = TLSACCESS_GENERIC;
-#else
- DWORD idx = GetThreadTLSIndex();
- TLSACCESSMODE mode = GetTLSAccessMode(idx);
-#endif
-
-#ifdef _DEBUG
- {
- static BOOL f = TRUE;
- f = !f;
- if (f)
- {
- mode = TLSACCESS_GENERIC;
- }
- }
-#endif
-
- switch (mode)
- {
- case TLSACCESS_WNT:
-#ifndef FEATURE_PAL
- {
- unsigned __int32 tlsofs = offsetof(TEB, TlsSlots) + (idx * sizeof(void*));
-
- static const BYTE code[] = {0x64,0x8b,0x1d}; // mov ebx, dword ptr fs:[IMM32]
- EmitBytes(code, sizeof(code));
- Emit32(tlsofs);
- }
-#else // !FEATURE_PAL
- _ASSERTE("TLSACCESS_WNT mode is not supported");
-#endif // !FEATURE_PAL
- break;
-
- case TLSACCESS_GENERIC:
-#ifdef FEATURE_IMPLICIT_TLS
- X86EmitCall(NewExternalCodeLabel((LPVOID) GetThread), sizeof(void*));
-#else
- X86EmitPushImm32(idx);
-
- // call TLSGetValue
- X86EmitCall(NewExternalCodeLabel((LPVOID) TlsGetValue), sizeof(void*));
-#endif
- // mov ebx,eax
- Emit16(0xc389);
- break;
- default:
- _ASSERTE(0);
- }
+ X86EmitCurrentThreadFetch(kEBX, 0);
// cmp ebx, 0
static const BYTE b[] = { 0x83, 0xFB, 0x0};
@@ -3150,7 +2983,6 @@ VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOf
#endif // _TARGET_X86_
// ebx <-- GetThread()
- // Trashes X86TLSFetch_TRASHABLE_REGS
X86EmitCurrentThreadFetch(kEBX, 0);
#if _DEBUG
diff --git a/src/vm/i386/stublinkerx86.h b/src/vm/i386/stublinkerx86.h
index 76d1f95845..50dc3b35a5 100644
--- a/src/vm/i386/stublinkerx86.h
+++ b/src/vm/i386/stublinkerx86.h
@@ -219,11 +219,7 @@ class StubLinkerCPU : public StubLinker
VOID X86EmitLeaRIP(CodeLabel *target, X86Reg reg);
#endif
- static const unsigned X86TLSFetch_TRASHABLE_REGS = (1<<kEAX) | (1<<kEDX) | (1<<kECX);
- VOID X86EmitTLSFetch(DWORD idx, X86Reg dstreg, unsigned preservedRegSet);
-
VOID X86EmitCurrentThreadFetch(X86Reg dstreg, unsigned preservedRegSet);
- VOID X86EmitCurrentAppDomainFetch(X86Reg dstreg, unsigned preservedRegSet);
VOID X86EmitIndexRegLoad(X86Reg dstreg, X86Reg srcreg, __int32 ofs = 0);
VOID X86EmitIndexRegStore(X86Reg dstreg, __int32 ofs, X86Reg srcreg);
@@ -421,7 +417,7 @@ class StubLinkerCPU : public StubLinker
VOID EmitDebugBreak();
#endif // !FEATURE_STUBS_AS_IL
-#if defined(_DEBUG) && (defined(_TARGET_AMD64_) || defined(_TARGET_X86_)) && !defined(FEATURE_PAL)
+#if defined(_DEBUG) && !defined(FEATURE_PAL)
//===========================================================================
// Emits code to log JITHelper access
void EmitJITHelperLoggingThunk(PCODE pJitHelper, LPVOID helperFuncCount);
diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
index 8cff03ae60..1611d585a5 100644
--- a/src/vm/jithelpers.cpp
+++ b/src/vm/jithelpers.cpp
@@ -5110,6 +5110,24 @@ HCIMPL0(void, JIT_ThrowArgumentOutOfRangeException)
HCIMPLEND
/*********************************************************************/
+HCIMPL0(void, JIT_ThrowPlatformNotSupportedException)
+{
+ FCALL_CONTRACT;
+
+ /* Make no assumptions about the current machine state */
+ ResetCurrentContext();
+
+ FC_GC_POLL_NOT_NEEDED(); // throws always open up for GC
+
+ HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION); // Set up a frame
+
+ COMPlusThrow(kPlatformNotSupportedException);
+
+ HELPER_METHOD_FRAME_END();
+}
+HCIMPLEND
+
+/*********************************************************************/
HCIMPL0(void, JIT_Overflow)
{
FCALL_CONTRACT;
diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
index 2a8fa908e9..1cefcaa807 100644
--- a/src/vm/jitinterface.cpp
+++ b/src/vm/jitinterface.cpp
@@ -676,16 +676,7 @@ BOOL CEEInfo::shouldEnforceCallvirtRestriction(
CORINFO_MODULE_HANDLE scopeHnd)
{
LIMITED_METHOD_CONTRACT;
- // see vsw 599197
- // verification rule added in whidbey requiring virtual methods
- // to be called via callvirt except if certain other rules are
- // obeyed.
-
- if (g_pConfig->LegacyVirtualMethodCallVerification())
- return false;
- else
- return true;
-
+ return TRUE;
}
#ifdef FEATURE_READYTORUN_COMPILER
@@ -2267,7 +2258,14 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
MethodTable* pMT = VMClsHnd.GetMethodTable();
- if (pMT->IsByRefLike())
+ if (VMClsHnd.IsNativeValueType())
+ {
+ // native value types have no GC pointers
+ result = 0;
+ memset(gcPtrs, TYPE_GC_NONE,
+ (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
+ }
+ else if (pMT->IsByRefLike())
{
// TODO: TypedReference should ideally be implemented as a by-ref-like struct containing a ByReference<T> field, in
// which case the check for g_TypedReferenceMT below would not be necessary
@@ -2287,13 +2285,6 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
result = ComputeGCLayout(VMClsHnd.AsMethodTable(), gcPtrs);
}
}
- else if (VMClsHnd.IsNativeValueType())
- {
- // native value types have no GC pointers
- result = 0;
- memset(gcPtrs, TYPE_GC_NONE,
- (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
- }
else
{
_ASSERTE(pMT->IsValueType());
@@ -4585,6 +4576,156 @@ BOOL CEEInfo::areTypesEquivalent(
}
/*********************************************************************/
+// See if a cast from fromClass to toClass will succeed, fail, or needs
+// to be resolved at runtime.
+TypeCompareState CEEInfo::compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass)
+{
+ CONTRACTL {
+ SO_TOLERANT;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ TypeCompareState result = TypeCompareState::May;
+
+ JIT_TO_EE_TRANSITION();
+
+ TypeHandle fromHnd = (TypeHandle) fromClass;
+ TypeHandle toHnd = (TypeHandle) toClass;
+
+#ifdef FEATURE_COMINTEROP
+ // If casting from a com object class, don't try to optimize.
+ if (fromHnd.IsComObjectType())
+ {
+ result = TypeCompareState::May;
+ }
+ else
+#endif // FEATURE_COMINTEROP
+
+ // If casting from ICastable, don't try to optimize
+ if (fromHnd.GetMethodTable()->IsICastable())
+ {
+ result = TypeCompareState::May;
+ }
+ // If casting to Nullable<T>, don't try to optimize
+ else if (Nullable::IsNullableType(toHnd))
+ {
+ result = TypeCompareState::May;
+ }
+ // If the types are not shared, we can check directly.
+ else if (!fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
+ {
+ result = fromHnd.CanCastTo(toHnd) ? TypeCompareState::Must : TypeCompareState::MustNot;
+ }
+ // Casting from a shared type to an unshared type.
+ else if (fromHnd.IsCanonicalSubtype() && !toHnd.IsCanonicalSubtype())
+ {
+ // Only handle casts to interface types for now
+ if (toHnd.IsInterface())
+ {
+ // Do a preliminary check.
+ BOOL canCast = fromHnd.CanCastTo(toHnd);
+
+ // Pass back positive results unfiltered. The unknown type
+ // parameters in fromClass did not come into play.
+ if (canCast)
+ {
+ result = TypeCompareState::Must;
+ }
+ // For negative results, the unknown type parameter in
+ // fromClass might match some instantiated interface,
+ // either directly or via variance.
+ //
+ // However, CanCastTo will report failure in such cases since
+ // __Canon won't match the instantiated type on the
+ // interface (which can't be __Canon since we screened out
+ // canonical subtypes for toClass above). So only report
+ // failure if the interface is not instantiated.
+ else if (!toHnd.HasInstantiation())
+ {
+ result = TypeCompareState::MustNot;
+ }
+ }
+ }
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ // In R2R it is a breaking change for a previously positive
+ // cast to become negative, but not for a previously negative
+ // cast to become positive. So in R2R a negative result is
+ // always reported back as May.
+ if (IsReadyToRunCompilation() && (result == TypeCompareState::MustNot))
+ {
+ result = TypeCompareState::May;
+ }
+#endif // FEATURE_READYTORUN_COMPILER
+
+ EE_TO_JIT_TRANSITION();
+
+ return result;
+}
+
+/*********************************************************************/
+// See if types represented by cls1 and cls2 compare equal, not
+// equal, or the comparison needs to be resolved at runtime.
+TypeCompareState CEEInfo::compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2)
+{
+ CONTRACTL {
+ SO_TOLERANT;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ TypeCompareState result = TypeCompareState::May;
+
+ JIT_TO_EE_TRANSITION();
+
+ TypeHandle hnd1 = (TypeHandle) cls1;
+ TypeHandle hnd2 = (TypeHandle) cls2;
+
+ // If neither type is a canonical subtype, type handle comparison suffices
+ if (!hnd1.IsCanonicalSubtype() && !hnd2.IsCanonicalSubtype())
+ {
+ result = (hnd1 == hnd2 ? TypeCompareState::Must : TypeCompareState::MustNot);
+ }
+ // If either or both types are canonical subtypes, we can sometimes prove inequality.
+ else
+ {
+ // If either is a value type then the types cannot
+ // be equal unless the type defs are the same.
+ if (hnd1.IsValueType() || hnd2.IsValueType())
+ {
+ if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
+ {
+ result = TypeCompareState::MustNot;
+ }
+ }
+ // If we have two ref types that are not __Canon, then the
+ // types cannot be equal unless the type defs are the same.
+ else
+ {
+ TypeHandle canonHnd = TypeHandle(g_pCanonMethodTableClass);
+ if ((hnd1 != canonHnd) && (hnd2 != canonHnd))
+ {
+ if (!hnd1.GetMethodTable()->HasSameTypeDefAs(hnd2.GetMethodTable()))
+ {
+ result = TypeCompareState::MustNot;
+ }
+ }
+ }
+ }
+
+ EE_TO_JIT_TRANSITION();
+
+ return result;
+}
+
+/*********************************************************************/
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE CEEInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
@@ -8683,6 +8824,45 @@ CORINFO_METHOD_HANDLE CEEInfo::resolveVirtualMethod(CORINFO_METHOD_HANDLE method
return result;
}
+/*********************************************************************/
+CORINFO_METHOD_HANDLE CEEInfo::getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg)
+{
+ CONTRACTL {
+ SO_TOLERANT;
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ CORINFO_METHOD_HANDLE result = NULL;
+
+ JIT_TO_EE_TRANSITION();
+
+ MethodDesc* pMD = GetMethod(ftn);
+ bool requiresInstMTArg = false;
+
+ if (pMD->IsUnboxingStub())
+ {
+ MethodTable* pMT = pMD->GetMethodTable();
+ MethodDesc* pUnboxedMD = pMT->GetUnboxedEntryPointMD(pMD);
+
+ result = (CORINFO_METHOD_HANDLE)pUnboxedMD;
+ requiresInstMTArg = !!pUnboxedMD->RequiresInstMethodTableArg();
+ }
+
+ if (requiresInstMethodTableArg != NULL)
+ {
+ *requiresInstMethodTableArg = requiresInstMTArg;
+ }
+
+ EE_TO_JIT_TRANSITION();
+
+ return result;
+}
+
+/*********************************************************************/
void CEEInfo::expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_GENERICHANDLE_RESULT * pResult)
@@ -8764,17 +8944,7 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS
switch(normType)
{
case ELEMENT_TYPE_I1:
- {
- targetClass = MscorlibBinder::GetClass(CLASS__SBYTE_ENUM_EQUALITYCOMPARER);
- break;
- }
-
case ELEMENT_TYPE_I2:
- {
- targetClass = MscorlibBinder::GetClass(CLASS__SHORT_ENUM_EQUALITYCOMPARER);
- break;
- }
-
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_I4:
@@ -9871,19 +10041,6 @@ DWORD CEEInfo::getThreadTLSIndex(void **ppIndirection)
if (ppIndirection != NULL)
*ppIndirection = NULL;
- JIT_TO_EE_TRANSITION();
-
-#if !defined(CROSSGEN_COMPILE) && !defined(FEATURE_IMPLICIT_TLS)
- result = GetThreadTLSIndex();
-
- // The JIT can use the optimized TLS access only if the runtime is using it as well.
- // (This is necessaryto make managed code work well under appverifier.)
- if (GetTLSAccessMode(result) == TLSACCESS_GENERIC)
- result = (DWORD)-1;
-#endif
-
- EE_TO_JIT_TRANSITION();
-
return result;
}
@@ -12032,24 +12189,11 @@ CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
//
// Notify the debugger that we have successfully jitted the function
//
- if (ftn->HasNativeCode())
+ if (g_pDebugInterface)
{
- //
- // Nothing to do here (don't need to notify the debugger
- // because the function has already been successfully jitted)
- //
- // This is the case where we aborted the jit because of a deadlock cycle
- // in initClass.
- //
- }
- else
- {
- if (g_pDebugInterface)
+ if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
{
- if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
- {
- g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
- }
+ g_pDebugInterface->JITComplete(ftn, (TADDR)*nativeEntry);
}
}
}
diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h
index b6d846ee7f..ccb88d8a42 100644
--- a/src/vm/jitinterface.h
+++ b/src/vm/jitinterface.h
@@ -22,6 +22,14 @@
#define MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT ((GetOsPageSize() / 2) - 1)
#endif // !FEATURE_PAL
+
+enum StompWriteBarrierCompletionAction
+{
+ SWB_PASS = 0x0,
+ SWB_ICACHE_FLUSH = 0x1,
+ SWB_EE_RESTART = 0x2
+};
+
class Stub;
class MethodDesc;
class FieldDesc;
@@ -294,20 +302,20 @@ public:
WriteBarrierManager();
void Initialize();
- void UpdateEphemeralBounds(bool isRuntimeSuspended);
- void UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck);
+ int UpdateEphemeralBounds(bool isRuntimeSuspended);
+ int UpdateWriteWatchAndCardTableLocations(bool isRuntimeSuspended, bool bReqUpperBoundsCheck);
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
- void SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
- void SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
+ int SwitchToWriteWatchBarrier(bool isRuntimeSuspended);
+ int SwitchToNonWriteWatchBarrier(bool isRuntimeSuspended);
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+ size_t GetCurrentWriteBarrierSize();
protected:
- size_t GetCurrentWriteBarrierSize();
size_t GetSpecificWriteBarrierSize(WriteBarrierType writeBarrier);
PBYTE CalculatePatchLocation(LPVOID base, LPVOID label, int offset);
PCODE GetCurrentWriteBarrierCode();
- void ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended);
+ int ChangeWriteBarrierTo(WriteBarrierType newWriteBarrier, bool isRuntimeSuspended);
bool NeedDifferentWriteBarrier(bool bReqUpperBoundsCheck, WriteBarrierType* pNewWriteBarrierType);
private:
@@ -554,6 +562,20 @@ public:
CORINFO_CLASS_HANDLE cls2
);
+ // See if a cast from fromClass to toClass will succeed, fail, or needs
+ // to be resolved at runtime.
+ TypeCompareState compareTypesForCast(
+ CORINFO_CLASS_HANDLE fromClass,
+ CORINFO_CLASS_HANDLE toClass
+ );
+
+ // See if types represented by cls1 and cls2 compare equal, not
+ // equal, or the comparison needs to be resolved at runtime.
+ TypeCompareState compareTypesForEquality(
+ CORINFO_CLASS_HANDLE cls1,
+ CORINFO_CLASS_HANDLE cls2
+ );
+
// returns is the intersection of cls1 and cls2.
CORINFO_CLASS_HANDLE mergeClasses(
CORINFO_CLASS_HANDLE cls1,
@@ -744,6 +766,11 @@ public:
CORINFO_CONTEXT_HANDLE ownerType
);
+ CORINFO_METHOD_HANDLE getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg
+ );
+
CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(
CORINFO_CLASS_HANDLE elemType
);
diff --git a/src/vm/jitinterfacegen.cpp b/src/vm/jitinterfacegen.cpp
index 38f1a7436a..b630e7f998 100644
--- a/src/vm/jitinterfacegen.cpp
+++ b/src/vm/jitinterfacegen.cpp
@@ -47,24 +47,10 @@ EXTERN_C Object* JIT_NewArr1OBJ_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
EXTERN_C Object* JIT_NewArr1VC_MP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
EXTERN_C Object* JIT_NewArr1VC_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
-extern "C" void* JIT_GetSharedNonGCStaticBase_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedNonGCStaticBaseNoCtor_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedGCStaticBase_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedGCStaticBaseNoCtor_Slow(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-
-extern "C" void* JIT_GetSharedNonGCStaticBase_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedGCStaticBase_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-extern "C" void* JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain(SIZE_T moduleDomainID, DWORD dwModuleClassID);
-
#ifdef _TARGET_AMD64_
extern WriteBarrierManager g_WriteBarrierManager;
#endif // _TARGET_AMD64_
-#ifndef FEATURE_IMPLICIT_TLS
-EXTERN_C DWORD gThreadTLSIndex;
-EXTERN_C DWORD gAppDomainTLSIndex;
-#endif
#endif // _WIN64
/*********************************************************************/
@@ -73,99 +59,6 @@ EXTERN_C DWORD gAppDomainTLSIndex;
/*********************************************************************/
#ifndef _TARGET_X86_
-#if defined(_TARGET_AMD64_)
-
-void MakeIntoJumpStub(LPVOID pStubAddress, LPVOID pTarget)
-{
- BYTE* pbStubAddress = (BYTE*)pStubAddress;
- BYTE* pbTarget = (BYTE*)pTarget;
-
- DWORD dwOldProtect;
- if (!ClrVirtualProtect(pbStubAddress, 5, PAGE_EXECUTE_READWRITE, &dwOldProtect))
- {
- ThrowLastError();
- }
-
- DWORD diff = (DWORD)(pbTarget - (pbStubAddress + 5));
-
- // Make sure that the offset fits in 32-bits
- _ASSERTE( FitsInI4(pbTarget - (pbStubAddress + 5)) );
-
- // Write a jmp pcrel32 instruction
- //
- // 0xe9xxxxxxxx
- pbStubAddress[0] = 0xE9;
- *((DWORD*)&pbStubAddress[1]) = diff;
-
- ClrVirtualProtect(pbStubAddress, 5, dwOldProtect, &dwOldProtect);
-}
-
-EXTERN_C void JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_BoxFastMPIGT__PatchTLSLabel();
-EXTERN_C void AllocateStringFastMP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset();
-EXTERN_C void JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset();
-
-
-static const LPVOID InlineGetThreadLocations[] = {
- (PVOID)JIT_TrialAllocSFastMP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_BoxFastMPIGT__PatchTLSLabel,
- (PVOID)AllocateStringFastMP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_NewArr1VC_MP_InlineGetThread__PatchTLSOffset,
- (PVOID)JIT_NewArr1OBJ_MP_InlineGetThread__PatchTLSOffset,
-};
-
-EXTERN_C void JIT_GetSharedNonGCStaticBase__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedGCStaticBase__PatchTLSLabel();
-EXTERN_C void JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel();
-
-static const LPVOID InlineGetAppDomainLocations[] = {
- (PVOID)JIT_GetSharedNonGCStaticBase__PatchTLSLabel,
- (PVOID)JIT_GetSharedNonGCStaticBaseNoCtor__PatchTLSLabel,
- (PVOID)JIT_GetSharedGCStaticBase__PatchTLSLabel,
- (PVOID)JIT_GetSharedGCStaticBaseNoCtor__PatchTLSLabel
-};
-
-
-#endif // defined(_TARGET_AMD64_)
-
-#if defined(_WIN64) && !defined(FEATURE_IMPLICIT_TLS)
-void FixupInlineGetters(DWORD tlsSlot, const LPVOID * pLocations, int nLocations)
-{
- BYTE* pInlineGetter;
- DWORD dwOldProtect;
- for (int i=0; i<nLocations; i++)
- {
- pInlineGetter = (BYTE*)GetEEFuncEntryPoint((BYTE*)pLocations[i]);
-
- static const DWORD cbPatch = 9;
- if (!ClrVirtualProtect(pInlineGetter, cbPatch, PAGE_EXECUTE_READWRITE, &dwOldProtect))
- {
- ThrowLastError();
- }
-
- DWORD offset = (tlsSlot * sizeof(LPVOID) + offsetof(TEB, TlsSlots));
-
-#if defined(_TARGET_AMD64_)
- // mov r??, gs:[TLS offset]
- _ASSERTE_ALL_BUILDS("clr/src/VM/JITinterfaceGen.cpp",
- pInlineGetter[0] == 0x65 &&
- pInlineGetter[2] == 0x8B &&
- pInlineGetter[4] == 0x25 &&
- "Initialization failure while stomping instructions for the TLS slot offset: the instruction at the given offset did not match what we expect");
-
- *((DWORD*)(pInlineGetter + 5)) = offset;
-#else // _TARGET_AMD64_
- PORTABILITY_ASSERT("FixupInlineGetters");
-#endif //_TARGET_AMD64_
-
- FlushInstructionCache(GetCurrentProcess(), pInlineGetter, cbPatch);
- ClrVirtualProtect(pInlineGetter, cbPatch, dwOldProtect, &dwOldProtect);
- }
-}
-#endif // defined(_WIN64) && !defined(FEATURE_IMPLICIT_TLS)
-
void InitJITHelpers1()
{
STANDARD_VM_CONTRACT;
@@ -176,18 +69,6 @@ void InitJITHelpers1()
g_WriteBarrierManager.Initialize();
-#ifndef FEATURE_IMPLICIT_TLS
- if (gThreadTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- FixupInlineGetters(gThreadTLSIndex, InlineGetThreadLocations, COUNTOF(InlineGetThreadLocations));
- }
-
- if (gAppDomainTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- FixupInlineGetters(gAppDomainTLSIndex, InlineGetAppDomainLocations, COUNTOF(InlineGetAppDomainLocations));
- }
-#endif // !FEATURE_IMPLICIT_TLS
-
// Allocation helpers, faster but non-logging
if (!((TrackAllocationsEnabled()) ||
(LoggingOn(LF_GCALLOC, LL_INFO10))
@@ -196,43 +77,27 @@ void InitJITHelpers1()
#endif // _DEBUG
))
{
+#ifdef FEATURE_PAL
+ SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable);
+ SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
+
+ ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
+#else // FEATURE_PAL
// if (multi-proc || server GC)
if (GCHeapUtilities::UseThreadAllocationContexts())
{
-#ifdef FEATURE_IMPLICIT_TLS
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_NewS_MP_FastPortable);
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_NewS_MP_FastPortable);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_FastPortable);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_FastPortable);
-
- ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateString_MP_FastPortable), ECall::FastAllocateString);
-#else // !FEATURE_IMPLICIT_TLS
- // If the TLS for Thread is low enough use the super-fast helpers
- if (gThreadTLSIndex < TLS_MINIMUM_AVAILABLE)
- {
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastMP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_TrialAllocSFastMP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastMP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_InlineGetThread);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_InlineGetThread);
-
- ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP_InlineGetThread), ECall::FastAllocateString);
- }
- else
- {
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastMP);
- SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_TrialAllocSFastMP);
- SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastMP);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP);
- SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP);
+ SetJitHelperFunction(CORINFO_HELP_NEWSFAST, JIT_TrialAllocSFastMP_InlineGetThread);
+ SetJitHelperFunction(CORINFO_HELP_NEWSFAST_ALIGN8, JIT_TrialAllocSFastMP_InlineGetThread);
+ SetJitHelperFunction(CORINFO_HELP_BOX, JIT_BoxFastMP_InlineGetThread);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_VC, JIT_NewArr1VC_MP_InlineGetThread);
+ SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_MP_InlineGetThread);
- ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP), ECall::FastAllocateString);
- }
-#endif // FEATURE_IMPLICIT_TLS
+ ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastMP_InlineGetThread), ECall::FastAllocateString);
}
else
{
-#ifndef FEATURE_PAL
// Replace the 1p slow allocation helpers with faster version
//
// When we're running Workstation GC on a single proc box we don't have
@@ -244,27 +109,9 @@ void InitJITHelpers1()
SetJitHelperFunction(CORINFO_HELP_NEWARR_1_OBJ, JIT_NewArr1OBJ_UP);
ECall::DynamicallyAssignFCallImpl(GetEEFuncEntryPoint(AllocateStringFastUP), ECall::FastAllocateString);
-#endif // !FEATURE_PAL
}
+#endif // FEATURE_PAL
}
-
- if(IsSingleAppDomain())
- {
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain);
- }
-#ifndef FEATURE_IMPLICIT_TLS
- else
- if (gAppDomainTLSIndex >= TLS_MINIMUM_AVAILABLE)
- {
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase_Slow);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase_Slow);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor_Slow);
- SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor_Slow);
- }
-#endif // !FEATURE_IMPLICIT_TLS
#endif // _TARGET_AMD64_
}
diff --git a/src/vm/method.hpp b/src/vm/method.hpp
index 5f860be1e7..3953b05a16 100644
--- a/src/vm/method.hpp
+++ b/src/vm/method.hpp
@@ -1239,11 +1239,6 @@ public:
{
LIMITED_METHOD_DAC_CONTRACT;
- // This policy will need to change some more before tiered compilation feature
- // can be properly supported across a broad range of scenarios. For instance it
- // wouldn't interact correctly with debugging at the moment because we enable
- // it too aggresively and it conflicts with the operations of those features.
-
// Keep in-sync with MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
// to ensure native slots are available where needed.
return g_pConfig->TieredCompilation() &&
@@ -1252,10 +1247,9 @@ public:
HasNativeCodeSlot() &&
!IsUnboxingStub() &&
!IsInstantiatingStub() &&
- !IsDynamicMethod();
-
- // We should add an exclusion for modules with debuggable code gen flags
-
+ !IsDynamicMethod() &&
+ !CORDisableJITOptimizations(GetModule()->GetDebuggerInfoBits()) &&
+ !CORProfilerDisableTieredCompilation();
}
#endif
diff --git a/src/vm/mscorlib.h b/src/vm/mscorlib.h
index 4942e0d8a9..f20e8d30b1 100644
--- a/src/vm/mscorlib.h
+++ b/src/vm/mscorlib.h
@@ -224,9 +224,6 @@ DEFINE_CLASS(RUNTIME_CLASS, WinRT, RuntimeClass)
#endif // FEATURE_COMINTEROP
DEFINE_CLASS_U(Interop, CriticalHandle, CriticalHandle)
-#ifdef _DEBUG
-DEFINE_FIELD_U(_stackTrace, CriticalHandle, m_debugStackTrace)
-#endif
DEFINE_FIELD_U(handle, CriticalHandle, m_handle)
DEFINE_FIELD_U(_isClosed, CriticalHandle, m_isClosed)
DEFINE_CLASS(CRITICAL_HANDLE, Interop, CriticalHandle)
@@ -933,7 +930,7 @@ DEFINE_CLASS(TP_WAIT_CALLBACK, Threading, _ThreadPoolWaitCa
DEFINE_METHOD(TP_WAIT_CALLBACK, PERFORM_WAIT_CALLBACK, PerformWaitCallback, SM_RetBool)
DEFINE_CLASS(TIMER_QUEUE, Threading, TimerQueue)
-DEFINE_METHOD(TIMER_QUEUE, APPDOMAIN_TIMER_CALLBACK, AppDomainTimerCallback, SM_RetVoid)
+DEFINE_METHOD(TIMER_QUEUE, APPDOMAIN_TIMER_CALLBACK, AppDomainTimerCallback, SM_Int_RetVoid)
DEFINE_CLASS(TIMESPAN, System, TimeSpan)
@@ -1420,9 +1417,9 @@ DEFINE_CLASS(LOADERALLOCATORSCOUT, Reflection, LoaderAllocatorS
DEFINE_CLASS(CONTRACTEXCEPTION, CodeContracts, ContractException)
DEFINE_CLASS_U(CodeContracts, ContractException, ContractExceptionObject)
-DEFINE_FIELD_U(_Kind, ContractExceptionObject, _Kind)
-DEFINE_FIELD_U(_UserMessage, ContractExceptionObject, _UserMessage)
-DEFINE_FIELD_U(_Condition, ContractExceptionObject, _Condition)
+DEFINE_FIELD_U(_kind, ContractExceptionObject, _Kind)
+DEFINE_FIELD_U(_userMessage, ContractExceptionObject, _UserMessage)
+DEFINE_FIELD_U(_condition, ContractExceptionObject, _Condition)
#ifdef FEATURE_COMINTEROP
DEFINE_CLASS(ASYNC_TRACING_EVENT_ARGS, WindowsFoundationDiag, TracingStatusChangedEventArgs)
@@ -1452,8 +1449,6 @@ DEFINE_METHOD(UTF8BUFFERMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, NoSig)
// Classes referenced in EqualityComparer<T>.Default optimization
DEFINE_CLASS(BYTE_EQUALITYCOMPARER, CollectionsGeneric, ByteEqualityComparer)
-DEFINE_CLASS(SHORT_ENUM_EQUALITYCOMPARER, CollectionsGeneric, ShortEnumEqualityComparer`1)
-DEFINE_CLASS(SBYTE_ENUM_EQUALITYCOMPARER, CollectionsGeneric, SByteEnumEqualityComparer`1)
DEFINE_CLASS(ENUM_EQUALITYCOMPARER, CollectionsGeneric, EnumEqualityComparer`1)
DEFINE_CLASS(LONG_ENUM_EQUALITYCOMPARER, CollectionsGeneric, LongEnumEqualityComparer`1)
DEFINE_CLASS(NULLABLE_EQUALITYCOMPARER, CollectionsGeneric, NullableEqualityComparer`1)
diff --git a/src/vm/object.h b/src/vm/object.h
index 20d7d50961..84ed0a5f1b 100644
--- a/src/vm/object.h
+++ b/src/vm/object.h
@@ -952,6 +952,13 @@ public:
return GetMethodTable()->GetApproxArrayElementTypeHandle();
}
+ PTR_OBJECTREF GetDataPtr()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC;
+ return dac_cast<PTR_OBJECTREF>(dac_cast<PTR_BYTE>(this) + GetDataOffset());
+ }
+
static SIZE_T GetDataOffset()
{
LIMITED_METHOD_CONTRACT;
@@ -2868,9 +2875,6 @@ class SafeHandle : public Object
// Modifying the order or fields of this object may require
// other changes to the classlib class definition of this
// object or special handling when loading this system class.
-#ifdef _DEBUG
- STRINGREF m_debugStackTrace; // Where we allocated this SafeHandle
-#endif
Volatile<LPVOID> m_handle;
Volatile<INT32> m_state; // Combined ref count and closed/disposed state (for atomicity)
Volatile<CLR_BOOL> m_ownsHandle;
@@ -2938,9 +2942,6 @@ class CriticalHandle : public Object
// Modifying the order or fields of this object may require
// other changes to the classlib class definition of this
// object or special handling when loading this system class.
-#ifdef _DEBUG
- STRINGREF m_debugStackTrace; // Where we allocated this CriticalHandle
-#endif
Volatile<LPVOID> m_handle;
Volatile<CLR_BOOL> m_isClosed;
diff --git a/src/vm/peimagelayout.cpp b/src/vm/peimagelayout.cpp
index 94810a0e61..2096a9bcb8 100644
--- a/src/vm/peimagelayout.cpp
+++ b/src/vm/peimagelayout.cpp
@@ -445,7 +445,7 @@ MappedImageLayout::MappedImageLayout(HANDLE hFile, PEImage* pOwner)
// if (!HasNativeHeader())
// ThrowHR(COR_E_BADIMAGEFORMAT);
- if (HasNativeHeader())
+ if (HasNativeHeader() && g_fAllowNativeImages)
{
if (!IsNativeMachineFormat())
ThrowHR(COR_E_BADIMAGEFORMAT);
@@ -501,7 +501,7 @@ MappedImageLayout::MappedImageLayout(HANDLE hFile, PEImage* pOwner)
if (!HasCorHeader())
ThrowHR(COR_E_BADIMAGEFORMAT);
- if (HasNativeHeader() || HasReadyToRunHeader())
+ if ((HasNativeHeader() || HasReadyToRunHeader()) && g_fAllowNativeImages)
{
//Do base relocation for PE, if necessary.
if (!IsNativeMachineFormat())
diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp
index d2f24bde29..813af75f48 100644
--- a/src/vm/prestub.cpp
+++ b/src/vm/prestub.cpp
@@ -2586,9 +2586,6 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock
//
// Optimization cases
//
- // TODO-ARM : If the optimization cases are implemented in CreateDictionaryLookupHelper,
- // It's ifndef for ARM will be removed.
-#ifndef _TARGET_ARM_
if (signatureKind == ENCODE_TYPE_HANDLE)
{
SigPointer sigptr(pBlob, -1);
@@ -2631,7 +2628,6 @@ void ProcessDynamicDictionaryLookup(TransitionBlock * pTransitionBlock
return;
}
}
-#endif // !_TARGET_ARM_
if (pContextMT != NULL && pContextMT->GetNumDicts() > 0xFFFF)
ThrowHR(COR_E_BADIMAGEFORMAT);
diff --git a/src/vm/proftoeeinterfaceimpl.cpp b/src/vm/proftoeeinterfaceimpl.cpp
index 3958bdf354..b9e5481e0f 100644
--- a/src/vm/proftoeeinterfaceimpl.cpp
+++ b/src/vm/proftoeeinterfaceimpl.cpp
@@ -589,6 +589,10 @@ COM_METHOD ProfToEEInterfaceImpl::QueryInterface(REFIID id, void ** pInterface)
{
*pInterface = static_cast<ICorProfilerInfo8 *>(this);
}
+ else if (id == IID_ICorProfilerInfo9)
+ {
+ *pInterface = static_cast<ICorProfilerInfo9 *>(this);
+ }
else if (id == IID_IUnknown)
{
*pInterface = static_cast<IUnknown *>(static_cast<ICorProfilerInfo *>(this));
@@ -2592,24 +2596,28 @@ HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
if (SUCCEEDED(hr))
{
+ PCODE pCodeStart = NULL;
CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
- ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
-
- // Now that tiered compilation can create more than one jitted code version for the same rejit id
- // we are arbitrarily choosing the first one to return. To return all of them we'd presumably need
- // a new profiler API.
- NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
- for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
{
- PCODE pCodeStart = iter->GetNativeCode();
- hr = GetCodeInfoFromCodeStart(
- pCodeStart,
- cCodeInfos,
- pcCodeInfos,
- codeInfos);
- break;
+ CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
+
+ ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
+
+ NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
+ for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
+ {
+ // Now that tiered compilation can create more than one jitted code version for the same rejit id
+ // we are arbitrarily choosing the first one to return. To address a specific version of native code
+ // use GetCodeInfo4.
+ pCodeStart = iter->GetNativeCode();
+ break;
+ }
}
+ hr = GetCodeInfoFromCodeStart(pCodeStart,
+ cCodeInfos,
+ pcCodeInfos,
+ codeInfos);
}
}
EX_CATCH_HRESULT(hr);
@@ -5042,7 +5050,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
ULONG32 cMap,
ULONG32 * pcMap, // [out]
COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
- {
+{
CONTRACTL
{
// MethodDesc::FindOrCreateTypicalSharedInstantiation throws
@@ -5070,7 +5078,7 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
LL_INFO1000,
"**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
functionId, reJitId));
-
+
if (functionId == NULL)
{
return E_INVALIDARG;
@@ -5082,36 +5090,51 @@ HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
return E_INVALIDARG;
}
- if (reJitId != 0)
+ HRESULT hr = S_OK;
+
+ EX_TRY
{
- return E_NOTIMPL;
- }
+ // Cast to proper type
+ MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
-#ifdef DEBUGGING_SUPPORTED
- // Cast to proper type
- MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
+ if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
+ {
+ // In this case, we used to replace pMD with its canonical instantiation
+ // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
+ // to get to this point anyway, since any MethodDesc a profiler gets from us
+ // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
+ // We assert here just in case a test proves me wrong, but generally we will
+ // disallow this code path.
+ _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
+ hr = E_INVALIDARG;
+ }
+ else
+ {
+ PCODE pCodeStart = NULL;
+ CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
+ ILCodeVersion ilCodeVersion = NULL;
+ {
+ CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
- if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
- {
- // In this case, we used to replace pMD with its canonical instantiation
- // (FindOrCreateTypicalSharedInstantiation). However, a profiler should never be able
- // to get to this point anyway, since any MethodDesc a profiler gets from us
- // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
- // We assert here just in case a test proves me wrong, but generally we will
- // disallow this code path.
- _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
- return E_INVALIDARG;
- }
+ pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
+
+ NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
+ for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
+ {
+ // Now that tiered compilation can create more than one jitted code version for the same rejit id
+ // we are arbitrarily choosing the first one to return. To address a specific version of native code
+ // use GetILToNativeMapping3.
+ pCodeStart = iter->GetNativeCode();
+ break;
+ }
+ }
- if (g_pDebugInterface == NULL)
- {
- return CORPROF_E_DEBUGGING_DISABLED;
+ hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map);
+ }
}
+ EX_CATCH_HRESULT(hr);
- return (g_pDebugInterface->GetILToNativeMapping(pMD, cMap, pcMap, map));
-#else
- return E_NOTIMPL;
-#endif
+ return hr;
}
@@ -6583,6 +6606,231 @@ HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
}
/*
+ * GetNativeCodeStartAddresses
+ *
+ * Gets all of the native code addresses associated with a particular function. iered compilation
+ * potentially creates different native code versions for a method, and this function allows profilers
+ * to view all native versions of a method.
+ *
+ * Parameters:
+ * functionID - The function that is being requested.
+ * reJitId - The ReJIT id.
+ * cCodeStartAddresses - A parameter for indicating the size of buffer for the codeStartAddresses parameter.
+ * pcCodeStartAddresses - An optional parameter for returning the true size of the codeStartAddresses parameter.
+ * codeStartAddresses - The array to be filled up with native code addresses.
+ *
+ * Returns:
+ * S_OK if successful
+ *
+ */
+HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID,
+ ReJITID reJitId,
+ ULONG32 cCodeStartAddresses,
+ ULONG32 *pcCodeStartAddresses,
+ UINT_PTR codeStartAddresses[])
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ EE_THREAD_NOT_REQUIRED;
+ CAN_TAKE_LOCK;
+
+ SO_NOT_MAINLINE;
+
+ PRECONDITION(CheckPointer(pcCodeStartAddresses, NULL_OK));
+ PRECONDITION(CheckPointer(codeStartAddresses, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ if (functionID == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
+ (LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n",
+ functionID, reJitId));
+
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ if (pcCodeStartAddresses != NULL)
+ {
+ *pcCodeStartAddresses = 0;
+ }
+
+ MethodDesc * methodDesc = FunctionIdToMethodDesc(functionID);
+ PTR_MethodDesc pMD = PTR_MethodDesc(methodDesc);
+ ULONG32 trueLen = 0;
+ StackSArray<UINT_PTR> addresses;
+
+ CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
+
+ ILCodeVersion ilCodeVersion = NULL;
+ {
+ CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
+
+ ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
+
+ NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
+ for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
+ {
+ addresses.Append((*iter).GetNativeCode());
+
+ ++trueLen;
+ }
+ }
+
+ if (pcCodeStartAddresses != NULL)
+ {
+ *pcCodeStartAddresses = trueLen;
+ }
+
+ if (codeStartAddresses != NULL)
+ {
+ if (cCodeStartAddresses < trueLen)
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ }
+ else
+ {
+ for(ULONG32 i = 0; i < trueLen; ++i)
+ {
+ codeStartAddresses[i] = addresses[i];
+ }
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+/*
+ * GetILToNativeMapping3
+ *
+ * This overload behaves the same as GetILToNativeMapping2, except it allows the profiler
+ * to address specific native code versions instead of defaulting to the first one.
+ *
+ * Parameters:
+ * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
+ * cMap - size of the map array
+ * pcMap - how many items are returned in the map array
+ * map - an array to store the il to native mappings in
+ *
+ * Returns:
+ * S_OK if successful
+ *
+ */
+HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cMap,
+ ULONG32 *pcMap,
+ COR_DEBUG_IL_TO_NATIVE_MAP map[])
+{
+ CONTRACTL
+ {
+ THROWS;
+ DISABLED(GC_NOTRIGGER);
+ MODE_ANY;
+ CAN_TAKE_LOCK;
+
+ SO_NOT_MAINLINE;
+
+ PRECONDITION(CheckPointer(pcMap, NULL_OK));
+ PRECONDITION(CheckPointer(map, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
+ (LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: GetILToNativeMapping3 0x%p.\n",
+ pNativeCodeStartAddress));
+
+ if (pNativeCodeStartAddress == NULL)
+ {
+ return E_INVALIDARG;
+ }
+
+ if ((cMap > 0) &&
+ ((pcMap == NULL) || (map == NULL)))
+ {
+ return E_INVALIDARG;
+ }
+
+#ifdef DEBUGGING_SUPPORTED
+ if (g_pDebugInterface == NULL)
+ {
+ return CORPROF_E_DEBUGGING_DISABLED;
+ }
+
+ return (g_pDebugInterface->GetILToNativeMapping(pNativeCodeStartAddress, cMap, pcMap, map));
+#else
+ return E_NOTIMPL;
+#endif
+}
+
+/*
+ * GetCodeInfo4
+ *
+ * Gets the location and size of a jitted function. Tiered compilation potentially creates different native code
+ * versions for a method, and this overload allows profilers to specify which native version it would like the
+ * code info for.
+ *
+ * Parameters:
+ * pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
+ * cCodeInfos - size of the codeInfos array
+ * pcCodeInfos - how many items are returned in the codeInfos array
+ * codeInfos - an array to store the code infos in
+ *
+ * Returns:
+ * S_OK if successful
+ *
+ */
+HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cCodeInfos,
+ ULONG32* pcCodeInfos,
+ COR_PRF_CODE_INFO codeInfos[])
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_ANY;
+ EE_THREAD_NOT_REQUIRED;
+ CAN_TAKE_LOCK;
+
+ SO_NOT_MAINLINE;
+
+ PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
+ PRECONDITION(CheckPointer(codeInfos, NULL_OK));
+ }
+ CONTRACTL_END;
+
+ PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
+ kP2EEAllowableAfterAttach | kP2EETriggers,
+ (LF_CORPROF,
+ LL_INFO1000,
+ "**PROF: GetCodeInfo4 0x%p.\n",
+ pNativeCodeStartAddress));
+
+ if ((cCodeInfos != 0) && (codeInfos == NULL))
+ {
+ return E_INVALIDARG;
+ }
+
+ return GetCodeInfoFromCodeStart(pNativeCodeStartAddress,
+ cCodeInfos,
+ pcCodeInfos,
+ codeInfos);
+}
+
+/*
* GetStringLayout
*
* This function describes to a profiler the internal layout of a string.
diff --git a/src/vm/proftoeeinterfaceimpl.h b/src/vm/proftoeeinterfaceimpl.h
index ed53ae2192..7c3c88b439 100644
--- a/src/vm/proftoeeinterfaceimpl.h
+++ b/src/vm/proftoeeinterfaceimpl.h
@@ -133,7 +133,7 @@ typedef struct _PROFILER_STACK_WALK_DATA PROFILER_STACK_WALK_DATA;
// from the profiler implementation. The profiler will call back on the v-table
// to get at EE internals as required.
-class ProfToEEInterfaceImpl : public ICorProfilerInfo8
+class ProfToEEInterfaceImpl : public ICorProfilerInfo9
{
public:
@@ -577,6 +577,29 @@ public:
// end ICorProfilerInfo8
+ // beging ICorProfilerInfo9
+
+ COM_METHOD GetNativeCodeStartAddresses(
+ FunctionID functionID,
+ ReJITID reJitId,
+ ULONG32 cCodeStartAddresses,
+ ULONG32 *pcCodeStartAddresses,
+ UINT_PTR codeStartAddresses[]);
+
+ COM_METHOD GetILToNativeMapping3(
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cMap,
+ ULONG32 *pcMap,
+ COR_DEBUG_IL_TO_NATIVE_MAP map[]);
+
+ COM_METHOD GetCodeInfo4(
+ UINT_PTR pNativeCodeStartAddress,
+ ULONG32 cCodeInfos,
+ ULONG32* pcCodeInfos,
+ COR_PRF_CODE_INFO codeInfos[]);
+
+ // end ICorProfilerInfo9
+
protected:
// Internal Helper Functions
diff --git a/src/vm/readytoruninfo.cpp b/src/vm/readytoruninfo.cpp
index 5ac1eb114d..bcb8e8364d 100644
--- a/src/vm/readytoruninfo.cpp
+++ b/src/vm/readytoruninfo.cpp
@@ -456,6 +456,13 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker
PEFile * pFile = pModule->GetFile();
+ if (!IsReadyToRunEnabled())
+ {
+ // Log message is ignored in this case.
+ DoLog(NULL);
+ return NULL;
+ }
+
// Ignore ReadyToRun for introspection-only loads
if (pFile->IsIntrospectionOnly())
{
@@ -476,13 +483,6 @@ PTR_ReadyToRunInfo ReadyToRunInfo::Initialize(Module * pModule, AllocMemTracker
return NULL;
}
- if (!IsReadyToRunEnabled())
- {
- // Log message is ignored in this case.
- DoLog(NULL);
- return NULL;
- }
-
if (CORProfilerDisableAllNGenImages() || CORProfilerUseProfileImages())
{
DoLog("Ready to Run disabled - profiler disabled native images");
diff --git a/src/vm/safehandle.cpp b/src/vm/safehandle.cpp
index d79c5a749a..5e0626b9e7 100644
--- a/src/vm/safehandle.cpp
+++ b/src/vm/safehandle.cpp
@@ -62,9 +62,6 @@ void SafeHandle::AddRef()
// Cannot use "this" after Release, which toggles the GC mode.
SAFEHANDLEREF sh(this);
-#ifdef _DEBUG
- VALIDATEOBJECTREF(sh->m_debugStackTrace);
-#endif
_ASSERTE(sh->IsFullyInitialized());
// To prevent handle recycling security attacks we must enforce the
@@ -137,9 +134,6 @@ void SafeHandle::Release(bool fDispose)
// Cannot use "this" after RunReleaseMethod, which toggles the GC mode.
SAFEHANDLEREF sh(this);
-#ifdef _DEBUG
- VALIDATEOBJECTREF(sh->m_debugStackTrace);
-#endif
_ASSERTE(sh->IsFullyInitialized());
// See AddRef above for the design of the synchronization here. Basically we
@@ -236,9 +230,6 @@ void SafeHandle::Dispose()
// Release may trigger a GC.
SAFEHANDLEREF sh(this);
-#ifdef _DEBUG
- VALIDATEOBJECTREF(sh->m_debugStackTrace);
-#endif
_ASSERTE(sh->IsFullyInitialized());
GCPROTECT_BEGIN(sh);
diff --git a/src/vm/siginfo.cpp b/src/vm/siginfo.cpp
index 40a55cb6f0..be919c8b7e 100644
--- a/src/vm/siginfo.cpp
+++ b/src/vm/siginfo.cpp
@@ -4969,7 +4969,7 @@ void ReportByRefPointersFromByRefLikeObject(promote_func *fn, ScanContext *sc, P
}
// TODO: GetApproxFieldTypeHandleThrowing may throw. This is a potential stress problem for fragile NGen of non-CoreLib
- // assemblies. It won’t ever throw for CoreCLR with R2R. Figure out if anything needs to be done to deal with the
+ // assemblies. It won't ever throw for CoreCLR with R2R. Figure out if anything needs to be done to deal with the
// exception.
PTR_MethodTable pFieldMT = pFD->GetApproxFieldTypeHandleThrowing().AsMethodTable();
if (!pFieldMT->IsByRefLike())
diff --git a/src/vm/stubmgr.h b/src/vm/stubmgr.h
index 10cba00de7..b18520a1d1 100644
--- a/src/vm/stubmgr.h
+++ b/src/vm/stubmgr.h
@@ -26,6 +26,22 @@
// The set of stub managers is extensible, but should be kept to a reasonable number
// as they are currently linearly searched & queried for each stub.
//
+//
+// IMPORTANT IMPLEMENTATION NOTE: Due to code versioning, tracing through a jitted code
+// call is a speculative exercise. A trace could predict that calling method Foo would run
+// jitted code at address 0x1234, however afterwards code versioning redirects Foo to call
+// an alternate jitted code body at address 0x5678. To handle this stub managers should
+// either:
+// a) stop tracing at offset zero of the newly called jitted code. The debugger knows
+// to treat offset 0 in jitted code as potentially being any jitted code instance
+// b) trace all the way through the jitted method such that regardless of which jitted
+// code instance gets called the trace will still end at the predicted location.
+//
+// If we wanted to be more rigorous about this we should probably have different trace
+// results for intra-jitted and inter-jitted trace results but given the relative
+// stability of this part of the code I haven't attacked that problem right now. It does
+// work as-is.
+//
#ifndef __stubmgr_h__
diff --git a/src/vm/synch.cpp b/src/vm/synch.cpp
index e4fae65855..c21e4f53a0 100644
--- a/src/vm/synch.cpp
+++ b/src/vm/synch.cpp
@@ -668,8 +668,19 @@ bool CLRLifoSemaphore::WaitForSignal(DWORD timeoutMs)
#endif // FEATURE_PAL
}
+ if (!waitSuccessful)
+ {
+ // Unregister the waiter. The wait subsystem used above guarantees that a thread that wakes due to a timeout does
+ // not observe a signal to the object being waited upon.
+ Counts toSubtract;
+ ++toSubtract.waiterCount;
+ Counts countsBeforeUpdate = m_counts.ExchangeAdd(-toSubtract);
+ _ASSERTE(countsBeforeUpdate.waiterCount != (UINT16)0);
+ return false;
+ }
+
// Unregister the waiter if this thread will not be waiting anymore, and try to acquire the semaphore
- Counts counts = m_counts.VolatileLoad();
+ Counts counts = m_counts;
while (true)
{
_ASSERTE(counts.waiterCount != (UINT16)0);
@@ -679,16 +690,8 @@ bool CLRLifoSemaphore::WaitForSignal(DWORD timeoutMs)
--newCounts.signalCount;
--newCounts.waiterCount;
}
- else if (!waitSuccessful)
- {
- --newCounts.waiterCount;
- }
- // This waiter has woken up and this needs to be reflected in the count of waiters signaled to wake. Since we don't
- // have thread-specific signal state, there is not enough information to tell whether this thread woke up because it
- // was signaled. For instance, this thread may have timed out and then we don't know whether this thread also got
- // signaled. So in any woken case, decrement the count if possible. As such, timeouts could cause more waiters to
- // wake than necessary.
+ // This waiter has woken up and this needs to be reflected in the count of waiters signaled to wake
if (counts.countOfWaitersSignaledToWake != (UINT8)0)
{
--newCounts.countOfWaitersSignaledToWake;
@@ -706,11 +709,6 @@ bool CLRLifoSemaphore::WaitForSignal(DWORD timeoutMs)
counts = countsBeforeUpdate;
}
-
- if (!waitSuccessful)
- {
- return false;
- }
}
}
@@ -721,7 +719,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs)
_ASSERTE(m_handle != nullptr);
// Acquire the semaphore or register as a waiter
- Counts counts = m_counts.VolatileLoad();
+ Counts counts = m_counts;
while (true)
{
_ASSERTE(counts.signalCount <= m_maximumSignalCount);
@@ -764,7 +762,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorC
}
// Try to acquire the semaphore or register as a spinner
- Counts counts = m_counts.VolatileLoad();
+ Counts counts = m_counts;
while (true)
{
Counts newCounts = counts;
@@ -811,7 +809,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorC
ClrSleepEx(0, false);
// Try to acquire the semaphore and unregister as a spinner
- counts = m_counts.VolatileLoad();
+ counts = m_counts;
while (true)
{
_ASSERTE(counts.spinnerCount != (UINT8)0);
@@ -843,7 +841,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorC
}
#else // !_TARGET_ARM64_
const UINT32 Sleep0Threshold = 10;
- YieldProcessorWithBackOffNormalizationInfo normalizationInfo;
+ YieldProcessorNormalizationInfo normalizationInfo;
#ifdef FEATURE_PAL
// The PAL's wait subsystem is quite slow, spin more to compensate for the more expensive wait
spinCount *= 2;
@@ -870,7 +868,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorC
}
// Try to acquire the semaphore and unregister as a spinner
- counts = m_counts.VolatileLoad();
+ counts = m_counts;
while (true)
{
_ASSERTE(counts.spinnerCount != (UINT8)0);
@@ -895,7 +893,7 @@ bool CLRLifoSemaphore::Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorC
#endif // _TARGET_ARM64_
// Unregister as a spinner, and acquire the semaphore or register as a waiter
- counts = m_counts.VolatileLoad();
+ counts = m_counts;
while (true)
{
_ASSERTE(counts.spinnerCount != (UINT8)0);
@@ -936,7 +934,7 @@ void CLRLifoSemaphore::Release(INT32 releaseCount)
_ASSERTE(m_handle != INVALID_HANDLE_VALUE);
INT32 countOfWaitersToWake;
- Counts counts = m_counts.VolatileLoad();
+ Counts counts = m_counts;
while (true)
{
Counts newCounts = counts;
diff --git a/src/vm/synch.h b/src/vm/synch.h
index c8e9baf481..30e6c30672 100644
--- a/src/vm/synch.h
+++ b/src/vm/synch.h
@@ -205,6 +205,12 @@ private:
return data;
}
+ Counts operator -() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return -(INT64)data;
+ }
+
Counts &operator =(UINT64 data)
{
LIMITED_METHOD_CONTRACT;
@@ -213,16 +219,16 @@ private:
return *this;
}
- Counts VolatileLoad() const
+ Counts CompareExchange(Counts toCounts, Counts fromCounts)
{
LIMITED_METHOD_CONTRACT;
- return ::VolatileLoad(&data);
+ return (UINT64)InterlockedCompareExchange64((LONG64 *)&data, (LONG64)toCounts, (LONG64)fromCounts);
}
- Counts CompareExchange(Counts toCounts, Counts fromCounts)
+ Counts ExchangeAdd(Counts toAdd)
{
LIMITED_METHOD_CONTRACT;
- return (UINT64)InterlockedCompareExchange64((LONG64 *)&data, (LONG64)toCounts, (LONG64)fromCounts);
+ return (UINT64)InterlockedExchangeAdd64((LONG64 *)&data, (LONG64)toAdd);
}
};
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 56bdffb1f1..d9ee637b1a 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -63,18 +63,12 @@ SPTR_IMPL(ThreadStore, ThreadStore, s_pThreadStore);
CONTEXT *ThreadStore::s_pOSContext = NULL;
CLREvent *ThreadStore::s_pWaitForStackCrawlEvent;
-static CrstStatic s_initializeYieldProcessorNormalizedCrst;
-
#ifndef DACCESS_COMPILE
BOOL Thread::s_fCleanFinalizedThread = FALSE;
-#ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-BOOL Thread::s_fEnforceEEThreadNotRequiredContracts = FALSE;
-#endif
-
Volatile<LONG> Thread::s_threadPoolCompletionCountOverflow = 0;
CrstStatic g_DeadlockAwareCrst;
@@ -290,9 +284,6 @@ bool Thread::DetectHandleILStubsForDebugger()
return false;
}
-
-#ifdef FEATURE_IMPLICIT_TLS
-
extern "C" {
#ifndef __llvm__
__declspec(thread)
@@ -304,26 +295,15 @@ ThreadLocalInfo gCurrentThreadInfo =
NULL, // m_pThread
NULL, // m_pAppDomain
NULL, // m_EETlsData
-#if defined(FEATURE_MERGE_JIT_AND_ENGINE)
- NULL, // m_pCompiler
-#endif
};
} // extern "C"
// index into TLS Array. Definition added by compiler
EXTERN_C UINT32 _tls_index;
-#else // FEATURE_IMPLICIT_TLS
-extern "C" {
-GVAL_IMPL_INIT(DWORD, gThreadTLSIndex, TLS_OUT_OF_INDEXES); // index ( (-1) == uninitialized )
-GVAL_IMPL_INIT(DWORD, gAppDomainTLSIndex, TLS_OUT_OF_INDEXES); // index ( (-1) == uninitialized )
-}
-#endif // FEATURE_IMPLICIT_TLS
-
#ifndef DACCESS_COMPILE
-#ifdef FEATURE_IMPLICIT_TLS
BOOL SetThread(Thread* t)
{
- LIMITED_METHOD_CONTRACT
+ LIMITED_METHOD_CONTRACT
gCurrentThreadInfo.m_pThread = t;
return TRUE;
@@ -331,52 +311,12 @@ BOOL SetThread(Thread* t)
BOOL SetAppDomain(AppDomain* ad)
{
- LIMITED_METHOD_CONTRACT
+ LIMITED_METHOD_CONTRACT
gCurrentThreadInfo.m_pAppDomain = ad;
return TRUE;
}
-#if defined(FEATURE_MERGE_JIT_AND_ENGINE)
-extern "C"
-{
-
-void* GetJitTls()
-{
- LIMITED_METHOD_CONTRACT
-
- return gCurrentThreadInfo.m_pJitTls;
-}
-
-void SetJitTls(void* v)
-{
- LIMITED_METHOD_CONTRACT
- gCurrentThreadInfo.m_pJitTls = v;
-}
-
-}
-#endif // defined(FEATURE_MERGE_JIT_AND_ENGINE)
-
-#define ThreadInited() (TRUE)
-
-#else // FEATURE_IMPLICIT_TLS
-BOOL SetThread(Thread* t)
-{
- WRAPPER_NO_CONTRACT
- return UnsafeTlsSetValue(GetThreadTLSIndex(), t);
-}
-
-BOOL SetAppDomain(AppDomain* ad)
-{
- WRAPPER_NO_CONTRACT
- return UnsafeTlsSetValue(GetAppDomainTLSIndex(), ad);
-}
-
-#define ThreadInited() (gThreadTLSIndex != TLS_OUT_OF_INDEXES)
-
-#endif // FEATURE_IMPLICIT_TLS
-
-
BOOL Thread::Alert ()
{
CONTRACTL {
@@ -681,7 +621,6 @@ Thread* SetupThread(BOOL fInternal)
}
CONTRACTL_END;
- _ASSERTE(ThreadInited());
Thread* pThread;
if ((pThread = GetThread()) != NULL)
return pThread;
@@ -782,18 +721,6 @@ Thread* SetupThread(BOOL fInternal)
!pThread->PrepareApartmentAndContext())
ThrowOutOfMemory();
-#ifndef FEATURE_IMPLICIT_TLS
- // make sure we will not fail when we store in TLS in the future.
- if (!UnsafeTlsSetValue(gThreadTLSIndex, NULL))
- {
- ThrowOutOfMemory();
- }
- if (!UnsafeTlsSetValue(GetAppDomainTLSIndex(), NULL))
- {
- ThrowOutOfMemory();
- }
-#endif
-
// reset any unstarted bits on the thread object
FastInterlockAnd((ULONG *) &pThread->m_State, ~Thread::TS_Unstarted);
FastInterlockOr((ULONG *) &pThread->m_State, Thread::TS_LegalToJoin);
@@ -915,7 +842,6 @@ Thread* SetupUnstartedThread(BOOL bRequiresTSL)
}
CONTRACTL_END;
- _ASSERTE(ThreadInited());
Thread* pThread = new Thread();
FastInterlockOr((ULONG *) &pThread->m_State,
@@ -1112,42 +1038,11 @@ HRESULT Thread::DetachThread(BOOL fDLLThreadDetach)
return S_OK;
}
-#ifndef FEATURE_IMPLICIT_TLS
-//---------------------------------------------------------------------------
-// Returns the TLS index for the Thread. This is strictly for the use of
-// our ASM stub generators that generate inline code to access the Thread.
-// Normally, you should use GetThread().
-//---------------------------------------------------------------------------
-DWORD GetThreadTLSIndex()
-{
- LIMITED_METHOD_CONTRACT;
-
- return gThreadTLSIndex;
-}
-
-//---------------------------------------------------------------------------
-// Returns the TLS index for the AppDomain. This is strictly for the use of
-// our ASM stub generators that generate inline code to access the AppDomain.
-// Normally, you should use GetAppDomain().
-//---------------------------------------------------------------------------
-DWORD GetAppDomainTLSIndex()
-{
- LIMITED_METHOD_CONTRACT;
-
- return gAppDomainTLSIndex;
-}
-#endif
-
DWORD GetRuntimeId()
{
LIMITED_METHOD_CONTRACT;
-#ifndef FEATURE_IMPLICIT_TLS
- _ASSERTE(GetThreadTLSIndex() != TLS_OUT_OF_INDEXES);
- return GetThreadTLSIndex() + 3;
-#else
return _tls_index;
-#endif
}
//---------------------------------------------------------------------------
@@ -1191,165 +1086,6 @@ Thread* WINAPI CreateThreadBlockThrow()
DWORD_PTR Thread::OBJREF_HASH = OBJREF_TABSIZE;
#endif
-#ifndef FEATURE_IMPLICIT_TLS
-
-#ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-// ----------------------------------------------------------------------------
-// GetThreadGenericFullCheck
-//
-// Description:
-// The non-PAL, x86 / x64 assembly versions of GetThreadGeneric call into this C
-// function to optionally do some verification before returning the EE Thread object
-// for the current thread. Currently the primary enforcement this function does is
-// around the EE_THREAD_(NOT)_REQUIRED contracts. For a definition of these
-// contracts, how they're used, and how temporary "safe" scopes may be created
-// using BEGIN_GETTHREAD_ALLOWED / END_GETTHREAD_ALLOWED, see the comments at the top
-// of contract.h.
-//
-// The EE_THREAD_(NOT)_REQUIRED contracts are enforced as follows:
-// * code:EEContract::DoChecks enforces the following:
-// * On entry to an EE_THREAD_REQUIRED function, GetThread() != NULL
-// * An EE_THREAD_REQUIRED function may not be called from an
-// EE_THREAD_NOT_REQUIRED function, unless there is an intervening
-// BEGIN/END_GETTHREAD_ALLOWED scope
-// * This function (GetThreadGenericFullCheck) enforces that an
-// EE_THREAD_NOT_REQUIRED function may not call GetThread(), unless there is
-// an intervening BEGIN/END_GETTHREAD_ALLOWED scope. While this enforcement
-// is straightforward below, the tricky part is getting
-// GetThreadGenericFullCheck() to actually be called when GetThread() is
-// called, given the optimizations around GetThread():
-// * code:InitThreadManager ensures that non-PAL, debug, x86/x64 builds that
-// run with COMPlus_EnforceEEThreadNotRequiredContracts set are forced to
-// use GetThreadGeneric instead of the dynamically generated optimized
-// TLS getter.
-// * The non-PAL, debug, x86/x64 GetThreadGeneric() (implemented in the
-// processor-specific assembly files) knows to call
-// GetThreadGenericFullCheck() to do the enforcement.
-//
-Thread * GetThreadGenericFullCheck()
-{
- // Can not have a dynamic contract here. Contract depends on GetThreadGeneric.
- // Contract here causes stack overflow.
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
-
- if (!ThreadInited())
- {
- // #GTInfiniteRecursion
- //
- // Normally, we'd want to assert here, but that could lead to infinite recursion.
- // Bringing up the assert dialog requires a string lookup, which requires getting
- // the Thread's UI culture ID, which, or course, requires getting the Thread. So
- // we'll just break instead.
- DebugBreak();
- }
-
- if (g_fEEStarted &&
-
- // Using ShouldEnforceEEThreadNotRequiredContracts() instead
- // of directly checking CLRConfig::GetConfigValue, as the latter contains a dynamic
- // contract and therefore calls GetThread(), which would cause infinite recursion.
- Thread::ShouldEnforceEEThreadNotRequiredContracts() &&
-
- // The following verifies that it's safe to call GetClrDebugState() below without
- // risk of its callees invoking extra error checking or fiber code that could
- // recursively call GetThread() and overflow the stack
- (CExecutionEngine::GetTlsData() != NULL))
- {
- // It's safe to peek into the debug state, so let's do so, to see if
- // our caller is really allowed to be calling GetThread(). This enforces
- // the EE_THREAD_NOT_REQUIRED contract.
- ClrDebugState * pDbg = GetClrDebugState(FALSE); // FALSE=don't allocate
- if ((pDbg != NULL) && (!pDbg->IsGetThreadAllowed()))
- {
- // We need to bracket the ASSERTE with BEGIN/END_GETTHREAD_ALLOWED to avoid
- // infinite recursion (see
- // code:GetThreadGenericFullCheck#GTInfiniteRecursion). The ASSERTE here will
- // cause us to reenter this function to get the thread (again). However,
- // BEGIN/END_GETTHREAD_ALLOWED at least stops the recursion right then and
- // there, as it prevents us from reentering this block yet again (since
- // BEGIN/END_GETTHREAD_ALLOWED causes pDbg->IsGetThreadAllowed() to be TRUE).
- // All such reentries to this function will quickly return the thread without
- // executing the code below, so the original ASSERTE can proceed.
- BEGIN_GETTHREAD_ALLOWED;
- _ASSERTE(!"GetThread() called in a EE_THREAD_NOT_REQUIRED scope. If the GetThread() call site has a clear code path for a return of NULL, then consider using GetThreadNULLOk() or BEGIN/END_GETTHREAD_ALLOWED");
- END_GETTHREAD_ALLOWED;
- }
- }
-
- Thread * pThread = (Thread *) UnsafeTlsGetValue(gThreadTLSIndex);
-
- // set bogus last error to help find places that fail to save it across GetThread calls
- ::SetLastError(LAST_ERROR_TRASH_VALUE);
-
- return pThread;
-}
-
-#endif // ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
-//
-// Some platforms have this implemented in assembly
-//
-EXTERN_C Thread* STDCALL GetThreadGeneric(VOID);
-EXTERN_C AppDomain* STDCALL GetAppDomainGeneric(VOID);
-#else
-Thread* STDCALL GetThreadGeneric()
-{
- // Can not have contract here. Contract depends on GetThreadGeneric.
- // Contract here causes stack overflow.
- //CONTRACTL {
- // NOTHROW;
- // GC_NOTRIGGER;
- //}
- //CONTRACTL_END;
-
- // see code:GetThreadGenericFullCheck#GTInfiniteRecursion
- _ASSERTE(ThreadInited());
-
- Thread* pThread = (Thread*)UnsafeTlsGetValue(gThreadTLSIndex);
-
- TRASH_LASTERROR;
-
- return pThread;
-}
-
-AppDomain* STDCALL GetAppDomainGeneric()
-{
- // No contract. This function is called during ExitTask.
- //CONTRACTL {
- // NOTHROW;
- // GC_NOTRIGGER;
- //}
- //CONTRACTL_END;
-
- _ASSERTE(ThreadInited());
-
- AppDomain* pAppDomain = (AppDomain*)UnsafeTlsGetValue(GetAppDomainTLSIndex());
-
- TRASH_LASTERROR;
-
- return pAppDomain;
-}
-#endif // defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
-
-//
-// FLS getter to avoid unnecessary indirection via execution engine. It will be used if we get high TLS slot
-// from the OS where we cannot use the fast optimized assembly helpers. (It happens pretty often in hosted scenarios).
-//
-LPVOID* ClrFlsGetBlockDirect()
-{
- LIMITED_METHOD_CONTRACT;
-
- return (LPVOID*)UnsafeTlsGetValue(CExecutionEngine::GetTlsIndex());
-}
-
-extern "C" void * ClrFlsGetBlock();
-
-#endif // FEATURE_IMPLICIT_TLS
-
-
extern "C" void STDCALL JIT_PatchedCodeStart();
extern "C" void STDCALL JIT_PatchedCodeLast();
@@ -1365,7 +1101,7 @@ void InitThreadManager()
}
CONTRACTL_END;
- s_initializeYieldProcessorNormalizedCrst.Init(CrstLeafLock);
+ InitializeYieldProcessorNormalizedCrst();
// All patched helpers should fit into one page.
// If you hit this assert on retail build, there is most likely problem with BBT script.
@@ -1387,98 +1123,24 @@ void InitThreadManager()
#ifndef FEATURE_PAL
-#ifdef FEATURE_IMPLICIT_TLS
_ASSERTE(GetThread() == NULL);
- // Mscordbi calculates the address of currentThread pointer using OFFSETOF__TLS__tls_CurrentThread. Ensure that
- // value is correct.
+ PTEB Teb = NtCurrentTeb();
+ BYTE** tlsArray = (BYTE**)Teb->ThreadLocalStoragePointer;
+ BYTE* tlsData = (BYTE*)tlsArray[_tls_index];
- PTEB Teb;
- BYTE* tlsData;
- BYTE** tlsArray;
+ size_t offsetOfCurrentThreadInfo = (BYTE*)&gCurrentThreadInfo - tlsData;
- Teb = NtCurrentTeb();
- tlsArray = (BYTE**)Teb->ThreadLocalStoragePointer;
- tlsData = (BYTE*)tlsArray[_tls_index];
+ _ASSERTE(offsetOfCurrentThreadInfo < 0x8000);
+ _ASSERTE(_tls_index < 0x10000);
- Thread **ppThread = (Thread**) (tlsData + OFFSETOF__TLS__tls_CurrentThread);
- _ASSERTE_ALL_BUILDS("clr/src/VM/Threads.cpp",
- (&(gCurrentThreadInfo.m_pThread) == ppThread) &&
- "Offset of m_pThread as specified by OFFSETOF__TLS__tls_CurrentThread is not correct. "
- "This can change due to addition/removal of declspec(Thread) thread local variables.");
+ // Save gCurrentThreadInfo location for debugger
+ g_TlsIndex = (DWORD)(_tls_index + (offsetOfCurrentThreadInfo << 16) + 0x80000000);
- _ASSERTE_ALL_BUILDS("clr/src/VM/Threads.cpp",
- ((BYTE*)&(gCurrentThreadInfo.m_EETlsData) == tlsData + OFFSETOF__TLS__tls_EETlsData) &&
- "Offset of m_EETlsData as specified by OFFSETOF__TLS__tls_EETlsData is not correct. "
- "This can change due to addition/removal of declspec(Thread) thread local variables.");
-#else
- _ASSERTE(gThreadTLSIndex == TLS_OUT_OF_INDEXES);
-#endif
_ASSERTE(g_TrapReturningThreads == 0);
#endif // !FEATURE_PAL
- // Consult run-time switches that choose whether to use generic or optimized
- // versions of GetThread and GetAppDomain
-
- BOOL fUseGenericTlsGetters = FALSE;
-
-#ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
- // Debug builds allow user to throw a switch to force use of the generic GetThread
- // for the sole purpose of enforcing EE_THREAD_NOT_REQUIRED contracts
- if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnforceEEThreadNotRequiredContracts) != 0)
- {
- // Set this static on Thread so this value can be safely read later on by
- // code:GetThreadGenericFullCheck
- Thread::s_fEnforceEEThreadNotRequiredContracts = TRUE;
-
- fUseGenericTlsGetters = TRUE;
- }
-#endif
-
-#ifndef FEATURE_IMPLICIT_TLS
- // Now, we setup GetThread and GetAppDomain to point to their optimized or generic versions. Irrespective
- // of the version they call into, we write opcode sequence into the dummy GetThread/GetAppDomain
- // implementations (living in jithelp.s/.asm) via the MakeOptimizedTlsGetter calls below.
- //
- // For this to work, we must ensure that the dummy versions lie between the JIT_PatchedCodeStart
- // and JIT_PatchedCodeLast code range (which lies in the .text section) so that when we change the protection
- // above, we do so for GetThread and GetAppDomain as well.
-
- //---------------------------------------------------------------------------
- // INITIALIZE GetThread
- //---------------------------------------------------------------------------
-
- // No backout necessary - part of the one time global initialization
- gThreadTLSIndex = UnsafeTlsAlloc();
- if (gThreadTLSIndex == TLS_OUT_OF_INDEXES)
- COMPlusThrowWin32();
-
- MakeOptimizedTlsGetter(gThreadTLSIndex, (PVOID)GetThread, TLS_GETTER_MAX_SIZE, (POPTIMIZEDTLSGETTER)GetThreadGeneric, fUseGenericTlsGetters);
-
- //---------------------------------------------------------------------------
- // INITIALIZE GetAppDomain
- //---------------------------------------------------------------------------
-
- // No backout necessary - part of the one time global initialization
- gAppDomainTLSIndex = UnsafeTlsAlloc();
- if (gAppDomainTLSIndex == TLS_OUT_OF_INDEXES)
- COMPlusThrowWin32();
-
- MakeOptimizedTlsGetter(gAppDomainTLSIndex, (PVOID)GetAppDomain, TLS_GETTER_MAX_SIZE, (POPTIMIZEDTLSGETTER)GetAppDomainGeneric, fUseGenericTlsGetters);
-
- //---------------------------------------------------------------------------
- // Switch general purpose TLS getter to more efficient one if possible
- //---------------------------------------------------------------------------
-
- // Make sure that the TLS index is allocated
- CExecutionEngine::CheckThreadState(0, FALSE);
-
- DWORD masterSlotIndex = CExecutionEngine::GetTlsIndex();
- CLRFLSGETBLOCK pGetter = (CLRFLSGETBLOCK)MakeOptimizedTlsGetter(masterSlotIndex, (PVOID)ClrFlsGetBlock, TLS_GETTER_MAX_SIZE);
- __ClrFlsGetBlock = pGetter ? pGetter : ClrFlsGetBlockDirect;
-#else
__ClrFlsGetBlock = CExecutionEngine::GetTlsData;
-#endif // FEATURE_IMPLICIT_TLS
IfFailThrow(Thread::CLRSetThreadStackGuarantee(Thread::STSGuarantee_Force));
@@ -11748,104 +11410,3 @@ ULONGLONG Thread::QueryThreadProcessorUsage()
return ullCurrentUsage - ullPreviousUsage;
}
#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// YieldProcessorNormalized
-
-// Defaults are for when InitializeYieldProcessorNormalized has not yet been called or when no measurement is done, and are
-// tuned for Skylake processors
-int g_yieldsPerNormalizedYield = 1; // current value is for Skylake processors, this would be 9 for pre-Skylake
-int g_optimalMaxNormalizedYieldsPerSpinIteration = 7;
-
-static Volatile<bool> s_isYieldProcessorNormalizedInitialized = false;
-
-void InitializeYieldProcessorNormalized()
-{
- LIMITED_METHOD_CONTRACT;
-
- CrstHolder lock(&s_initializeYieldProcessorNormalizedCrst);
-
- if (s_isYieldProcessorNormalizedInitialized)
- {
- return;
- }
-
- // Intel pre-Skylake processor: measured typically 14-17 cycles per yield
- // Intel post-Skylake processor: measured typically 125-150 cycles per yield
- const int MeasureDurationMs = 10;
- const int MaxYieldsPerNormalizedYield = 10; // measured typically 8-9 on pre-Skylake
- const int MinNsPerNormalizedYield = 37; // measured typically 37-46 on post-Skylake
- const int NsPerOptimialMaxSpinIterationDuration = 272; // approx. 900 cycles, measured 281 on pre-Skylake, 263 on post-Skylake
- const int NsPerSecond = 1000 * 1000 * 1000;
-
- LARGE_INTEGER li;
- if (!QueryPerformanceFrequency(&li) || (ULONGLONG)li.QuadPart < 1000 / MeasureDurationMs)
- {
- // High precision clock not available or clock resolution is too low, resort to defaults
- s_isYieldProcessorNormalizedInitialized = true;
- return;
- }
- ULONGLONG ticksPerSecond = li.QuadPart;
-
- // Measure the nanosecond delay per yield
- ULONGLONG measureDurationTicks = ticksPerSecond / (1000 / MeasureDurationMs);
- unsigned int yieldCount = 0;
- QueryPerformanceCounter(&li);
- ULONGLONG startTicks = li.QuadPart;
- ULONGLONG elapsedTicks;
- do
- {
- // On some systems, querying the high performance counter has relatively significant overhead. Do enough yields to mask
- // the timing overhead. Assuming one yield has a delay of MinNsPerNormalizedYield, 1000 yields would have a delay in the
- // low microsecond range.
- for (int i = 0; i < 1000; ++i)
- {
- YieldProcessor();
- }
- yieldCount += 1000;
-
- QueryPerformanceCounter(&li);
- ULONGLONG nowTicks = li.QuadPart;
- elapsedTicks = nowTicks - startTicks;
- } while (elapsedTicks < measureDurationTicks);
- double nsPerYield = (double)elapsedTicks * NsPerSecond / ((double)yieldCount * ticksPerSecond);
- if (nsPerYield < 1)
- {
- nsPerYield = 1;
- }
-
- // Calculate the number of yields required to span the duration of a normalized yield
- int yieldsPerNormalizedYield = (int)(MinNsPerNormalizedYield / nsPerYield + 0.5);
- if (yieldsPerNormalizedYield < 1)
- {
- yieldsPerNormalizedYield = 1;
- }
- else if (yieldsPerNormalizedYield > MaxYieldsPerNormalizedYield)
- {
- yieldsPerNormalizedYield = MaxYieldsPerNormalizedYield;
- }
-
- // Calculate the maximum number of yields that would be optimal for a late spin iteration. Typically, we would not want to
- // spend excessive amounts of time (thousands of cycles) doing only YieldProcessor, as SwitchToThread/Sleep would do a
- // better job of allowing other work to run.
- int optimalMaxNormalizedYieldsPerSpinIteration =
- (int)(NsPerOptimialMaxSpinIterationDuration / (yieldsPerNormalizedYield * nsPerYield) + 0.5);
- if (optimalMaxNormalizedYieldsPerSpinIteration < 1)
- {
- optimalMaxNormalizedYieldsPerSpinIteration = 1;
- }
-
- g_yieldsPerNormalizedYield = yieldsPerNormalizedYield;
- g_optimalMaxNormalizedYieldsPerSpinIteration = optimalMaxNormalizedYieldsPerSpinIteration;
- s_isYieldProcessorNormalizedInitialized = true;
-}
-
-void EnsureYieldProcessorNormalizedInitialized()
-{
- WRAPPER_NO_CONTRACT;
-
- if (!s_isYieldProcessorNormalizedInitialized)
- {
- InitializeYieldProcessorNormalized();
- }
-}
diff --git a/src/vm/threads.h b/src/vm/threads.h
index 17cc1f305d..bae1db49f6 100644
--- a/src/vm/threads.h
+++ b/src/vm/threads.h
@@ -586,8 +586,6 @@ enum ThreadpoolThreadType
//
// Public functions for ASM code generators
//
-// int GetThreadTLSIndex() - returns TLS index used to point to Thread
-// int GetAppDomainTLSIndex() - returns TLS index used to point to AppDomain
// Thread* __stdcall CreateThreadBlockThrow() - creates new Thread on reverse p-invoke
//
// Public functions for one-time init/cleanup
@@ -629,14 +627,6 @@ Thread* SetupThreadNoThrow(HRESULT *phresult = NULL);
Thread* SetupUnstartedThread(BOOL bRequiresTSL=TRUE);
void DestroyThread(Thread *th);
-
-//---------------------------------------------------------------------------
-//---------------------------------------------------------------------------
-#ifndef FEATURE_IMPLICIT_TLS
-DWORD GetThreadTLSIndex();
-DWORD GetAppDomainTLSIndex();
-#endif
-
DWORD GetRuntimeId();
EXTERN_C Thread* WINAPI CreateThreadBlockThrow();
@@ -3891,23 +3881,6 @@ private:
ULONG m_ulEnablePreemptiveGCCount;
#endif // _DEBUG
-#ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-private:
- // Set once on initialization, single-threaded, inside friend code:InitThreadManager,
- // based on whether the user has set COMPlus_EnforceEEThreadNotRequiredContracts.
- // This is then later accessed via public
- // code:Thread::ShouldEnforceEEThreadNotRequiredContracts. See
- // code:GetThreadGenericFullCheck for details.
- static BOOL s_fEnforceEEThreadNotRequiredContracts;
-
-public:
- static BOOL ShouldEnforceEEThreadNotRequiredContracts();
-
-#endif // ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
-
-
private:
// For suspends:
CLREvent m_DebugSuspendEvent;
@@ -7386,7 +7359,6 @@ inline void SetTypeHandleOnThreadForAlloc(TypeHandle th)
#endif // CROSSGEN_COMPILE
-#ifdef FEATURE_IMPLICIT_TLS
class Compiler;
// users of OFFSETOF__TLS__tls_CurrentThread macro expect the offset of these variables wrt to _tls_start to be stable.
// Defining each of the following thread local variable separately without the struct causes the offsets to change in
@@ -7398,11 +7370,7 @@ struct ThreadLocalInfo
Thread* m_pThread;
AppDomain* m_pAppDomain;
void** m_EETlsData; // ClrTlsInfo::data
-#ifdef FEATURE_MERGE_JIT_AND_ENGINE
- void* m_pJitTls;
-#endif
};
-#endif // FEATURE_IMPLICIT_TLS
class ThreadStateHolder
{
@@ -7508,76 +7476,4 @@ private:
BOOL Debug_IsLockedViaThreadSuspension();
-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// YieldProcessorNormalized
-
-extern int g_yieldsPerNormalizedYield;
-extern int g_optimalMaxNormalizedYieldsPerSpinIteration;
-
-void InitializeYieldProcessorNormalized();
-void EnsureYieldProcessorNormalizedInitialized();
-
-class YieldProcessorNormalizationInfo
-{
-private:
- int yieldsPerNormalizedYield;
-
-public:
- YieldProcessorNormalizationInfo() : yieldsPerNormalizedYield(g_yieldsPerNormalizedYield)
- {
- }
-
- friend void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &);
-};
-
-FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo)
-{
- LIMITED_METHOD_CONTRACT;
-
- int n = normalizationInfo.yieldsPerNormalizedYield;
- while (--n >= 0)
- {
- YieldProcessor();
- }
-}
-
-class YieldProcessorWithBackOffNormalizationInfo
-{
-private:
- int yieldsPerNormalizedYield;
- int optimalMaxNormalizedYieldsPerSpinIteration;
- int optimalMaxYieldsPerSpinIteration;
-
-public:
- YieldProcessorWithBackOffNormalizationInfo()
- : yieldsPerNormalizedYield(g_yieldsPerNormalizedYield),
- optimalMaxNormalizedYieldsPerSpinIteration(g_optimalMaxNormalizedYieldsPerSpinIteration),
- optimalMaxYieldsPerSpinIteration(yieldsPerNormalizedYield * optimalMaxNormalizedYieldsPerSpinIteration)
- {
- }
-
- friend void YieldProcessorWithBackOffNormalized(const YieldProcessorWithBackOffNormalizationInfo &, unsigned int);
-};
-
-FORCEINLINE void YieldProcessorWithBackOffNormalized(
- const YieldProcessorWithBackOffNormalizationInfo &normalizationInfo,
- unsigned int spinIteration)
-{
- LIMITED_METHOD_CONTRACT;
-
- int n;
- if (spinIteration <= 30 && (1 << spinIteration) < normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration)
- {
- n = (1 << spinIteration) * normalizationInfo.yieldsPerNormalizedYield;
- }
- else
- {
- n = normalizationInfo.optimalMaxYieldsPerSpinIteration;
- }
- while (--n >= 0)
- {
- YieldProcessor();
- }
-}
-
#endif //__threads_h__
diff --git a/src/vm/threads.inl b/src/vm/threads.inl
index ee2aaacf94..f5a439c350 100644
--- a/src/vm/threads.inl
+++ b/src/vm/threads.inl
@@ -22,7 +22,6 @@
#include "frames.h"
#ifndef DACCESS_COMPILE
-#ifdef FEATURE_IMPLICIT_TLS
#ifndef __llvm__
EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
@@ -40,18 +39,8 @@ EXTERN_C inline AppDomain* STDCALL GetAppDomain()
return gCurrentThreadInfo.m_pAppDomain;
}
-#endif // FEATURE_IMPLICIT_TLS
#endif // !DACCESS_COMPILE
-#ifdef ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-// See code:GetThreadGenericFullCheck
-inline /* static */ BOOL Thread::ShouldEnforceEEThreadNotRequiredContracts()
-{
- LIMITED_METHOD_CONTRACT;
- return s_fEnforceEEThreadNotRequiredContracts;
-}
-#endif // ENABLE_GET_THREAD_GENERIC_FULL_CHECK
-
inline void Thread::IncLockCount()
{
LIMITED_METHOD_CONTRACT;
diff --git a/src/vm/threadstatics.h b/src/vm/threadstatics.h
index bd52496489..970f730234 100644
--- a/src/vm/threadstatics.h
+++ b/src/vm/threadstatics.h
@@ -66,7 +66,7 @@ struct ThreadLocalModule
_ASSERTE(m_pGCStatics != NULL);
- return dac_cast<PTR_BYTE>((PTR_OBJECTREF)((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr());
+ return dac_cast<PTR_BYTE>(((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr());
}
inline PTR_BYTE GetGCStaticsBaseHandle()
{
@@ -125,7 +125,7 @@ struct ThreadLocalModule
_ASSERTE(m_pGCStatics != NULL);
- return (PTR_OBJECTREF)((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr();
+ return ((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr();
}
inline OBJECTHANDLE GetPrecomputedGCStaticsBaseHandle()
diff --git a/src/vm/tieredcompilation.cpp b/src/vm/tieredcompilation.cpp
index ea69bbfec7..48c6670fb2 100644
--- a/src/vm/tieredcompilation.cpp
+++ b/src/vm/tieredcompilation.cpp
@@ -24,25 +24,17 @@
//
// This feature is incomplete and currently experimental. To enable it
// you need to set COMPLUS_EXPERIMENTAL_TieredCompilation = 1. When the environment
-// variable is unset the runtime should work as normal, but when it is set there are
-// anticipated incompatibilities and limited cross cutting test coverage so far.
-// Profiler - Anticipated incompatible with ReJIT, untested in general
-// ETW - Anticipated incompatible with the ReJIT id of the MethodJitted rundown events
-// Managed debugging - Anticipated incompatible with breakpoints/stepping that are
-// active when a method is recompiled.
-//
-//
-// Testing that has been done so far largely consists of regression testing with
-// the environment variable off + functional/perf testing of the Music Store ASP.Net
-// workload as a basic example that the feature can work. Running the coreclr repo
-// tests with the env var on generates about a dozen failures in JIT tests. The issues
-// are likely related to assertions about optimization behavior but haven't been
-// properly investigated yet.
+// variable is unset the runtime should work as normal, but when it is there are a few
+// known issues
+// ETW - Native to IL maps aren't correctly emitted (probably tier1 wrong, tier0 right)
+// Profiler - Still missing APIs that allow profilers to correctly get native to IL
+// maps for all code bodies.
//
-// If you decide to try this out on a new workload and run into trouble a quick note
-// on github is appreciated but this code may have high churn for a while to come and
-// there will be no sense investing a lot of time investigating only to have it rendered
-// moot by changes. I aim to keep this comment updated as things change.
+// Diagnostic tools have minimal testing that we are aware of and its possible they
+// made additional assumptions about runtime implementation that have been invalidated
+// by this feature. VS debugging does appear to work at a basic level at least.
+//
+// I aim to keep this comment updated as things change.
//
//
// # Important entrypoints in this code:
@@ -156,14 +148,20 @@ void TieredCompilationManager::AsyncPromoteMethodToTier1(MethodDesc* pMethodDesc
if (cur->GetOptimizationTier() == NativeCodeVersion::OptimizationTier1)
{
// we've already promoted
+ LOG((LF_TIEREDCOMPILATION, LL_INFO100000, "TieredCompilationManager::AsyncPromoteMethodToTier1 Method=0x%pM (%s::%s) ignoring already promoted method\n",
+ pMethodDesc, pMethodDesc->m_pszDebugClassName, pMethodDesc->m_pszDebugMethodName));
return;
}
}
- if (FAILED(ilVersion.AddNativeCodeVersion(pMethodDesc, &t1NativeCodeVersion)))
+ HRESULT hr = S_OK;
+ if (FAILED(hr = ilVersion.AddNativeCodeVersion(pMethodDesc, &t1NativeCodeVersion)))
{
// optimization didn't work for some reason (presumably OOM)
// just give up and continue on
+ STRESS_LOG2(LF_TIEREDCOMPILATION, LL_WARNING, "TieredCompilationManager::AsyncPromoteMethodToTier1: "
+ "AddNativeCodeVersion failed hr=0x%x, method=%pM\n",
+ hr, pMethodDesc);
return;
}
t1NativeCodeVersion.SetOptimizationTier(NativeCodeVersion::OptimizationTier1);
@@ -189,6 +187,10 @@ void TieredCompilationManager::AsyncPromoteMethodToTier1(MethodDesc* pMethodDesc
m_methodsToOptimize.InsertTail(pMethodListItem);
}
+ LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::AsyncPromoteMethodToTier1 Method=0x%pM (%s::%s), code version id=0x%x queued\n",
+ pMethodDesc, pMethodDesc->m_pszDebugClassName, pMethodDesc->m_pszDebugMethodName,
+ t1NativeCodeVersion.GetVersionId()));
+
if (0 == m_countOptimizationThreadsRunning && !m_isAppDomainShuttingDown)
{
// Our current policy throttles at 1 thread, but in the future we
@@ -367,11 +369,15 @@ BOOL TieredCompilationManager::CompileCodeVersion(NativeCodeVersion nativeCodeVe
EX_TRY
{
pCode = pMethod->PrepareCode(nativeCodeVersion);
+ LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::CompileCodeVersion Method=0x%pM (%s::%s), code version id=0x%x, code ptr=0x%p\n",
+ pMethod, pMethod->m_pszDebugClassName, pMethod->m_pszDebugMethodName,
+ nativeCodeVersion.GetVersionId(),
+ pCode));
}
EX_CATCH
{
// Failing to jit should be rare but acceptable. We will leave whatever code already exists in place.
- STRESS_LOG2(LF_TIEREDCOMPILATION, LL_INFO10, "TieredCompilationManager::CompileMethod: Method %pM failed to jit, hr=0x%x\n",
+ STRESS_LOG2(LF_TIEREDCOMPILATION, LL_INFO10, "TieredCompilationManager::CompileCodeVersion: Method %pM failed to jit, hr=0x%x\n",
pMethod, GET_EXCEPTION()->GetHR());
}
EX_END_CATCH(RethrowTerminalExceptions)
@@ -400,6 +406,10 @@ void TieredCompilationManager::ActivateCodeVersion(NativeCodeVersion nativeCodeV
CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
ilParent = nativeCodeVersion.GetILCodeVersion();
hr = ilParent.SetActiveNativeCodeVersion(nativeCodeVersion, FALSE);
+ LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::ActivateCodeVersion Method=0x%pM (%s::%s), code version id=0x%x. SetActiveNativeCodeVersion ret=0x%x\n",
+ pMethod, pMethod->m_pszDebugClassName, pMethod->m_pszDebugMethodName,
+ nativeCodeVersion.GetVersionId(),
+ hr));
}
if (hr == CORPROF_E_RUNTIME_SUSPEND_REQUIRED)
{
@@ -413,6 +423,10 @@ void TieredCompilationManager::ActivateCodeVersion(NativeCodeVersion nativeCodeV
{
CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
hr = ilParent.SetActiveNativeCodeVersion(nativeCodeVersion, TRUE);
+ LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::ActivateCodeVersion Method=0x%pM (%s::%s), code version id=0x%x. [Suspended] SetActiveNativeCodeVersion ret=0x%x\n",
+ pMethod, pMethod->m_pszDebugClassName, pMethod->m_pszDebugMethodName,
+ nativeCodeVersion.GetVersionId(),
+ hr));
}
ThreadSuspend::RestartEE(FALSE, TRUE);
}
diff --git a/src/vm/vars.cpp b/src/vm/vars.cpp
index ff941d2101..343f1545c8 100644
--- a/src/vm/vars.cpp
+++ b/src/vm/vars.cpp
@@ -120,13 +120,10 @@ GPTR_IMPL_INIT(StressLog, g_pStressLog, &StressLog::theLog);
GPTR_IMPL(RCWCleanupList,g_pRCWCleanupList);
#endif // FEATURE_COMINTEROP
+GVAL_IMPL_INIT(DWORD, g_TlsIndex, TLS_OUT_OF_INDEXES);
#ifndef DACCESS_COMPILE
-// <TODO> @TODO Remove eventually - </TODO> determines whether the verifier throws an exception when something fails
-bool g_fVerifierOff;
-
-
// <TODO> @TODO - PROMOTE. </TODO>
OBJECTHANDLE g_pPreallocatedOutOfMemoryException;
OBJECTHANDLE g_pPreallocatedStackOverflowException;
@@ -294,50 +291,5 @@ extern "C" RAW_KEYWORD(volatile) const GSCookie s_gsCookie = 0;
__GlobalVal< GSCookie > s_gsCookie(&g_dacGlobals.dac__s_gsCookie);
#endif //!DACCESS_COMPILE
-BOOL IsCompilationProcess()
-{
- LIMITED_METHOD_DAC_CONTRACT;
-#if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
- return g_pCEECompileInfo != NULL;
-#else
- return FALSE;
-#endif
-}
-
//==============================================================================
-enum NingenState
-{
- kNotInitialized = 0,
- kNingenEnabled = 1,
- kNingenDisabled = 2,
-};
-
-extern int g_ningenState;
-int g_ningenState = kNotInitialized;
-
-// Removes all execution of managed or third-party code in the ngen compilation process.
-BOOL NingenEnabled()
-{
- LIMITED_METHOD_CONTRACT;
-
-#ifdef CROSSGEN_COMPILE
- // Always enable ningen for cross-compile
- return TRUE;
-#else // CROSSGEN_COMPILE
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // Note that ningen is enabled by default to get byte-to-byte identical NGen images between native compile and cross-compile
- if (g_ningenState == kNotInitialized)
- {
- // This code must be idempotent as we don't have a lock to prevent a race to initialize g_ningenState.
- g_ningenState = (IsCompilationProcess() && (0 != CLRConfig::GetConfigValue(CLRConfig::INTERNAL_Ningen))) ? kNingenEnabled : kNingenDisabled;
- }
-
- return g_ningenState == kNingenEnabled;
-#else
- return FALSE;
-#endif
-
-#endif // CROSSGEN_COMPILE
-}
diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp
index c9f4848692..820260a0f2 100644
--- a/src/vm/vars.hpp
+++ b/src/vm/vars.hpp
@@ -97,7 +97,6 @@ class Crst;
class RCWCleanupList;
#endif // FEATURE_COMINTEROP
class BBSweep;
-struct IAssemblyUsageLog;
//
// loader handles are opaque types that track object pointers that have a lifetime
@@ -406,9 +405,7 @@ GPTR_DECL(MethodDesc, g_pExecuteBackoutCodeHelperMethod);
GPTR_DECL(MethodDesc, g_pObjectFinalizerMD);
-//<TODO> @TODO Remove eventually - determines whether the verifier throws an exception when something fails</TODO>
-EXTERN bool g_fVerifierOff;
-
+GVAL_DECL(DWORD, g_TlsIndex);
// Global System Information
extern SYSTEM_INFO g_SystemInfo;
@@ -845,10 +842,24 @@ extern bool g_fReadyToRunCompilation;
// Returns true if this is NGen compilation process.
// This is a superset of CompilationDomain::IsCompilationDomain() as there is more
// than one AppDomain in ngen (the DefaultDomain)
-BOOL IsCompilationProcess();
+inline BOOL IsCompilationProcess()
+{
+#ifdef CROSSGEN_COMPILE
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
// Flag for cross-platform ngen: Removes all execution of managed or third-party code in the ngen compilation process.
-BOOL NingenEnabled();
+inline BOOL NingenEnabled()
+{
+#ifdef CROSSGEN_COMPILE
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
// Passed to JitManager APIs to determine whether to avoid calling into the host.
// The profiling API stackwalking uses this to ensure to avoid re-entering the host
diff --git a/src/vm/vertable.h b/src/vm/vertable.h
deleted file mode 100644
index 9fbf5fda5b..0000000000
--- a/src/vm/vertable.h
+++ /dev/null
@@ -1,380 +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.
-
-/*
- * Types for pop stack/push stack
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * 1 I1/U1
- * 2 I2/U2
- * 4 I4/U4
- * 8 I8/U8
- * r R4
- * d R8
- * o objref (can be an array or null)
- * [ single dimensional array of (prefix)
- * & byref/managed ptr (prefix)
- *
- * Pop only
- * ~~~~~~~~
- * R real number
- * N number -any integer or real number
- * Q number or unmanaged pointer
- * X number, unmanaged pointer, managed pointer, or objref [Obsolete]
- * Y integer (I1..I4), unmanaged pointer, managed pointer, or objref
- * I Integral type (1, 2, 4, or 8 byte, or platform-independent integer type)
- * A Anything
- *
- * CE "ceq" semantics - pop 2 arguments, do type checking as if for "ceq" instruction:
- * Integer Real ManagedPtr UnmanagedPtr Objref
- * Integer y
- * Real y
- * ManagedPtr y y
- * UnmanagedPtr y
- * Objref y y
- *
- * CG "cgt" semantics - pop 2 arguments, do type checking as if for "cgt" instruction:
- * Integer Real ManagedPtr UnmanagedPtr Objref
- * Integer y
- * Real y
- * ManagedPtr y
- * UnmanagedPtr
- * Objref y
- *
- * = Pop another item off the stack, and it must be the same type (int,real,objref,etc.) as the
- * last item popped (note, System.Int32 <-> I4 etc. are allowed). Other value
- * classes are NOT allowed.
- *
- * i (deprecated) Platform independent size value, but NOT an objref (I4/R4/ptr on 32-bit, I8/R8/ptr on 64-bit)
- * p (deprecated) Platform independent size value OR objref
- * * (deprecated) anything
-
- * Push only
- * ~~~~~~~~~
- * n null objref (valid for push only)
- * - Rewind the stack to undo the last pop (you cannot have trashed that location, though)
- *
- * Usage: <pop stack> : <operand checks> <push stack> <branches> <!>
- *
- * Order is important! Operand checks come after pop stack and before push stack.
- * For example, to check the operand being a valid local variable number (only), do ":L"
- *
- * If there is a "!" at the end, it means the instruction is either invalid, not supported, or that
- * there is a case statement to handle the instruction. If no case statement exists, the verifier
- * will fail verification of the method.
- *
- * ! can be used to perform some operand checks and/or stack pops/pushes, while still allowing specific
- * behavior; e.g. verifying that the inline operand is a valid local variable number.
- *
- * <operand checks>
- * ~~~~~~~~~~~~~~~~
- * #d Overwrite inline operand with digit "d" (must be in 0...9 range)
- * L Check that the operand is a valid local variable number.
- * A Check that the operand is a valid argument number.
- *
- * <branches>
- * ~~~~~~~~~~
- * b1 - one byte conditional branch
- * b4 - four byte conditional branch
- * u1 - one byte unconditional branch
- * u4 - four byte unconditional branch
- * l1 - one byte leave
- * l4 - one byte leave
- *
- */
-
-VEROPCODE(CEE_NOP, ":")
-VEROPCODE(CEE_BREAK, ":")
-VEROPCODE(CEE_LDARG_0, ":#0A!")
-VEROPCODE(CEE_LDARG_1, ":#1A!")
-VEROPCODE(CEE_LDARG_2, ":#2A!")
-VEROPCODE(CEE_LDARG_3, ":#3A!")
-VEROPCODE(CEE_LDLOC_0, ":#0L!")
-VEROPCODE(CEE_LDLOC_1, ":#1L!")
-VEROPCODE(CEE_LDLOC_2, ":#2L!")
-VEROPCODE(CEE_LDLOC_3, ":#3L!")
-VEROPCODE(CEE_STLOC_0, ":#0L!")
-VEROPCODE(CEE_STLOC_1, ":#1L!")
-VEROPCODE(CEE_STLOC_2, ":#2L!")
-VEROPCODE(CEE_STLOC_3, ":#3L!")
-VEROPCODE(CEE_LDARG_S, ":A!")
-VEROPCODE(CEE_LDARGA_S, ":A!")
-VEROPCODE(CEE_STARG_S, ":A!")
-VEROPCODE(CEE_LDLOC_S, ":L!")
-VEROPCODE(CEE_LDLOCA_S, ":L!")
-VEROPCODE(CEE_STLOC_S, ":L!")
-VEROPCODE(CEE_LDNULL, ":n")
-VEROPCODE(CEE_LDC_I4_M1, ":4")
-VEROPCODE(CEE_LDC_I4_0, ":4")
-VEROPCODE(CEE_LDC_I4_1, ":4")
-VEROPCODE(CEE_LDC_I4_2, ":4")
-VEROPCODE(CEE_LDC_I4_3, ":4")
-VEROPCODE(CEE_LDC_I4_4, ":4")
-VEROPCODE(CEE_LDC_I4_5, ":4")
-VEROPCODE(CEE_LDC_I4_6, ":4")
-VEROPCODE(CEE_LDC_I4_7, ":4")
-VEROPCODE(CEE_LDC_I4_8, ":4")
-VEROPCODE(CEE_LDC_I4_S, ":4")
-VEROPCODE(CEE_LDC_I4, ":4")
-VEROPCODE(CEE_LDC_I8, ":8")
-VEROPCODE(CEE_LDC_R4, ":r")
-VEROPCODE(CEE_LDC_R8, ":d")
-VEROPCODE(CEE_UNUSED49, "!")
-VEROPCODE(CEE_DUP, "!")
-VEROPCODE(CEE_POP, "A:")
-VEROPCODE(CEE_JMP, "!") // Unverifiable !
-VEROPCODE(CEE_CALL, "!")
-VEROPCODE(CEE_CALLI, "!")
-VEROPCODE(CEE_RET, "!")
-VEROPCODE(CEE_BR_S, ":u1")
-VEROPCODE(CEE_BRFALSE_S, "Y:b1")
-VEROPCODE(CEE_BRTRUE_S, "Y:b1")
-VEROPCODE(CEE_BEQ_S, "CE:b1")
-VEROPCODE(CEE_BGE_S, "CG:b1")
-VEROPCODE(CEE_BGT_S, "CG:b1")
-VEROPCODE(CEE_BLE_S, "CG:b1")
-VEROPCODE(CEE_BLT_S, "CG:b1")
-VEROPCODE(CEE_BNE_UN_S, "CE:b1")
-VEROPCODE(CEE_BGE_UN_S, "CG:b1")
-VEROPCODE(CEE_BGT_UN_S, "CG:b1")
-VEROPCODE(CEE_BLE_UN_S, "CG:b1")
-VEROPCODE(CEE_BLT_UN_S, "CG:b1")
-VEROPCODE(CEE_BR, ":u4")
-VEROPCODE(CEE_BRFALSE, "Y:b4")
-VEROPCODE(CEE_BRTRUE, "Y:b4")
-VEROPCODE(CEE_BEQ, "CE:b4")
-VEROPCODE(CEE_BGE, "CG:b4")
-VEROPCODE(CEE_BGT, "CG:b4")
-VEROPCODE(CEE_BLE, "CG:b4")
-VEROPCODE(CEE_BLT, "CG:b4")
-VEROPCODE(CEE_BNE_UN, "CE:b4")
-VEROPCODE(CEE_BGE_UN, "CG:b4")
-VEROPCODE(CEE_BGT_UN, "CG:b4")
-VEROPCODE(CEE_BLE_UN, "CG:b4")
-VEROPCODE(CEE_BLT_UN, "CG:b4")
-VEROPCODE(CEE_SWITCH, "!")
-VEROPCODE(CEE_LDIND_I1, "&1:4")
-VEROPCODE(CEE_LDIND_U1, "&1:4")
-VEROPCODE(CEE_LDIND_I2, "&2:4")
-VEROPCODE(CEE_LDIND_U2, "&2:4")
-VEROPCODE(CEE_LDIND_I4, "&4:4")
-VEROPCODE(CEE_LDIND_U4, "&4:4")
-VEROPCODE(CEE_LDIND_I8, "&8:8")
-VEROPCODE(CEE_LDIND_I, "&i:i") // <TODO> not correct on 64 bit</TODO>
-VEROPCODE(CEE_LDIND_R4, "&r:r")
-VEROPCODE(CEE_LDIND_R8, "&d:d")
-VEROPCODE(CEE_LDIND_REF, "!")
-VEROPCODE(CEE_STIND_REF, "!")
-VEROPCODE(CEE_STIND_I1, "4&1:")
-VEROPCODE(CEE_STIND_I2, "4&2:")
-VEROPCODE(CEE_STIND_I4, "4&4:")
-VEROPCODE(CEE_STIND_I8, "8&8:")
-VEROPCODE(CEE_STIND_R4, "r&r:")
-VEROPCODE(CEE_STIND_R8, "d&d:")
-VEROPCODE(CEE_ADD, "N=:-")
-VEROPCODE(CEE_SUB, "N=:-")
-VEROPCODE(CEE_MUL, "N=:-")
-VEROPCODE(CEE_DIV, "N=:-")
-VEROPCODE(CEE_DIV_UN, "I=:-")
-VEROPCODE(CEE_REM, "N=:-")
-VEROPCODE(CEE_REM_UN, "I=:-")
-VEROPCODE(CEE_AND, "I=:-")
-VEROPCODE(CEE_OR, "I=:-")
-VEROPCODE(CEE_XOR, "I=:-")
-VEROPCODE(CEE_SHL, "4I:-")
-VEROPCODE(CEE_SHR, "4I:-")
-VEROPCODE(CEE_SHR_UN, "4I:-")
-VEROPCODE(CEE_NEG, "N:-")
-VEROPCODE(CEE_NOT, "I:-")
-VEROPCODE(CEE_CONV_I1, "Q:4")
-VEROPCODE(CEE_CONV_I2, "Q:4")
-VEROPCODE(CEE_CONV_I4, "Q:4")
-VEROPCODE(CEE_CONV_I8, "Q:8")
-VEROPCODE(CEE_CONV_R4, "N:r")
-VEROPCODE(CEE_CONV_R8, "N:d")
-VEROPCODE(CEE_CONV_U4, "Q:4")
-VEROPCODE(CEE_CONV_U8, "Q:8")
-VEROPCODE(CEE_CALLVIRT, "!")
-VEROPCODE(CEE_CPOBJ, "!")
-VEROPCODE(CEE_LDOBJ, "!")
-VEROPCODE(CEE_LDSTR, "!")
-VEROPCODE(CEE_NEWOBJ, "!")
-VEROPCODE(CEE_CASTCLASS, "!")
-VEROPCODE(CEE_ISINST, "!")
-VEROPCODE(CEE_CONV_R_UN, "Q:r")
-VEROPCODE(CEE_UNUSED58, "!")
-VEROPCODE(CEE_UNUSED1, "!")
-VEROPCODE(CEE_UNBOX, "!")
-VEROPCODE(CEE_THROW, "!")
-VEROPCODE(CEE_LDFLD, "!")
-VEROPCODE(CEE_LDFLDA, "!")
-VEROPCODE(CEE_STFLD, "!")
-VEROPCODE(CEE_LDSFLD, "!")
-VEROPCODE(CEE_LDSFLDA, "!")
-VEROPCODE(CEE_STSFLD, "!")
-VEROPCODE(CEE_STOBJ, "!")
-VEROPCODE(CEE_CONV_OVF_I1_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I2_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I4_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I8_UN, "Q:8")
-VEROPCODE(CEE_CONV_OVF_U1_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U2_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U4_UN, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U8_UN, "Q:8")
-VEROPCODE(CEE_CONV_OVF_I_UN, "Q:i")
-VEROPCODE(CEE_CONV_OVF_U_UN, "Q:i")
-VEROPCODE(CEE_BOX, "!")
-VEROPCODE(CEE_NEWARR, "!")
-VEROPCODE(CEE_LDLEN, "[*:4")
-VEROPCODE(CEE_LDELEMA, "!")
-VEROPCODE(CEE_LDELEM_I1, "4[1:4")
-VEROPCODE(CEE_LDELEM_U1, "4[1:4")
-VEROPCODE(CEE_LDELEM_I2, "4[2:4")
-VEROPCODE(CEE_LDELEM_U2, "4[2:4")
-VEROPCODE(CEE_LDELEM_I4, "4[4:4")
-VEROPCODE(CEE_LDELEM_U4, "4[4:4")
-VEROPCODE(CEE_LDELEM_I8, "4[8:8")
-VEROPCODE(CEE_LDELEM_I, "4[i:i")
-VEROPCODE(CEE_LDELEM_R4, "4[r:r")
-VEROPCODE(CEE_LDELEM_R8, "4[d:d")
-VEROPCODE(CEE_LDELEM_REF, "!")
-VEROPCODE(CEE_STELEM_I, "i4[i:")
-VEROPCODE(CEE_STELEM_I1, "44[1:")
-VEROPCODE(CEE_STELEM_I2, "44[2:")
-VEROPCODE(CEE_STELEM_I4, "44[4:")
-VEROPCODE(CEE_STELEM_I8, "84[8:")
-VEROPCODE(CEE_STELEM_R4, "r4[r:")
-VEROPCODE(CEE_STELEM_R8, "d4[d:")
-VEROPCODE(CEE_STELEM_REF, "!")
-VEROPCODE(CEE_LDELEM, "!")
-VEROPCODE(CEE_STELEM, "!")
-VEROPCODE(CEE_UNBOX_ANY, "!")
-VEROPCODE(CEE_UNUSED5, "!")
-VEROPCODE(CEE_UNUSED6, "!")
-VEROPCODE(CEE_UNUSED7, "!")
-VEROPCODE(CEE_UNUSED8, "!")
-VEROPCODE(CEE_UNUSED9, "!")
-VEROPCODE(CEE_UNUSED10, "!")
-VEROPCODE(CEE_UNUSED11, "!")
-VEROPCODE(CEE_UNUSED12, "!")
-VEROPCODE(CEE_UNUSED13, "!")
-VEROPCODE(CEE_UNUSED14, "!")
-VEROPCODE(CEE_UNUSED15, "!")
-VEROPCODE(CEE_UNUSED16, "!")
-VEROPCODE(CEE_UNUSED17, "!")
-VEROPCODE(CEE_CONV_OVF_I1, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U1, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I2, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U2, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I4, "Q:4")
-VEROPCODE(CEE_CONV_OVF_U4, "Q:4")
-VEROPCODE(CEE_CONV_OVF_I8, "Q:8")
-VEROPCODE(CEE_CONV_OVF_U8, "Q:8")
-VEROPCODE(CEE_UNUSED50, "!")
-VEROPCODE(CEE_UNUSED18, "!")
-VEROPCODE(CEE_UNUSED19, "!")
-VEROPCODE(CEE_UNUSED20, "!")
-VEROPCODE(CEE_UNUSED21, "!")
-VEROPCODE(CEE_UNUSED22, "!")
-VEROPCODE(CEE_UNUSED23, "!")
-VEROPCODE(CEE_REFANYVAL, "!")
-VEROPCODE(CEE_CKFINITE, "R:-")
-VEROPCODE(CEE_UNUSED24, "!")
-VEROPCODE(CEE_UNUSED25, "!")
-VEROPCODE(CEE_MKREFANY, "!")
-VEROPCODE(CEE_UNUSED59, "!")
-VEROPCODE(CEE_UNUSED60, "!")
-VEROPCODE(CEE_UNUSED61, "!")
-VEROPCODE(CEE_UNUSED62, "!")
-VEROPCODE(CEE_UNUSED63, "!")
-VEROPCODE(CEE_UNUSED64, "!")
-VEROPCODE(CEE_UNUSED65, "!")
-VEROPCODE(CEE_UNUSED66, "!")
-VEROPCODE(CEE_UNUSED67, "!")
-VEROPCODE(CEE_LDTOKEN, "!")
-VEROPCODE(CEE_CONV_U2, "Q:4")
-VEROPCODE(CEE_CONV_U1, "Q:4")
-VEROPCODE(CEE_CONV_I, "Q:i")
-VEROPCODE(CEE_CONV_OVF_I, "Q:i")
-VEROPCODE(CEE_CONV_OVF_U, "Q:i")
-VEROPCODE(CEE_ADD_OVF, "I=:-")
-VEROPCODE(CEE_ADD_OVF_UN, "I=:-")
-VEROPCODE(CEE_MUL_OVF, "I=:-")
-VEROPCODE(CEE_MUL_OVF_UN, "I=:-")
-VEROPCODE(CEE_SUB_OVF, "I=:-")
-VEROPCODE(CEE_SUB_OVF_UN, "I=:-")
-VEROPCODE(CEE_ENDFINALLY, "!")
-VEROPCODE(CEE_LEAVE, ":l4")
-VEROPCODE(CEE_LEAVE_S, ":l1")
-VEROPCODE(CEE_STIND_I, "i&i:") // <TODO> : 64 bit</TODO>
-VEROPCODE(CEE_CONV_U, "Q:i")
-VEROPCODE(CEE_UNUSED26, "!")
-VEROPCODE(CEE_UNUSED27, "!")
-VEROPCODE(CEE_UNUSED28, "!")
-VEROPCODE(CEE_UNUSED29, "!")
-VEROPCODE(CEE_UNUSED30, "!")
-VEROPCODE(CEE_UNUSED31, "!")
-VEROPCODE(CEE_UNUSED32, "!")
-VEROPCODE(CEE_UNUSED33, "!")
-VEROPCODE(CEE_UNUSED34, "!")
-VEROPCODE(CEE_UNUSED35, "!")
-VEROPCODE(CEE_UNUSED36, "!")
-VEROPCODE(CEE_UNUSED37, "!")
-VEROPCODE(CEE_UNUSED38, "!")
-VEROPCODE(CEE_UNUSED39, "!")
-VEROPCODE(CEE_UNUSED40, "!")
-VEROPCODE(CEE_UNUSED41, "!")
-VEROPCODE(CEE_UNUSED42, "!")
-VEROPCODE(CEE_UNUSED43, "!")
-VEROPCODE(CEE_UNUSED44, "!")
-VEROPCODE(CEE_UNUSED45, "!")
-VEROPCODE(CEE_UNUSED46, "!")
-VEROPCODE(CEE_UNUSED47, "!")
-VEROPCODE(CEE_UNUSED48, "!")
-VEROPCODE(CEE_PREFIX7, "!")
-VEROPCODE(CEE_PREFIX6, "!")
-VEROPCODE(CEE_PREFIX5, "!")
-VEROPCODE(CEE_PREFIX4, "!")
-VEROPCODE(CEE_PREFIX3, "!")
-VEROPCODE(CEE_PREFIX2, "!")
-VEROPCODE(CEE_PREFIX1, "!")
-VEROPCODE(CEE_PREFIXREF, "!")
-VEROPCODE(CEE_ARGLIST, "!")
-VEROPCODE(CEE_CEQ, "CE:4")
-VEROPCODE(CEE_CGT, "CG:4")
-VEROPCODE(CEE_CGT_UN, "CE:4")
-VEROPCODE(CEE_CLT, "CG:4")
-VEROPCODE(CEE_CLT_UN, "CG:4")
-VEROPCODE(CEE_LDFTN, "!")
-VEROPCODE(CEE_LDVIRTFTN, "!")
-VEROPCODE(CEE_UNUSED56, "!")
-VEROPCODE(CEE_LDARG, ":A!")
-VEROPCODE(CEE_LDARGA, ":A!")
-VEROPCODE(CEE_STARG, ":A!")
-VEROPCODE(CEE_LDLOC, ":L!")
-VEROPCODE(CEE_LDLOCA, ":L!")
-VEROPCODE(CEE_STLOC, ":L!")
-VEROPCODE(CEE_LOCALLOC, "i:i!") // Unverifiable !
-VEROPCODE(CEE_UNUSED57, "!")
-VEROPCODE(CEE_ENDFILTER, "4:!")
-VEROPCODE(CEE_UNALIGNED, ":")
-VEROPCODE(CEE_VOLATILE, ":")
-VEROPCODE(CEE_TAILCALL, ":")
-VEROPCODE(CEE_INITOBJ, "!")
-VEROPCODE(CEE_CONSTRAINED, ":")
-VEROPCODE(CEE_CPBLK, "ii4:!") // Unverifiable !
-VEROPCODE(CEE_INITBLK, "i44:!") // Unverifiable !
-VEROPCODE(CEE_UNUSED69, "!")
-VEROPCODE(CEE_RETHROW, "!")
-VEROPCODE(CEE_UNUSED51, "!")
-VEROPCODE(CEE_SIZEOF, "!")
-VEROPCODE(CEE_REFANYTYPE, "!")
-VEROPCODE(CEE_READONLY, ":")
-VEROPCODE(CEE_UNUSED53, "!")
-VEROPCODE(CEE_UNUSED54, "!")
-VEROPCODE(CEE_UNUSED55, "!")
-VEROPCODE(CEE_UNUSED70, "!")
-VEROPCODE(CEE_ILLEGAL, "!")
-VEROPCODE(CEE_MACRO_END, "!")
-VEROPCODE(CEE_COUNT, "!")
-
diff --git a/src/vm/win32threadpool.cpp b/src/vm/win32threadpool.cpp
index 97c020a4b6..4210060755 100644
--- a/src/vm/win32threadpool.cpp
+++ b/src/vm/win32threadpool.cpp
@@ -104,6 +104,7 @@ DWORD ThreadpoolMgr::NextCompletedWorkRequestsTime;
LARGE_INTEGER ThreadpoolMgr::CurrentSampleStartTime;
unsigned int ThreadpoolMgr::WorkerThreadSpinLimit;
+bool ThreadpoolMgr::IsHillClimbingDisabled;
int ThreadpoolMgr::ThreadAdjustmentInterval;
#define INVALID_HANDLE ((HANDLE) -1)
@@ -355,6 +356,7 @@ BOOL ThreadpoolMgr::Initialize()
EX_TRY
{
WorkerThreadSpinLimit = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ThreadPool_UnfairSemaphoreSpinLimit);
+ IsHillClimbingDisabled = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HillClimbing_Disable) != 0;
ThreadAdjustmentInterval = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HillClimbing_SampleIntervalLow);
pADTPCount->InitResources();
@@ -4962,9 +4964,7 @@ void ThreadpoolMgr::DeleteTimer(TimerInfo* timerInfo)
if (timerInfo->Context != NULL)
{
GCX_COOP();
- DelegateInfo *pDelInfo = (DelegateInfo *)timerInfo->Context;
- pDelInfo->Release();
- RecycleMemory( pDelInfo, MEMTYPE_DelegateInfo );
+ delete (ThreadpoolMgr::TimerInfoContext*)timerInfo->Context;
}
if (timerInfo->ExternalEventSafeHandle != NULL)
@@ -4978,7 +4978,7 @@ void ThreadpoolMgr::DeleteTimer(TimerInfo* timerInfo)
// We add TimerInfos from deleted timers into a linked list.
// A worker thread will later release the handles held by the TimerInfo
-// and recycle them if possible (See DelegateInfo::MakeDelegateInfo)
+// and recycle them if possible.
void ThreadpoolMgr::QueueTimerInfoForRelease(TimerInfo *pTimerInfo)
{
CONTRACTL
@@ -5048,10 +5048,7 @@ void ThreadpoolMgr::FlushQueueOfTimerInfos()
GCX_COOP();
if (pCurrTimerInfo->Context != NULL)
{
- DelegateInfo *pCurrDelInfo = (DelegateInfo *) pCurrTimerInfo->Context;
- pCurrDelInfo->Release();
-
- RecycleMemory( pCurrDelInfo, MEMTYPE_DelegateInfo );
+ delete (ThreadpoolMgr::TimerInfoContext*)pCurrTimerInfo->Context;
}
if (pCurrTimerInfo->ExternalEventSafeHandle != NULL)
diff --git a/src/vm/win32threadpool.h b/src/vm/win32threadpool.h
index 764c65efdc..2a3a3bbb24 100644
--- a/src/vm/win32threadpool.h
+++ b/src/vm/win32threadpool.h
@@ -220,6 +220,11 @@ public:
MEMTYPE_COUNT = 3,
};
+ typedef struct {
+ ADID AppDomainId;
+ INT32 TimerId;
+ } TimerInfoContext;
+
static BOOL Initialize();
static BOOL SetMaxThreadsHelper(DWORD MaxWorkerThreads,
@@ -856,7 +861,7 @@ public:
{
ThreadCounter::Counts counts = WorkerCounter.GetCleanCounts();
if (counts.NumActive <= counts.MaxWorking)
- return true;
+ return !IsHillClimbingDisabled;
}
return false;
@@ -1020,6 +1025,7 @@ private:
static LARGE_INTEGER CurrentSampleStartTime;
static unsigned int WorkerThreadSpinLimit;
+ static bool IsHillClimbingDisabled;
static int ThreadAdjustmentInterval;
SPTR_DECL(WorkRequest,WorkRequestHead); // Head of work request queue
diff --git a/src/vm/yieldprocessornormalized.cpp b/src/vm/yieldprocessornormalized.cpp
new file mode 100644
index 0000000000..94daeb42f5
--- /dev/null
+++ b/src/vm/yieldprocessornormalized.cpp
@@ -0,0 +1,105 @@
+// 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"
+
+// Defaults are for when InitializeYieldProcessorNormalized has not yet been called or when no measurement is done, and are
+// tuned for Skylake processors
+unsigned int g_yieldsPerNormalizedYield = 1; // current value is for Skylake processors, this is expected to be ~9 for pre-Skylake
+unsigned int g_optimalMaxNormalizedYieldsPerSpinIteration = 7;
+
+static Volatile<bool> s_isYieldProcessorNormalizedInitialized = false;
+static CrstStatic s_initializeYieldProcessorNormalizedCrst;
+
+void InitializeYieldProcessorNormalizedCrst()
+{
+ WRAPPER_NO_CONTRACT;
+ s_initializeYieldProcessorNormalizedCrst.Init(CrstLeafLock);
+}
+
+static void InitializeYieldProcessorNormalized()
+{
+ WRAPPER_NO_CONTRACT;
+
+ CrstHolder lock(&s_initializeYieldProcessorNormalizedCrst);
+
+ if (s_isYieldProcessorNormalizedInitialized)
+ {
+ return;
+ }
+
+ // Intel pre-Skylake processor: measured typically 14-17 cycles per yield
+ // Intel post-Skylake processor: measured typically 125-150 cycles per yield
+ const int MeasureDurationMs = 10;
+ const int NsPerSecond = 1000 * 1000 * 1000;
+
+ LARGE_INTEGER li;
+ if (!QueryPerformanceFrequency(&li) || (ULONGLONG)li.QuadPart < 1000 / MeasureDurationMs)
+ {
+ // High precision clock not available or clock resolution is too low, resort to defaults
+ s_isYieldProcessorNormalizedInitialized = true;
+ return;
+ }
+ ULONGLONG ticksPerSecond = li.QuadPart;
+
+ // Measure the nanosecond delay per yield
+ ULONGLONG measureDurationTicks = ticksPerSecond / (1000 / MeasureDurationMs);
+ unsigned int yieldCount = 0;
+ QueryPerformanceCounter(&li);
+ ULONGLONG startTicks = li.QuadPart;
+ ULONGLONG elapsedTicks;
+ do
+ {
+ // On some systems, querying the high performance counter has relatively significant overhead. Do enough yields to mask
+ // the timing overhead. Assuming one yield has a delay of MinNsPerNormalizedYield, 1000 yields would have a delay in the
+ // low microsecond range.
+ for (int i = 0; i < 1000; ++i)
+ {
+ YieldProcessor();
+ }
+ yieldCount += 1000;
+
+ QueryPerformanceCounter(&li);
+ ULONGLONG nowTicks = li.QuadPart;
+ elapsedTicks = nowTicks - startTicks;
+ } while (elapsedTicks < measureDurationTicks);
+ double nsPerYield = (double)elapsedTicks * NsPerSecond / ((double)yieldCount * ticksPerSecond);
+ if (nsPerYield < 1)
+ {
+ nsPerYield = 1;
+ }
+
+ // Calculate the number of yields required to span the duration of a normalized yield. Since nsPerYield is at least 1, this
+ // value is naturally limited to MinNsPerNormalizedYield.
+ int yieldsPerNormalizedYield = (int)(MinNsPerNormalizedYield / nsPerYield + 0.5);
+ if (yieldsPerNormalizedYield < 1)
+ {
+ yieldsPerNormalizedYield = 1;
+ }
+ _ASSERTE(yieldsPerNormalizedYield <= MinNsPerNormalizedYield);
+
+ // Calculate the maximum number of yields that would be optimal for a late spin iteration. Typically, we would not want to
+ // spend excessive amounts of time (thousands of cycles) doing only YieldProcessor, as SwitchToThread/Sleep would do a
+ // better job of allowing other work to run.
+ int optimalMaxNormalizedYieldsPerSpinIteration =
+ (int)(NsPerOptimalMaxSpinIterationDuration / (yieldsPerNormalizedYield * nsPerYield) + 0.5);
+ if (optimalMaxNormalizedYieldsPerSpinIteration < 1)
+ {
+ optimalMaxNormalizedYieldsPerSpinIteration = 1;
+ }
+
+ g_yieldsPerNormalizedYield = yieldsPerNormalizedYield;
+ g_optimalMaxNormalizedYieldsPerSpinIteration = optimalMaxNormalizedYieldsPerSpinIteration;
+ s_isYieldProcessorNormalizedInitialized = true;
+}
+
+void EnsureYieldProcessorNormalizedInitialized()
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!s_isYieldProcessorNormalizedInitialized)
+ {
+ InitializeYieldProcessorNormalized();
+ }
+}
diff --git a/src/vm/yieldprocessornormalized.h b/src/vm/yieldprocessornormalized.h
new file mode 100644
index 0000000000..8fcf10b7ca
--- /dev/null
+++ b/src/vm/yieldprocessornormalized.h
@@ -0,0 +1,103 @@
+// 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.
+
+#pragma once
+
+const unsigned int MinNsPerNormalizedYield = 37; // measured typically 37-46 on post-Skylake
+const unsigned int NsPerOptimalMaxSpinIterationDuration = 272; // approx. 900 cycles, measured 281 on pre-Skylake, 263 on post-Skylake
+
+extern unsigned int g_yieldsPerNormalizedYield;
+extern unsigned int g_optimalMaxNormalizedYieldsPerSpinIteration;
+
+void InitializeYieldProcessorNormalizedCrst();
+void EnsureYieldProcessorNormalizedInitialized();
+
+class YieldProcessorNormalizationInfo
+{
+private:
+ unsigned int yieldsPerNormalizedYield;
+ unsigned int optimalMaxNormalizedYieldsPerSpinIteration;
+ unsigned int optimalMaxYieldsPerSpinIteration;
+
+public:
+ YieldProcessorNormalizationInfo()
+ : yieldsPerNormalizedYield(g_yieldsPerNormalizedYield),
+ optimalMaxNormalizedYieldsPerSpinIteration(g_optimalMaxNormalizedYieldsPerSpinIteration),
+ optimalMaxYieldsPerSpinIteration(yieldsPerNormalizedYield * optimalMaxNormalizedYieldsPerSpinIteration)
+ {
+ }
+
+ friend void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &);
+ friend void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &, unsigned int);
+ friend void YieldProcessorWithBackOffNormalized(const YieldProcessorNormalizationInfo &, unsigned int);
+};
+
+FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ unsigned int n = normalizationInfo.yieldsPerNormalizedYield;
+ _ASSERTE(n != 0);
+ do
+ {
+ YieldProcessor();
+ } while (--n != 0);
+}
+
+FORCEINLINE void YieldProcessorNormalized(const YieldProcessorNormalizationInfo &normalizationInfo, unsigned int count)
+{
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(count != 0);
+
+ if (sizeof(SIZE_T) <= sizeof(unsigned int))
+ {
+ // On platforms with a small SIZE_T, prevent overflow on the multiply below. normalizationInfo.yieldsPerNormalizedYield
+ // is limited to MinNsPerNormalizedYield by InitializeYieldProcessorNormalized().
+ const unsigned int MaxCount = (unsigned int)SIZE_T_MAX / MinNsPerNormalizedYield;
+ if (count > MaxCount)
+ {
+ count = MaxCount;
+ }
+ }
+
+ SIZE_T n = (SIZE_T)count * normalizationInfo.yieldsPerNormalizedYield;
+ _ASSERTE(n != 0);
+ do
+ {
+ YieldProcessor();
+ } while (--n != 0);
+}
+
+FORCEINLINE void YieldProcessorWithBackOffNormalized(
+ const YieldProcessorNormalizationInfo &normalizationInfo,
+ unsigned int spinIteration)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration cannot exceed the value below based on calculations done in
+ // InitializeYieldProcessorNormalized()
+ const unsigned int MaxOptimalMaxNormalizedYieldsPerSpinIteration =
+ NsPerOptimalMaxSpinIterationDuration * 3 / (MinNsPerNormalizedYield * 2) + 1;
+ _ASSERTE(normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration <= MaxOptimalMaxNormalizedYieldsPerSpinIteration);
+
+ // This shift value should be adjusted based on the asserted condition below
+ const UINT8 MaxShift = 3;
+ static_assert_no_msg(((unsigned int)1 << (MaxShift + 1)) >= MaxOptimalMaxNormalizedYieldsPerSpinIteration);
+
+ unsigned int n;
+ if (spinIteration <= MaxShift &&
+ ((unsigned int)1 << spinIteration) < normalizationInfo.optimalMaxNormalizedYieldsPerSpinIteration)
+ {
+ n = ((unsigned int)1 << spinIteration) * normalizationInfo.yieldsPerNormalizedYield;
+ }
+ else
+ {
+ n = normalizationInfo.optimalMaxYieldsPerSpinIteration;
+ }
+ _ASSERTE(n != 0);
+ do
+ {
+ YieldProcessor();
+ } while (--n != 0);
+}
diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp
index 01d3a3b7cc..f0e9d9e8c4 100644
--- a/src/zap/zapinfo.cpp
+++ b/src/zap/zapinfo.cpp
@@ -3107,6 +3107,16 @@ BOOL ZapInfo::areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE
return m_pEEJitInfo->areTypesEquivalent(cls1, cls2);
}
+TypeCompareState ZapInfo::compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass)
+{
+ return m_pEEJitInfo->compareTypesForCast(fromClass, toClass);
+}
+
+TypeCompareState ZapInfo::compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2)
+{
+ return m_pEEJitInfo->compareTypesForEquality(cls1, cls2);
+}
+
CORINFO_CLASS_HANDLE ZapInfo::mergeClasses(
CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2)
@@ -3698,12 +3708,18 @@ void ZapInfo::getMethodVTableOffset(CORINFO_METHOD_HANDLE method,
CORINFO_METHOD_HANDLE ZapInfo::resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
CORINFO_CLASS_HANDLE implementingClass,
- CORINFO_CONTEXT_HANDLE ownerType
- )
+ CORINFO_CONTEXT_HANDLE ownerType)
{
return m_pEEJitInfo->resolveVirtualMethod(virtualMethod, implementingClass, ownerType);
}
+CORINFO_METHOD_HANDLE ZapInfo::getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg)
+{
+ return m_pEEJitInfo->getUnboxedEntry(ftn, requiresInstMethodTableArg);
+}
+
CORINFO_CLASS_HANDLE ZapInfo::getDefaultEqualityComparerClass(
CORINFO_CLASS_HANDLE elemType)
{
diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h
index 5bb86dd88a..1c73d4a0f5 100644
--- a/src/zap/zapinfo.h
+++ b/src/zap/zapinfo.h
@@ -573,6 +573,9 @@ public:
CorInfoType getTypeForPrimitiveValueClass(CORINFO_CLASS_HANDLE cls);
BOOL canCast(CORINFO_CLASS_HANDLE child, CORINFO_CLASS_HANDLE parent);
BOOL areTypesEquivalent(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+ TypeCompareState compareTypesForCast(CORINFO_CLASS_HANDLE fromClass, CORINFO_CLASS_HANDLE toClass);
+ TypeCompareState compareTypesForEquality(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2);
+
CORINFO_CLASS_HANDLE mergeClasses(CORINFO_CLASS_HANDLE cls1,
CORINFO_CLASS_HANDLE cls2);
BOOL shouldEnforceCallvirtRestriction(CORINFO_MODULE_HANDLE scope);
@@ -672,12 +675,14 @@ public:
CORINFO_METHOD_HANDLE resolveVirtualMethod(
CORINFO_METHOD_HANDLE virtualMethod,
CORINFO_CLASS_HANDLE implementingClass,
- CORINFO_CONTEXT_HANDLE ownerType
- );
+ CORINFO_CONTEXT_HANDLE ownerType);
+
+ CORINFO_METHOD_HANDLE getUnboxedEntry(
+ CORINFO_METHOD_HANDLE ftn,
+ bool* requiresInstMethodTableArg);
CORINFO_CLASS_HANDLE getDefaultEqualityComparerClass(
- CORINFO_CLASS_HANDLE elemType
- );
+ CORINFO_CLASS_HANDLE elemType);
void expandRawHandleIntrinsic(
CORINFO_RESOLVED_TOKEN * pResolvedToken,
diff --git a/src/zap/zapper.cpp b/src/zap/zapper.cpp
index 5e964b4f7c..3765135ad3 100644
--- a/src/zap/zapper.cpp
+++ b/src/zap/zapper.cpp
@@ -5,12 +5,6 @@
#include "common.h"
-
-#ifndef FEATURE_MERGE_JIT_AND_ENGINE
-#include "metahost.h"
-#endif
-
-
#include "coregen.h"
#include "clr/fs/dir.h"
@@ -444,15 +438,6 @@ Zapper::Zapper(ZapperOptions *pOptions)
Init(pOptions);
}
-#ifndef FEATURE_MERGE_JIT_AND_ENGINE
-
-//
-// Pointer to the activated CLR interface provided by the shim.
-//
-extern ICLRRuntimeInfo *g_pCLRRuntime;
-
-#endif // FEATURE_MERGE_JIT_AND_ENGINE
-
void Zapper::Init(ZapperOptions *pOptions, bool fFreeZapperOptions)
{
m_pEEJitInfo = NULL;