From 279c65addef74b1007fcd3392f6a15a13e9ed073 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 12 Apr 2023 09:18:23 -0400 Subject: [PATCH 01/21] [mono][aot] Make the names of some of the aotconst variables more descriptive. (#84673) --- src/mono/mono/mini/mini-llvm.c | 39 ++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 27b69953cf2e53..598ce4e675645c 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -1912,6 +1912,15 @@ create_builder (EmitContext *ctx) return builder; } +static char* +ji_type_to_string_lower (MonoJumpInfoType type) +{ + char *name = g_strdup (mono_ji_type_to_string (type)); + size_t len = strlen (name); + for (size_t i = 0; i < len; ++i) + name [i] = GINT_TO_CHAR (tolower (name [i])); + return name; +} static char* get_aotconst_name (MonoJumpInfoType type, gconstpointer data, int got_offset) @@ -1937,18 +1946,30 @@ get_aotconst_name (MonoJumpInfoType type, gconstpointer data, int got_offset) case MONO_PATCH_INFO_GC_NURSERY_START: case MONO_PATCH_INFO_GC_NURSERY_BITS: case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG: - name = g_strdup_printf ("%s", mono_ji_type_to_string (type)); - len = strlen (name); - for (size_t i = 0; i < len; ++i) - name [i] = GINT_TO_CHAR (tolower (name [i])); + name = ji_type_to_string_lower (type); break; - default: - name = g_strdup_printf ("%s_%d", mono_ji_type_to_string (type), got_offset); - len = strlen (name); - for (size_t i = 0; i < len; ++i) - name [i] = GINT_TO_CHAR (tolower (name [i])); + case MONO_PATCH_INFO_METHOD: + case MONO_PATCH_INFO_METHOD_RGCTX: { + MonoMethod *method = (MonoMethod*)data; + char *typestr = ji_type_to_string_lower (type); + char *n = g_strdup (method->name); + len = strlen (n); + for (size_t i = 0; i < len; ++i) { + if (!isalnum (n [i])) + n [i] = '_'; + } + name = g_strdup_printf ("%s_%s_%d", typestr, n, got_offset); + g_free (typestr); + g_free (n); + break; + } + default: { + char *typestr = ji_type_to_string_lower (type); + name = g_strdup_printf ("%s_%d", typestr, got_offset); + g_free (typestr); break; } + } return name; } From 965a1bee1854b113e98a6173830a49473ef1a860 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Wed, 12 Apr 2023 15:52:42 +0200 Subject: [PATCH 02/21] Don't use AVX-512 for small inputs in Memmove due to throttle issues (#84577) --- src/coreclr/jit/codegenxarch.cpp | 7 ++++++- src/coreclr/jit/lsraxarch.cpp | 8 +++++++- src/coreclr/jit/targetamd64.h | 2 ++ src/coreclr/jit/targetx86.h | 2 ++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 23272cbea41500..40941e78456d71 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -2581,7 +2581,12 @@ void CodeGen::genCodeForMemmove(GenTreeBlk* tree) regNumber src = genConsumeReg(srcIndir->Addr()); unsigned size = tree->Size(); - const unsigned simdSize = compiler->roundDownSIMDSize(size); + unsigned simdSize = compiler->roundDownSIMDSize(size); + if (size <= ZMM_RECOMMENDED_THRESHOLD) + { + // Only use ZMM for large data due to possible CPU throttle issues + simdSize = min(YMM_REGSIZE_BYTES, simdSize); + } if ((size >= simdSize) && (simdSize > 0)) { // Number of SIMD regs needed to save the whole src to regs. diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 5e62513fd2e539..b1717bcfe0f1a7 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -1535,7 +1535,13 @@ int LinearScan::BuildBlockStore(GenTreeBlk* blkNode) // Lowering was expected to get rid of memmove in case of zero assert(size > 0); - const unsigned simdSize = compiler->roundDownSIMDSize(size); + unsigned simdSize = compiler->roundDownSIMDSize(size); + if (size <= ZMM_RECOMMENDED_THRESHOLD) + { + // Only use ZMM for large data due to possible CPU throttle issues + simdSize = min(YMM_REGSIZE_BYTES, compiler->roundDownSIMDSize(size)); + } + if ((size >= simdSize) && (simdSize > 0)) { unsigned simdRegs = size / simdSize; diff --git a/src/coreclr/jit/targetamd64.h b/src/coreclr/jit/targetamd64.h index bf5b0d57c8d81f..6ac906ec7f0560 100644 --- a/src/coreclr/jit/targetamd64.h +++ b/src/coreclr/jit/targetamd64.h @@ -112,6 +112,8 @@ #define STACK_ALIGN 16 // stack alignment requirement #define STACK_ALIGN_SHIFT 4 // Shift-right amount to convert size in bytes to size in STACK_ALIGN units == log2(STACK_ALIGN) + #define ZMM_RECOMMENDED_THRESHOLD 128 // A general recommendation to use ZMM for data starting from this size in bytes + #if ETW_EBP_FRAMED #define RBM_ETW_FRAMED_EBP RBM_NONE #define RBM_ETW_FRAMED_EBP_LIST diff --git a/src/coreclr/jit/targetx86.h b/src/coreclr/jit/targetx86.h index e6916ed952001a..64b763a5e8b7ec 100644 --- a/src/coreclr/jit/targetx86.h +++ b/src/coreclr/jit/targetx86.h @@ -116,6 +116,8 @@ #define YMM_REGSIZE_BYTES 32 // YMM register size in bytes #define ZMM_REGSIZE_BYTES 64 // ZMM register size in bytes + #define ZMM_RECOMMENDED_THRESHOLD 128 // A general recommendation to use ZMM for data starting from this size in bytes + #define REGNUM_BITS 6 // number of bits in a REG_* #define REGSIZE_BYTES 4 // number of bytes in one register From 7a0c3a392bcaadba66ece6e34c211f701051ac3f Mon Sep 17 00:00:00 2001 From: Vitek Karas <10670590+vitek-karas@users.noreply.github.com> Date: Wed, 12 Apr 2023 06:59:39 -0700 Subject: [PATCH 03/21] Avoid warnings due to RUC on type when marking assembly as library (#84620) Marking an assembly as "library" will mark all public APIs. If some of the marked members have RUC on them we decided we don't want to produce warnings, since there's nothing especially wrong with the library. The callers of those members would still get the right warnings. Currently linker implements this correctly for methods and properties, but it fails for fields and events and it still produces some warnings, especially if the RUC is on the parent type. This change fixes those cases and adds a special test for the library marked assembly in combination with several RUCs. Fixes https://github.com/dotnet/runtime/issues/81864 --- .../src/linker/Linker.Steps/MarkStep.cs | 42 ++++++++++--- .../RequiresCapabilityTests.cs | 8 ++- .../RequiresInLibraryAssembly.cs | 62 +++++++++++++++++++ .../RequiresCapability/RequiresViaXml.cs | 2 - 4 files changed, 104 insertions(+), 10 deletions(-) create mode 100644 src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInLibraryAssembly.cs diff --git a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs index fbe2ee3439aabf..515a3018fc486e 100644 --- a/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs +++ b/src/tools/illink/src/linker/Linker.Steps/MarkStep.cs @@ -1775,9 +1775,19 @@ void ProcessAnalysisAnnotationsForField (FieldDefinition field, DependencyKind d (origin.Provider is MethodDefinition originMethod && CompilerGeneratedState.IsNestedFunctionOrStateMachineMember (originMethod))); } - if (dependencyKind == DependencyKind.DynamicallyAccessedMemberOnType) { + switch (dependencyKind) { + // Marked through things like descriptor - don't want to warn as it's intentional choice + case DependencyKind.AlreadyMarked: + case DependencyKind.TypePreserve: + case DependencyKind.PreservedMethod: + return; + + case DependencyKind.DynamicallyAccessedMemberOnType: ReportWarningsForTypeHierarchyReflectionAccess (field, origin); return; + + default: + break; } if (Annotations.ShouldSuppressAnalysisWarningsForRequiresUnreferencedCode (origin.Provider, out _)) @@ -3189,9 +3199,10 @@ protected virtual void ProcessMethod (MethodDefinition method, in DependencyInfo if (!Annotations.ProcessSatelliteAssemblies && KnownMembers.IsSatelliteAssemblyMarker (method)) Annotations.ProcessSatelliteAssemblies = true; } else if (method.TryGetProperty (out PropertyDefinition? property)) - MarkProperty (property, new DependencyInfo (DependencyKind.PropertyOfPropertyMethod, method)); - else if (method.TryGetEvent (out EventDefinition? @event)) - MarkEvent (@event, new DependencyInfo (DependencyKind.EventOfEventMethod, method)); + MarkProperty (property, new DependencyInfo (PropagateDependencyKindToAccessors (reason.Kind, DependencyKind.PropertyOfPropertyMethod), method)); + else if (method.TryGetEvent (out EventDefinition? @event)) { + MarkEvent (@event, new DependencyInfo (PropagateDependencyKindToAccessors(reason.Kind, DependencyKind.EventOfEventMethod), method)); + } if (method.HasMetadataParameters ()) { #pragma warning disable RS0030 // MethodReference.Parameters is banned. It's easiest to leave the code as is for now @@ -3270,6 +3281,20 @@ protected virtual void DoAdditionalMethodProcessing (MethodDefinition method) { } + static DependencyKind PropagateDependencyKindToAccessors(DependencyKind parentDependencyKind, DependencyKind kind) + { + switch (parentDependencyKind) { + // If the member is marked due to descriptor or similar, propagate the original reason to suppress some warnings correctly + case DependencyKind.AlreadyMarked: + case DependencyKind.TypePreserve: + case DependencyKind.PreservedMethod: + return parentDependencyKind; + + default: + return kind; + } + } + void MarkImplicitlyUsedFields (TypeDefinition type) { if (type?.HasFields != true) @@ -3506,9 +3531,12 @@ protected internal virtual void MarkEvent (EventDefinition evt, in DependencyInf using var eventScope = ScopeStack.PushScope (new MessageOrigin (evt)); MarkCustomAttributes (evt, new DependencyInfo (DependencyKind.CustomAttribute, evt)); - MarkMethodIfNotNull (evt.AddMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin); - MarkMethodIfNotNull (evt.InvokeMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin); - MarkMethodIfNotNull (evt.RemoveMethod, new DependencyInfo (DependencyKind.EventMethod, evt), ScopeStack.CurrentScope.Origin); + + DependencyKind dependencyKind = PropagateDependencyKindToAccessors(reason.Kind, DependencyKind.EventMethod); + MarkMethodIfNotNull (evt.AddMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin); + MarkMethodIfNotNull (evt.InvokeMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin); + MarkMethodIfNotNull (evt.RemoveMethod, new DependencyInfo (dependencyKind, evt), ScopeStack.CurrentScope.Origin); + DoAdditionalEventProcessing (evt); } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs index 12e0844b559389..b711d35078c660 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresCapabilityTests.cs @@ -58,6 +58,12 @@ public Task RequiresInCompilerGeneratedCodeRelease () return RunTest (); } + [Fact] + public Task RequiresInLibraryAssembly () + { + return RunTest (); + } + [Fact] public Task RequiresOnAttribute () { @@ -112,4 +118,4 @@ public Task SuppressRequires () return RunTest (nameof (SuppressRequires)); } } -} \ No newline at end of file +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInLibraryAssembly.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInLibraryAssembly.cs new file mode 100644 index 00000000000000..d5b55e0b4970d0 --- /dev/null +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInLibraryAssembly.cs @@ -0,0 +1,62 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics.CodeAnalysis; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.RequiresCapability +{ + [SetupLinkerArgument ("-a", "test.exe", "library")] + + [SkipKeptItemsValidation] + [ExpectedNoWarnings] + public class RequiresInLibraryAssembly + { + public static void Main () + { + } + + [RequiresDynamicCode ("--MethodWhichRequires--")] + public static void MethodWhichRequires () { } + + [RequiresDynamicCode ("--InstanceMethodWhichRequires--")] + public void InstanceMethodWhichRequires () { } + } + + [ExpectedNoWarnings] + public sealed class ClassWithDAMAnnotatedMembers + { + public static void Method ([DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] Type type) { } + + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + public static Type Field; + } + + [ExpectedNoWarnings] + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] + public sealed class ClassWithDAMAnnotation + { + public void Method () { } + } + + [ExpectedNoWarnings] + [RequiresUnreferencedCode ("--ClassWithRequires--")] + public sealed class ClassWithRequires + { + public static int Field; + + internal static int InternalField; + + private static int PrivateField; + + public static void Method () { } + + public void InstanceMethod () { } + + public static int Property { get; set; } + + public static event EventHandler PropertyChanged; + } +} diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs index 46e199fc84bd75..5ad0c16f5503fc 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/RequiresCapability/RequiresViaXml.cs @@ -17,8 +17,6 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability [SetupLinkerDescriptorFile ("RequiresViaXml.descriptor.xml")] [SkipKeptItemsValidation] [ExpectedNoWarnings] - // [LogContains ("--RequiresOnlyViaDescriptor--")] // https://github.com/dotnet/linker/issues/2103 - [ExpectedWarning ("IL2026", "RequiresOnFieldOnlyViaDescriptor.Field", FileName = "RequiresViaXml.descriptor.xml", ProducedBy = Tool.Trimmer)] class RequiresViaXml { From c31d2641271f66bf1ba338bb9f1d3c478b9449ba Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 12 Apr 2023 10:55:27 -0400 Subject: [PATCH 04/21] [mono][llvm] Avoid making volatile loads/stores to variables marked INDIRECT. (#84674) Variables in the JIT are marked INDIRECT when their address is taken. Using volatile loads/stores prevents LLVM from optimizing away the address taking. Re: https://github.com/dotnet/perf-autofiling-issues/issues/15699. --- src/mono/mono/mini/mini-llvm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 598ce4e675645c..e9adc6f69bbbfd 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -1443,7 +1443,7 @@ emit_store (LLVMBuilderRef builder, LLVMValueRef Val, LLVMValueRef PointerVal, * If vreg is volatile, emit a load from its address. */ static LLVMValueRef -emit_volatile_load (EmitContext *ctx, int vreg) +emit_volatile_load (EmitContext *ctx, MonoInst *var, int vreg) { MonoType *t; LLVMValueRef v; @@ -1451,7 +1451,8 @@ emit_volatile_load (EmitContext *ctx, int vreg) // On arm64, we pass the rgctx in a callee saved // register on arm64 (x15), and llvm might keep the value in that register // even through the register is marked as 'reserved' inside llvm. - v = emit_load (ctx->builder, ctx->addresses [vreg]->type, ctx->addresses [vreg]->value, "", TRUE); + gboolean is_volatile = (var->flags & MONO_INST_VOLATILE) != 0; + v = emit_load (ctx->builder, ctx->addresses [vreg]->type, ctx->addresses [vreg]->value, "", is_volatile); t = ctx->vreg_cli_types [vreg]; if (t && !m_type_is_byref (t)) { /* @@ -1482,8 +1483,9 @@ emit_volatile_store (EmitContext *ctx, int vreg) if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) { g_assert (ctx->addresses [vreg]); #ifdef TARGET_WASM + gboolean is_volatile = (var->flags & MONO_INST_VOLATILE) != 0; /* Need volatile stores otherwise the compiler might move them */ - emit_store (ctx->builder, convert (ctx, ctx->values [vreg], type_to_llvm_type (ctx, var->inst_vtype)), ctx->addresses [vreg]->value, TRUE); + emit_store (ctx->builder, convert (ctx, ctx->values [vreg], type_to_llvm_type (ctx, var->inst_vtype)), ctx->addresses [vreg]->value, is_volatile); #else LLVMBuildStore (ctx->builder, convert (ctx, ctx->values [vreg], type_to_llvm_type (ctx, var->inst_vtype)), ctx->addresses [vreg]->value); #endif @@ -3828,7 +3830,8 @@ emit_gc_pin (EmitContext *ctx, LLVMBuilderRef builder, int vreg) if (ctx->values [vreg] == LLVMConstNull (IntPtrType ())) return; MonoInst *var = get_vreg_to_inst (ctx->cfg, vreg); - if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT|MONO_INST_IS_DEAD)) + if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_IS_DEAD)) + /* Volatile variables are stored to the stack already */ return; g_assert (vreg < ctx->gc_var_indexes_len); LLVMValueRef index0 = const_int32 (0); @@ -3872,7 +3875,7 @@ emit_entry_bb (EmitContext *ctx, LLVMBuilderRef builder) for (guint32 i = 0; i < cfg->next_vreg; ++i) { if (vreg_is_ref (cfg, i)) { MonoInst *var = get_vreg_to_inst (ctx->cfg, i); - if (!(var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT|MONO_INST_IS_DEAD))) { + if (!(var && var->flags & (MONO_INST_VOLATILE|MONO_INST_IS_DEAD))) { ctx->gc_var_indexes [i] = ngc_vars + 1; ngc_vars ++; ctx->gc_var_indexes_len = i + 1; @@ -5761,7 +5764,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) MonoInst *var = get_vreg_to_inst (cfg, ins->sreg1); if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) && var->opcode != OP_GSHAREDVT_ARG_REGOFFSET) { - lhs = emit_volatile_load (ctx, ins->sreg1); + lhs = emit_volatile_load (ctx, var, ins->sreg1); } else { /* It is ok for SETRET to have an uninitialized argument */ if (!values [ins->sreg1] && ins->opcode != OP_SETRET) { @@ -5777,7 +5780,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (spec [MONO_INST_SRC2] != ' ' && spec [MONO_INST_SRC2] != 'v') { MonoInst *var = get_vreg_to_inst (cfg, ins->sreg2); if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) { - rhs = emit_volatile_load (ctx, ins->sreg2); + rhs = emit_volatile_load (ctx, var, ins->sreg2); } else { if (!values [ins->sreg2]) { set_failure (ctx, "sreg2"); @@ -5792,7 +5795,7 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) if (spec [MONO_INST_SRC3] != ' ' && spec [MONO_INST_SRC3] != 'v') { MonoInst *var = get_vreg_to_inst (cfg, ins->sreg3); if (var && var->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) { - arg3 = emit_volatile_load (ctx, ins->sreg3); + arg3 = emit_volatile_load (ctx, var, ins->sreg3); } else { if (!values [ins->sreg3]) { set_failure (ctx, "sreg3"); From 0b081118dedcbc01d445f3f56222fde9d86f3f44 Mon Sep 17 00:00:00 2001 From: Eirik Tsarpalis Date: Wed, 12 Apr 2023 15:59:13 +0100 Subject: [PATCH 05/21] Add a `JsonSerializerOptions.TryGetTypeInfo` method. (#84411) * Mark the return type of the JsonSerializer.GetTypeInfo method as nullable. * Use new TryGetTypeInfo method instead. --- .../gen/JsonSourceGenerator.Emitter.cs | 29 +++----------- .../System.Text.Json/ref/System.Text.Json.cs | 1 + .../JsonSerializerOptions.Caching.cs | 40 +++++++++++++++++-- .../Serialization/JsonSerializerOptions.cs | 15 +++++++ .../Serialization/OptionsTests.cs | 27 ++++++++++++- 5 files changed, 85 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index c773f7d0069437..8384e36c8a4822 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -1322,33 +1322,16 @@ private string GetGetTypeInfoImplementation() { StringBuilder sb = new(); + // JsonSerializerContext.GetTypeInfo override -- returns cached metadata via JsonSerializerOptions sb.Append( @$"/// public override {JsonTypeInfoTypeRef}? GetTypeInfo({TypeTypeRef} type) -{{"); - // This method body grows linearly over the number of generated types. - // In line with https://github.com/dotnet/runtime/issues/77897 we should - // eventually replace this method with a direct call to Options.GetTypeInfo(). - // We can't do this currently because Options.GetTypeInfo throws whereas - // this GetTypeInfo returns null for unsupported types, so we need new API to support it. - foreach (TypeGenerationSpec metadata in _currentContext.TypesWithMetadataGenerated) - { - if (metadata.ClassType != ClassType.TypeUnsupportedBySourceGen) - { - sb.Append($@" - if (type == typeof({metadata.TypeRef})) - {{ - return this.{metadata.TypeInfoPropertyName}; - }} +{{ + {OptionsInstanceVariableName}.TryGetTypeInfo(type, out {JsonTypeInfoTypeRef}? typeInfo); + return typeInfo; +}} "); - } - } - - sb.AppendLine(@" - return null; -}"); - - // Explicit IJsonTypeInfoResolver implementation + // Explicit IJsonTypeInfoResolver implementation -- the source of truth for metadata resolution sb.AppendLine(); sb.Append(@$"{JsonTypeInfoTypeRef}? {JsonTypeInfoResolverTypeRef}.GetTypeInfo({TypeTypeRef} type, {JsonSerializerOptionsTypeRef} {OptionsLocalVariableName}) {{"); diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 0e02787a776f2b..f090117148d9a6 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -404,6 +404,7 @@ public JsonSerializerOptions(System.Text.Json.JsonSerializerOptions options) { } [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Getting a converter for a type may require reflection which depends on unreferenced code.")] public System.Text.Json.Serialization.JsonConverter GetConverter(System.Type typeToConvert) { throw null; } public System.Text.Json.Serialization.Metadata.JsonTypeInfo GetTypeInfo(System.Type type) { throw null; } + public bool TryGetTypeInfo(System.Type type, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Text.Json.Serialization.Metadata.JsonTypeInfo typeInfo) { throw null; } public void MakeReadOnly() { } } public enum JsonTokenType : byte diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs index a33b14b61070b9..24ceef724491c6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Caching.cs @@ -59,16 +59,50 @@ public JsonTypeInfo GetTypeInfo(Type type) return GetTypeInfoInternal(type, resolveIfMutable: true); } + /// + /// Tries to get the contract metadata resolved by the current instance. + /// + /// The type to resolve contract metadata for. + /// The resolved contract metadata, or if not contract could be resolved. + /// if a contract for was found, or otherwise. + /// is . + /// is not valid for serialization. + /// + /// Returned metadata can be downcast to and used with the relevant overloads. + /// + /// If the instance is locked for modification, the method will return a cached instance for the metadata. + /// + public bool TryGetTypeInfo(Type type, [NotNullWhen(true)] out JsonTypeInfo? typeInfo) + { + if (type is null) + { + ThrowHelper.ThrowArgumentNullException(nameof(type)); + } + + if (JsonTypeInfo.IsInvalidForSerialization(type)) + { + ThrowHelper.ThrowArgumentException_CannotSerializeInvalidType(nameof(type), type, null, null); + } + + typeInfo = GetTypeInfoInternal(type, ensureNotNull: null, resolveIfMutable: true); + return typeInfo is not null; + } + /// /// Same as GetTypeInfo but without validation and additional knobs. /// - internal JsonTypeInfo GetTypeInfoInternal( + [return: NotNullIfNotNull(nameof(ensureNotNull))] + internal JsonTypeInfo? GetTypeInfoInternal( Type type, bool ensureConfigured = true, + // We can't assert non-nullability on the basis of boolean parameters, + // so use a nullable representation instead to piggy-back on the NotNullIfNotNull attribute. + bool? ensureNotNull = true, bool resolveIfMutable = false, bool fallBackToNearestAncestorType = false) { Debug.Assert(!fallBackToNearestAncestorType || IsReadOnly, "ancestor resolution should only be invoked in read-only options."); + Debug.Assert(ensureNotNull is null or true, "Explicitly passing false will result in invalid result annotation."); JsonTypeInfo? typeInfo = null; @@ -85,7 +119,7 @@ internal JsonTypeInfo GetTypeInfoInternal( typeInfo = GetTypeInfoNoCaching(type); } - if (typeInfo == null) + if (typeInfo is null && ensureNotNull == true) { ThrowHelper.ThrowNotSupportedException_NoMetadataForType(type, TypeInfoResolver); } @@ -241,7 +275,7 @@ private static CacheEntry CreateCacheEntry(Type type, CachingContext context) private CacheEntry? DetermineNearestAncestor(Type type, CacheEntry entry) { // In cases where the underlying TypeInfoResolver returns `null` for a given type, - // this method traverses the hierarchy above the given type to determine potential + // this method traverses the hierarchy above the type to determine potential // ancestors for which the resolver does provide metadata. This can be useful in // cases where we're using a source generator and are trying to serialize private // implementations of an interface that is supported by the source generator. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs index 5359499e0cbea5..49af791bc239a6 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.cs @@ -696,6 +696,21 @@ internal void ConfigureForJsonSerializer() case JsonSerializerContext ctx when AppContextSwitchHelper.IsSourceGenReflectionFallbackEnabled: // .NET 6 compatibility mode: enable fallback to reflection metadata for JsonSerializerContext _effectiveJsonTypeInfoResolver = JsonTypeInfoResolver.Combine(ctx, defaultResolver); + + if (_cachingContext is { } cachingContext) + { + // A cache has already been created by the source generator. + // Repeat the same configuration routine for that options instance, if different. + // Invalidate any cache entries that have already been stored. + if (cachingContext.Options != this) + { + cachingContext.Options.ConfigureForJsonSerializer(); + } + else + { + cachingContext.Clear(); + } + } break; } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs index d290fd8d259bb9..4a454f932b3262 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/OptionsTests.cs @@ -515,6 +515,8 @@ public static void Options_DisablingIsReflectionEnabledByDefaultSwitch_DefaultOp Assert.Throws(() => options.GetTypeInfo(typeof(string))); Assert.Throws(() => options.GetConverter(typeof(string))); + Assert.False(options.TryGetTypeInfo(typeof(string), out JsonTypeInfo? typeInfo)); + Assert.Null(typeInfo); Assert.Throws(() => JsonSerializer.Serialize("string")); Assert.Throws(() => JsonSerializer.Serialize("string", options)); @@ -552,6 +554,8 @@ public static void Options_DisablingIsReflectionEnabledByDefaultSwitch_NewOption Assert.Throws(() => JsonSerializer.Serialize("string", options)); Assert.Throws(() => JsonSerializer.Deserialize("\"string\"", options)); + Assert.False(options.TryGetTypeInfo(typeof(string), out JsonTypeInfo? typeInfo)); + Assert.Null(typeInfo); Assert.False(options.IsReadOnly); // failed operations should not lock the instance @@ -661,6 +665,10 @@ public static void Options_JsonSerializerContext_Net6CompatibilitySwitch_FallsBa JsonConverter converter = JsonContext.Default.Options.GetConverter(typeof(MyClass)); Assert.IsAssignableFrom>(converter); + // Serialization using JsonSerializerContext now uses the reflection fallback. + json = JsonSerializer.Serialize(unsupportedValue, unsupportedValue.GetType(), JsonContext.Default); + JsonTestHelper.AssertJsonEqual("""{"Value":"value", "Thing":null}""", json); + }, options).Dispose(); } @@ -1373,9 +1381,12 @@ public static void GetTypeInfo_MutableOptionsInstance(Type type) // An unset resolver results in NotSupportedException. Assert.Throws(() => options.GetTypeInfo(type)); + // And returns false in the Try-method + Assert.False(options.TryGetTypeInfo(type, out JsonTypeInfo? typeInfo)); + Assert.Null(typeInfo); options.TypeInfoResolver = new DefaultJsonTypeInfoResolver(); - JsonTypeInfo typeInfo = options.GetTypeInfo(type); + typeInfo = options.GetTypeInfo(type); Assert.Equal(type, typeInfo.Type); Assert.False(typeInfo.IsReadOnly); @@ -1385,6 +1396,12 @@ public static void GetTypeInfo_MutableOptionsInstance(Type type) Assert.NotSame(typeInfo, typeInfo2); + Assert.True(options.TryGetTypeInfo(type, out JsonTypeInfo? typeInfo3)); + Assert.Equal(type, typeInfo3.Type); + Assert.False(typeInfo3.IsReadOnly); + + Assert.NotSame(typeInfo, typeInfo3); + options.WriteIndented = true; // can mutate without issue } @@ -1404,6 +1421,9 @@ public static void GetTypeInfo_ImmutableOptionsInstance(Type type) JsonTypeInfo typeInfo2 = options.GetTypeInfo(type); Assert.Same(typeInfo, typeInfo2); + + Assert.True(options.TryGetTypeInfo(type, out JsonTypeInfo? typeInfo3)); + Assert.Same(typeInfo, typeInfo3); } [Fact] @@ -1451,6 +1471,7 @@ public static void GetTypeInfo_NullInput_ThrowsArgumentNullException() { var options = new JsonSerializerOptions(); Assert.Throws(() => options.GetTypeInfo(null)); + Assert.Throws(() => options.TryGetTypeInfo(null, out JsonTypeInfo? _)); } [Fact] @@ -1503,6 +1524,7 @@ public static void GetTypeInfo_InvalidInput_ThrowsArgumentException(Type type) { var options = new JsonSerializerOptions(); Assert.Throws(() => options.GetTypeInfo(type)); + Assert.Throws(() => options.TryGetTypeInfo(type, out JsonTypeInfo? _)); } [Fact] @@ -1512,6 +1534,9 @@ public static void GetTypeInfo_ResolverWithoutMetadata_ThrowsNotSupportedExcepti options.AddContext(); Assert.Throws(() => options.GetTypeInfo(typeof(BasicCompany))); + + Assert.False(options.TryGetTypeInfo(typeof(BasicCompany), out JsonTypeInfo? typeInfo)); + Assert.Null(typeInfo); } [Theory] From e4082bf294dc2caac5cfe09b7f3f206ef03d435d Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Wed, 12 Apr 2023 08:29:23 -0700 Subject: [PATCH 06/21] Implement proper parsing for primitives in config binding gen (#84154) * Implement proper parsing for primitives in config binding gen * Address feedback --- .../gen/CollectionSpec.cs | 11 +- ...igurationBindingSourceGenerator.Emitter.cs | 380 ++++++++----- ...igurationBindingSourceGenerator.Helpers.cs | 49 +- ...figurationBindingSourceGenerator.Parser.cs | 322 ++++++++--- .../ConfigurationBindingSourceGenerator.cs | 107 ++-- .../gen/ConfigurationSectionTypeSpec.cs | 13 + .../gen/ConstructionStrategy.cs | 3 +- .../gen/ExceptionMessages.cs | 12 + .../gen/MethodSpecifier.cs | 21 + ...nfiguration.Binder.SourceGeneration.csproj | 4 + .../gen/NullableSpec.cs | 1 - .../gen/ParsableFromStringTypeSpec.cs | 33 ++ .../gen/SourceGenerationSpec.cs | 50 +- .../gen/TypeSpec.cs | 9 +- .../gen/TypeSpecKind.cs | 22 +- .../ConfigurationBinderTests.Helpers.cs | 16 +- .../ConfigurationBinderTests.TestClasses.cs | 47 ++ .../tests/Common/ConfigurationBinderTests.cs | 89 ++- .../Baselines/TestBindCallGen.generated.txt | 96 ++-- .../TestConfigureCallGen.generated.txt | 68 ++- .../Baselines/TestGetCallGen.generated.txt | 68 ++- .../Baselines/TestPrimitivesGen.generated.txt | 505 ++++++++++++++++++ ...nfingurationBindingSourceGeneratorTests.cs | 61 +++ 23 files changed, 1515 insertions(+), 472 deletions(-) create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationSectionTypeSpec.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ExceptionMessages.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/MethodSpecifier.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ParsableFromStringTypeSpec.cs create mode 100644 src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestPrimitivesGen.generated.txt diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/CollectionSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/CollectionSpec.cs index 31058c49a009f9..f86f66803be639 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/CollectionSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/CollectionSpec.cs @@ -22,11 +22,18 @@ public CollectionSpec(ITypeSymbol type) : base(type) public CollectionSpec? ConcreteType { get; init; } } + internal sealed record ArraySpec : CollectionSpec + { + public ArraySpec(ITypeSymbol type) : base(type) { } + + public override TypeSpecKind SpecKind => TypeSpecKind.Array; + } + internal sealed record EnumerableSpec : CollectionSpec { public EnumerableSpec(ITypeSymbol type) : base(type) { } - public override TypeSpecKind SpecKind { get; init; } = TypeSpecKind.Enumerable; + public override TypeSpecKind SpecKind => TypeSpecKind.Enumerable; } internal sealed record DictionarySpec : CollectionSpec @@ -35,6 +42,6 @@ public DictionarySpec(INamedTypeSymbol type) : base(type) { } public override TypeSpecKind SpecKind => TypeSpecKind.Dictionary; - public required TypeSpec KeyType { get; init; } + public required ParsableFromStringTypeSpec KeyType { get; init; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs index 046b518f70a45d..f9133090ed0c0a 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Emitter.cs @@ -15,22 +15,18 @@ private sealed partial class Emitter { private static class Expression { - public const string nullableSectionValue = "section?.Value"; public const string sectionKey = "section.Key"; + public const string sectionPath = "section.Path"; public const string sectionValue = "section.Value"; - - public const string ConvertFromBase64String = "Convert.FromBase64String"; } private static class FullyQualifiedDisplayName { - public const string ArgumentNullException = "global::System.ArgumentNullException"; public const string Helpers = $"global::{GeneratorProjectName}.{Identifier.Helpers}"; public const string IConfiguration = "global::Microsoft.Extensions.Configuration.IConfiguration"; public const string IConfigurationSection = IConfiguration + "Section"; public const string InvalidOperationException = "global::System.InvalidOperationException"; public const string IServiceCollection = "global::Microsoft.Extensions.DependencyInjection.IServiceCollection"; - public const string NotSupportedException = "global::System.NotSupportedException"; } private enum InitializationKind @@ -91,7 +87,7 @@ private void EmitConfigureMethod() EmitCheckForNullArgument_WithBlankLine(Identifier.configuration, useFullyQualifiedNames: true); - foreach (TypeSpec type in _generationSpec.Methods[MethodSpecifier.Configure]) + foreach (TypeSpec type in _generationSpec.RootConfigTypes[MethodSpecifier.Configure]) { string typeDisplayString = type.FullyQualifiedDisplayString; @@ -99,7 +95,7 @@ private void EmitConfigureMethod() _writer.WriteBlockStart($@"return {Identifier.services}.{Identifier.Configure}<{typeDisplayString}>({Identifier.obj} =>"); EmitIConfigurationHasValueOrChildrenCheck(); - EmitBindLogicFromIConfiguration(type, Identifier.obj, InitializationKind.None); + EmitBindLogicFromRootMethod(type, Identifier.obj, InitializationKind.None); _writer.WriteBlockEnd(");"); _writer.WriteBlockEnd(); @@ -128,12 +124,12 @@ private void EmitGetMethod() EmitIConfigurationHasValueOrChildrenCheck(); - foreach (TypeSpec type in _generationSpec.Methods[MethodSpecifier.Get]) + foreach (TypeSpec type in _generationSpec.RootConfigTypes[MethodSpecifier.Get]) { string typeDisplayString = type.FullyQualifiedDisplayString; _writer.WriteBlockStart($"if (typeof(T) == typeof({typeDisplayString}))"); - EmitBindLogicFromIConfiguration(type, Identifier.obj, InitializationKind.Declaration); + EmitBindLogicFromRootMethod(type, Identifier.obj, InitializationKind.Declaration); _writer.WriteLine($"return (T)(object){Identifier.obj};"); _writer.WriteBlockEnd(); _writer.WriteBlankLine(); @@ -155,7 +151,7 @@ private void EmitBindMethods() _writer.WriteBlankLine(); } - foreach (TypeSpec type in _generationSpec.Methods[MethodSpecifier.Bind]) + foreach (TypeSpec type in _generationSpec.RootConfigTypes[MethodSpecifier.Bind]) { EmitBindMethod(type); _writer.WriteBlankLine(); @@ -202,7 +198,7 @@ private void EmitHelperUsingStatements() private void EmitBindCoreMethods() { - foreach (TypeSpec type in _generationSpec.Methods[MethodSpecifier.BindCore]) + foreach (TypeSpec type in _generationSpec.RootConfigTypes[MethodSpecifier.BindCore]) { EmitBindCoreMethod(type); _writer.WriteBlankLine(); @@ -223,33 +219,33 @@ private void EmitBindCoreImpl(TypeSpec type) { case TypeSpecKind.Array: { - EmitBindCoreImplForArray((type as EnumerableSpec)!); + EmitBindCoreImplForArray((ArraySpec)type); } break; - case TypeSpecKind.IConfigurationSection: + case TypeSpecKind.Enumerable: { - EmitCastToIConfigurationSection(); - EmitAssignment(Identifier.obj, Identifier.section); + EmitBindCoreImplForEnumerable((EnumerableSpec)type); } break; case TypeSpecKind.Dictionary: { - EmitBindCoreImplForDictionary((type as DictionarySpec)!); + EmitBindCoreImplForDictionary((DictionarySpec)type); } break; - case TypeSpecKind.Enumerable: + case TypeSpecKind.IConfigurationSection: { - EmitBindCoreImplForEnumerable((type as EnumerableSpec)!); + EmitCastToIConfigurationSection(); + EmitAssignment(Identifier.obj, Identifier.section); } break; case TypeSpecKind.Object: { - EmitBindCoreImplForObject((type as ObjectSpec)!); + EmitBindCoreImplForObject((ObjectSpec)type); } break; case TypeSpecKind.Nullable: { - EmitBindCoreImpl((type as NullableSpec)!.UnderlyingType); + EmitBindCoreImpl(((NullableSpec)type).UnderlyingType); } break; default: @@ -258,19 +254,17 @@ private void EmitBindCoreImpl(TypeSpec type) } } - private void EmitBindCoreImplForArray(EnumerableSpec type) + private void EmitBindCoreImplForArray(ArraySpec type) { - EnumerableSpec concreteType = (type.ConcreteType as EnumerableSpec)!; - Debug.Assert(type.SpecKind == TypeSpecKind.Array && type.ConcreteType is not null); + EnumerableSpec concreteType = (EnumerableSpec)type.ConcreteType; EmitCheckForNullArgument_WithBlankLine_IfRequired(isValueType: false); + // Create, bind, and add elements to temp list. string tempVarName = GetIncrementalVarName(Identifier.temp); - - // Create and bind to temp list EmitBindCoreCall(concreteType, tempVarName, Identifier.configuration, InitializationKind.Declaration); - // Resize array and copy fill with additional + // Resize array and copy additional elements. _writer.WriteBlock($$""" {{Identifier.Int32}} {{Identifier.originalCount}} = {{Identifier.obj}}.{{Identifier.Length}}; {{Identifier.Array}}.{{Identifier.Resize}}(ref {{Identifier.obj}}, {{Identifier.originalCount}} + {{tempVarName}}.{{Identifier.Count}}); @@ -278,95 +272,115 @@ private void EmitBindCoreImplForArray(EnumerableSpec type) """); } - private void EmitBindCoreImplForDictionary(DictionarySpec type) + private void EmitBindCoreImplForEnumerable(EnumerableSpec type) { EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType); - TypeSpec keyType = type.KeyType; TypeSpec elementType = type.ElementType; - EmitVarDeclaration(keyType, Identifier.key); - _writer.WriteBlockStart($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())"); + _writer.WriteBlockStart($"if ({Identifier.HasValueOrChildren}({Identifier.section}))"); - // Parse key - EmitBindLogicFromString( - keyType, - Identifier.key, - expressionForConfigStringValue: Expression.sectionKey, - writeExtraOnSuccess: Emit_BindAndAddLogic_ForElement); + string addStatement = $"{Identifier.obj}.{Identifier.Add}({Identifier.element})"; - void Emit_BindAndAddLogic_ForElement() + if (elementType.SpecKind is TypeSpecKind.ParsableFromString) { - // For simple types: do regular dictionary add - if (elementType.SpecKind == TypeSpecKind.StringBasedParse) + ParsableFromStringTypeSpec stringParsableType = (ParsableFromStringTypeSpec)elementType; + if (stringParsableType.StringParsableTypeKind is StringParsableTypeKind.ConfigValue) { - EmitVarDeclaration(elementType, Identifier.element); - EmitBindLogicFromIConfigurationSectionValue( - elementType, - Identifier.element, - InitializationKind.SimpleAssignment, - writeExtraOnSuccess: () => EmitAssignment($"{Identifier.obj}[{Identifier.key}]", Identifier.element)); + string tempVarName = GetIncrementalVarName(Identifier.stringValue); + _writer.WriteBlockStart($"if ({Expression.sectionValue} is string {tempVarName})"); + _writer.WriteLine($"{Identifier.obj}.{Identifier.Add}({tempVarName});"); + _writer.WriteBlockEnd(); } - else // For complex types: + else { - string displayString = elementType.MinimalDisplayString + (elementType.IsValueType ? string.Empty : "?"); - - // If key already exists, bind to value to existing element instance if not null (for ref types) - string conditionToUseExistingElement = $"if ({Identifier.obj}.{Identifier.TryGetValue}({Identifier.key}, out {displayString} {Identifier.element})"; - conditionToUseExistingElement += !elementType.IsValueType - ? $" && {Identifier.element} is not null)" - : ")"; - _writer.WriteBlockStart(conditionToUseExistingElement); - EmitBindLogicForElement(InitializationKind.None); - _writer.WriteBlockEnd(); - - // Else, create new element instance and bind to that - _writer.WriteBlockStart("else"); - EmitBindLogicForElement(InitializationKind.SimpleAssignment); - _writer.WriteBlockEnd(); - - void EmitBindLogicForElement(InitializationKind initKind) - { - EmitBindLogicFromIConfigurationSectionValue(elementType, Identifier.element, initKind); - EmitAssignment($"{Identifier.obj}[{Identifier.key}]", Identifier.element); - } + EmitVarDeclaration(elementType, Identifier.element); + EmitBindLogicFromString(stringParsableType, Identifier.element, Expression.sectionValue, Expression.sectionPath, () => _writer.WriteLine($"{addStatement};")); } } + else + { + EmitBindCoreCall(elementType, Identifier.element, Identifier.section, InitializationKind.Declaration); + _writer.WriteLine($"{addStatement};"); + } - // End foreach loop. + _writer.WriteBlockEnd(); _writer.WriteBlockEnd(); } - private void EmitBindCoreImplForEnumerable(EnumerableSpec type) + private void EmitBindCoreImplForDictionary(DictionarySpec type) { EmitCheckForNullArgument_WithBlankLine_IfRequired(type.IsValueType); - TypeSpec elementType = type.ElementType; - - EmitVarDeclaration(elementType, Identifier.element); _writer.WriteBlockStart($"foreach ({Identifier.IConfigurationSection} {Identifier.section} in {Identifier.configuration}.{Identifier.GetChildren}())"); + _writer.WriteBlockStart($"if ({Identifier.HasValueOrChildren}({Identifier.section}))"); + + // Parse key + ParsableFromStringTypeSpec keyType = type.KeyType; - EmitBindLogicFromIConfigurationSectionValue( - elementType, - Identifier.element, - InitializationKind.SimpleAssignment, - writeExtraOnSuccess: EmitAddLogicForElement); + if (keyType.StringParsableTypeKind is StringParsableTypeKind.ConfigValue) + { + _writer.WriteLine($"{keyType.MinimalDisplayString} {Identifier.key} = {Expression.sectionKey};"); + Emit_BindAndAddLogic_ForElement(); + } + else + { + EmitVarDeclaration(keyType, Identifier.key); + EmitBindLogicFromString( + keyType, + Identifier.key, + expressionForConfigStringValue: Expression.sectionKey, + expressionForConfigValuePath: Expression.sectionValue, + writeOnSuccess: Emit_BindAndAddLogic_ForElement); + } - void EmitAddLogicForElement() + void Emit_BindAndAddLogic_ForElement() { - string addExpression = $"{Identifier.obj}.{Identifier.Add}({Identifier.element})"; - if (elementType.IsValueType) + TypeSpec elementType = type.ElementType; + + if (elementType.SpecKind == TypeSpecKind.ParsableFromString) { - _writer.WriteLine($"{addExpression};"); + ParsableFromStringTypeSpec stringParsableType = (ParsableFromStringTypeSpec)elementType; + if (stringParsableType.StringParsableTypeKind is StringParsableTypeKind.ConfigValue) + { + string tempVarName = GetIncrementalVarName(Identifier.stringValue); + _writer.WriteBlockStart($"if ({Expression.sectionValue} is string {tempVarName})"); + _writer.WriteLine($"{Identifier.obj}[{Identifier.key}] = {tempVarName};"); + _writer.WriteBlockEnd(); + } + else + { + EmitVarDeclaration(elementType, Identifier.element); + EmitBindLogicFromString( + stringParsableType, + Identifier.element, + Expression.sectionValue, + Expression.sectionPath, + () => _writer.WriteLine($"{Identifier.obj}[{Identifier.key}] = {Identifier.element};")); + } } - else + else // For complex types: { - _writer.WriteLine($"if ({Identifier.element} is not null) {{ {addExpression}; }}"); + string elementTypeDisplayString = elementType.MinimalDisplayString + (elementType.IsValueType ? string.Empty : "?"); + + // If key already exists, bind to value to existing element instance if not null (for ref types). + string conditionToUseExistingElement = $"{Identifier.obj}.{Identifier.TryGetValue}({Identifier.key}, out {elementTypeDisplayString} {Identifier.element})"; + if (!elementType.IsValueType) + { + conditionToUseExistingElement += $" && {Identifier.element} is not null"; + } + _writer.WriteBlockStart($"if (!({conditionToUseExistingElement}))"); + EmitObjectInit(elementType, Identifier.element, InitializationKind.SimpleAssignment); + _writer.WriteBlockEnd(); + + EmitBindCoreCall(elementType, $"{Identifier.element}!", Identifier.section, InitializationKind.None); + _writer.WriteLine($"{Identifier.obj}[{Identifier.key}] = {Identifier.element};"); } } _writer.WriteBlockEnd(); + _writer.WriteBlockEnd(); } private void EmitBindCoreImplForObject(ObjectSpec type) @@ -400,25 +414,19 @@ private void EmitBindCoreImplForProperty(PropertySpec property, TypeSpec propert string expressionForConfigSectionAccess = $@"{Identifier.configuration}.{Identifier.GetSection}(""{configurationKeyName}"")"; string expressionForConfigValueIndexer = $@"{Identifier.configuration}[""{configurationKeyName}""]"; - bool canGet = property.CanGet; bool canSet = property.CanSet; switch (propertyType.SpecKind) { - case TypeSpecKind.System_Object: - { - EmitAssignment(expressionForPropertyAccess, $"{expressionForConfigValueIndexer}!"); - } - break; - case TypeSpecKind.StringBasedParse: - case TypeSpecKind.ByteArray: + case TypeSpecKind.ParsableFromString: { if (canSet) { EmitBindLogicFromString( - propertyType, + (ParsableFromStringTypeSpec)propertyType, expressionForPropertyAccess, - expressionForConfigValueIndexer); + expressionForConfigValueIndexer, + expressionForConfigValuePath: $@"{expressionForConfigSectionAccess}.{Identifier.Path}"); } } break; @@ -438,7 +446,7 @@ private void EmitBindCoreImplForProperty(PropertySpec property, TypeSpec propert break; case TypeSpecKind.Nullable: { - TypeSpec underlyingType = (propertyType as NullableSpec)!.UnderlyingType; + TypeSpec underlyingType = ((NullableSpec)propertyType).UnderlyingType; EmitBindCoreImplForProperty(property, underlyingType, parentType); } break; @@ -454,9 +462,9 @@ private void EmitBindCoreImplForProperty(PropertySpec property, TypeSpec propert } } - private void EmitBindLogicFromIConfiguration(TypeSpec type, string expressionForMemberAccess, InitializationKind initKind) + private void EmitBindLogicFromRootMethod(TypeSpec type, string expressionForMemberAccess, InitializationKind initKind) { - if (type.SpecKind is TypeSpecKind.StringBasedParse or TypeSpecKind.ByteArray) + if (type.SpecKind is TypeSpecKind.ParsableFromString) { if (initKind is InitializationKind.Declaration) { @@ -467,7 +475,7 @@ private void EmitBindLogicFromIConfiguration(TypeSpec type, string expressionFor { EmitCastToIConfigurationSection(); } - EmitBindLogicFromString(type, expressionForMemberAccess, Expression.sectionValue); + EmitBindLogicFromString((ParsableFromStringTypeSpec)type, expressionForMemberAccess, Expression.sectionValue, Expression.sectionPath); } else { @@ -475,19 +483,6 @@ private void EmitBindLogicFromIConfiguration(TypeSpec type, string expressionFor } } - private void EmitBindLogicFromIConfigurationSectionValue(TypeSpec type, string expressionForMemberAccess, InitializationKind initKind, Action? writeExtraOnSuccess = null) - { - if (type.SpecKind is TypeSpecKind.StringBasedParse or TypeSpecKind.ByteArray) - { - EmitBindLogicFromString(type, expressionForMemberAccess, Expression.sectionValue, writeExtraOnSuccess); - } - else - { - EmitBindCoreCall(type, expressionForMemberAccess, Identifier.section, initKind); - writeExtraOnSuccess?.Invoke(); - } - } - private void EmitBindCoreCall( TypeSpec type, string expressionForMemberAccess, @@ -588,49 +583,33 @@ private void EmitBindCoreCallForProperty( } private void EmitBindLogicFromString( - TypeSpec type, + ParsableFromStringTypeSpec type, string expressionForMemberAccess, string expressionForConfigStringValue, - Action? writeExtraOnSuccess = null) + string expressionForConfigValuePath, + Action? writeOnSuccess = null) { - string typeDisplayString = type.FullyQualifiedDisplayString; + StringParsableTypeKind typeKind = type.StringParsableTypeKind; + Debug.Assert(typeKind is not StringParsableTypeKind.None); + string stringValueVarName = GetIncrementalVarName(Identifier.stringValue); - string assignmentCondition = $"{expressionForConfigStringValue} is string {stringValueVarName}"; - string rhs; - if (type.SpecialType != SpecialType.None) - { - rhs = type.SpecialType switch - { - SpecialType.System_String => stringValueVarName, - SpecialType.System_Object => "default", - _ => $"{typeDisplayString}.{Identifier.Parse}({stringValueVarName})" - }; - } - else if (type.SpecKind == TypeSpecKind.Enum) - { - string enumValueVarName = GetIncrementalVarName(Identifier.enumValue); - assignmentCondition += $" && {Identifier.Enum}.{Identifier.TryParse}({stringValueVarName}, true, out {typeDisplayString} {enumValueVarName})"; - rhs = enumValueVarName; - } - else if (type.SpecKind == TypeSpecKind.ByteArray) - { - rhs = $"{Expression.ConvertFromBase64String}({stringValueVarName})"; - } - else - { - return; - } + _writer.WriteBlockStart($"if ({expressionForConfigStringValue} is string {stringValueVarName})"); - _writer.WriteBlockStart($"if ({assignmentCondition})"); - EmitAssignment(expressionForMemberAccess, rhs); - writeExtraOnSuccess?.Invoke(); + string parsedValue = typeKind is StringParsableTypeKind.ConfigValue + ? stringValueVarName + : $"{GetHelperMethodDisplayString(type.ParseMethodName)}({stringValueVarName}, () => {expressionForConfigValuePath})"; + + EmitAssignment(expressionForMemberAccess, parsedValue); + writeOnSuccess?.Invoke(); _writer.WriteBlockEnd(); + + return; } private void EmitObjectInit(TypeSpec type, string expressionForMemberAccess, InitializationKind initKind) { - if (initKind is InitializationKind.None or InitializationKind.None) + if (initKind is InitializationKind.None) { return; } @@ -638,9 +617,9 @@ private void EmitObjectInit(TypeSpec type, string expressionForMemberAccess, Ini string displayString = GetTypeDisplayString(type); string expressionForInit = null; - if (type is EnumerableSpec { SpecKind: TypeSpecKind.Array } arrayType) + if (type is ArraySpec) { - expressionForInit = $"new {_arrayBracketsRegex.Replace(displayString, "[0]", 1)};"; + expressionForInit = $"new {_arrayBracketsRegex.Replace(displayString, "[0]", 1)}"; } else if (type.ConstructionStrategy != ConstructionStrategy.ParameterlessConstructor) { @@ -692,6 +671,15 @@ private void EmitHelperMethods() { EmitHasChildrenMethod(); } + + if (_generationSpec.PrimitivesForHelperGen.Count > 0) + { + foreach (ParsableFromStringTypeSpec type in _generationSpec.PrimitivesForHelperGen) + { + _writer.WriteBlankLine(); + EmitPrimitiveParseMethod(type); + } + } } private void EmitHasValueOrChildrenMethod() @@ -722,6 +710,102 @@ private void EmitHasChildrenMethod() """); } + private void EmitPrimitiveParseMethod(ParsableFromStringTypeSpec type) + { + string innerExceptionTypeDisplayString; + string cultureInfoTypeDisplayString; + string numberStylesTypeDisplayString; + + if (_useFullyQualifiedNames) + { + innerExceptionTypeDisplayString = "global::System.Exception"; + cultureInfoTypeDisplayString = "global::System.Globalization.CultureInfo"; + numberStylesTypeDisplayString = "global::System.Globalization.NumberStyles"; + } + else + { + innerExceptionTypeDisplayString = "Exception"; + cultureInfoTypeDisplayString = "CultureInfo"; + numberStylesTypeDisplayString = "NumberStyles"; + } + + string invariantCultureExpression = $"{cultureInfoTypeDisplayString}.InvariantCulture"; + + string expressionForParsedValue; + StringParsableTypeKind typeKind = type.StringParsableTypeKind; + string typeDisplayString = type.MinimalDisplayString; + + switch (typeKind) + { + case StringParsableTypeKind.Enum: + { + expressionForParsedValue = $"({typeDisplayString}){Identifier.Enum}.{Identifier.Parse}(typeof({typeDisplayString}), {Identifier.stringValue}, ignoreCase: true)"; + } + break; + case StringParsableTypeKind.ByteArray: + { + expressionForParsedValue = $"Convert.FromBase64String({Identifier.stringValue})"; + } + break; + case StringParsableTypeKind.Integer: + { + expressionForParsedValue = $"{typeDisplayString}.{Identifier.Parse}({Identifier.stringValue}, {numberStylesTypeDisplayString}.Integer, {invariantCultureExpression})"; + } + break; + case StringParsableTypeKind.Float: + { + expressionForParsedValue = $"{typeDisplayString}.{Identifier.Parse}({Identifier.stringValue}, {numberStylesTypeDisplayString}.Float, {invariantCultureExpression})"; + } + break; + case StringParsableTypeKind.Parse: + { + expressionForParsedValue = $"{typeDisplayString}.{Identifier.Parse}({Identifier.stringValue})"; + } + break; + case StringParsableTypeKind.ParseInvariant: + { + expressionForParsedValue = $"{typeDisplayString}.{Identifier.Parse}({Identifier.stringValue}, {invariantCultureExpression})"; ; + } + break; + case StringParsableTypeKind.CultureInfo: + { + expressionForParsedValue = $"{cultureInfoTypeDisplayString}.GetCultureInfo({Identifier.stringValue})"; + } + break; + case StringParsableTypeKind.Uri: + { + expressionForParsedValue = $"new Uri({Identifier.stringValue}, UriKind.RelativeOrAbsolute)"; + } + break; + default: + { + Debug.Fail($"Invalid string parsable kind: {typeKind}"); + return; + } + } + + string exceptionTypeDisplayString = _useFullyQualifiedNames ? FullyQualifiedDisplayName.InvalidOperationException : Identifier.InvalidOperationException; + + _writer.WriteBlock($$""" + public static {{typeDisplayString}} {{type.ParseMethodName}}(string {{Identifier.stringValue}}, Func {{Identifier.getPath}}) + { + try + { + return {{expressionForParsedValue}}; + """); + + string exceptionArg1 = string.Format(ExceptionMessages.FailedBinding, $"{{{Identifier.getPath}()}}", $"{{typeof({typeDisplayString})}}"); + + _writer.WriteBlock($$""" + } + catch ({{innerExceptionTypeDisplayString}} {{Identifier.exception}}) + { + throw new {{exceptionTypeDisplayString}}($"{{exceptionArg1}}", {{Identifier.exception}}); + } + } + """); + } + private void EmitVarDeclaration(TypeSpec type, string varName) => _writer.WriteLine($"{type.MinimalDisplayString} {varName};"); private void EmitAssignment(string lhsSource, string rhsSource) => _writer.WriteLine($"{lhsSource} = {rhsSource};"); @@ -732,7 +816,7 @@ private void EmitCastToIConfigurationSection() string exceptionTypeDisplayString; if (_useFullyQualifiedNames) { - sectionTypeDisplayString = FullyQualifiedDisplayName.IConfigurationSection; + sectionTypeDisplayString = "global::Microsoft.Extensions.Configuration.IConfigurationSection"; exceptionTypeDisplayString = FullyQualifiedDisplayName.InvalidOperationException; } else @@ -750,7 +834,7 @@ private void EmitCastToIConfigurationSection() } private void Emit_NotSupportedException_UnableToBindType(string reason, string typeDisplayString = "{typeof(T)}") => - _writer.WriteLine(@$"throw new {FullyQualifiedDisplayName.NotSupportedException}($""{string.Format(ExceptionMessages.TypeNotSupported, typeDisplayString, reason)}"");"); + _writer.WriteLine(@$"throw new global::System.NotSupportedException($""{string.Format(ExceptionMessages.TypeNotSupported, typeDisplayString, reason)}"");"); private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType) { @@ -763,8 +847,8 @@ private void EmitCheckForNullArgument_WithBlankLine_IfRequired(bool isValueType) private void EmitCheckForNullArgument_WithBlankLine(string argName, bool useFullyQualifiedNames = false) { string exceptionTypeDisplayString = useFullyQualifiedNames - ? FullyQualifiedDisplayName.ArgumentNullException - : Identifier.ArgumentNullException; + ? "global::System.ArgumentNullException" + : "ArgumentNullException"; _writer.WriteBlock($$""" if ({{argName}} is null) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs index 2394107a2f6d65..1dd35c4418d189 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Helpers.cs @@ -34,10 +34,17 @@ public sealed partial class ConfigurationBindingSourceGenerator defaultSeverity: DiagnosticSeverity.Error, isEnabledByDefault: true); - // Unlike sourcegen warnings, exception messages should not be localized so we keep them in source. - private static class ExceptionMessages + private static class NotSupportedReason { - public const string TypeNotSupported = "Unable to bind to type '{0}': '{1}'"; + public const string AbstractOrInterfaceNotSupported = "Abstract or interface types are not supported"; + public const string NeedPublicParameterlessConstructor = "Only objects with public parameterless ctors are supported"; + public const string CollectionNotSupported = "The collection type is not supported"; + public const string DictionaryKeyNotSupported = "The dictionary key type is not supported"; + public const string ElementTypeNotSupported = "The collection element type is not supported"; + public const string MultiDimArraysNotSupported = "Multidimensional arrays are not supported."; + public const string NullableUnderlyingTypeNotSupported = "Nullable underlying type is not supported"; + public const string TypeNotDetectedAsInput = "Generator parser did not detect the type as input"; + public const string TypeNotSupported = "The type is not supported"; } private static class Identifier @@ -45,6 +52,8 @@ private static class Identifier public const string configuration = nameof(configuration); public const string element = nameof(element); public const string enumValue = nameof(enumValue); + public const string exception = nameof(exception); + public const string getPath = nameof(getPath); public const string key = nameof(key); public const string obj = nameof(obj); public const string originalCount = nameof(originalCount); @@ -56,7 +65,6 @@ private static class Identifier public const string Add = nameof(Add); public const string Any = nameof(Any); - public const string ArgumentNullException = nameof(ArgumentNullException); public const string Array = nameof(Array); public const string Bind = nameof(Bind); public const string BindCore = nameof(BindCore); @@ -64,6 +72,8 @@ private static class Identifier public const string CopyTo = nameof(CopyTo); public const string ContainsKey = nameof(ContainsKey); public const string Count = nameof(Count); + public const string CultureInfo = nameof(CultureInfo); + public const string CultureNotFoundException = nameof(CultureNotFoundException); public const string Enum = nameof(Enum); public const string GeneratedConfigurationBinder = nameof(GeneratedConfigurationBinder); public const string Get = nameof(Get); @@ -76,42 +86,45 @@ private static class Identifier public const string IConfiguration = nameof(IConfiguration); public const string IConfigurationSection = nameof(IConfigurationSection); public const string Int32 = "int"; + public const string InvalidOperationException = nameof(InvalidOperationException); + public const string InvariantCulture = nameof(InvariantCulture); public const string Length = nameof(Length); public const string Parse = nameof(Parse); + public const string Path = nameof(Path); public const string Resize = nameof(Resize); + public const string TryCreate = nameof(TryCreate); public const string TryGetValue = nameof(TryGetValue); public const string TryParse = nameof(TryParse); + public const string Uri = nameof(Uri); public const string Value = nameof(Value); } - private static class NotSupportedReason - { - public const string AbstractOrInterfaceNotSupported = "Abstract or interface types are not supported"; - public const string NeedPublicParameterlessConstructor = "Only objects with public parameterless ctors are supported"; - public const string CollectionNotSupported = "The collection type is not supported"; - public const string DictionaryKeyNotSupported = "The dictionary key type is not supported"; - public const string ElementTypeNotSupported = "The collection element type is not supported"; - public const string MultiDimArraysNotSupported = "Multidimensional arrays are not supported."; - public const string NullableUnderlyingTypeNotSupported = "Nullable underlying type is not supported"; - public const string TypeNotDetectedAsInput = "Generator parser did not detect the type as input"; - public const string TypeNotSupported = "The type is not supported"; - } - private static class TypeFullName { public const string ConfigurationKeyNameAttribute = "Microsoft.Extensions.Configuration.ConfigurationKeyNameAttribute"; + public const string CultureInfo = "System.Globalization.CultureInfo"; + public const string DateOnly = "System.DateOnly"; + public const string DateTimeOffset = "System.DateTimeOffset"; public const string Dictionary = "System.Collections.Generic.Dictionary`2"; public const string GenericIDictionary = "System.Collections.Generic.IDictionary`2"; + public const string Guid = "System.Guid"; + public const string Half = "System.Half"; public const string HashSet = "System.Collections.Generic.HashSet`1"; public const string IConfiguration = "Microsoft.Extensions.Configuration.IConfiguration"; public const string IConfigurationSection = "Microsoft.Extensions.Configuration.IConfigurationSection"; public const string IDictionary = "System.Collections.Generic.IDictionary"; + public const string Int128 = "System.Int128"; public const string ISet = "System.Collections.Generic.ISet`1"; public const string IServiceCollection = "Microsoft.Extensions.DependencyInjection.IServiceCollection"; public const string List = "System.Collections.Generic.List`1"; + public const string TimeOnly = "System.TimeOnly"; + public const string TimeSpan = "System.TimeSpan"; + public const string UInt128 = "System.UInt128"; + public const string Uri = "System.Uri"; + public const string Version = "System.Version"; } - private static bool TypesAreEqual(ITypeSymbol first, ITypeSymbol second) + private static bool TypesAreEqual(ITypeSymbol first, ITypeSymbol? second) => first.Equals(second, SymbolEqualityComparer.Default); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Parser.cs index 26ed3669ccdb7f..077bf0f4f0b488 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Parser.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.Parser.cs @@ -1,10 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Runtime.InteropServices.ComTypes; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Operations; @@ -14,10 +17,8 @@ public sealed partial class ConfigurationBindingSourceGenerator { private sealed class Parser { - private const string GlobalNameSpaceString = ""; - private readonly SourceProductionContext _context; - private readonly KnownTypeData _typeData; + private readonly KnownTypeSymbols _typeSymbols; private readonly HashSet _typesForBindMethodGen = new(); private readonly HashSet _typesForGetMethodGen = new(); @@ -27,22 +28,25 @@ private sealed class Parser private readonly HashSet _unsupportedTypes = new(SymbolEqualityComparer.Default); private readonly Dictionary _createdSpecs = new(SymbolEqualityComparer.Default); + private readonly HashSet _primitivesForHelperGen = new(); private readonly HashSet _namespaces = new() { "System", - "System.Linq", + "System.Globalization", "Microsoft.Extensions.Configuration" }; - public Parser(SourceProductionContext context, KnownTypeData typeData) + private MethodSpecifier _methodsToGen; + + public Parser(SourceProductionContext context, KnownTypeSymbols typeSymbols) { _context = context; - _typeData = typeData; + _typeSymbols = typeSymbols; } public SourceGenerationSpec? GetSourceGenerationSpec(ImmutableArray operations) { - if (_typeData.SymbolForIConfiguration is null || _typeData.SymbolForIServiceCollection is null) + if (_typeSymbols.IConfiguration is null || _typeSymbols.IServiceCollection is null) { return null; } @@ -71,7 +75,7 @@ public Parser(SourceProductionContext context, KnownTypeData typeData) } } - Dictionary> methods = new() + Dictionary> rootConfigTypes = new() { [MethodSpecifier.Bind] = _typesForBindMethodGen, [MethodSpecifier.Get] = _typesForGetMethodGen, @@ -79,7 +83,7 @@ public Parser(SourceProductionContext context, KnownTypeData typeData) [MethodSpecifier.BindCore] = _typesForBindCoreMethodGen, }; - return new SourceGenerationSpec(methods, _namespaces); + return new SourceGenerationSpec(rootConfigTypes, _methodsToGen, _primitivesForHelperGen, _namespaces); } private void ProcessBindCall(BinderInvocationOperation binderOperation) @@ -89,7 +93,7 @@ private void ProcessBindCall(BinderInvocationOperation binderOperation) // We're looking for IConfiguration.Bind(object). if (operation is IInvocationOperation { Arguments: { Length: 2 } arguments } && operation.TargetMethod.IsExtensionMethod && - TypesAreEqual(_typeData.SymbolForIConfiguration, arguments[0].Parameter.Type) && + TypesAreEqual(_typeSymbols.IConfiguration, arguments[0].Parameter.Type) && arguments[1].Parameter.Type.SpecialType == SpecialType.System_Object) { IConversionOperation argument = arguments[1].Value as IConversionOperation; @@ -104,7 +108,7 @@ private void ProcessBindCall(BinderInvocationOperation binderOperation) return; } - AddTargetConfigType(_typesForBindMethodGen, namedType, binderOperation.Location); + AddRootConfigType(MethodSpecifier.Bind, namedType, binderOperation.Location); static ITypeSymbol? ResolveType(IOperation argument) => argument switch @@ -129,7 +133,7 @@ private void ProcessGetCall(BinderInvocationOperation binderOperation) if (operation is IInvocationOperation { Arguments.Length: 1 } invocationOperation && invocationOperation.TargetMethod.IsExtensionMethod && invocationOperation.TargetMethod.IsGenericMethod && - TypesAreEqual(_typeData.SymbolForIConfiguration, invocationOperation.TargetMethod.Parameters[0].Type)) + TypesAreEqual(_typeSymbols.IConfiguration, invocationOperation.TargetMethod.Parameters[0].Type)) { ITypeSymbol? type = invocationOperation.TargetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); if (type is not INamedTypeSymbol { } namedType || @@ -139,7 +143,7 @@ private void ProcessGetCall(BinderInvocationOperation binderOperation) return; } - AddTargetConfigType(_typesForGetMethodGen, namedType, binderOperation.Location); + AddRootConfigType(MethodSpecifier.Get, namedType, binderOperation.Location); } } @@ -151,8 +155,8 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) if (operation is IInvocationOperation { Arguments.Length: 2 } invocationOperation && invocationOperation.TargetMethod.IsExtensionMethod && invocationOperation.TargetMethod.IsGenericMethod && - TypesAreEqual(_typeData.SymbolForIServiceCollection, invocationOperation.TargetMethod.Parameters[0].Type) && - TypesAreEqual(_typeData.SymbolForIConfiguration, invocationOperation.TargetMethod.Parameters[1].Type)) + TypesAreEqual(_typeSymbols.IServiceCollection, invocationOperation.TargetMethod.Parameters[0].Type) && + TypesAreEqual(_typeSymbols.IConfiguration, invocationOperation.TargetMethod.Parameters[1].Type)) { ITypeSymbol? type = invocationOperation.TargetMethod.TypeArguments[0].WithNullableAnnotation(NullableAnnotation.None); if (type is not INamedTypeSymbol { } namedType || @@ -161,11 +165,11 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) return; } - AddTargetConfigType(_typesForConfigureMethodGen, namedType, binderOperation.Location); + AddRootConfigType(MethodSpecifier.Configure, namedType, binderOperation.Location); } } - private TypeSpec? AddTargetConfigType(HashSet specs, ITypeSymbol type, Location? location) + private TypeSpec? AddRootConfigType(MethodSpecifier method, ITypeSymbol type, Location? location) { if (type is not INamedTypeSymbol namedType || ContainsGenericParameters(namedType)) { @@ -173,10 +177,23 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) } TypeSpec? spec = GetOrCreateTypeSpec(namedType, location); - if (spec != null && - !specs.Contains(spec)) + HashSet types = method switch + { + MethodSpecifier.Configure => _typesForConfigureMethodGen, + MethodSpecifier.Get => _typesForGetMethodGen, + MethodSpecifier.Bind => _typesForBindMethodGen, + MethodSpecifier.BindCore => _typesForBindCoreMethodGen, + _ => throw new InvalidOperationException($"Invalid method for config binding method generation: {method}") + }; + + if (spec != null) { - specs.Add(spec); + types.Add(spec); + _methodsToGen |= method; + if (method is not MethodSpecifier.Bind) + { + _methodsToGen |= MethodSpecifier.HasValueOrChildren; + } } return spec; @@ -189,11 +206,7 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) return spec; } - if (type.SpecialType == SpecialType.System_Object) - { - return CacheSpec(new TypeSpec(type) { Location = location, SpecKind = TypeSpecKind.System_Object }); - } - else if (type is INamedTypeSymbol { IsGenericType: true } genericType && + if (type is INamedTypeSymbol { IsGenericType: true } genericType && genericType.ConstructUnboundGenericType() is INamedTypeSymbol { } unboundGeneric && unboundGeneric.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T) { @@ -201,46 +214,55 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) ? CacheSpec(new NullableSpec(type) { Location = location, UnderlyingType = underlyingType }) : null; } - else if (type.SpecialType != SpecialType.None) + else if (IsSupportedArrayType(type, location, out ITypeSymbol? elementType)) { - return CacheSpec(new TypeSpec(type) { Location = location }); + if (elementType.SpecialType is SpecialType.System_Byte) + { + return CacheSpec(new ParsableFromStringTypeSpec(type) { Location = location, StringParsableTypeKind = StringParsableTypeKind.ByteArray }); + } + + spec = CreateArraySpec((type as IArrayTypeSymbol)!, location); + if (spec is null) + { + return null; + } + + RegisterTypeForBindCoreMethodGen(MethodSpecifier.BindCore, spec); + return CacheSpec(spec); } - else if (IsEnum(type)) + else if (IsParsableFromString(type, out StringParsableTypeKind specialTypeKind)) { - return CacheSpec(new TypeSpec(type) { Location = location, SpecKind = TypeSpecKind.Enum }); + return CacheSpec( + new ParsableFromStringTypeSpec(type) + { + Location = location, + StringParsableTypeKind = specialTypeKind + }); } - else if (type is IArrayTypeSymbol { } arrayType) + else if (IsCollection(type)) { - spec = CreateArraySpec(arrayType, location); + spec = CreateCollectionSpec((INamedTypeSymbol)type, location); if (spec is null) { return null; } - if (spec.SpecKind != TypeSpecKind.ByteArray) - { - Debug.Assert(spec.SpecKind is TypeSpecKind.Array); - _typesForBindCoreMethodGen.Add(spec); - } - + RegisterTypeForBindCoreMethodGen(MethodSpecifier.BindCore, spec); return CacheSpec(spec); } - else if (TypesAreEqual(type, _typeData.SymbolForIConfigurationSection)) + else if (TypesAreEqual(type, _typeSymbols.IConfigurationSection)) { - return CacheSpec(new TypeSpec(type) { Location = location, SpecKind = TypeSpecKind.IConfigurationSection }); + return CacheSpec(new ConfigurationSectionTypeSpec(type) { Location = location }); } else if (type is INamedTypeSymbol namedType) { - spec = IsCollection(namedType) - ? CreateCollectionSpec(namedType, location) - : CreateObjectSpec(namedType, location); - + spec = CreateObjectSpec(namedType, location); if (spec is null) { return null; } - _typesForBindCoreMethodGen.Add(spec); + RegisterTypeForBindCoreMethodGen(MethodSpecifier.BindCore, spec); return CacheSpec(spec); } @@ -249,17 +271,133 @@ private void ProcessConfigureCall(BinderInvocationOperation binderOperation) T CacheSpec(T? s) where T : TypeSpec { + TypeSpecKind typeKind = s.SpecKind; + Debug.Assert(typeKind is not TypeSpecKind.Unknown); + string @namespace = s.Namespace; - if (@namespace != null && @namespace != GlobalNameSpaceString) + if (@namespace != null && @namespace != "") { _namespaces.Add(@namespace); } + if (typeKind is TypeSpecKind.ParsableFromString) + { + ParsableFromStringTypeSpec type = ((ParsableFromStringTypeSpec)(object)s); + if (type.StringParsableTypeKind is not StringParsableTypeKind.ConfigValue) + { + _primitivesForHelperGen.Add(type); + } + } + _createdSpecs[type] = s; return s; } } + private void RegisterTypeForBindCoreMethodGen(MethodSpecifier method, TypeSpec spec) + { + _typesForBindCoreMethodGen.Add(spec); + _methodsToGen |= method; + } + + private bool IsParsableFromString(ITypeSymbol type, out StringParsableTypeKind typeKind) + { + if (type is not INamedTypeSymbol namedType) + { + typeKind = StringParsableTypeKind.None; + return false; + } + + if (IsEnum(namedType)) + { + typeKind = StringParsableTypeKind.Enum; + return true; + } + + SpecialType specialType = namedType.SpecialType; + + switch (specialType) + { + case SpecialType.System_String: + case SpecialType.System_Object: + { + typeKind = StringParsableTypeKind.ConfigValue; + return true; + } + case SpecialType.System_Boolean: + case SpecialType.System_Char: + { + typeKind = StringParsableTypeKind.Parse; + return true; + } + case SpecialType.System_Single: + case SpecialType.System_Double: + case SpecialType.System_Decimal: + { + typeKind = StringParsableTypeKind.Float; + return true; + } + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_Int32: + case SpecialType.System_Int64: + case SpecialType.System_SByte: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + case SpecialType.System_UInt64: + { + typeKind = StringParsableTypeKind.Integer; + return true; + } + case SpecialType.System_DateTime: + { + typeKind = StringParsableTypeKind.ParseInvariant; + return true; + } + case SpecialType.None: + { + if (TypesAreEqual(type, _typeSymbols.CultureInfo)) + { + typeKind = StringParsableTypeKind.CultureInfo; + } + else if (TypesAreEqual(type, _typeSymbols.DateTimeOffset) || + TypesAreEqual(type, _typeSymbols.DateOnly) || + TypesAreEqual(type, _typeSymbols.TimeOnly) || + TypesAreEqual(type, _typeSymbols.TimeSpan)) + { + typeKind = StringParsableTypeKind.ParseInvariant; + } + else if (TypesAreEqual(type, _typeSymbols.Int128) || + TypesAreEqual(type, _typeSymbols.Half) || + TypesAreEqual(type, _typeSymbols.UInt128)) + { + typeKind = StringParsableTypeKind.ParseInvariant; + } + else if (TypesAreEqual(type, _typeSymbols.Uri)) + { + typeKind = StringParsableTypeKind.Uri; + } + else if (TypesAreEqual(type, _typeSymbols.Version) || + TypesAreEqual(type, _typeSymbols.Guid)) + { + typeKind = StringParsableTypeKind.Parse; + } + else + { + typeKind = StringParsableTypeKind.None; + return false; + } + + return true; + } + default: + { + typeKind = StringParsableTypeKind.None; + return false; + } + } + } + private bool TryGetTypeSpec(ITypeSymbol type, string unsupportedReason, out TypeSpec? spec) { spec = GetOrCreateTypeSpec(type); @@ -273,41 +411,43 @@ private bool TryGetTypeSpec(ITypeSymbol type, string unsupportedReason, out Type return true; } - private EnumerableSpec? CreateArraySpec(IArrayTypeSymbol arrayType, Location? location) + private ArraySpec? CreateArraySpec(IArrayTypeSymbol arrayType, Location? location) { - if (arrayType.Rank > 1) + if (!TryGetTypeSpec(arrayType.ElementType, NotSupportedReason.ElementTypeNotSupported, out TypeSpec elementSpec)) { - ReportUnsupportedType(arrayType, NotSupportedReason.MultiDimArraysNotSupported, location); return null; } - if (!TryGetTypeSpec(arrayType.ElementType, NotSupportedReason.ElementTypeNotSupported, out TypeSpec? elementSpec)) + // We want a Bind method for List as a temp holder for the array values. + EnumerableSpec? listSpec = ConstructAndCacheGenericTypeForBind(_typeSymbols.List, arrayType.ElementType) as EnumerableSpec; + // We know the element type is supported. + Debug.Assert(listSpec != null); + + return new ArraySpec(arrayType) { - return null; - } + Location = location, + ElementType = elementSpec, + ConcreteType = listSpec, + }; + } - EnumerableSpec spec; - if (elementSpec.SpecialType is SpecialType.System_Byte) + private bool IsSupportedArrayType(ITypeSymbol type, Location? location, [NotNullWhen(true)] out ITypeSymbol? elementType) + { + if (type is not IArrayTypeSymbol arrayType) { - spec = new EnumerableSpec(arrayType) { Location = location, SpecKind = TypeSpecKind.ByteArray, ElementType = elementSpec }; + elementType = null; + return false; } - else - { - // We want a Bind method for List as a temp holder for the array values. - EnumerableSpec? listSpec = ConstructAndCacheGenericTypeForBind(_typeData.SymbolForList, arrayType.ElementType) as EnumerableSpec; - // We know the element type is supported. - Debug.Assert(listSpec != null); - spec = new EnumerableSpec(arrayType) - { - Location = location, - SpecKind = TypeSpecKind.Array, - ElementType = elementSpec, - ConcreteType = listSpec, - }; + if (arrayType.Rank > 1) + { + ReportUnsupportedType(arrayType, NotSupportedReason.MultiDimArraysNotSupported, location); + elementType = null; + return false; } - return spec; + elementType = arrayType.ElementType; + return true; } private CollectionSpec? CreateCollectionSpec(INamedTypeSymbol type, Location? location) @@ -332,17 +472,17 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc return null; } - if (keySpec.SpecKind != TypeSpecKind.StringBasedParse) + if (keySpec.SpecKind != TypeSpecKind.ParsableFromString) { ReportUnsupportedType(type, NotSupportedReason.DictionaryKeyNotSupported, location); return null; } DictionarySpec? concreteType = null; - if (IsInterfaceMatch(type, _typeData.SymbolForGenericIDictionary) || IsInterfaceMatch(type, _typeData.SymbolForIDictionary)) + if (IsInterfaceMatch(type, _typeSymbols.GenericIDictionary) || IsInterfaceMatch(type, _typeSymbols.IDictionary)) { // We know the key and element types are supported. - concreteType = ConstructAndCacheGenericTypeForBind(_typeData.SymbolForDictionary, keyType, elementType) as DictionarySpec; + concreteType = ConstructAndCacheGenericTypeForBind(_typeSymbols.Dictionary, keyType, elementType) as DictionarySpec; Debug.Assert(concreteType != null); } else if (!CanConstructObject(type, location) || !HasAddMethod(type, elementType, keyType)) @@ -354,7 +494,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc return new DictionarySpec(type) { Location = location, - KeyType = keySpec, + KeyType = (ParsableFromStringTypeSpec)keySpec, ElementType = elementSpec, ConstructionStrategy = ConstructionStrategy.ParameterlessConstructor, ConcreteType = concreteType @@ -364,7 +504,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc private TypeSpec? ConstructAndCacheGenericTypeForBind(INamedTypeSymbol type, params ITypeSymbol[] parameters) { Debug.Assert(type.IsGenericType); - return AddTargetConfigType(_typesForBindMethodGen, type.Construct(parameters), location: null); + return AddRootConfigType(MethodSpecifier.Bind, type.Construct(parameters), location: null); } private EnumerableSpec? CreateEnumerableSpec(INamedTypeSymbol type, Location? location, ITypeSymbol elementType) @@ -375,14 +515,14 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc } EnumerableSpec? concreteType = null; - if (IsInterfaceMatch(type, _typeData.SymbolForISet)) + if (IsInterfaceMatch(type, _typeSymbols.ISet)) { - concreteType = ConstructAndCacheGenericTypeForBind(_typeData.SymbolForHashSet, elementType) as EnumerableSpec; + concreteType = ConstructAndCacheGenericTypeForBind(_typeSymbols.HashSet, elementType) as EnumerableSpec; } - else if (IsInterfaceMatch(type, _typeData.SymbolForICollection) || - IsInterfaceMatch(type, _typeData.SymbolForGenericIList)) + else if (IsInterfaceMatch(type, _typeSymbols.ICollection) || + IsInterfaceMatch(type, _typeSymbols.GenericIList)) { - concreteType = ConstructAndCacheGenericTypeForBind(_typeData.SymbolForList, elementType) as EnumerableSpec; + concreteType = ConstructAndCacheGenericTypeForBind(_typeSymbols.List, elementType) as EnumerableSpec; } else if (!CanConstructObject(type, location) || !HasAddMethod(type, elementType)) { @@ -414,7 +554,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc _createdSpecs.Add(type, objectSpec); INamedTypeSymbol current = type; - while (current != null) + while (current is not null) { foreach (ISymbol member in current.GetMembers()) { @@ -431,7 +571,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc } else { - AttributeData? attributeData = property.GetAttributes().FirstOrDefault(a => TypesAreEqual(a.AttributeClass, _typeData.SymbolForConfigurationKeyNameAttribute)); + AttributeData? attributeData = property.GetAttributes().FirstOrDefault(a => TypesAreEqual(a.AttributeClass, _typeSymbols.ConfigurationKeyNameAttribute)); string? configKeyName = attributeData?.ConstructorArguments.FirstOrDefault().Value as string ?? propertyName; PropertySpec spec = new PropertySpec(property) { Type = propertyTypeSpec, ConfigurationKeyName = configKeyName }; @@ -439,6 +579,14 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc { objectSpec.Properties.Add(spec); } + + if (propertyTypeSpec.SpecKind is TypeSpecKind.Object or + TypeSpecKind.Array or + TypeSpecKind.Enumerable or + TypeSpecKind.Dictionary) + { + _methodsToGen |= MethodSpecifier.HasChildren; + } } } } @@ -451,7 +599,7 @@ private DictionarySpec CreateDictionarySpec(INamedTypeSymbol type, Location? loc private bool IsCandidateEnumerable(INamedTypeSymbol type, out ITypeSymbol? elementType) { - INamedTypeSymbol? @interface = GetInterface(type, _typeData.SymbolForICollection); + INamedTypeSymbol? @interface = GetInterface(type, _typeSymbols.ICollection); if (@interface is not null) { @@ -465,7 +613,7 @@ private bool IsCandidateEnumerable(INamedTypeSymbol type, out ITypeSymbol? eleme private bool IsCandidateDictionary(INamedTypeSymbol type, out ITypeSymbol? keyType, out ITypeSymbol? elementType) { - INamedTypeSymbol? @interface = GetInterface(type, _typeData.SymbolForGenericIDictionary); + INamedTypeSymbol? @interface = GetInterface(type, _typeSymbols.GenericIDictionary); if (@interface is not null) { keyType = @interface.TypeArguments[0]; @@ -473,10 +621,10 @@ private bool IsCandidateDictionary(INamedTypeSymbol type, out ITypeSymbol? keyTy return true; } - if (IsInterfaceMatch(type, _typeData.SymbolForIDictionary)) + if (IsInterfaceMatch(type, _typeSymbols.IDictionary)) { - keyType = _typeData.SymbolForString; - elementType = _typeData.SymbolForString; + keyType = _typeSymbols.String; + elementType = _typeSymbols.String; return true; } @@ -485,8 +633,8 @@ private bool IsCandidateDictionary(INamedTypeSymbol type, out ITypeSymbol? keyTy return false; } - private bool IsCollection(INamedTypeSymbol type) => - GetInterface(type, _typeData.SymbolForIEnumerable) is not null; + private bool IsCollection(ITypeSymbol type) => + type is INamedTypeSymbol namedType && GetInterface(namedType, _typeSymbols.IEnumerable) is not null; private static INamedTypeSymbol? GetInterface(INamedTypeSymbol type, INamedTypeSymbol @interface) { diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.cs index 11a4269ae22eca..46b4ed1789b7e5 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationBindingSourceGenerator.cs @@ -57,7 +57,7 @@ private static void Execute(CompilationData compilationData, ImmutableArray= LanguageVersion.CSharp11; if (LanguageVersionIsSupported) { - TypeData = new KnownTypeData(compilation); + TypeSymbols = new KnownTypeSymbols(compilation); } } } - private sealed record KnownTypeData + private sealed record KnownTypeSymbols { - public INamedTypeSymbol SymbolForGenericIList { get; } - public INamedTypeSymbol SymbolForICollection { get; } - public INamedTypeSymbol SymbolForIEnumerable { get; } - public INamedTypeSymbol SymbolForString { get; } - - public INamedTypeSymbol? SymbolForConfigurationKeyNameAttribute { get; } - public INamedTypeSymbol? SymbolForDictionary { get; } - public INamedTypeSymbol? SymbolForGenericIDictionary { get; } - public INamedTypeSymbol? SymbolForHashSet { get; } - public INamedTypeSymbol? SymbolForIConfiguration { get; } - public INamedTypeSymbol? SymbolForIConfigurationSection { get; } - public INamedTypeSymbol? SymbolForIDictionary { get; } - public INamedTypeSymbol? SymbolForIServiceCollection { get; } - public INamedTypeSymbol? SymbolForISet { get; } - public INamedTypeSymbol? SymbolForList { get; } - - public KnownTypeData(CSharpCompilation compilation) + public INamedTypeSymbol GenericIList { get; } + public INamedTypeSymbol ICollection { get; } + public INamedTypeSymbol IEnumerable { get; } + public INamedTypeSymbol String { get; } + + public INamedTypeSymbol? CultureInfo { get; } + public INamedTypeSymbol? DateOnly { get; } + public INamedTypeSymbol? DateTimeOffset { get; } + public INamedTypeSymbol? Guid { get; } + public INamedTypeSymbol? Half { get; } + public INamedTypeSymbol? Int128 { get; } + public INamedTypeSymbol? TimeOnly { get; } + public INamedTypeSymbol? TimeSpan { get; } + public INamedTypeSymbol? UInt128 { get; } + public INamedTypeSymbol? Uri { get; } + public INamedTypeSymbol? Version { get; } + + public INamedTypeSymbol? ConfigurationKeyNameAttribute { get; } + public INamedTypeSymbol? Dictionary { get; } + public INamedTypeSymbol? GenericIDictionary { get; } + public INamedTypeSymbol? HashSet { get; } + public INamedTypeSymbol? IConfiguration { get; } + public INamedTypeSymbol? IConfigurationSection { get; } + public INamedTypeSymbol? IDictionary { get; } + public INamedTypeSymbol? IServiceCollection { get; } + public INamedTypeSymbol? ISet { get; } + public INamedTypeSymbol? List { get; } + + public KnownTypeSymbols(CSharpCompilation compilation) { - SymbolForIEnumerable = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable); - SymbolForConfigurationKeyNameAttribute = compilation.GetBestTypeByMetadataName(TypeFullName.ConfigurationKeyNameAttribute); - SymbolForIConfiguration = compilation.GetBestTypeByMetadataName(TypeFullName.IConfiguration); - SymbolForIConfigurationSection = compilation.GetBestTypeByMetadataName(TypeFullName.IConfigurationSection); - SymbolForIServiceCollection = compilation.GetBestTypeByMetadataName(TypeFullName.IServiceCollection); - SymbolForString = compilation.GetSpecialType(SpecialType.System_String); - - // Collections - SymbolForIDictionary = compilation.GetBestTypeByMetadataName(TypeFullName.IDictionary); - - // Use for type equivalency checks for unbounded generics - SymbolForICollection = compilation.GetSpecialType(SpecialType.System_Collections_Generic_ICollection_T).ConstructUnboundGenericType(); - SymbolForGenericIDictionary = compilation.GetBestTypeByMetadataName(TypeFullName.GenericIDictionary)?.ConstructUnboundGenericType(); - SymbolForGenericIList = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IList_T).ConstructUnboundGenericType(); - SymbolForISet = compilation.GetBestTypeByMetadataName(TypeFullName.ISet)?.ConstructUnboundGenericType(); - - // Used to construct concrete types at runtime; cannot also be constructed - SymbolForDictionary = compilation.GetBestTypeByMetadataName(TypeFullName.Dictionary); - SymbolForHashSet = compilation.GetBestTypeByMetadataName(TypeFullName.HashSet); - SymbolForList = compilation.GetBestTypeByMetadataName(TypeFullName.List); + // Primitives (needed because they are Microsoft.CodeAnalysis.SpecialType.None) + CultureInfo = compilation.GetBestTypeByMetadataName(TypeFullName.CultureInfo); + DateOnly = compilation.GetBestTypeByMetadataName(TypeFullName.DateOnly); + DateTimeOffset = compilation.GetBestTypeByMetadataName(TypeFullName.DateTimeOffset); + Guid = compilation.GetBestTypeByMetadataName(TypeFullName.Guid); + Half = compilation.GetBestTypeByMetadataName(TypeFullName.Half); + Int128 = compilation.GetBestTypeByMetadataName(TypeFullName.Int128); + TimeOnly = compilation.GetBestTypeByMetadataName(TypeFullName.TimeOnly); + TimeSpan = compilation.GetBestTypeByMetadataName(TypeFullName.TimeSpan); + UInt128 = compilation.GetBestTypeByMetadataName(TypeFullName.UInt128); + Uri = compilation.GetBestTypeByMetadataName(TypeFullName.Uri); + Version = compilation.GetBestTypeByMetadataName(TypeFullName.Version); + + // Used to verify input configuation binding API calls. + ConfigurationKeyNameAttribute = compilation.GetBestTypeByMetadataName(TypeFullName.ConfigurationKeyNameAttribute); + IConfiguration = compilation.GetBestTypeByMetadataName(TypeFullName.IConfiguration); + IConfigurationSection = compilation.GetBestTypeByMetadataName(TypeFullName.IConfigurationSection); + IServiceCollection = compilation.GetBestTypeByMetadataName(TypeFullName.IServiceCollection); + + // Collections. + IEnumerable = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable); + IDictionary = compilation.GetBestTypeByMetadataName(TypeFullName.IDictionary); + + // Used for type equivalency checks for unbounded generics. + ICollection = compilation.GetSpecialType(SpecialType.System_Collections_Generic_ICollection_T).ConstructUnboundGenericType(); + GenericIDictionary = compilation.GetBestTypeByMetadataName(TypeFullName.GenericIDictionary)?.ConstructUnboundGenericType(); + GenericIList = compilation.GetSpecialType(SpecialType.System_Collections_Generic_IList_T).ConstructUnboundGenericType(); + ISet = compilation.GetBestTypeByMetadataName(TypeFullName.ISet)?.ConstructUnboundGenericType(); + + // Used to construct concrete types at runtime; cannot also be constructed. + Dictionary = compilation.GetBestTypeByMetadataName(TypeFullName.Dictionary); + HashSet = compilation.GetBestTypeByMetadataName(TypeFullName.HashSet); + List = compilation.GetBestTypeByMetadataName(TypeFullName.List); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationSectionTypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationSectionTypeSpec.cs new file mode 100644 index 00000000000000..533a98c0c07100 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConfigurationSectionTypeSpec.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Microsoft.CodeAnalysis; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal sealed record ConfigurationSectionTypeSpec : TypeSpec + { + public ConfigurationSectionTypeSpec(ITypeSymbol type) : base(type) { } + public override TypeSpecKind SpecKind => TypeSpecKind.IConfigurationSection; + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConstructionStrategy.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConstructionStrategy.cs index e235b2cf483974..21db02547258ac 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConstructionStrategy.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ConstructionStrategy.cs @@ -6,7 +6,6 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration internal enum ConstructionStrategy { NotApplicable = 0, - NotSupported = 1, - ParameterlessConstructor = 2, + ParameterlessConstructor = 1, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ExceptionMessages.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ExceptionMessages.cs new file mode 100644 index 00000000000000..d31ed9a7836621 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ExceptionMessages.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. + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + // Runtime exception messages; not localized so we keep them in source. + internal static class ExceptionMessages + { + public const string TypeNotSupported = "Unable to bind to type '{0}': '{1}'"; + public const string FailedBinding = "Failed to convert configuration value at '{0}' to type '{1}'."; + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/MethodSpecifier.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/MethodSpecifier.cs new file mode 100644 index 00000000000000..ef928da735c533 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/MethodSpecifier.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + [Flags] + internal enum MethodSpecifier + { + None = 0x0, + // Root methods + Bind = 0x1, + Get = 0x2, + Configure = 0x4, + // Helper methods + BindCore = 0x8, + HasValueOrChildren = 0x10, + HasChildren = 0x20, + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj index b37529ecbc87e7..5b9340c1d16223 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/Microsoft.Extensions.Configuration.Binder.SourceGeneration.csproj @@ -27,8 +27,12 @@ + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/NullableSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/NullableSpec.cs index 69ad69cdbfdd8b..a75c2819548f20 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/NullableSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/NullableSpec.cs @@ -9,7 +9,6 @@ internal sealed record NullableSpec : TypeSpec { public NullableSpec(ITypeSymbol type) : base(type) { } public override TypeSpecKind SpecKind => TypeSpecKind.Nullable; - public override ConstructionStrategy ConstructionStrategy => UnderlyingType.ConstructionStrategy; public required TypeSpec UnderlyingType { get; init; } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ParsableFromStringTypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ParsableFromStringTypeSpec.cs new file mode 100644 index 00000000000000..96dd5f8072e896 --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/ParsableFromStringTypeSpec.cs @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using Microsoft.CodeAnalysis; + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + internal sealed record ParsableFromStringTypeSpec : TypeSpec + { + public ParsableFromStringTypeSpec(ITypeSymbol type) : base(type) { } + + public override TypeSpecKind SpecKind => TypeSpecKind.ParsableFromString; + + public required StringParsableTypeKind StringParsableTypeKind { get; init; } + + private string? _parseMethodName; + public string ParseMethodName + { + get + { + Debug.Assert(StringParsableTypeKind is not StringParsableTypeKind.ConfigValue); + + _parseMethodName ??= StringParsableTypeKind is StringParsableTypeKind.ByteArray + ? "ParseByteArray" + // MinimalDisplayString.Length is certainly > 2. + : $"Parse{(char.ToUpper(MinimalDisplayString[0]) + MinimalDisplayString.Substring(1)).Replace(".", "")}"; + + return _parseMethodName; + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceGenerationSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceGenerationSpec.cs index aeeb9e19a6daa6..f4964c5ba99932 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceGenerationSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/SourceGenerationSpec.cs @@ -1,59 +1,17 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; +using Microsoft.CodeAnalysis; namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal sealed record SourceGenerationSpec( - Dictionary> Methods, + Dictionary> RootConfigTypes, + MethodSpecifier MethodsToGen, + HashSet PrimitivesForHelperGen, HashSet Namespaces) { - private MethodSpecifier? _methodsToGen; - public MethodSpecifier MethodsToGen - { - get - { - if (!_methodsToGen.HasValue) - { - _methodsToGen = MethodSpecifier.None; - - foreach (KeyValuePair> method in Methods) - { - if (method.Value.Count > 0) - { - MethodSpecifier specifier = method.Key; - - if (specifier is MethodSpecifier.Configure or MethodSpecifier.Get) - { - _methodsToGen |= MethodSpecifier.HasValueOrChildren; - } - else if (specifier is MethodSpecifier.BindCore) - { - _methodsToGen |= MethodSpecifier.HasChildren; - } - - _methodsToGen |= specifier; - } - } - } - - return _methodsToGen.Value; - } - } - } - - [Flags] - internal enum MethodSpecifier - { - None = 0x0, - Bind = 0x1, - Get = 0x2, - Configure = 0x4, - BindCore = 0x8, - HasValueOrChildren = 0x10, - HasChildren = 0x20, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpec.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpec.cs index 06ad7ceeb292d5..d4da7d138863cb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpec.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpec.cs @@ -5,7 +5,7 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { - internal record TypeSpec + internal abstract record TypeSpec { private static readonly SymbolDisplayFormat s_minimalDisplayFormat = new SymbolDisplayFormat( globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, @@ -18,7 +18,6 @@ public TypeSpec(ITypeSymbol type) FullyQualifiedDisplayString = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); MinimalDisplayString = type.ToDisplayString(s_minimalDisplayFormat); Namespace = type.ContainingNamespace?.ToDisplayString(); - SpecialType = type.SpecialType; IsValueType = type.IsValueType; } @@ -28,13 +27,9 @@ public TypeSpec(ITypeSymbol type) public string? Namespace { get; } - public SpecialType SpecialType { get; } - public bool IsValueType { get; } - public bool PassToBindCoreByRef => IsValueType || SpecKind == TypeSpecKind.Array; - - public virtual TypeSpecKind SpecKind { get; init; } + public abstract TypeSpecKind SpecKind { get; } public virtual ConstructionStrategy ConstructionStrategy { get; init; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpecKind.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpecKind.cs index 810a4aaae6eb05..dcfc27bc297183 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpecKind.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/gen/TypeSpecKind.cs @@ -5,15 +5,27 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { internal enum TypeSpecKind { - StringBasedParse = 0, - Enum = 1, + Unknown = 0, + ParsableFromString = 1, Object = 2, Array = 3, Enumerable = 4, Dictionary = 5, IConfigurationSection = 6, - System_Object = 7, - ByteArray = 8, - Nullable = 9, + Nullable = 7, + } + + internal enum StringParsableTypeKind + { + None = 0, + ConfigValue = 1, + Enum = 2, + ByteArray = 3, + Integer = 4, + Float = 5, + Parse = 6, + ParseInvariant = 7, + CultureInfo = 8, + Uri = 9, } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs index 9a90d0e0481b4e..a1d1a72ffab20f 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.Helpers.cs @@ -4,6 +4,7 @@ using System.Collections; using System.Collections.Generic; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Test; namespace Microsoft.Extensions #if BUILDING_SOURCE_GENERATOR_TESTS @@ -11,14 +12,23 @@ namespace Microsoft.Extensions #endif .Configuration.Binder.Tests { - public static class TestHelpers + internal static class TestHelpers { - public static bool NotSourceGenMode + public const bool NotSourceGenMode #if BUILDING_SOURCE_GENERATOR_TESTS = false; #else = true; -#endif +#endif + + public static IConfiguration GetConfigurationFromJsonString(string json) + { + var builder = new ConfigurationBuilder(); + var configuration = builder + .AddJsonStream(TestStreamHelpers.StringToStream(json)) + .Build(); + return configuration; + } } #region // Shared test classes diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs index 650f4d004c71af..cc6eaf4fb38fc7 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.TestClasses.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using Microsoft.Extensions.Configuration; using Xunit; @@ -566,5 +567,51 @@ public override string? TestVirtualSet public string? ExposeTestVirtualSet() => _testVirtualSet; } + + public class ClassWithDirectSelfReference + { + public string MyString { get; set; } + public ClassWithDirectSelfReference MyClass { get; set; } + } + + public class ClassWithIndirectSelfReference + { + public string MyString { get; set; } + public List MyList { get; set; } + } + + public record RecordWithPrimitives + { + public bool Prop0 { get; set; } + public byte Prop1 { get; set; } + public sbyte Prop2 { get; set; } + public char Prop3 { get; set; } + public double Prop4 { get; set; } + public string Prop5 { get; set; } + public int Prop6 { get; set; } + public short Prop8 { get; set; } + public long Prop9 { get; set; } + public float Prop10 { get; set; } + public ushort Prop13 { get; set; } + public uint Prop14 { get; set; } + public ulong Prop15 { get; set; } + public object Prop16 { get; set; } + public CultureInfo Prop17 { get; set; } + public DateTime Prop19 { get; set; } + public DateTimeOffset Prop20 { get; set; } + public decimal Prop21 { get; set; } + public TimeSpan Prop23 { get; set; } + public Guid Prop24 { get; set; } + public Uri Prop25 { get; set; } + public Version Prop26 { get; set; } + public DayOfWeek Prop27 { get; set; } +#if NETCOREAPP + public Int128 Prop7 { get; set; } + public Half Prop11 { get; set; } + public UInt128 Prop12 { get; set; } + public DateOnly Prop18 { get; set; } + public TimeOnly Prop22 { get; set; } +#endif + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs index 89af4c37e21b60..abd3af76290229 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/Common/ConfigurationBinderTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Globalization; using System.Linq; using System.Reflection; using Microsoft.Extensions.Configuration; @@ -424,7 +425,7 @@ public void ConsistentExceptionOnFailedBinding(Type type) getValueException.Message); } - [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Ensure exception messages are in sync + [Fact] public void ExceptionOnFailedBindingIncludesPath() { const string IncorrectValue = "Invalid data"; @@ -1274,7 +1275,7 @@ public void CanBindByteArrayWhenValueIsNull() Assert.Null(options.MyByteArray); } - [ConditionalFact(typeof(TestHelpers), nameof(TestHelpers.NotSourceGenMode))] // Ensure exception messages are in sync + [Fact] public void ExceptionWhenTryingToBindToByteArray() { var dic = new Dictionary @@ -1463,12 +1464,6 @@ public void RecursiveTypeGraphs_DirectRef() Assert.Null(deeplyNested.MyClass); } - public class ClassWithDirectSelfReference - { - public string MyString { get; set; } - public ClassWithDirectSelfReference MyClass { get; set; } - } - [Fact] public void RecursiveTypeGraphs_IndirectRef() { @@ -1498,10 +1493,82 @@ public void RecursiveTypeGraphs_IndirectRef() Assert.Null(deeplyNested.MyList); } - public class ClassWithIndirectSelfReference + [Fact] + public void TypeWithPrimitives_Pass() { - public string MyString { get; set; } - public List MyList { get; set; } + var data = @"{ + ""Prop0"": true, + ""Prop1"": 1, + ""Prop2"": 2, + ""Prop3"": ""C"", + ""Prop4"": 3.2, + ""Prop5"": ""Hello, world!"", + ""Prop6"": 4, + ""Prop8"": 9, + ""Prop9"": 7, + ""Prop10"": 2.3, + ""Prop13"": 5, + ""Prop14"": 10, + ""Prop15"": 11, + ""Prop16"": ""obj always parsed as string"", + ""Prop17"": ""yo-NG"", + ""Prop19"": ""2023-03-29T18:23:43.9977489+00:00"", + ""Prop20"": ""2023-03-29T18:21:22.8046981+00:00"", + ""Prop21"": 5.3, + ""Prop23"": ""10675199.02:48:05.4775807"", + ""Prop24"": ""e905a75b-d195-494d-8938-e55dcee44574"", + ""Prop25"": ""https://microsoft.com"", + ""Prop26"": ""4.3.2.1"", + }"; + + var configuration = TestHelpers.GetConfigurationFromJsonString(data); + var obj = configuration.Get(); + + Assert.True(obj.Prop0); + Assert.Equal(1, obj.Prop1); + Assert.Equal(2, obj.Prop2); + Assert.Equal('C', obj.Prop3); + Assert.Equal(3.2, obj.Prop4); + Assert.Equal("Hello, world!", obj.Prop5); + Assert.Equal(4, obj.Prop6); + Assert.Equal(9, obj.Prop8); + Assert.Equal(7, obj.Prop9); + Assert.Equal((float)2.3, obj.Prop10); + Assert.Equal(5, obj.Prop13); + Assert.Equal((uint)10, obj.Prop14); + Assert.Equal((ulong)11, obj.Prop15); + Assert.Equal("obj always parsed as string", obj.Prop16); + Assert.Equal(CultureInfo.GetCultureInfoByIetfLanguageTag("yo-NG"), obj.Prop17); + Assert.Equal(DateTime.Parse("2023-03-29T18:23:43.9977489+00:00", CultureInfo.InvariantCulture), obj.Prop19); + Assert.Equal(DateTimeOffset.Parse("2023-03-29T18:21:22.8046981+00:00", CultureInfo.InvariantCulture), obj.Prop20); + Assert.Equal((decimal)5.3, obj.Prop21); + Assert.Equal(TimeSpan.Parse("10675199.02:48:05.4775807", CultureInfo.InvariantCulture), obj.Prop23); + Assert.Equal(Guid.Parse("e905a75b-d195-494d-8938-e55dcee44574"), obj.Prop24); + Uri.TryCreate("https://microsoft.com", UriKind.RelativeOrAbsolute, out Uri? value); + Assert.Equal(value, obj.Prop25); +#if BUILDING_SOURCE_GENERATOR_TESTS + Assert.Equal(Version.Parse("4.3.2.1"), obj.Prop26); +#endif + Assert.Equal(CultureInfo.GetCultureInfo("yo-NG"), obj.Prop17); + +#if NETCOREAPP + data = @"{ + ""Prop7"": 9, + ""Prop11"": 65500, + ""Prop12"": 34, + ""Prop18"": ""2002-03-22"", + ""Prop22"": ""18:26:38.7327436"", + }"; + + configuration = TestHelpers.GetConfigurationFromJsonString(data); + configuration.Bind(obj); + + Assert.Equal((Int128)9, obj.Prop7); + Assert.Equal((Half)65500, obj.Prop11); + Assert.Equal((UInt128)34, obj.Prop12); + Assert.Equal(DateOnly.Parse("2002-03-22"), obj.Prop18); + Assert.Equal(TimeOnly.Parse("18:26:38.7327436"), obj.Prop22); +#endif } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt index 30c909d2d5e9dd..8f615985702f29 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestBindCallGen.generated.txt @@ -9,7 +9,7 @@ internal static class GeneratedConfigurationBinder namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using System; - using System.Linq; + using System.Globalization; using Microsoft.Extensions.Configuration; using System.Collections.Generic; @@ -22,13 +22,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - int element; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Value is string stringValue0) + if (HasValueOrChildren(section)) { - element = int.Parse(stringValue0); - obj.Add(element); + int element; + if (section.Value is string stringValue0) + { + element = ParseInt(stringValue0, () => section.Path); + obj.Add(element); + } } } } @@ -40,17 +43,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - string key; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Key is string stringValue1) + if (HasValueOrChildren(section)) { - key = stringValue1; - string element; - if (section.Value is string stringValue2) + string key = section.Key; + if (section.Value is string stringValue1) { - element = stringValue2; - obj[key] = element; + obj[key] = stringValue1; } } } @@ -67,23 +67,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - string key; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Key is string stringValue3) + if (HasValueOrChildren(section)) { - key = stringValue3; - if (obj.TryGetValue(key, out Program.MyClass2? element) && element is not null) - { - BindCore(section, ref element); - obj[key] = element; - } - else + string key = section.Key; + if (!(obj.TryGetValue(key, out Program.MyClass2? element) && element is not null)) { element = new Program.MyClass2(); - BindCore(section, ref element); - obj[key] = element; } + BindCore(section, ref element!); + obj[key] = element; } } } @@ -95,41 +89,41 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - if (configuration["MyString"] is string stringValue6) + if (configuration["MyString"] is string stringValue3) { - obj.MyString = stringValue6; + obj.MyString = stringValue3; } - if (configuration["MyInt"] is string stringValue7) + if (configuration["MyInt"] is string stringValue4) { - obj.MyInt = int.Parse(stringValue7); + obj.MyInt = ParseInt(stringValue4, () => configuration.GetSection("MyInt").Path); } - IConfigurationSection section8 = configuration.GetSection("MyList"); - if (HasChildren(section8)) + IConfigurationSection section5 = configuration.GetSection("MyList"); + if (HasChildren(section5)) { - List temp9 = obj.MyList; - temp9 ??= new List(); - BindCore(section8, ref temp9); - obj.MyList = temp9; + List temp6 = obj.MyList; + temp6 ??= new List(); + BindCore(section5, ref temp6); + obj.MyList = temp6; } - IConfigurationSection section10 = configuration.GetSection("MyDictionary"); - if (HasChildren(section10)) + IConfigurationSection section7 = configuration.GetSection("MyDictionary"); + if (HasChildren(section7)) { - Dictionary temp11 = obj.MyDictionary; - temp11 ??= new Dictionary(); - BindCore(section10, ref temp11); - obj.MyDictionary = temp11; + Dictionary temp8 = obj.MyDictionary; + temp8 ??= new Dictionary(); + BindCore(section7, ref temp8); + obj.MyDictionary = temp8; } - IConfigurationSection section12 = configuration.GetSection("MyComplexDictionary"); - if (HasChildren(section12)) + IConfigurationSection section9 = configuration.GetSection("MyComplexDictionary"); + if (HasChildren(section9)) { - Dictionary temp13 = obj.MyComplexDictionary; - temp13 ??= new Dictionary(); - BindCore(section12, ref temp13); - obj.MyComplexDictionary = temp13; + Dictionary temp10 = obj.MyComplexDictionary; + temp10 ??= new Dictionary(); + BindCore(section9, ref temp10); + obj.MyComplexDictionary = temp10; } } @@ -141,5 +135,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } return false; } + + public static int ParseInt(string stringValue, Func getPath) + { + try + { + return int.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt index 6f19224ea7b84d..735f5247fedd7d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestConfigureCallGen.generated.txt @@ -30,7 +30,7 @@ internal static class GeneratedConfigurationBinder namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using System; - using System.Linq; + using System.Globalization; using Microsoft.Extensions.Configuration; using System.Collections.Generic; @@ -43,13 +43,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - int element; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Value is string stringValue1) + if (HasValueOrChildren(section)) { - element = int.Parse(stringValue1); - obj.Add(element); + int element; + if (section.Value is string stringValue1) + { + element = ParseInt(stringValue1, () => section.Path); + obj.Add(element); + } } } } @@ -61,17 +64,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - string key; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Key is string stringValue2) + if (HasValueOrChildren(section)) { - key = stringValue2; - string element; - if (section.Value is string stringValue3) + string key = section.Key; + if (section.Value is string stringValue2) { - element = stringValue3; - obj[key] = element; + obj[key] = stringValue2; } } } @@ -84,32 +84,32 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - if (configuration["MyString"] is string stringValue4) + if (configuration["MyString"] is string stringValue3) { - obj.MyString = stringValue4; + obj.MyString = stringValue3; } - if (configuration["MyInt"] is string stringValue5) + if (configuration["MyInt"] is string stringValue4) { - obj.MyInt = int.Parse(stringValue5); + obj.MyInt = ParseInt(stringValue4, () => configuration.GetSection("MyInt").Path); } - IConfigurationSection section6 = configuration.GetSection("MyList"); - if (HasChildren(section6)) + IConfigurationSection section5 = configuration.GetSection("MyList"); + if (HasChildren(section5)) { - List temp7 = obj.MyList; - temp7 ??= new List(); - BindCore(section6, ref temp7); - obj.MyList = temp7; + List temp6 = obj.MyList; + temp6 ??= new List(); + BindCore(section5, ref temp6); + obj.MyList = temp6; } - IConfigurationSection section8 = configuration.GetSection("MyDictionary"); - if (HasChildren(section8)) + IConfigurationSection section7 = configuration.GetSection("MyDictionary"); + if (HasChildren(section7)) { - Dictionary temp9 = obj.MyDictionary; - temp9 ??= new Dictionary(); - BindCore(section8, ref temp9); - obj.MyDictionary = temp9; + Dictionary temp8 = obj.MyDictionary; + temp8 ??= new Dictionary(); + BindCore(section7, ref temp8); + obj.MyDictionary = temp8; } } @@ -130,5 +130,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } return false; } + + public static int ParseInt(string stringValue, Func getPath) + { + try + { + return int.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt index 32e497efd4df1d..bdb48ea091890d 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestGetCallGen.generated.txt @@ -29,7 +29,7 @@ internal static class GeneratedConfigurationBinder namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration { using System; - using System.Linq; + using System.Globalization; using Microsoft.Extensions.Configuration; using System.Collections.Generic; @@ -42,13 +42,16 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - int element; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Value is string stringValue1) + if (HasValueOrChildren(section)) { - element = int.Parse(stringValue1); - obj.Add(element); + int element; + if (section.Value is string stringValue1) + { + element = ParseInt(stringValue1, () => section.Path); + obj.Add(element); + } } } } @@ -60,17 +63,14 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - string key; foreach (IConfigurationSection section in configuration.GetChildren()) { - if (section.Key is string stringValue2) + if (HasValueOrChildren(section)) { - key = stringValue2; - string element; - if (section.Value is string stringValue3) + string key = section.Key; + if (section.Value is string stringValue2) { - element = stringValue3; - obj[key] = element; + obj[key] = stringValue2; } } } @@ -83,32 +83,32 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration throw new ArgumentNullException(nameof(obj)); } - if (configuration["MyString"] is string stringValue4) + if (configuration["MyString"] is string stringValue3) { - obj.MyString = stringValue4; + obj.MyString = stringValue3; } - if (configuration["MyInt"] is string stringValue5) + if (configuration["MyInt"] is string stringValue4) { - obj.MyInt = int.Parse(stringValue5); + obj.MyInt = ParseInt(stringValue4, () => configuration.GetSection("MyInt").Path); } - IConfigurationSection section6 = configuration.GetSection("MyList"); - if (HasChildren(section6)) + IConfigurationSection section5 = configuration.GetSection("MyList"); + if (HasChildren(section5)) { - List temp7 = obj.MyList; - temp7 ??= new List(); - BindCore(section6, ref temp7); - obj.MyList = temp7; + List temp6 = obj.MyList; + temp6 ??= new List(); + BindCore(section5, ref temp6); + obj.MyList = temp6; } - IConfigurationSection section8 = configuration.GetSection("MyDictionary"); - if (HasChildren(section8)) + IConfigurationSection section7 = configuration.GetSection("MyDictionary"); + if (HasChildren(section7)) { - Dictionary temp9 = obj.MyDictionary; - temp9 ??= new Dictionary(); - BindCore(section8, ref temp9); - obj.MyDictionary = temp9; + Dictionary temp8 = obj.MyDictionary; + temp8 ??= new Dictionary(); + BindCore(section7, ref temp8); + obj.MyDictionary = temp8; } } @@ -129,5 +129,17 @@ namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration } return false; } + + public static int ParseInt(string stringValue, Func getPath) + { + try + { + return int.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestPrimitivesGen.generated.txt b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestPrimitivesGen.generated.txt new file mode 100644 index 00000000000000..152b551d7c96ca --- /dev/null +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/Baselines/TestPrimitivesGen.generated.txt @@ -0,0 +1,505 @@ +// +#nullable enable + +internal static class GeneratedConfigurationBinder +{ + public static void Bind(this global::Microsoft.Extensions.Configuration.IConfiguration configuration, global::Program.MyClass obj) => global::Microsoft.Extensions.Configuration.Binder.SourceGeneration.Helpers.BindCore(configuration, ref obj); +} + +namespace Microsoft.Extensions.Configuration.Binder.SourceGeneration +{ + using System; + using System.Globalization; + using Microsoft.Extensions.Configuration; + + internal static class Helpers + { + public static void BindCore(IConfiguration configuration, ref Program.MyClass obj) + { + if (obj is null) + { + throw new ArgumentNullException(nameof(obj)); + } + + if (configuration["Prop0"] is string stringValue0) + { + obj.Prop0 = ParseBool(stringValue0, () => configuration.GetSection("Prop0").Path); + } + + if (configuration["Prop1"] is string stringValue1) + { + obj.Prop1 = ParseByte(stringValue1, () => configuration.GetSection("Prop1").Path); + } + + if (configuration["Prop2"] is string stringValue2) + { + obj.Prop2 = ParseSbyte(stringValue2, () => configuration.GetSection("Prop2").Path); + } + + if (configuration["Prop3"] is string stringValue3) + { + obj.Prop3 = ParseChar(stringValue3, () => configuration.GetSection("Prop3").Path); + } + + if (configuration["Prop4"] is string stringValue4) + { + obj.Prop4 = ParseDouble(stringValue4, () => configuration.GetSection("Prop4").Path); + } + + if (configuration["Prop5"] is string stringValue5) + { + obj.Prop5 = stringValue5; + } + + if (configuration["Prop6"] is string stringValue6) + { + obj.Prop6 = ParseInt(stringValue6, () => configuration.GetSection("Prop6").Path); + } + + if (configuration["Prop8"] is string stringValue7) + { + obj.Prop8 = ParseShort(stringValue7, () => configuration.GetSection("Prop8").Path); + } + + if (configuration["Prop9"] is string stringValue8) + { + obj.Prop9 = ParseLong(stringValue8, () => configuration.GetSection("Prop9").Path); + } + + if (configuration["Prop10"] is string stringValue9) + { + obj.Prop10 = ParseFloat(stringValue9, () => configuration.GetSection("Prop10").Path); + } + + if (configuration["Prop13"] is string stringValue10) + { + obj.Prop13 = ParseUshort(stringValue10, () => configuration.GetSection("Prop13").Path); + } + + if (configuration["Prop14"] is string stringValue11) + { + obj.Prop14 = ParseUint(stringValue11, () => configuration.GetSection("Prop14").Path); + } + + if (configuration["Prop15"] is string stringValue12) + { + obj.Prop15 = ParseUlong(stringValue12, () => configuration.GetSection("Prop15").Path); + } + + if (configuration["Prop16"] is string stringValue13) + { + obj.Prop16 = stringValue13; + } + + if (configuration["Prop17"] is string stringValue14) + { + obj.Prop17 = ParseCultureInfo(stringValue14, () => configuration.GetSection("Prop17").Path); + } + + if (configuration["Prop19"] is string stringValue15) + { + obj.Prop19 = ParseDateTime(stringValue15, () => configuration.GetSection("Prop19").Path); + } + + if (configuration["Prop20"] is string stringValue16) + { + obj.Prop20 = ParseDateTimeOffset(stringValue16, () => configuration.GetSection("Prop20").Path); + } + + if (configuration["Prop21"] is string stringValue17) + { + obj.Prop21 = ParseDecimal(stringValue17, () => configuration.GetSection("Prop21").Path); + } + + if (configuration["Prop23"] is string stringValue18) + { + obj.Prop23 = ParseTimeSpan(stringValue18, () => configuration.GetSection("Prop23").Path); + } + + if (configuration["Prop24"] is string stringValue19) + { + obj.Prop24 = ParseGuid(stringValue19, () => configuration.GetSection("Prop24").Path); + } + + if (configuration["Prop25"] is string stringValue20) + { + obj.Prop25 = ParseUri(stringValue20, () => configuration.GetSection("Prop25").Path); + } + + if (configuration["Prop26"] is string stringValue21) + { + obj.Prop26 = ParseVersion(stringValue21, () => configuration.GetSection("Prop26").Path); + } + + if (configuration["Prop27"] is string stringValue22) + { + obj.Prop27 = ParseDayOfWeek(stringValue22, () => configuration.GetSection("Prop27").Path); + } + + if (configuration["Prop7"] is string stringValue23) + { + obj.Prop7 = ParseInt128(stringValue23, () => configuration.GetSection("Prop7").Path); + } + + if (configuration["Prop11"] is string stringValue24) + { + obj.Prop11 = ParseHalf(stringValue24, () => configuration.GetSection("Prop11").Path); + } + + if (configuration["Prop12"] is string stringValue25) + { + obj.Prop12 = ParseUInt128(stringValue25, () => configuration.GetSection("Prop12").Path); + } + + if (configuration["Prop18"] is string stringValue26) + { + obj.Prop18 = ParseDateOnly(stringValue26, () => configuration.GetSection("Prop18").Path); + } + + if (configuration["Prop22"] is string stringValue27) + { + obj.Prop22 = ParseTimeOnly(stringValue27, () => configuration.GetSection("Prop22").Path); + } + + if (configuration["Prop22"] is string stringValue28) + { + obj.Prop22 = ParseByteArray(stringValue28, () => configuration.GetSection("Prop22").Path); + } + + if (configuration["Prop23"] is string stringValue29) + { + obj.Prop23 = ParseInt(stringValue29, () => configuration.GetSection("Prop23").Path); + } + + if (configuration["Prop24"] is string stringValue30) + { + obj.Prop24 = ParseDateTime(stringValue30, () => configuration.GetSection("Prop24").Path); + } + } + + + public static bool ParseBool(string stringValue, Func getPath) + { + try + { + return bool.Parse(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(bool)}'.", exception); + } + } + + public static byte ParseByte(string stringValue, Func getPath) + { + try + { + return byte.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte)}'.", exception); + } + } + + public static sbyte ParseSbyte(string stringValue, Func getPath) + { + try + { + return sbyte.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(sbyte)}'.", exception); + } + } + + public static char ParseChar(string stringValue, Func getPath) + { + try + { + return char.Parse(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(char)}'.", exception); + } + } + + public static double ParseDouble(string stringValue, Func getPath) + { + try + { + return double.Parse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(double)}'.", exception); + } + } + + public static int ParseInt(string stringValue, Func getPath) + { + try + { + return int.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(int)}'.", exception); + } + } + + public static short ParseShort(string stringValue, Func getPath) + { + try + { + return short.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(short)}'.", exception); + } + } + + public static long ParseLong(string stringValue, Func getPath) + { + try + { + return long.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(long)}'.", exception); + } + } + + public static float ParseFloat(string stringValue, Func getPath) + { + try + { + return float.Parse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(float)}'.", exception); + } + } + + public static ushort ParseUshort(string stringValue, Func getPath) + { + try + { + return ushort.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(ushort)}'.", exception); + } + } + + public static uint ParseUint(string stringValue, Func getPath) + { + try + { + return uint.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(uint)}'.", exception); + } + } + + public static ulong ParseUlong(string stringValue, Func getPath) + { + try + { + return ulong.Parse(stringValue, NumberStyles.Integer, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(ulong)}'.", exception); + } + } + + public static CultureInfo ParseCultureInfo(string stringValue, Func getPath) + { + try + { + return CultureInfo.GetCultureInfo(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(CultureInfo)}'.", exception); + } + } + + public static DateTime ParseDateTime(string stringValue, Func getPath) + { + try + { + return DateTime.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateTime)}'.", exception); + } + } + + public static DateTimeOffset ParseDateTimeOffset(string stringValue, Func getPath) + { + try + { + return DateTimeOffset.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateTimeOffset)}'.", exception); + } + } + + public static decimal ParseDecimal(string stringValue, Func getPath) + { + try + { + return decimal.Parse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(decimal)}'.", exception); + } + } + + public static TimeSpan ParseTimeSpan(string stringValue, Func getPath) + { + try + { + return TimeSpan.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(TimeSpan)}'.", exception); + } + } + + public static Guid ParseGuid(string stringValue, Func getPath) + { + try + { + return Guid.Parse(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Guid)}'.", exception); + } + } + + public static Uri ParseUri(string stringValue, Func getPath) + { + try + { + return new Uri(stringValue, UriKind.RelativeOrAbsolute); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Uri)}'.", exception); + } + } + + public static Version ParseVersion(string stringValue, Func getPath) + { + try + { + return Version.Parse(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Version)}'.", exception); + } + } + + public static DayOfWeek ParseDayOfWeek(string stringValue, Func getPath) + { + try + { + return (DayOfWeek)Enum.Parse(typeof(DayOfWeek), stringValue, ignoreCase: true); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DayOfWeek)}'.", exception); + } + } + + public static Int128 ParseInt128(string stringValue, Func getPath) + { + try + { + return Int128.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Int128)}'.", exception); + } + } + + public static Half ParseHalf(string stringValue, Func getPath) + { + try + { + return Half.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(Half)}'.", exception); + } + } + + public static UInt128 ParseUInt128(string stringValue, Func getPath) + { + try + { + return UInt128.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(UInt128)}'.", exception); + } + } + + public static DateOnly ParseDateOnly(string stringValue, Func getPath) + { + try + { + return DateOnly.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(DateOnly)}'.", exception); + } + } + + public static TimeOnly ParseTimeOnly(string stringValue, Func getPath) + { + try + { + return TimeOnly.Parse(stringValue, CultureInfo.InvariantCulture); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(TimeOnly)}'.", exception); + } + } + + public static byte[] ParseByteArray(string stringValue, Func getPath) + { + try + { + return Convert.FromBase64String(stringValue); + } + catch (Exception exception) + { + throw new InvalidOperationException($"Failed to convert configuration value at '{getPath()}' to type '{typeof(byte[])}'.", exception); + } + } + } +} diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfingurationBindingSourceGeneratorTests.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfingurationBindingSourceGeneratorTests.cs index c0832f30107279..5120cfa062dc69 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfingurationBindingSourceGeneratorTests.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/tests/SourceGenerationTests/ConfingurationBindingSourceGeneratorTests.cs @@ -114,6 +114,65 @@ public class MyClass await VerifyAgainstBaselineUsingFile("TestConfigureCallGen.generated.txt", testSourceCode); } + [Fact] + public async Task TestBaseline_TestPrimitivesGen() + { + string testSourceCode = """ + using System; + using System.Globalization; + using Microsoft.Extensions.Configuration; + + public class Program + { + public static void Main() + { + ConfigurationBuilder configurationBuilder = new(); + IConfigurationRoot config = configurationBuilder.Build(); + + MyClass obj = new(); + config.Bind(obj); + } + + public class MyClass + { + public bool Prop0 { get; set; } + public byte Prop1 { get; set; } + public sbyte Prop2 { get; set; } + public char Prop3 { get; set; } + public double Prop4 { get; set; } + public string Prop5 { get; set; } + public int Prop6 { get; set; } + public short Prop8 { get; set; } + public long Prop9 { get; set; } + public float Prop10 { get; set; } + public ushort Prop13 { get; set; } + public uint Prop14 { get; set; } + public ulong Prop15 { get; set; } + public object Prop16 { get; set; } + public CultureInfo Prop17 { get; set; } + public DateTime Prop19 { get; set; } + public DateTimeOffset Prop20 { get; set; } + public decimal Prop21 { get; set; } + public TimeSpan Prop23 { get; set; } + public Guid Prop24 { get; set; } + public Uri Prop25 { get; set; } + public Version Prop26 { get; set; } + public DayOfWeek Prop27 { get; set; } + public Int128 Prop7 { get; set; } + public Half Prop11 { get; set; } + public UInt128 Prop12 { get; set; } + public DateOnly Prop18 { get; set; } + public TimeOnly Prop22 { get; set; } + public byte[] Prop22 { get; set; } + public int Prop23 { get; set; } + public DateTime Prop24 { get; set; } + } + } + """; + + await VerifyAgainstBaselineUsingFile("TestPrimitivesGen.generated.txt", testSourceCode); + } + [Fact] public async Task LangVersionMustBeCharp11OrHigher() { @@ -151,11 +210,13 @@ await RoslynTestUtils.RunGenerator( new ConfigurationBindingSourceGenerator(), new[] { typeof(ConfigurationBinder).Assembly, + typeof(CultureInfo).Assembly, typeof(IConfiguration).Assembly, typeof(IServiceCollection).Assembly, typeof(IDictionary).Assembly, typeof(ServiceCollection).Assembly, typeof(OptionsConfigurationServiceCollectionExtensions).Assembly, + typeof(Uri).Assembly, }, new[] { testSourceCode }, langVersion: langVersion).ConfigureAwait(false); From 063adfe9f2925c5c6c74e5d30d04a7d5a085e144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Fi=C5=A1era?= Date: Wed, 12 Apr 2023 17:38:52 +0200 Subject: [PATCH 07/21] [browser] Wasm SDK packed as a nuget package (#84082) --- .../Sdk/Sdk.props | 2 +- .../Sdk/Sdk.targets.in | 2 +- ...Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj | 14 + ...icrosoft.NET.Sdk.WebAssembly.Browser.props | 43 ++ ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 493 ++++++++++++++ .../Microsoft.NET.Sdk.WebAssembly.Pack.props | 20 + ...Microsoft.NET.Sdk.WebAssembly.Pack.targets | 12 + .../build/Wasm.web.config | 44 ++ .../WorkloadManifest.targets.in | 6 +- src/mono/nuget/mono-packages.proj | 1 + .../AssetsComputingHelper.cs | 86 +++ .../BootJsonData.cs | 157 +++++ .../ComputeWasmBuildAssets.cs | 266 ++++++++ .../ComputeWasmPublishAssets.cs | 628 ++++++++++++++++++ .../FileHasher.cs | 35 + .../GenerateWasmBootJson.cs | 341 ++++++++++ ...soft.NET.Sdk.WebAssembly.Pack.Tasks.csproj | 32 + 17 files changed, 2178 insertions(+), 4 deletions(-) create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets create mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs create mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj diff --git a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props index 2890daaf708283..dae0b088f16071 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props +++ b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props @@ -1,5 +1,5 @@ - + wasm browser true diff --git a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in index 0f9edfb14f10d3..60d993f9c1a531 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in +++ b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in @@ -9,7 +9,7 @@ $([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', 'WasmAppHost')) - true + true diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj new file mode 100644 index 00000000000000..32b0ded6b35fd7 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj @@ -0,0 +1,14 @@ + + + + + SDK for building and publishing WebAssembly applications. + + + + + + + + + diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props new file mode 100644 index 00000000000000..dc074e761f24e1 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props @@ -0,0 +1,43 @@ + + + + + false + + exe + + false + + false + + + false + + + true + partial + false + + + / + Root + $(StaticWebAssetsAdditionalBuildPropertiesToRemove);RuntimeIdentifier;SelfContained + ComputeFilesToPublish;GetCurrentProjectPublishStaticWebAssetItems + $(StaticWebAssetsAdditionalPublishProperties);BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true + $(StaticWebAssetsAdditionalPublishPropertiesToRemove);NoBuild;RuntimeIdentifier + + + + + + diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets new file mode 100644 index 00000000000000..3fe69f51c2e0ed --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -0,0 +1,493 @@ + + + + + true + + + true + + + + + + + $(MSBuildThisFileDirectory)..\ + <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net8.0 + <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472 + <_WebAssemblySdkTasksAssembly>$(WebAssemblySdkDirectoryRoot)tools\$(_WebAssemblySdkTasksTFM)\Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.dll + + + + + + + + true + true + + + false + false + true + false + false + false + <_AggressiveAttributeTrimming Condition="'$(_AggressiveAttributeTrimming)' == ''">true + false + true + false + + + false + false + false + false + true + + + + false + + false + _GatherWasmFilesToPublish;$(WasmNestedPublishAppDependsOn) + <_WasmNestedPublishAppPreTarget>ComputeFilesToPublish + + + + + + + + + + + + $(ResolveStaticWebAssetsInputsDependsOn); + _AddWasmStaticWebAssets; + + + + _GenerateBuildWasmBootJson; + $(StaticWebAssetsPrepareForRunDependsOn) + + + + $(ResolvePublishStaticWebAssetsDependsOn); + ProcessPublishFilesForWasm; + ComputeWasmExtensions; + _AddPublishWasmBootJsonToStaticWebAssets; + + + + $(GenerateStaticWebAssetsPublishManifestDependsOn); + GeneratePublishWasmBootJson; + + + + $(AddWasmStaticWebAssetsDependsOn); + ResolveWasmOutputs; + + + $(GenerateBuildWasmBootJsonDependsOn); + ResolveStaticWebAssetsInputs; + + + $(GeneratePublishWasmBootJsonDependsOn); + + + + + + + + + + + + + + + + + + + + <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(InvariantGlobalization)' != 'true'">$(BlazorWebAssemblyLoadAllGlobalizationData) + <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(_BlazorWebAssemblyLoadAllGlobalizationData)' == ''">false + <_BlazorIcuDataFileName Condition="'$(InvariantGlobalization)' != 'true' AND '$(BlazorWebAssemblyLoadAllGlobalizationData)' != 'true'">$(BlazorIcuDataFileName) + <_LoadCustomIcuData>false + <_LoadCustomIcuData Condition="'$(_BlazorIcuDataFileName)' != ''">true + + + + + + <_BlazorEnableTimeZoneSupport>$(BlazorEnableTimeZoneSupport) + <_BlazorEnableTimeZoneSupport Condition="'$(_BlazorEnableTimeZoneSupport)' == ''">true + <_WasmInvariantGlobalization>$(InvariantGlobalization) + <_WasmInvariantGlobalization Condition="'$(_WasmInvariantGlobalization)' == ''">true + <_WasmCopyOutputSymbolsToOutputDirectory>$(CopyOutputSymbolsToOutputDirectory) + <_WasmCopyOutputSymbolsToOutputDirectory Condition="'$(_WasmCopyOutputSymbolsToOutputDirectory)'==''">true + <_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache) + <_BlazorWebAssemblyJiterpreter>$(BlazorWebAssemblyJiterpreter) + <_BlazorWebAssemblyRuntimeOptions>$(BlazorWebAssemblyRuntimeOptions) + + + $(OutputPath)$(PublishDirName)\ + + + + + + + + <_WasmConfigFileCandidates Include="@(StaticWebAsset)" Condition="'%(SourceType)' == 'Discovered'" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_WasmBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json + + + + <_BuildWasmBootJson + Include="$(_WasmBuildBootJsonPath)" + RelativePath="_framework/blazor.boot.json" /> + + + + + + + + + + + + + + + + + <_WasmBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json + + + + <_WasmJsModuleCandidatesForBuild + Include="@(StaticWebAsset)" + Condition="'%(StaticWebAsset.AssetTraitName)' == 'JSModule' and '%(StaticWebAsset.AssetTraitValue)' == 'JSLibraryModule' and '%(AssetKind)' != 'Publish'" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_WasmPublishPrefilteredAssets + Include="@(StaticWebAsset)" + Condition="'%(StaticWebAsset.AssetTraitName)' == 'WasmResource' or '%(StaticWebAsset.AssetTraitName)' == 'Culture' or '%(AssetRole)' == 'Alternative'" /> + + + + <_DotNetJsItem Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.DestinationSubPath)' == 'dotnet.js' AND '%(ResolvedFileToPublish.AssetType)' == 'native'" /> + + + + <_DotNetJsVersion>%(_DotNetJsItem.NuGetPackageVersion) + + + + + + + + + + + + + + + + + + + <_BlazorExtensionsCandidate Include="@(BlazorPublishExtension->'%(FullPath)')"> + $(PackageId) + Computed + $(PublishDir)wwwroot + $(StaticWebAssetBasePath) + %(BlazorPublishExtension.RelativePath) + Publish + All + Primary + WasmResource + extension:%(BlazorPublishExtension.ExtensionName) + Never + PreserveNewest + %(BlazorPublishExtension.Identity) + + + + + + + + + + + + + + + + + + <_PublishWasmBootJson + Include="$(IntermediateOutputPath)blazor.publish.boot.json" + RelativePath="_framework/blazor.boot.json" /> + + + + + + + + + + + <_WasmPublishAsset + Include="@(StaticWebAsset)" + Condition="'%(AssetKind)' != 'Build' and '%(StaticWebAsset.AssetTraitValue)' != 'manifest' and ('%(StaticWebAsset.AssetTraitName)' == 'WasmResource' or '%(StaticWebAsset.AssetTraitName)' == 'Culture') and '%(StaticWebAsset.AssetTraitValue)' != 'boot'" /> + + <_WasmPublishConfigFile + Include="@(StaticWebAsset)" + Condition="'%(StaticWebAsset.AssetTraitName)' == 'WasmResource' and '%(StaticWebAsset.AssetTraitValue)' == 'settings'"/> + + <_WasmJsModuleCandidatesForPublish + Include="@(StaticWebAsset)" + Condition="'%(StaticWebAsset.AssetTraitName)' == 'JSModule' and '%(StaticWebAsset.AssetTraitValue)' == 'JSLibraryModule' and '%(AssetKind)' != 'Build'" /> + + + <_WasmPublishAsset Remove="@(_BlazorExtensionsCandidatesForPublish)" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props new file mode 100644 index 00000000000000..a41609b5c15a65 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props @@ -0,0 +1,20 @@ + + + + browser-wasm + + + <_WebAssemblyPropsFile>$(MSBuildThisFileDirectory)\Microsoft.NET.Sdk.WebAssembly.Browser.props + <_WebAssemblyTargetsFile>$(MSBuildThisFileDirectory)\Microsoft.NET.Sdk.WebAssembly.Browser.targets + + diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets new file mode 100644 index 00000000000000..df15f880ba1b39 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets @@ -0,0 +1,12 @@ + + diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config new file mode 100644 index 00000000000000..586d3565ed1eb4 --- /dev/null +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in index c9a2c7494450fd..b42b351e97ac2f 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in @@ -20,6 +20,8 @@ <_BrowserWorkloadNotSupportedForTFM Condition="$([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '6.0'))">true <_BrowserWorkloadDisabled>$(_BrowserWorkloadNotSupportedForTFM) + <_UsingBlazorOrWasmSdk Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' or '$(UsingMicrosoftNETSdkWebAssembly)' == 'true'">true + @@ -39,7 +41,7 @@ <_WasmNativeWorkloadNeeded Condition="'$(RunAOTCompilation)' == 'true' or '$(WasmEnableSIMD)' == 'true' or '$(WasmBuildNative)' == 'true' or - '$(WasmGenerateAppBundle)' == 'true' or '$(UsingMicrosoftNETSdkBlazorWebAssembly)' != 'true'" >true + '$(WasmGenerateAppBundle)' == 'true' or '$(_UsingBlazorOrWasmSdk)' != 'true'" >true false true @@ -59,7 +61,7 @@ true - + false true diff --git a/src/mono/nuget/mono-packages.proj b/src/mono/nuget/mono-packages.proj index 6a2ddff782b75e..438ec97ace3e1a 100644 --- a/src/mono/nuget/mono-packages.proj +++ b/src/mono/nuget/mono-packages.proj @@ -8,6 +8,7 @@ + diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs new file mode 100644 index 00000000000000..2854594ae10547 --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Microsoft.NET.Sdk.WebAssembly; + +public class AssetsComputingHelper +{ + public static bool ShouldFilterCandidate( + ITaskItem candidate, + bool timezoneSupport, + bool invariantGlobalization, + bool copySymbols, + string customIcuCandidateFilename, + out string reason) + { + var extension = candidate.GetMetadata("Extension"); + var fileName = candidate.GetMetadata("FileName"); + var assetType = candidate.GetMetadata("AssetType"); + var fromMonoPackage = string.Equals( + candidate.GetMetadata("NuGetPackageId"), + "Microsoft.NETCore.App.Runtime.Mono.browser-wasm", + StringComparison.Ordinal); + + reason = extension switch + { + ".a" when fromMonoPackage => "extension is .a is not supported.", + ".c" when fromMonoPackage => "extension is .c is not supported.", + ".h" when fromMonoPackage => "extension is .h is not supported.", + // It is safe to filter out all XML files since we are not interested in any XML file from the list + // of ResolvedFilesToPublish to become a static web asset. Things like this include XML doc files and + // so on. + ".xml" => "it is a documentation file", + ".rsp" when fromMonoPackage => "extension is .rsp is not supported.", + ".props" when fromMonoPackage => "extension is .props is not supported.", + ".blat" when !timezoneSupport => "timezone support is not enabled.", + ".dat" when invariantGlobalization && fileName.StartsWith("icudt") => "invariant globalization is enabled", + ".dat" when !string.IsNullOrEmpty(customIcuCandidateFilename) && fileName != customIcuCandidateFilename => "custom icu file will be used instead of icu from the runtime pack", + ".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor", + ".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor", + ".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor", + ".js" when assetType == "native" && fileName != "dotnet" => $"{fileName}{extension} is not used by Blazor", + ".pdb" when !copySymbols => "copying symbols is disabled", + ".symbols" when fromMonoPackage => "extension .symbols is not required.", + _ => null + }; + + return reason != null; + } + + public static string GetCandidateRelativePath(ITaskItem candidate) + { + var destinationSubPath = candidate.GetMetadata("DestinationSubPath"); + if (!string.IsNullOrEmpty(destinationSubPath)) + return $"_framework/{destinationSubPath}"; + + var relativePath = candidate.GetMetadata("FileName") + candidate.GetMetadata("Extension"); + return $"_framework/{relativePath}"; + } + + public static ITaskItem GetCustomIcuAsset(ITaskItem candidate) + { + var customIcuCandidate = new TaskItem(candidate); + var relativePath = GetCandidateRelativePath(customIcuCandidate); + customIcuCandidate.SetMetadata("RelativePath", relativePath); + customIcuCandidate.SetMetadata("AssetTraitName", "BlazorWebAssemblyResource"); + customIcuCandidate.SetMetadata("AssetTraitValue", "native"); + customIcuCandidate.SetMetadata("AssetType", "native"); + return customIcuCandidate; + } + + public static bool TryGetAssetFilename(ITaskItem candidate, out string filename) + { + bool candidateIsValid = candidate != null && !string.IsNullOrEmpty(candidate.ItemSpec); + filename = candidateIsValid ? + $"{candidate.GetMetadata("FileName")}" : + ""; + return candidateIsValid; + } +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs new file mode 100644 index 00000000000000..282d5cf6d0a580 --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs @@ -0,0 +1,157 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Runtime.Serialization; +using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary; + +namespace Microsoft.NET.Sdk.WebAssembly; + +/// +/// Defines the structure of a Blazor boot JSON file +/// +public class BootJsonData +{ + /// + /// Gets the name of the assembly with the application entry point + /// + public string entryAssembly { get; set; } + + /// + /// Gets the set of resources needed to boot the application. This includes the transitive + /// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file, + /// and any PDBs to be loaded. + /// + /// Within , dictionary keys are resource names, + /// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...') + /// as used for subresource integrity checking. + /// + public ResourcesData resources { get; set; } = new ResourcesData(); + + /// + /// Gets a value that determines whether to enable caching of the + /// inside a CacheStorage instance within the browser. + /// + public bool cacheBootResources { get; set; } + + /// + /// Gets a value that determines if this is a debug build. + /// + public bool debugBuild { get; set; } + + /// + /// Gets a value that determines if the linker is enabled. + /// + public bool linkerEnabled { get; set; } + + /// + /// Config files for the application + /// + public List config { get; set; } + + /// + /// Gets or sets the that determines how icu files are loaded. + /// + public ICUDataMode icuDataMode { get; set; } + + /// + /// Gets or sets a value that determines if the caching startup memory is enabled. + /// + public bool? startupMemoryCache { get; set; } + + /// + /// Gets a value for mono runtime options. + /// + public string[] runtimeOptions { get; set; } + + /// + /// Gets or sets configuration extensions. + /// + public Dictionary> extensions { get; set; } +} + +public class ResourcesData +{ + /// + /// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc. + /// + public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary(); + + /// + /// "assembly" (.dll) resources + /// + public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary(); + + /// + /// "debug" (.pdb) resources + /// + [DataMember(EmitDefaultValue = false)] + public ResourceHashesByNameDictionary pdb { get; set; } + + /// + /// localization (.satellite resx) resources + /// + [DataMember(EmitDefaultValue = false)] + public Dictionary satelliteResources { get; set; } + + /// + /// Assembly (.dll) resources that are loaded lazily during runtime + /// + [DataMember(EmitDefaultValue = false)] + public ResourceHashesByNameDictionary lazyAssembly { get; set; } + + /// + /// JavaScript module initializers that Blazor will be in charge of loading. + /// + [DataMember(EmitDefaultValue = false)] + public ResourceHashesByNameDictionary libraryInitializers { get; set; } + + /// + /// Extensions created by users customizing the initialization process. The format of the file(s) + /// is up to the user. + /// + [DataMember(EmitDefaultValue = false)] + public Dictionary extensions { get; set; } + + /// + /// Additional assets that the runtime consumes as part of the boot process. + /// + [DataMember(EmitDefaultValue = false)] + public Dictionary runtimeAssets { get; set; } + +} + +public enum ICUDataMode : int +{ + // Note that the numeric values are serialized and used in JS code, so don't change them without also updating the JS code + + /// + /// Load optimized icu data file based on the user's locale + /// + Sharded = 0, + + /// + /// Use the combined icudt.dat file + /// + All = 1, + + /// + /// Do not load any icu data files. + /// + Invariant = 2, + + /// + /// Load custom icu file provided by the developer. + /// + Custom = 3, +} + +[DataContract] +public class AdditionalAsset +{ + [DataMember(Name = "hash")] + public string Hash { get; set; } + + [DataMember(Name = "behavior")] + public string Behavior { get; set; } +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs new file mode 100644 index 00000000000000..68a563322f613e --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs @@ -0,0 +1,266 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.NET.Sdk.WebAssembly; + +namespace Microsoft.NET.Sdk.WebAssembly; + +// This task does the build work of processing the project inputs and producing a set of pseudo-static web assets. +public class ComputeWasmBuildAssets : Task +{ + [Required] + public ITaskItem[] Candidates { get; set; } + + public ITaskItem CustomIcuCandidate { get; set; } + + [Required] + public ITaskItem[] ProjectAssembly { get; set; } + + [Required] + public ITaskItem[] ProjectDebugSymbols { get; set; } + + [Required] + public ITaskItem[] SatelliteAssemblies { get; set; } + + [Required] + public ITaskItem[] ProjectSatelliteAssemblies { get; set; } + + [Required] + public string OutputPath { get; set; } + + [Required] + public bool TimeZoneSupport { get; set; } + + [Required] + public bool InvariantGlobalization { get; set; } + + [Required] + public bool CopySymbols { get; set; } + + public bool FingerprintDotNetJs { get; set; } + + [Output] + public ITaskItem[] AssetCandidates { get; set; } + + [Output] + public ITaskItem[] FilesToRemove { get; set; } + + public override bool Execute() + { + var filesToRemove = new List(); + var assetCandidates = new List(); + + try + { + if (ProjectAssembly.Length != 1) + { + Log.LogError("Invalid number of project assemblies '{0}'", string.Join("," + Environment.NewLine, ProjectAssembly.Select(a => a.ItemSpec))); + return true; + } + + if (ProjectDebugSymbols.Length > 1) + { + Log.LogError("Invalid number of symbol assemblies '{0}'", string.Join("," + Environment.NewLine, ProjectDebugSymbols.Select(a => a.ItemSpec))); + return true; + } + + if (AssetsComputingHelper.TryGetAssetFilename(CustomIcuCandidate, out string customIcuCandidateFilename)) + { + var customIcuCandidate = AssetsComputingHelper.GetCustomIcuAsset(CustomIcuCandidate); + assetCandidates.Add(customIcuCandidate); + } + + for (int i = 0; i < Candidates.Length; i++) + { + var candidate = Candidates[i]; + if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason)) + { + Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); + filesToRemove.Add(candidate); + continue; + } + + var satelliteAssembly = SatelliteAssemblies.FirstOrDefault(s => s.ItemSpec == candidate.ItemSpec); + if (satelliteAssembly != null) + { + var inferredCulture = satelliteAssembly.GetMetadata("DestinationSubDirectory").Trim('\\', '/'); + Log.LogMessage(MessageImportance.Low, "Found satellite assembly '{0}' asset for candidate '{1}' with inferred culture '{2}'", satelliteAssembly.ItemSpec, candidate.ItemSpec, inferredCulture); + + var assetCandidate = new TaskItem(satelliteAssembly); + assetCandidate.SetMetadata("AssetKind", "Build"); + assetCandidate.SetMetadata("AssetRole", "Related"); + assetCandidate.SetMetadata("AssetTraitName", "Culture"); + assetCandidate.SetMetadata("AssetTraitValue", inferredCulture); + assetCandidate.SetMetadata("RelativePath", $"_framework/{inferredCulture}/{satelliteAssembly.GetMetadata("FileName")}{satelliteAssembly.GetMetadata("Extension")}"); + assetCandidate.SetMetadata("RelatedAsset", Path.GetFullPath(Path.Combine(OutputPath, "wwwroot", "_framework", Path.GetFileName(assetCandidate.GetMetadata("ResolvedFrom"))))); + + assetCandidates.Add(assetCandidate); + continue; + } + + if (candidate.GetMetadata("FileName") == "dotnet" && candidate.GetMetadata("Extension") == ".js") + { + string newDotnetJSFileName = null; + string newDotNetJSFullPath = null; + if (FingerprintDotNetJs) + { + var itemHash = FileHasher.GetFileHash(candidate.ItemSpec); + newDotnetJSFileName = $"dotnet.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js"; + + var originalFileFullPath = Path.GetFullPath(candidate.ItemSpec); + var originalFileDirectory = Path.GetDirectoryName(originalFileFullPath); + + newDotNetJSFullPath = Path.Combine(originalFileDirectory, newDotnetJSFileName); + } + else + { + newDotNetJSFullPath = candidate.ItemSpec; + newDotnetJSFileName = Path.GetFileName(newDotNetJSFullPath); + } + + var newDotNetJs = new TaskItem(newDotNetJSFullPath, candidate.CloneCustomMetadata()); + newDotNetJs.SetMetadata("OriginalItemSpec", candidate.ItemSpec); + + var newRelativePath = $"_framework/{newDotnetJSFileName}"; + newDotNetJs.SetMetadata("RelativePath", newRelativePath); + + newDotNetJs.SetMetadata("AssetTraitName", "WasmResource"); + newDotNetJs.SetMetadata("AssetTraitValue", "native"); + + assetCandidates.Add(newDotNetJs); + continue; + } + else + { + string relativePath = AssetsComputingHelper.GetCandidateRelativePath(candidate); + candidate.SetMetadata("RelativePath", relativePath); + } + + // Workaround for https://github.com/dotnet/aspnetcore/issues/37574. + // For items added as "Reference" in project references, the OriginalItemSpec is incorrect. + // Ignore it, and use the FullPath instead. + if (candidate.GetMetadata("ReferenceSourceTarget") == "ProjectReference") + { + candidate.SetMetadata("OriginalItemSpec", candidate.ItemSpec); + } + + var culture = candidate.GetMetadata("Culture"); + if (!string.IsNullOrEmpty(culture)) + { + candidate.SetMetadata("AssetKind", "Build"); + candidate.SetMetadata("AssetRole", "Related"); + candidate.SetMetadata("AssetTraitName", "Culture"); + candidate.SetMetadata("AssetTraitValue", culture); + var fileName = candidate.GetMetadata("FileName"); + var suffixIndex = fileName.Length - ".resources".Length; + var relatedAssetPath = Path.GetFullPath(Path.Combine( + OutputPath, + "wwwroot", + "_framework", + fileName.Substring(0, suffixIndex) + ProjectAssembly[0].GetMetadata("Extension"))); + + candidate.SetMetadata("RelatedAsset", relatedAssetPath); + + Log.LogMessage(MessageImportance.Low, "Found satellite assembly '{0}' asset for inferred candidate '{1}' with culture '{2}'", candidate.ItemSpec, relatedAssetPath, culture); + } + + assetCandidates.Add(candidate); + } + + var intermediateAssembly = new TaskItem(ProjectAssembly[0]); + intermediateAssembly.SetMetadata("RelativePath", $"_framework/{intermediateAssembly.GetMetadata("FileName")}{intermediateAssembly.GetMetadata("Extension")}"); + assetCandidates.Add(intermediateAssembly); + + if (ProjectDebugSymbols.Length > 0) + { + var debugSymbols = new TaskItem(ProjectDebugSymbols[0]); + debugSymbols.SetMetadata("RelativePath", $"_framework/{debugSymbols.GetMetadata("FileName")}{debugSymbols.GetMetadata("Extension")}"); + assetCandidates.Add(debugSymbols); + } + + for (int i = 0; i < ProjectSatelliteAssemblies.Length; i++) + { + var projectSatelliteAssembly = ProjectSatelliteAssemblies[i]; + var candidateCulture = projectSatelliteAssembly.GetMetadata("Culture"); + Log.LogMessage( + "Found satellite assembly '{0}' asset for project '{1}' with culture '{2}'", + projectSatelliteAssembly.ItemSpec, + intermediateAssembly.ItemSpec, + candidateCulture); + + var assetCandidate = new TaskItem(Path.GetFullPath(projectSatelliteAssembly.ItemSpec), projectSatelliteAssembly.CloneCustomMetadata()); + var projectAssemblyAssetPath = Path.GetFullPath(Path.Combine( + OutputPath, + "wwwroot", + "_framework", + ProjectAssembly[0].GetMetadata("FileName") + ProjectAssembly[0].GetMetadata("Extension"))); + + var normalizedPath = assetCandidate.GetMetadata("TargetPath").Replace('\\', '/'); + + assetCandidate.SetMetadata("AssetKind", "Build"); + assetCandidate.SetMetadata("AssetRole", "Related"); + assetCandidate.SetMetadata("AssetTraitName", "Culture"); + assetCandidate.SetMetadata("AssetTraitValue", candidateCulture); + assetCandidate.SetMetadata("RelativePath", Path.Combine("_framework", normalizedPath)); + assetCandidate.SetMetadata("RelatedAsset", projectAssemblyAssetPath); + + assetCandidates.Add(assetCandidate); + } + + for (var i = 0; i < assetCandidates.Count; i++) + { + var candidate = assetCandidates[i]; + ApplyUniqueMetadataProperties(candidate); + } + } + catch (Exception ex) + { + Log.LogError(ex.ToString()); + return false; + } + + FilesToRemove = filesToRemove.ToArray(); + AssetCandidates = assetCandidates.ToArray(); + + return !Log.HasLoggedErrors; + } + + private static void ApplyUniqueMetadataProperties(ITaskItem candidate) + { + var extension = candidate.GetMetadata("Extension"); + var filename = candidate.GetMetadata("FileName"); + switch (extension) + { + case ".dll": + if (string.IsNullOrEmpty(candidate.GetMetadata("AssetTraitName"))) + { + candidate.SetMetadata("AssetTraitName", "WasmResource"); + candidate.SetMetadata("AssetTraitValue", "runtime"); + } + if (string.Equals(candidate.GetMetadata("ResolvedFrom"), "{HintPathFromItem}", StringComparison.Ordinal)) + { + candidate.RemoveMetadata("OriginalItemSpec"); + } + break; + case ".wasm": + case ".blat": + case ".dat" when filename.StartsWith("icudt"): + candidate.SetMetadata("AssetTraitName", "WasmResource"); + candidate.SetMetadata("AssetTraitValue", "native"); + break; + case ".pdb": + candidate.SetMetadata("AssetTraitName", "WasmResource"); + candidate.SetMetadata("AssetTraitValue", "symbol"); + candidate.RemoveMetadata("OriginalItemSpec"); + break; + default: + break; + } + } +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs new file mode 100644 index 00000000000000..d622db24a31a5e --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs @@ -0,0 +1,628 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Microsoft.NET.Sdk.WebAssembly; + +namespace Microsoft.NET.Sdk.WebAssembly; + +// This target computes the list of publish static web assets based on the changes that happen during publish and the list of build static +// web assets. +// In this target we need to do 2 things: +// * Harmonize the list of dlls produced at build time with the list of resolved files to publish. +// * We iterate over the list of existing static web assets and do as follows: +// * If we find the assembly in the resolved files to publish and points to the original assembly (linker disabled or assembly not linked) +// we create a new "Publish" static web asset for the assembly. +// * If we find the assembly in the resolved files to publish and points to a new location, we assume this assembly has been updated (as part of linking) +// and we create a new "Publish" static web asset for the asembly pointing to the new location. +// * If we don't find the assembly on the resolved files to publish it has been linked out from the app, so we don't add any new static web asset and we +// also avoid adding any existing related static web asset (satellite assemblies and compressed versions). +// * We update static web assets for satellite assemblies and compressed assets accordingly. +// * Look at the list of "native" assets and determine whether we need to create new publish assets for the current build assets or if we need to +// update the native assets because the app was ahead of time compiled. +public class ComputeWasmPublishAssets : Task +{ + [Required] + public ITaskItem[] ResolvedFilesToPublish { get; set; } + + public ITaskItem CustomIcuCandidate { get; set; } + + [Required] + public ITaskItem[] WasmAotAssets { get; set; } + + [Required] + public ITaskItem[] ExistingAssets { get; set; } + + [Required] + public bool TimeZoneSupport { get; set; } + + [Required] + public bool InvariantGlobalization { get; set; } + + [Required] + public bool CopySymbols { get; set; } + + [Required] + public string PublishPath { get; set; } + + [Required] + public string DotNetJsVersion { get; set; } + + public bool FingerprintDotNetJs { get; set; } + + [Output] + public ITaskItem[] NewCandidates { get; set; } + + [Output] + public ITaskItem[] FilesToRemove { get; set; } + + public override bool Execute() + { + var filesToRemove = new List(); + var newAssets = new List(); + + try + { + // We'll do a first pass over the resolved files to publish to figure out what files need to be removed + // as well as categorize resolved files into different groups. + var resolvedFilesToPublishToRemove = new Dictionary(StringComparer.Ordinal); + + // These assemblies are keyed of the assembly name "computed" based on the relative path, which must be + // unique. + var resolvedAssembliesToPublish = new Dictionary(StringComparer.Ordinal); + var resolvedSymbolsToPublish = new Dictionary(StringComparer.Ordinal); + var satelliteAssemblyToPublish = new Dictionary<(string, string), ITaskItem>(EqualityComparer<(string, string)>.Default); + var resolvedNativeAssetToPublish = new Dictionary(StringComparer.Ordinal); + GroupResolvedFilesToPublish( + resolvedFilesToPublishToRemove, + resolvedAssembliesToPublish, + satelliteAssemblyToPublish, + resolvedSymbolsToPublish, + resolvedNativeAssetToPublish); + + // Group candidate static web assets + var assemblyAssets = new Dictionary(); + var symbolAssets = new Dictionary(); + var nativeAssets = new Dictionary(); + var satelliteAssemblyAssets = new Dictionary(); + var compressedRepresentations = new Dictionary(); + GroupExistingStaticWebAssets( + assemblyAssets, + nativeAssets, + satelliteAssemblyAssets, + symbolAssets, + compressedRepresentations); + + var newStaticWebAssets = ComputeUpdatedAssemblies( + satelliteAssemblyToPublish, + filesToRemove, + resolvedAssembliesToPublish, + assemblyAssets, + satelliteAssemblyAssets, + compressedRepresentations); + + newAssets.AddRange(newStaticWebAssets); + + var nativeStaticWebAssets = ProcessNativeAssets( + nativeAssets, + resolvedFilesToPublishToRemove, + resolvedNativeAssetToPublish, + compressedRepresentations, + filesToRemove); + + newAssets.AddRange(nativeStaticWebAssets); + + var symbolStaticWebAssets = ProcessSymbolAssets( + symbolAssets, + compressedRepresentations, + resolvedFilesToPublishToRemove, + resolvedSymbolsToPublish, + filesToRemove); + + newAssets.AddRange(symbolStaticWebAssets); + + foreach (var kvp in resolvedFilesToPublishToRemove) + { + var resolvedPublishFileToRemove = kvp.Value; + filesToRemove.Add(resolvedPublishFileToRemove); + } + } + catch (Exception ex) + { + Log.LogError(ex.ToString()); + return false; + } + + FilesToRemove = filesToRemove.ToArray(); + NewCandidates = newAssets.ToArray(); + + return !Log.HasLoggedErrors; + } + + private List ProcessNativeAssets( + Dictionary nativeAssets, + IDictionary resolvedPublishFilesToRemove, + Dictionary resolvedNativeAssetToPublish, + Dictionary compressedRepresentations, + List filesToRemove) + { + var nativeStaticWebAssets = new List(); + + // Keep track of the updated assets to determine what compressed assets we can reuse + var updateMap = new Dictionary(); + + foreach (var kvp in nativeAssets) + { + var key = kvp.Key; + var asset = kvp.Value; + var isDotNetJs = IsDotNetJs(key); + var isDotNetWasm = IsDotNetWasm(key); + if (!isDotNetJs && !isDotNetWasm) + { + if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing)) + { + if (!resolvedPublishFilesToRemove.TryGetValue(existing.ItemSpec, out var removed)) + { + // This is a native asset like timezones.blat or similar that was not filtered and that needs to be updated + // to a publish asset. + var newAsset = new TaskItem(asset); + ApplyPublishProperties(newAsset); + nativeStaticWebAssets.Add(newAsset); + filesToRemove.Add(existing); + updateMap.Add(asset.ItemSpec, newAsset); + Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); + } + else + { + Log.LogMessage(MessageImportance.Low, "Removing asset '{0}'.", existing.ItemSpec); + // This was a file that was filtered, so just remove it, we don't need to add any publish static web asset + filesToRemove.Add(removed); + + // Remove the file from the list to avoid double processing later when we process other files we filtered. + resolvedPublishFilesToRemove.Remove(existing.ItemSpec); + } + } + + continue; + } + + if (isDotNetJs) + { + var aotDotNetJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.js"); + ITaskItem newDotNetJs = null; + if (aotDotNetJs != null && FingerprintDotNetJs) + { + newDotNetJs = new TaskItem(Path.GetFullPath(aotDotNetJs.ItemSpec), asset.CloneCustomMetadata()); + newDotNetJs.SetMetadata("OriginalItemSpec", aotDotNetJs.ItemSpec); + newDotNetJs.SetMetadata("RelativePath", $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}"); + + updateMap.Add(asset.ItemSpec, newDotNetJs); + Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetJs.ItemSpec); + } + else + { + newDotNetJs = new TaskItem(asset); + Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); + } + + ApplyPublishProperties(newDotNetJs); + nativeStaticWebAssets.Add(newDotNetJs); + if (resolvedNativeAssetToPublish.TryGetValue("dotnet.js", out var resolved)) + { + filesToRemove.Add(resolved); + } + continue; + } + + if (isDotNetWasm) + { + var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm"); + ITaskItem newDotNetWasm = null; + if (aotDotNetWasm != null) + { + newDotNetWasm = new TaskItem(Path.GetFullPath(aotDotNetWasm.ItemSpec), asset.CloneCustomMetadata()); + newDotNetWasm.SetMetadata("OriginalItemSpec", aotDotNetWasm.ItemSpec); + updateMap.Add(asset.ItemSpec, newDotNetWasm); + Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetWasm.ItemSpec); + } + else + { + newDotNetWasm = new TaskItem(asset); + Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); + } + + ApplyPublishProperties(newDotNetWasm); + nativeStaticWebAssets.Add(newDotNetWasm); + if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved)) + { + filesToRemove.Add(resolved); + } + continue; + } + } + + var compressedUpdatedFiles = ProcessCompressedAssets(compressedRepresentations, nativeAssets, updateMap); + foreach (var f in compressedUpdatedFiles) + { + nativeStaticWebAssets.Add(f); + } + + return nativeStaticWebAssets; + + static bool IsDotNetJs(string key) + { + var fileName = Path.GetFileName(key); + return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker"); + } + + static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal); + } + + private List ProcessSymbolAssets( + Dictionary symbolAssets, + Dictionary compressedRepresentations, + Dictionary resolvedPublishFilesToRemove, + Dictionary resolvedSymbolAssetToPublish, + List filesToRemove) + { + var symbolStaticWebAssets = new List(); + var updateMap = new Dictionary(); + + foreach (var kvp in symbolAssets) + { + var asset = kvp.Value; + if (resolvedSymbolAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing)) + { + if (!resolvedPublishFilesToRemove.TryGetValue(existing.ItemSpec, out var removed)) + { + // This is a symbol asset like classlibrary.pdb or similar that was not filtered and that needs to be updated + // to a publish asset. + var newAsset = new TaskItem(asset); + ApplyPublishProperties(newAsset); + symbolStaticWebAssets.Add(newAsset); + updateMap.Add(newAsset.ItemSpec, newAsset); + filesToRemove.Add(existing); + Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); + } + else + { + // This was a file that was filtered, so just remove it, we don't need to add any publish static web asset + filesToRemove.Add(removed); + + // Remove the file from the list to avoid double processing later when we process other files we filtered. + resolvedPublishFilesToRemove.Remove(existing.ItemSpec); + } + } + } + + var compressedFiles = ProcessCompressedAssets(compressedRepresentations, symbolAssets, updateMap); + + foreach (var file in compressedFiles) + { + symbolStaticWebAssets.Add(file); + } + + return symbolStaticWebAssets; + } + + private List ComputeUpdatedAssemblies( + IDictionary<(string, string assemblyName), ITaskItem> satelliteAssemblies, + List filesToRemove, + Dictionary resolvedAssembliesToPublish, + Dictionary assemblyAssets, + Dictionary satelliteAssemblyAssets, + Dictionary compressedRepresentations) + { + // All assemblies, satellite assemblies and gzip files are initially defined as build assets. + // We need to update them to publish assets when they haven't changed or when they have been linked. + // For satellite assemblies and compressed files, we won't include them in the list of assets to update + // when the original assembly they depend on has been linked out. + var assetsToUpdate = new Dictionary(); + var linkedAssets = new Dictionary(); + + foreach (var kvp in assemblyAssets) + { + var asset = kvp.Value; + var fileName = Path.GetFileName(asset.GetMetadata("RelativePath")); + if (resolvedAssembliesToPublish.TryGetValue(fileName, out var existing)) + { + // We found the assembly, so it'll have to be updated. + assetsToUpdate.Add(asset.ItemSpec, asset); + filesToRemove.Add(existing); + if (!string.Equals(asset.ItemSpec, existing.GetMetadata("FullPath"), StringComparison.Ordinal)) + { + linkedAssets.Add(asset.ItemSpec, existing); + } + } + } + + foreach (var kvp in satelliteAssemblyAssets) + { + var satelliteAssembly = kvp.Value; + var relatedAsset = satelliteAssembly.GetMetadata("RelatedAsset"); + if (assetsToUpdate.ContainsKey(relatedAsset)) + { + assetsToUpdate.Add(satelliteAssembly.ItemSpec, satelliteAssembly); + var culture = satelliteAssembly.GetMetadata("AssetTraitValue"); + var fileName = Path.GetFileName(satelliteAssembly.GetMetadata("RelativePath")); + if (satelliteAssemblies.TryGetValue((culture, fileName), out var existing)) + { + filesToRemove.Add(existing); + } + else + { + var message = $"Can't find the original satellite assembly in the list of resolved files to " + + $"publish for asset '{satelliteAssembly.ItemSpec}'."; + throw new InvalidOperationException(message); + } + } + } + + var compressedFiles = ProcessCompressedAssets(compressedRepresentations, assetsToUpdate, linkedAssets); + + foreach (var file in compressedFiles) + { + assetsToUpdate.Add(file.ItemSpec, file); + } + + var updatedAssetsMap = new Dictionary(StringComparer.Ordinal); + foreach (var asset in assetsToUpdate.Select(a => a.Value).OrderBy(a => a.GetMetadata("AssetRole"), Comparer.Create(OrderByAssetRole))) + { + var assetTraitName = asset.GetMetadata("AssetTraitName"); + switch (assetTraitName) + { + case "WasmResource": + ITaskItem newAsemblyAsset = null; + if (linkedAssets.TryGetValue(asset.ItemSpec, out var linked)) + { + newAsemblyAsset = new TaskItem(linked.GetMetadata("FullPath"), asset.CloneCustomMetadata()); + newAsemblyAsset.SetMetadata("OriginalItemSpec", linked.ItemSpec); + Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with linked version '{1}'", + asset.ItemSpec, + newAsemblyAsset.ItemSpec); + } + else + { + Log.LogMessage(MessageImportance.Low, "Linked asset not found for asset '{0}'", asset.ItemSpec); + newAsemblyAsset = new TaskItem(asset); + } + ApplyPublishProperties(newAsemblyAsset); + + updatedAssetsMap.Add(asset.ItemSpec, newAsemblyAsset); + break; + default: + // Satellite assembliess and compressed assets + var dependentAsset = new TaskItem(asset); + ApplyPublishProperties(dependentAsset); + UpdateRelatedAssetProperty(asset, dependentAsset, updatedAssetsMap); + Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); + + updatedAssetsMap.Add(asset.ItemSpec, dependentAsset); + break; + } + } + + return updatedAssetsMap.Values.ToList(); + } + + private List ProcessCompressedAssets( + Dictionary compressedRepresentations, + Dictionary assetsToUpdate, + Dictionary updatedAssets) + { + var processed = new List(); + var runtimeAssetsToUpdate = new List(); + foreach (var kvp in compressedRepresentations) + { + var compressedAsset = kvp.Value; + var relatedAsset = compressedAsset.GetMetadata("RelatedAsset"); + if (assetsToUpdate.ContainsKey(relatedAsset)) + { + if (!updatedAssets.ContainsKey(relatedAsset)) + { + Log.LogMessage(MessageImportance.Low, "Related assembly for '{0}' was not updated and the compressed asset can be reused.", relatedAsset); + var newCompressedAsset = new TaskItem(compressedAsset); + ApplyPublishProperties(newCompressedAsset); + runtimeAssetsToUpdate.Add(newCompressedAsset); + } + else + { + Log.LogMessage(MessageImportance.Low, "Related assembly for '{0}' was updated and the compressed asset will be discarded.", relatedAsset); + } + + processed.Add(kvp.Key); + } + } + + // Remove all the elements we've found to avoid having to iterate over them when we process other assets. + foreach (var element in processed) + { + compressedRepresentations.Remove(element); + } + + return runtimeAssetsToUpdate; + } + + private static void UpdateRelatedAssetProperty(ITaskItem asset, TaskItem newAsset, Dictionary updatedAssetsMap) + { + if (!updatedAssetsMap.TryGetValue(asset.GetMetadata("RelatedAsset"), out var updatedRelatedAsset)) + { + throw new InvalidOperationException("Related asset not found."); + } + + newAsset.SetMetadata("RelatedAsset", updatedRelatedAsset.ItemSpec); + } + + private int OrderByAssetRole(string left, string right) + { + var leftScore = GetScore(left); + var rightScore = GetScore(right); + + return leftScore - rightScore; + + static int GetScore(string candidate) => candidate switch + { + "Primary" => 0, + "Related" => 1, + "Alternative" => 2, + _ => throw new InvalidOperationException("Invalid asset role"), + }; + } + + private void ApplyPublishProperties(ITaskItem newAsemblyAsset) + { + newAsemblyAsset.SetMetadata("AssetKind", "Publish"); + newAsemblyAsset.SetMetadata("ContentRoot", Path.Combine(PublishPath, "wwwroot")); + newAsemblyAsset.SetMetadata("CopyToOutputDirectory", "Never"); + newAsemblyAsset.SetMetadata("CopyToPublishDirectory", "PreserveNewest"); + } + + private void GroupExistingStaticWebAssets( + Dictionary assemblyAssets, + Dictionary nativeAssets, + Dictionary satelliteAssemblyAssets, + Dictionary symbolAssets, + Dictionary compressedRepresentations) + { + foreach (var asset in ExistingAssets) + { + var traitName = asset.GetMetadata("AssetTraitName"); + if (IsWebAssemblyResource(traitName)) + { + var traitValue = asset.GetMetadata("AssetTraitValue"); + if (IsRuntimeAsset(traitValue)) + { + assemblyAssets.Add(asset.ItemSpec, asset); + } + else if (IsNativeAsset(traitValue)) + { + nativeAssets.Add(asset.ItemSpec, asset); + } + else if (IsSymbolAsset(traitValue)) + { + symbolAssets.Add(asset.ItemSpec, asset); + } + } + else if (IsCulture(traitName)) + { + satelliteAssemblyAssets.Add(asset.ItemSpec, asset); + } + else if (IsAlternative(asset)) + { + compressedRepresentations.Add(asset.ItemSpec, asset); + } + } + } + + private void GroupResolvedFilesToPublish( + Dictionary resolvedFilesToPublishToRemove, + Dictionary resolvedAssemblyToPublish, + Dictionary<(string, string), ITaskItem> satelliteAssemblyToPublish, + Dictionary resolvedSymbolsToPublish, + Dictionary resolvedNativeAssetToPublish) + { + var resolvedFilesToPublish = ResolvedFilesToPublish.ToList(); + if (AssetsComputingHelper.TryGetAssetFilename(CustomIcuCandidate, out string customIcuCandidateFilename)) + { + var customIcuCandidate = AssetsComputingHelper.GetCustomIcuAsset(CustomIcuCandidate); + resolvedFilesToPublish.Add(customIcuCandidate); + } + + foreach (var candidate in resolvedFilesToPublish) + { + if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason)) + { + Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); + if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec)) + { + resolvedFilesToPublishToRemove.Add(candidate.ItemSpec, candidate); + } + else + { + Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); + } + continue; + } + + var extension = candidate.GetMetadata("Extension"); + if (string.Equals(extension, ".dll", StringComparison.Ordinal)) + { + var culture = candidate.GetMetadata("Culture"); + var inferredCulture = candidate.GetMetadata("DestinationSubDirectory").Replace("\\", "/").Trim('/'); + if (!string.IsNullOrEmpty(culture) || !string.IsNullOrEmpty(inferredCulture)) + { + var finalCulture = !string.IsNullOrEmpty(culture) ? culture : inferredCulture; + var assemblyName = Path.GetFileName(candidate.GetMetadata("RelativePath").Replace("\\", "/")); + if (!satelliteAssemblyToPublish.ContainsKey((finalCulture, assemblyName))) + { + satelliteAssemblyToPublish.Add((finalCulture, assemblyName), candidate); + } + else + { + Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); + } + continue; + } + + var candidateName = Path.GetFileName(candidate.GetMetadata("RelativePath")); + if (!resolvedAssemblyToPublish.ContainsKey(candidateName)) + { + resolvedAssemblyToPublish.Add(candidateName, candidate); + } + else + { + Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); + } + + continue; + } + + if (string.Equals(extension, ".pdb", StringComparison.Ordinal)) + { + var candidateName = Path.GetFileName(candidate.GetMetadata("RelativePath")); + if (!resolvedSymbolsToPublish.ContainsKey(candidateName)) + { + resolvedSymbolsToPublish.Add(candidateName, candidate); + } + else + { + Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); + } + + continue; + } + + // Capture all the native unfiltered assets since we need to process them to determine what static web assets need to get + // upgraded + if (string.Equals(candidate.GetMetadata("AssetType"), "native", StringComparison.Ordinal)) + { + var candidateName = $"{candidate.GetMetadata("FileName")}{extension}"; + if (!resolvedNativeAssetToPublish.ContainsKey(candidateName)) + { + resolvedNativeAssetToPublish.Add(candidateName, candidate); + } + else + { + Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); + } + continue; + } + } + } + + private static bool IsNativeAsset(string traitValue) => string.Equals(traitValue, "native", StringComparison.Ordinal); + + private static bool IsRuntimeAsset(string traitValue) => string.Equals(traitValue, "runtime", StringComparison.Ordinal); + private static bool IsSymbolAsset(string traitValue) => string.Equals(traitValue, "symbol", StringComparison.Ordinal); + + private static bool IsAlternative(ITaskItem asset) => string.Equals(asset.GetMetadata("AssetRole"), "Alternative", StringComparison.Ordinal); + + private static bool IsCulture(string traitName) => string.Equals(traitName, "Culture", StringComparison.Ordinal); + + private static bool IsWebAssemblyResource(string traitName) => string.Equals(traitName, "WasmResource", StringComparison.Ordinal); +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs new file mode 100644 index 00000000000000..c264a1b42a4617 --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Numerics; +using System.Security.Cryptography; +using System.Text; + +namespace Microsoft.NET.Sdk.WebAssembly; + +public static class FileHasher +{ + public static string GetFileHash(string filePath) + { + using var hash = SHA256.Create(); + var bytes = Encoding.UTF8.GetBytes(filePath); + var hashBytes = hash.ComputeHash(bytes); + return ToBase36(hashBytes); + } + + private static string ToBase36(byte[] hash) + { + const string chars = "0123456789abcdefghijklmnopqrstuvwxyz"; + + var result = new char[10]; + var dividend = BigInteger.Abs(new BigInteger(hash.AsSpan().Slice(0, 9).ToArray())); + for (var i = 0; i < 10; i++) + { + dividend = BigInteger.DivRem(dividend, 36, out var remainder); + result[i] = chars[(int)remainder]; + } + + return new string(result); + } +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs new file mode 100644 index 00000000000000..d8a5a3d2ae9e6a --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs @@ -0,0 +1,341 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary; + +namespace Microsoft.NET.Sdk.WebAssembly; + +public class GenerateWasmBootJson : Task +{ + private static readonly string[] jiterpreterOptions = new[] { "jiterpreter-traces-enabled", "jiterpreter-interp-entry-enabled", "jiterpreter-jit-call-enabled" }; + + [Required] + public string AssemblyPath { get; set; } + + [Required] + public ITaskItem[] Resources { get; set; } + + [Required] + public bool DebugBuild { get; set; } + + [Required] + public bool LinkerEnabled { get; set; } + + [Required] + public bool CacheBootResources { get; set; } + + public bool LoadAllICUData { get; set; } + + public bool LoadCustomIcuData { get; set; } + + public string InvariantGlobalization { get; set; } + + public ITaskItem[] ConfigurationFiles { get; set; } + + public ITaskItem[] Extensions { get; set; } + + public string StartupMemoryCache { get; set; } + + public string Jiterpreter { get; set; } + + public string RuntimeOptions { get; set; } + + [Required] + public string OutputPath { get; set; } + + public ITaskItem[] LazyLoadedAssemblies { get; set; } + + public override bool Execute() + { + using var fileStream = File.Create(OutputPath); + var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name; + + try + { + WriteBootJson(fileStream, entryAssemblyName); + } + catch (Exception ex) + { + Log.LogError(ex.ToString()); + } + + return !Log.HasLoggedErrors; + } + + // Internal for tests + public void WriteBootJson(Stream output, string entryAssemblyName) + { + var icuDataMode = ICUDataMode.Sharded; + + if (string.Equals(InvariantGlobalization, "true", StringComparison.OrdinalIgnoreCase)) + { + icuDataMode = ICUDataMode.Invariant; + } + else if (LoadAllICUData) + { + icuDataMode = ICUDataMode.All; + } + else if (LoadCustomIcuData) + { + icuDataMode = ICUDataMode.Custom; + } + + var result = new BootJsonData + { + entryAssembly = entryAssemblyName, + cacheBootResources = CacheBootResources, + debugBuild = DebugBuild, + linkerEnabled = LinkerEnabled, + resources = new ResourcesData(), + config = new List(), + icuDataMode = icuDataMode, + startupMemoryCache = ParseOptionalBool(StartupMemoryCache), + }; + + if (!string.IsNullOrEmpty(RuntimeOptions)) + { + string[] runtimeOptions = RuntimeOptions.Split(' '); + result.runtimeOptions = runtimeOptions; + } + + bool? jiterpreter = ParseOptionalBool(Jiterpreter); + if (jiterpreter != null) + { + var runtimeOptions = result.runtimeOptions?.ToHashSet() ?? new HashSet(3); + foreach (var jiterpreterOption in jiterpreterOptions) + { + if (jiterpreter == true) + { + if (!runtimeOptions.Contains($"--no-{jiterpreterOption}")) + runtimeOptions.Add($"--{jiterpreterOption}"); + } + else + { + if (!runtimeOptions.Contains($"--{jiterpreterOption}")) + runtimeOptions.Add($"--no-{jiterpreterOption}"); + } + } + + result.runtimeOptions = runtimeOptions.ToArray(); + } + + // Build a two-level dictionary of the form: + // - assembly: + // - UriPath (e.g., "System.Text.Json.dll") + // - ContentHash (e.g., "4548fa2e9cf52986") + // - runtime: + // - UriPath (e.g., "dotnet.js") + // - ContentHash (e.g., "3448f339acf512448") + if (Resources != null) + { + var remainingLazyLoadAssemblies = new List(LazyLoadedAssemblies ?? Array.Empty()); + var resourceData = result.resources; + foreach (var resource in Resources) + { + ResourceHashesByNameDictionary resourceList = null; + + string behavior = null; + var fileName = resource.GetMetadata("FileName"); + var fileExtension = resource.GetMetadata("Extension"); + var assetTraitName = resource.GetMetadata("AssetTraitName"); + var assetTraitValue = resource.GetMetadata("AssetTraitValue"); + var resourceName = Path.GetFileName(resource.GetMetadata("RelativePath")); + + if (TryGetLazyLoadedAssembly(resourceName, out var lazyLoad)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a lazy loaded assembly.", resource.ItemSpec); + remainingLazyLoadAssemblies.Remove(lazyLoad); + resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary(); + resourceList = resourceData.lazyAssembly; + } + else if (string.Equals("Culture", assetTraitName, StringComparison.OrdinalIgnoreCase)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as satellite assembly with culture '{1}'.", resource.ItemSpec, assetTraitValue); + resourceData.satelliteResources ??= new Dictionary(StringComparer.OrdinalIgnoreCase); + resourceName = assetTraitValue + "/" + resourceName; + + if (!resourceData.satelliteResources.TryGetValue(assetTraitValue, out resourceList)) + { + resourceList = new ResourceHashesByNameDictionary(); + resourceData.satelliteResources.Add(assetTraitValue, resourceList); + } + } + else if (string.Equals("symbol", assetTraitValue, StringComparison.OrdinalIgnoreCase)) + { + if (TryGetLazyLoadedAssembly($"{fileName}.dll", out _)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a lazy loaded symbols file.", resource.ItemSpec); + resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary(); + resourceList = resourceData.lazyAssembly; + } + else + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as symbols file.", resource.ItemSpec); + resourceData.pdb ??= new ResourceHashesByNameDictionary(); + resourceList = resourceData.pdb; + } + } + else if (string.Equals("runtime", assetTraitValue, StringComparison.OrdinalIgnoreCase)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as an app assembly.", resource.ItemSpec); + resourceList = resourceData.assembly; + } + else if (string.Equals(assetTraitName, "WasmResource", StringComparison.OrdinalIgnoreCase) && + string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec); + if (string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase) && + string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) + { + behavior = "dotnetwasm"; + } + + resourceList = resourceData.runtime; + } + else if (string.Equals("JSModule", assetTraitName, StringComparison.OrdinalIgnoreCase) && + string.Equals(assetTraitValue, "JSLibraryModule", StringComparison.OrdinalIgnoreCase)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a library initializer resource.", resource.ItemSpec); + resourceData.libraryInitializers ??= new(); + resourceList = resourceData.libraryInitializers; + var targetPath = resource.GetMetadata("TargetPath"); + Debug.Assert(!string.IsNullOrEmpty(targetPath), "Target path for '{0}' must exist.", resource.ItemSpec); + AddResourceToList(resource, resourceList, targetPath); + continue; + } + else if (string.Equals("WasmResource", assetTraitName, StringComparison.OrdinalIgnoreCase) && + assetTraitValue.StartsWith("extension:", StringComparison.OrdinalIgnoreCase)) + { + Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as an extension resource '{1}'.", resource.ItemSpec, assetTraitValue); + var extensionName = assetTraitValue.Substring("extension:".Length); + resourceData.extensions ??= new(); + if (!resourceData.extensions.TryGetValue(extensionName, out resourceList)) + { + resourceList = new(); + resourceData.extensions[extensionName] = resourceList; + } + var targetPath = resource.GetMetadata("TargetPath"); + Debug.Assert(!string.IsNullOrEmpty(targetPath), "Target path for '{0}' must exist.", resource.ItemSpec); + AddResourceToList(resource, resourceList, targetPath); + continue; + } + else + { + Log.LogMessage(MessageImportance.Low, "Skipping resource '{0}' since it doesn't belong to a defined category.", resource.ItemSpec); + // This should include items such as XML doc files, which do not need to be recorded in the manifest. + continue; + } + + if (resourceList != null) + { + AddResourceToList(resource, resourceList, resourceName); + } + + if (!string.IsNullOrEmpty(behavior)) + { + resourceData.runtimeAssets ??= new Dictionary(); + AddToAdditionalResources(resource, resourceData.runtimeAssets, resourceName, behavior); + } + } + + if (remainingLazyLoadAssemblies.Count > 0) + { + const string message = "Unable to find '{0}' to be lazy loaded later. Confirm that project or " + + "package references are included and the reference is used in the project."; + + Log.LogError( + subcategory: null, + errorCode: "BLAZORSDK1001", + helpKeyword: null, + file: null, + lineNumber: 0, + columnNumber: 0, + endLineNumber: 0, + endColumnNumber: 0, + message: message, + string.Join(";", LazyLoadedAssemblies.Select(a => a.ItemSpec))); + + return; + } + } + + if (ConfigurationFiles != null) + { + foreach (var configFile in ConfigurationFiles) + { + result.config.Add(Path.GetFileName(configFile.ItemSpec)); + } + } + + if (Extensions != null && Extensions.Length > 0) + { + var configSerializer = new DataContractJsonSerializer(typeof(Dictionary), new DataContractJsonSerializerSettings + { + UseSimpleDictionaryFormat = true + }); + + result.extensions = new Dictionary> (); + foreach (var configExtension in Extensions) + { + var key = configExtension.GetMetadata("key"); + var config = (Dictionary)configSerializer.ReadObject(File.OpenRead(configExtension.ItemSpec)); + result.extensions[key] = config; + } + } + + var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings + { + UseSimpleDictionaryFormat = true + }); + + using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true); + serializer.WriteObject(writer, result); + + void AddResourceToList(ITaskItem resource, ResourceHashesByNameDictionary resourceList, string resourceKey) + { + if (!resourceList.ContainsKey(resourceKey)) + { + Log.LogMessage(MessageImportance.Low, "Added resource '{0}' to the manifest.", resource.ItemSpec); + resourceList.Add(resourceKey, $"sha256-{resource.GetMetadata("FileHash")}"); + } + } + } + + private static bool? ParseOptionalBool(string value) + { + if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out var boolValue)) + return null; + + return boolValue; + } + + private void AddToAdditionalResources(ITaskItem resource, Dictionary additionalResources, string resourceName, string behavior) + { + if (!additionalResources.ContainsKey(resourceName)) + { + Log.LogMessage(MessageImportance.Low, "Added resource '{0}' to the list of additional assets in the manifest.", resource.ItemSpec); + additionalResources.Add(resourceName, new AdditionalAsset + { + Hash = $"sha256-{resource.GetMetadata("FileHash")}", + Behavior = behavior + }); + } + } + + private bool TryGetLazyLoadedAssembly(string fileName, out ITaskItem lazyLoadedAssembly) + { + return (lazyLoadedAssembly = LazyLoadedAssemblies?.SingleOrDefault(a => a.ItemSpec == fileName)) != null; + } +} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj new file mode 100644 index 00000000000000..e56ee68e46a5eb --- /dev/null +++ b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj @@ -0,0 +1,32 @@ + + + + $(TargetFrameworkForNETCoreTasks);$(TargetFrameworkForNETFrameworkTasks) + $(NoWarn),CA1050,CA1850,CA1845,CA1859,NU5128 + Microsoft.NET.Sdk.WebAssembly + true + true + + + + + All + true + + + + + + + + + + + <_PublishFramework Remove="@(_PublishFramework)" /> + <_PublishFramework Include="$(TargetFrameworks)" /> + + + + + + From 63e39e24b43d9ee0148d39ba23134edc5febf6d4 Mon Sep 17 00:00:00 2001 From: Rahul Bhandari Date: Wed, 12 Apr 2023 09:36:07 -0700 Subject: [PATCH 08/21] update snapcraft.yaml for .NET (#84706) * Create snapcraft.yaml * Create snapcraft.yaml * Create snapcraft.yaml --- src/installer/pkg/snap/6.0/snapcraft.yaml | 43 ++++++++++++++++++++++ src/installer/pkg/snap/7.0/snapcraft.yaml | 44 +++++++++++++++++++++++ src/installer/pkg/snap/8.0/snapcraft.yaml | 44 +++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 src/installer/pkg/snap/6.0/snapcraft.yaml create mode 100644 src/installer/pkg/snap/7.0/snapcraft.yaml create mode 100644 src/installer/pkg/snap/8.0/snapcraft.yaml diff --git a/src/installer/pkg/snap/6.0/snapcraft.yaml b/src/installer/pkg/snap/6.0/snapcraft.yaml new file mode 100644 index 00000000000000..c9c25e01214982 --- /dev/null +++ b/src/installer/pkg/snap/6.0/snapcraft.yaml @@ -0,0 +1,43 @@ +name: dotnet-runtime-60 +base: core18 +version: 6.0.16 +summary: Cross-Platform .NET Core Runtime. +description: | + .NET Core runtimes and libraries which are optimized for running .NET Core apps in production. See https://dot.net/core. + .NET Core is a general purpose development platform maintained by Microsoft. + +grade: stable +confinement: strict + +apps: + dotnet: + command: dotnet + plugs: + - network + - network-bind + - removable-media + - home + +slots: + dotnet-runtime: + content: dotnet-runtime-60 + interface: content + read: [/] + +parts: + dotnet-runtime: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/45395f1b-8928-41c5-9585-f01d949b2afb/0911c4025fffc0f51c3ab535695c6ca6/dotnet-runtime-6.0.16-linux-x64.tar.gz + source-checksum: sha512/c8891b791a51e7d2c3164470dfd2af2ce59af3c26404e84075277e307df7dcd1e3ccf1a1a3c2655fe2eea8a30f8349b7adbbe5de4cedfee52da06729a505d8f5 + stage-packages: + - libicu60 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - liblttng-ust0 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - libdb5.3 + - libc6 diff --git a/src/installer/pkg/snap/7.0/snapcraft.yaml b/src/installer/pkg/snap/7.0/snapcraft.yaml new file mode 100644 index 00000000000000..691b7886a88cc6 --- /dev/null +++ b/src/installer/pkg/snap/7.0/snapcraft.yaml @@ -0,0 +1,44 @@ +name: dotnet-runtime-70 +base: core18 +version: 7.0.5 +summary: Cross-Platform .NET Core Runtime. +description: | + .NET Core runtimes and libraries which are optimized for running .NET Core apps in production. See https://dot.net/core. + .NET Core is a general purpose development platform maintained by Microsoft. + +grade: stable +confinement: strict + +apps: + dotnet: + command: dotnet + plugs: + - network + - network-bind + - removable-media + - home + +slots: + dotnet-runtime: + content: dotnet-runtime-70 + interface: content + read: [/] + +parts: + dotnet-runtime: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/e577f9c3-cf57-4f3c-aa2f-2c0c9ce7b9c2/16911adb0b0ac64ece205a8cf96a061d/dotnet-runtime-7.0.5-linux-x64.tar.gz + source-checksum: sha512/68014bdbf55bf455f59549c7d9d61ccc051e09fe74a975ca6b46d3269278d77c9cd167ba05760aef8ab413df4212f4f5cebdd1533779b49caf517eb4ec50cce5 + stage-packages: + - libicu60 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - liblttng-ust0 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - libdb5.3 + - libc6 + diff --git a/src/installer/pkg/snap/8.0/snapcraft.yaml b/src/installer/pkg/snap/8.0/snapcraft.yaml new file mode 100644 index 00000000000000..9668cb6a0a484a --- /dev/null +++ b/src/installer/pkg/snap/8.0/snapcraft.yaml @@ -0,0 +1,44 @@ +name: dotnet-runtime-80 +base: core18 +version: 8.0.0-preview.3.23174.8 +summary: Cross-Platform .NET Core Runtime. +description: | + .NET Core runtimes and libraries which are optimized for running .NET Core apps in production. See https://dot.net/core. + .NET Core is a general purpose development platform maintained by Microsoft. + +grade: stable +confinement: strict + +apps: + dotnet: + command: dotnet + plugs: + - network + - network-bind + - removable-media + - home + +slots: + dotnet-runtime: + content: dotnet-runtime-80 + interface: content + read: [/] + +parts: + dotnet-runtime: + plugin: dump + source: https://download.visualstudio.microsoft.com/download/pr/6c4d4118-bc92-4601-b42b-2b6e91fc28f6/7b3a642aab860b394982d48bf5681243/dotnet-runtime-8.0.0-preview.3.23174.8-linux-x64.tar.gz + source-checksum: sha512/d0da20d48448c654ee548668a585b2272c661eb84ec6f845b3a49c0143ba1bfa83865f69da6bb607353a571e8c84b8e63650edf816641b1c5a55fa77a59e09be + stage-packages: + - libicu60 + - libssl1.0.0 + - libcurl3 + - libgssapi-krb5-2 + - liblttng-ust0 + - libstdc++6 + - zlib1g + - libgcc1 + - libtinfo5 + - libdb5.3 + - libc6 + From 7526a4c6a0a095670f1135d983a349b4e867f2e2 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 12 Apr 2023 18:44:56 +0200 Subject: [PATCH 09/21] JIT: Add an in-release flag to enable physical promotion (#84689) Allow customers to enable this and also to be able to measure TP in the pass. --- src/coreclr/jit/jitconfigvalues.h | 3 +++ src/coreclr/jit/promotion.cpp | 2 +- src/tests/Common/testenvironment.proj | 6 +++--- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/jitconfigvalues.h b/src/coreclr/jit/jitconfigvalues.h index 9400b3017cd5e4..49b382a96885ad 100644 --- a/src/coreclr/jit/jitconfigvalues.h +++ b/src/coreclr/jit/jitconfigvalues.h @@ -618,6 +618,9 @@ CONFIG_INTEGER(JitCFGUseDispatcher, W("JitCFGUseDispatcher"), 2) // Enable tail merging CONFIG_INTEGER(JitEnableTailMerge, W("JitEnableTailMerge"), 1) +// Enable physical promotion +CONFIG_INTEGER(JitEnablePhysicalPromotion, W("JitEnablePhysicalPromotion"), 0) + #if defined(DEBUG) // JitFunctionFile: Name of a file that contains a list of functions. If the currently compiled function is in the // file, certain other JIT config variables will be active. If the currently compiled function is not in the file, diff --git a/src/coreclr/jit/promotion.cpp b/src/coreclr/jit/promotion.cpp index e23bae7133624e..af25903693dba5 100644 --- a/src/coreclr/jit/promotion.cpp +++ b/src/coreclr/jit/promotion.cpp @@ -20,7 +20,7 @@ PhaseStatus Compiler::PhysicalPromotion() return PhaseStatus::MODIFIED_NOTHING; } - if (!compStressCompile(STRESS_PHYSICAL_PROMOTION, 25)) + if ((JitConfig.JitEnablePhysicalPromotion() == 0) && !compStressCompile(STRESS_PHYSICAL_PROMOTION, 25)) { return PhaseStatus::MODIFIED_NOTHING; } diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj index f745c2d1285852..edf656273fadc1 100644 --- a/src/tests/Common/testenvironment.proj +++ b/src/tests/Common/testenvironment.proj @@ -49,7 +49,7 @@ DOTNET_JitStress; DOTNET_JitStressProcedureSplitting; DOTNET_JitStressRegs; - DOTNET_JitStressModeNames; + DOTNET_JitEnablePhysicalPromotion; DOTNET_TailcallStress; DOTNET_ReadyToRun; DOTNET_ZapDisable; @@ -215,8 +215,8 @@ - - + + From ebe11caae43041522d990bf9a5c0b00cc909f72d Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 12 Apr 2023 12:13:28 -0700 Subject: [PATCH 10/21] Allow promotion of structs with single float fields (#84627) * Allow promotion of structs with single float fields * Ensure x86 works for storing small types * Apply formatting patch --- src/coreclr/jit/codegencommon.cpp | 97 ++++++++++++------------------- src/coreclr/jit/lclvars.cpp | 33 ++--------- 2 files changed, 42 insertions(+), 88 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index bbb324ad95ef4e..0133175b5df32f 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -2917,50 +2917,18 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere // struct regArgElem { - unsigned varNum; // index into compiler->lvaTable[] for this register argument -#if defined(UNIX_AMD64_ABI) - var_types type; // the Jit type of this regArgTab entry -#endif // defined(UNIX_AMD64_ABI) - unsigned trashBy; // index into this regArgTab[] table of the register that will be copied to this register. - // That is, for regArgTab[x].trashBy = y, argument register number 'y' will be copied to - // argument register number 'x'. Only used when circular = true. - char slot; // 0 means the register is not used for a register argument - // 1 means the first part of a register argument - // 2, 3 or 4 means the second,third or fourth part of a multireg argument - bool stackArg; // true if the argument gets homed to the stack - bool writeThru; // true if the argument gets homed to both stack and register - bool processed; // true after we've processed the argument (and it is in its final location) - bool circular; // true if this register participates in a circular dependency loop. - -#ifdef UNIX_AMD64_ABI - - // For UNIX AMD64 struct passing, the type of the register argument slot can differ from - // the type of the lclVar in ways that are not ascertainable from lvType. - // So, for that case we retain the type of the register in the regArgTab. - - var_types getRegType(Compiler* compiler) - { - return type; // UNIX_AMD64 implementation - } - -#else // !UNIX_AMD64_ABI - - // In other cases, we simply use the type of the lclVar to determine the type of the register. - var_types getRegType(Compiler* compiler) - { - const LclVarDsc* varDsc = compiler->lvaGetDesc(varNum); - // Check if this is an HFA register arg and return the HFA type - if (varDsc->lvIsHfaRegArg()) - { - // Cannot have hfa types on windows arm targets - // in vararg methods. - assert(!TargetOS::IsWindows || !compiler->info.compIsVarArgs); - return varDsc->GetHfaType(); - } - return compiler->mangleVarArgsType(varDsc->lvType); - } - -#endif // !UNIX_AMD64_ABI + unsigned varNum; // index into compiler->lvaTable[] for this register argument + var_types type; // the Jit type of this regArgTab entry + unsigned trashBy; // index into this regArgTab[] table of the register that will be copied to this register. + // That is, for regArgTab[x].trashBy = y, argument register number 'y' will be copied to + // argument register number 'x'. Only used when circular = true. + char slot; // 0 means the register is not used for a register argument + // 1 means the first part of a register argument + // 2, 3 or 4 means the second,third or fourth part of a multireg argument + bool stackArg; // true if the argument gets homed to the stack + bool writeThru; // true if the argument gets homed to both stack and register + bool processed; // true after we've processed the argument (and it is in its final location) + bool circular; // true if this register participates in a circular dependency loop. } regArgTab[max(MAX_REG_ARG + 1, MAX_FLOAT_REG_ARG)] = {}; unsigned varNum; @@ -3034,12 +3002,26 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere if (!varTypeIsStruct(regType)) #endif // defined(UNIX_AMD64_ABI) { - // A struct might be passed partially in XMM register for System V calls. - // So a single arg might use both register files. - if (emitter::isFloatReg(varDsc->GetArgReg()) != doingFloat) + bool isFloatReg = emitter::isFloatReg(varDsc->GetArgReg()); + + if (isFloatReg != doingFloat) { + // A struct might be passed partially in XMM register for System V calls. + // So a single arg might use both register files. continue; } + else if (isFloatReg != varTypeUsesFloatArgReg(regType)) + { + if (regType == TYP_FLOAT) + { + regType = TYP_INT; + } + else + { + assert(regType == TYP_DOUBLE); + regType = TYP_LONG; + } + } } int slots = 0; @@ -3187,15 +3169,13 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere regArgTab[regArgNum + i].varNum = varNum; regArgTab[regArgNum + i].slot = static_cast(i + 1); -#if defined(UNIX_AMD64_ABI) regArgTab[regArgNum + i].type = regType; // Set the register type. -#endif // defined(UNIX_AMD64_ABI) } } for (int i = 0; i < slots; i++) { - regType = regArgTab[regArgNum + i].getRegType(compiler); + regType = regArgTab[regArgNum + i].type; regNumber regNum = genMapRegArgNumToRegNum(regArgNum + i, regType); #if !defined(UNIX_AMD64_ABI) @@ -3335,7 +3315,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere noway_assert(varDsc->lvIsInReg()); noway_assert(!regArgTab[argNum].stackArg); - var_types regType = regArgTab[argNum].getRegType(compiler); + var_types regType = regArgTab[argNum].type; regNumber regNum = genMapRegArgNumToRegNum(argNum, regType); regNumber destRegNum = REG_NA; @@ -3534,7 +3514,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere } else // Not a struct type { - storeType = compiler->mangleVarArgsType(genActualType(varDsc->TypeGet())); + storeType = genActualType(regArgTab[argNum].type); } size = emitActualTypeSize(storeType); #ifdef TARGET_X86 @@ -3861,7 +3841,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere varNum = regArgTab[argNum].varNum; varDsc = compiler->lvaGetDesc(varNum); - const var_types regType = regArgTab[argNum].getRegType(compiler); + const var_types regType = regArgTab[argNum].type; const regNumber regNum = genMapRegArgNumToRegNum(argNum, regType); const var_types varRegType = varDsc->GetRegisterType(); @@ -4025,7 +4005,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere { argRegCount = 2; int nextArgNum = argNum + 1; - regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].getRegType(compiler)); + regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type); noway_assert(regArgTab[nextArgNum].varNum == varNum); // Emit a shufpd with a 0 immediate, which preserves the 0th element of the dest reg // and moves the 0th element of the src reg into the 1st element of the dest reg. @@ -4051,9 +4031,8 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere { int nextArgNum = argNum + i; LclVarDsc* fieldVarDsc = compiler->lvaGetDesc(varDsc->lvFieldLclStart + i); - regNumber nextRegNum = - genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].getRegType(compiler)); - destRegNum = fieldVarDsc->GetRegNum(); + regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type); + destRegNum = fieldVarDsc->GetRegNum(); noway_assert(regArgTab[nextArgNum].varNum == varNum); noway_assert(genIsValidFloatReg(nextRegNum)); noway_assert(genIsValidFloatReg(destRegNum)); @@ -4072,7 +4051,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere { int nextArgNum = argNum + i; regArgElem* nextArgElem = ®ArgTab[nextArgNum]; - var_types nextArgType = nextArgElem->getRegType(compiler); + var_types nextArgType = nextArgElem->type; regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, nextArgType); noway_assert(nextArgElem->varNum == varNum); noway_assert(genIsValidFloatReg(nextRegNum)); @@ -4092,7 +4071,7 @@ void CodeGen::genFnPrologCalleeRegArgs(regNumber xtraReg, bool* pXtraRegClobbere int nextArgNum = argNum + regSlot; assert(!regArgTab[nextArgNum].processed); regArgTab[nextArgNum].processed = true; - regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].getRegType(compiler)); + regNumber nextRegNum = genMapRegArgNumToRegNum(nextArgNum, regArgTab[nextArgNum].type); regArgMaskLive &= ~genRegMask(nextRegNum); } #endif // FEATURE_MULTIREG_ARGS diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index eb856cf28309b7..ebaa81610df34c 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -2119,24 +2119,6 @@ bool Compiler::StructPromotionHelper::ShouldPromoteStructVar(unsigned lclNum) JITDUMP("Not promoting multi-reg returned struct local V%02u with holes.\n", lclNum); shouldPromote = false; } -#if defined(TARGET_AMD64) || defined(TARGET_ARM64) || defined(TARGET_ARM) || defined(TARGET_LOONGARCH64) || \ - defined(TARGET_RISCV64) - // TODO-PERF - Only do this when the LclVar is used in an argument context - // TODO-ARM64 - HFA support should also eliminate the need for this. - // TODO-ARM32 - HFA support should also eliminate the need for this. - // TODO-LSRA - Currently doesn't support the passing of floating point LCL_VARS in the integer registers - // - // For now we currently don't promote structs with a single float field - // Promoting it can cause us to shuffle it back and forth between the int and - // the float regs when it is used as a argument, which is very expensive for XARCH - // - else if ((structPromotionInfo.fieldCnt == 1) && varTypeIsFloating(structPromotionInfo.fields[0].fldType)) - { - JITDUMP("Not promoting promotable struct local V%02u: #fields = %d because it is a struct with " - "single float field.\n", - lclNum, structPromotionInfo.fieldCnt); - shouldPromote = false; - } #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) else if ((structPromotionInfo.fieldCnt == 2) && (varTypeIsFloating(structPromotionInfo.fields[0].fldType) || varTypeIsFloating(structPromotionInfo.fields[1].fldType))) @@ -2147,8 +2129,7 @@ bool Compiler::StructPromotionHelper::ShouldPromoteStructVar(unsigned lclNum) lclNum, structPromotionInfo.fieldCnt); shouldPromote = false; } -#endif -#endif // TARGET_AMD64 || TARGET_ARM64 || TARGET_ARM || TARGET_LOONGARCH64 || TARGET_RISCV64 +#endif // TARGET_LOONGARCH64 || TARGET_RISCV64 else if (varDsc->lvIsParam && !compiler->lvaIsImplicitByRefLocal(lclNum) && !varDsc->lvIsHfa()) { #if FEATURE_MULTIREG_STRUCT_PROMOTE @@ -2315,20 +2296,14 @@ bool Compiler::StructPromotionHelper::TryPromoteStructField(lvaStructFieldInfo& var_types fieldVarType = JITtype2varType(fieldCorType); unsigned fieldSize = genTypeSize(fieldVarType); - // Do not promote if the field is not a primitive type, is floating-point, - // or is not properly aligned. - // - // TODO-PERF: Structs containing a single floating-point field on Amd64 - // need to be passed in integer registers. Right now LSRA doesn't support - // passing of floating-point LCL_VARS in integer registers. Enabling promotion - // of such structs results in an assert in lsra right now. + // Do not promote if the field is not a primitive type or is not properly aligned. // // TODO-CQ: Right now we only promote an actual SIMD typed field, which would cause // a nested SIMD type to fail promotion. - if (fieldSize == 0 || fieldSize > TARGET_POINTER_SIZE || varTypeIsFloating(fieldVarType)) + if (fieldSize == 0 || fieldSize > TARGET_POINTER_SIZE) { JITDUMP("Promotion blocked: struct contains struct field with one field," - " but that field has invalid size or type.\n"); + " but that field has invalid size.\n"); return false; } From a56b458ba7480e9d90aefb440d395ecda8e5198d Mon Sep 17 00:00:00 2001 From: Jeff Handley Date: Wed, 12 Apr 2023 12:41:04 -0700 Subject: [PATCH 11/21] [fabricbot] Remove PRs from Eirik/Krzysztof/Layomi/Tarek project board when moved or excluded from area pod (#84718) --- .github/fabricbot.json | 214 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 212 insertions(+), 2 deletions(-) diff --git a/.github/fabricbot.json b/.github/fabricbot.json index 1649752d219dea..61713c9487c249 100644 --- a/.github/fabricbot.json +++ b/.github/fabricbot.json @@ -12540,6 +12540,217 @@ } } }, + { + "taskSource": "fabricbot-config", + "taskType": "trigger", + "capabilityId": "IssueResponder", + "subCapability": "IssuesOnlyResponder", + "version": "1.0", + "config": { + "taskName": "[Area Pod: Eirik / Krzysztof / Layomi / Tarek - PRs] Moved to Another Area", + "actions": [ + { + "name": "removeFromProject", + "parameters": { + "projectName": "Area Pod: Eirik / Krzysztof / Layomi / Tarek - PRs", + "isOrgProject": true + } + } + ], + "eventType": "pull_request", + "eventNames": [ + "pull_request" + ], + "conditions": { + "operator": "and", + "operands": [ + { + "operator": "and", + "operands": [ + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Configuration" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Logging" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Options" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-Extensions-Primitives" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Diagnostics.Activity" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Globalization" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Collections" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.ComponentModel.DataAnnotations" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.DateTime" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.IO.Ports" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Linq" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Text.Encoding" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Text.Encodings.Web" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Text.Json" + } + } + ] + }, + { + "operator": "not", + "operands": [ + { + "name": "hasLabel", + "parameters": { + "label": "area-System.Xml" + } + } + ] + } + ] + }, + { + "name": "isAction", + "parameters": { + "action": "unlabeled" + } + }, + { + "name": "isInProject", + "parameters": { + "projectName": "Area Pod: Eirik / Krzysztof / Layomi / Tarek - PRs", + "isOrgProject": true + } + } + ] + } + } + }, { "taskSource": "fabricbot-config", "taskType": "trigger", @@ -14177,10 +14388,9 @@ "taskName": "[Area Pod: Eirik / Krzysztof / Layomi / Tarek - PRs] Excluded", "actions": [ { - "name": "moveToProjectColumn", + "name": "removeFromProject", "parameters": { "projectName": "Area Pod: Eirik / Krzysztof / Layomi / Tarek - PRs", - "columnName": "Done", "isOrgProject": true } } From 82372edee19210dfd0bf533bb25b4142043789f8 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Wed, 12 Apr 2023 14:43:31 -0500 Subject: [PATCH 12/21] Resolve ILLink warnings in System.Security.Cryptography.Xml (#84468) * Resolve ILLink warnings in System.Security.Cryptography.Xml Fix #73432 --- .../Microsoft.Extensions.Configuration.Xml.cs | 12 +++ ...rosoft.Extensions.Configuration.Xml.csproj | 4 + ...rosoft.Extensions.Configuration.Xml.csproj | 4 + .../src/XmlConfigurationExtensions.cs | 6 ++ .../src/XmlConfigurationProvider.cs | 1 + .../src/XmlConfigurationSource.cs | 1 + .../src/XmlDocumentDecryptor.cs | 3 + .../src/XmlStreamConfigurationProvider.cs | 9 +- .../src/XmlStreamConfigurationSource.cs | 1 + .../ref/System.Security.Cryptography.Xml.cs | 19 ++++ .../System.Security.Cryptography.Xml.csproj | 4 + .../src/ILLink/ILLink.Suppressions.xml | 89 ------------------- .../src/Resources/Strings.resx | 4 +- .../System.Security.Cryptography.Xml.csproj | 3 +- .../Security/Cryptography/Xml/CipherData.cs | 1 + .../Cryptography/Xml/CipherReference.cs | 1 + .../Cryptography/Xml/CryptoHelpers.cs | 4 + .../Xml/DSASignatureDescription.cs | 8 ++ .../Cryptography/Xml/EncryptedData.cs | 1 + .../Security/Cryptography/Xml/EncryptedKey.cs | 1 + .../Cryptography/Xml/EncryptedReference.cs | 1 + .../Cryptography/Xml/EncryptedType.cs | 1 + .../Security/Cryptography/Xml/EncryptedXml.cs | 8 ++ .../Security/Cryptography/Xml/KeyInfo.cs | 2 + .../Cryptography/Xml/KeyInfoEncryptedKey.cs | 1 + .../Xml/RSAPKCS1SHA1SignatureDescription.cs | 2 + .../Xml/RSAPKCS1SHA256SignatureDescription.cs | 4 + .../Xml/RSAPKCS1SHA384SignatureDescription.cs | 4 + .../Xml/RSAPKCS1SHA512SignatureDescription.cs | 4 + .../Xml/RSAPKCS1SignatureDescription.cs | 11 +++ .../Security/Cryptography/Xml/Reference.cs | 3 + .../Security/Cryptography/Xml/Signature.cs | 1 + .../Security/Cryptography/Xml/SignedInfo.cs | 1 + .../Security/Cryptography/Xml/SignedXml.cs | 13 +++ .../Cryptography/Xml/SignedXmlDebugLog.cs | 3 + .../Cryptography/Xml/TransformChain.cs | 1 + .../Xml/XmlDecryptionTransform.cs | 14 ++- .../Cryptography/Xml/XmlLicenseTransform.cs | 16 ++-- 38 files changed, 163 insertions(+), 103 deletions(-) delete mode 100644 src/libraries/System.Security.Cryptography.Xml/src/ILLink/ILLink.Suppressions.xml diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.cs index a9cfb3bb3a5f27..889044c1071661 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.cs @@ -9,28 +9,36 @@ namespace Microsoft.Extensions.Configuration public static partial class XmlConfigurationExtensions { [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, Microsoft.Extensions.FileProviders.IFileProvider? provider, string path, bool optional, bool reloadOnChange) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.Action? configureSource) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path, bool optional) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlFile(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public static Microsoft.Extensions.Configuration.IConfigurationBuilder AddXmlStream(this Microsoft.Extensions.Configuration.IConfigurationBuilder builder, System.IO.Stream stream) { throw null; } } } namespace Microsoft.Extensions.Configuration.Xml { [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public partial class XmlConfigurationProvider : Microsoft.Extensions.Configuration.FileConfigurationProvider { public XmlConfigurationProvider(Microsoft.Extensions.Configuration.Xml.XmlConfigurationSource source) : base (default(Microsoft.Extensions.Configuration.FileConfigurationSource)) { } public override void Load(System.IO.Stream stream) { } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public partial class XmlConfigurationSource : Microsoft.Extensions.Configuration.FileConfigurationSource { public XmlConfigurationSource() { } @@ -41,12 +49,15 @@ public partial class XmlDocumentDecryptor public static readonly Microsoft.Extensions.Configuration.Xml.XmlDocumentDecryptor Instance; protected XmlDocumentDecryptor() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public System.Xml.XmlReader CreateDecryptingXmlReader(System.IO.Stream input, System.Xml.XmlReaderSettings? settings) { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] protected virtual System.Xml.XmlReader DecryptDocumentAndCreateXmlReader(System.Xml.XmlDocument document) { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public partial class XmlStreamConfigurationProvider : Microsoft.Extensions.Configuration.StreamConfigurationProvider { public XmlStreamConfigurationProvider(Microsoft.Extensions.Configuration.Xml.XmlStreamConfigurationSource source) : base (default(Microsoft.Extensions.Configuration.StreamConfigurationSource)) { } @@ -54,6 +65,7 @@ public override void Load(System.IO.Stream stream) { } public static System.Collections.Generic.IDictionary Read(System.IO.Stream stream, Microsoft.Extensions.Configuration.Xml.XmlDocumentDecryptor decryptor) { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application.")] public partial class XmlStreamConfigurationSource : Microsoft.Extensions.Configuration.StreamConfigurationSource { public XmlStreamConfigurationSource() { } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.csproj b/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.csproj index 7050e3b94bcf5d..e9f36a80ea65bb 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/ref/Microsoft.Extensions.Configuration.Xml.csproj @@ -7,6 +7,10 @@ + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj index b20d79127ec2c0..7cf288a00eb842 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/Microsoft.Extensions.Configuration.Xml.csproj @@ -17,6 +17,10 @@ Link="Common\System\ThrowHelper.cs" /> + + + + diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationExtensions.cs index 8b126367451414..716dc553848ac6 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationExtensions.cs @@ -22,6 +22,7 @@ public static class XmlConfigurationExtensions /// of . /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, string path) { return AddXmlFile(builder, provider: null, path: path, optional: false, reloadOnChange: false); @@ -36,6 +37,7 @@ public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builde /// Whether the file is optional. /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, string path, bool optional) { return AddXmlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: false); @@ -51,6 +53,7 @@ public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builde /// Whether the configuration should be reloaded if the file changes. /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, string path, bool optional, bool reloadOnChange) { return AddXmlFile(builder, provider: null, path: path, optional: optional, reloadOnChange: reloadOnChange); @@ -67,6 +70,7 @@ public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builde /// Whether the configuration should be reloaded if the file changes. /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, IFileProvider? provider, string path, bool optional, bool reloadOnChange) { ThrowHelper.ThrowIfNull(builder); @@ -93,6 +97,7 @@ public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builde /// Configures the source. /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builder, Action? configureSource) => builder.Add(configureSource); @@ -103,6 +108,7 @@ public static IConfigurationBuilder AddXmlFile(this IConfigurationBuilder builde /// The to read the XML configuration data from. /// The . [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public static IConfigurationBuilder AddXmlStream(this IConfigurationBuilder builder, Stream stream) { ThrowHelper.ThrowIfNull(builder); diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationProvider.cs index bfa1ac45f06fd6..029a24c2a46d2b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationProvider.cs @@ -10,6 +10,7 @@ namespace Microsoft.Extensions.Configuration.Xml /// Represents an XML file as an . /// [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public class XmlConfigurationProvider : FileConfigurationProvider { /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationSource.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationSource.cs index cbeb47c6689e23..e6279095d1178b 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationSource.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlConfigurationSource.cs @@ -9,6 +9,7 @@ namespace Microsoft.Extensions.Configuration.Xml /// An XML file based . /// [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public class XmlConfigurationSource : FileConfigurationSource { /// diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlDocumentDecryptor.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlDocumentDecryptor.cs index 07a09cb82c467d..51bfb352228a83 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlDocumentDecryptor.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlDocumentDecryptor.cs @@ -16,6 +16,7 @@ namespace Microsoft.Extensions.Configuration.Xml public class XmlDocumentDecryptor { internal const string RequiresDynamicCodeMessage = "Microsoft.Extensions.Configuration.Xml can use EncryptedXml which may contain XSLTs in the xml. XSLTs require dynamic code."; + internal const string RequiresUnreferencedCodeMessage = "Microsoft.Extensions.Configuration.Xml can use EncryptedXml. If you use encrypted XML files, your application might not have the algorithm implementations it needs. To avoid this problem, one option you can use is a DynamicDependency attribute to keep the algorithm implementations in your application."; /// /// Accesses the singleton decryptor instance. @@ -57,6 +58,7 @@ private static bool ContainsEncryptedData(XmlDocument document) /// The settings for the new instance. /// An that decrypts data transparently. [RequiresDynamicCode(RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] public XmlReader CreateDecryptingXmlReader(Stream input, XmlReaderSettings? settings) { // XML-based configurations aren't really all that big, so we can buffer @@ -97,6 +99,7 @@ public XmlReader CreateDecryptingXmlReader(Stream input, XmlReaderSettings? sett /// An XmlReader which can read the document. [UnsupportedOSPlatform("browser")] [RequiresDynamicCode(RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(RequiresUnreferencedCodeMessage)] protected virtual XmlReader DecryptDocumentAndCreateXmlReader(XmlDocument document) { // Perform the actual decryption step, updating the XmlDocument in-place. diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationProvider.cs index adf2a0773cc4d8..b2db3ebc0e3286 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationProvider.cs @@ -15,9 +15,14 @@ namespace Microsoft.Extensions.Configuration.Xml /// An XML file based . /// [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public class XmlStreamConfigurationProvider : StreamConfigurationProvider { - private const string NameAttributeKey = "Name"; + // work around https://github.com/dotnet/runtime/issues/81864 by splitting this into a separate class. + internal static class Consts + { + internal const string NameAttributeKey = "Name"; + } /// /// Constructor. @@ -229,7 +234,7 @@ private static void ReadAttributes(XmlReader reader, XmlConfigurationElement ele while (reader.MoveToNextAttribute()) { - if (string.Equals(reader.LocalName, NameAttributeKey, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(reader.LocalName, Consts.NameAttributeKey, StringComparison.OrdinalIgnoreCase)) { // If there is a namespace attached to current attribute if (!string.IsNullOrEmpty(reader.NamespaceURI)) diff --git a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationSource.cs b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationSource.cs index 70a39a35c4c158..8bcaee5554573e 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationSource.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Xml/src/XmlStreamConfigurationSource.cs @@ -9,6 +9,7 @@ namespace Microsoft.Extensions.Configuration.Xml /// Represents a XML file as an . /// [RequiresDynamicCode(XmlDocumentDecryptor.RequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(XmlDocumentDecryptor.RequiresUnreferencedCodeMessage)] public class XmlStreamConfigurationSource : StreamConfigurationSource { /// diff --git a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.cs b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.cs index b7412aaded369a..51c9221900827f 100644 --- a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.cs +++ b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.cs @@ -17,6 +17,7 @@ public CipherData(System.Security.Cryptography.Xml.CipherReference cipherReferen public byte[]? CipherValue { get { throw null; } set { } } public System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public void LoadXml(System.Xml.XmlElement value) { } } public sealed partial class CipherReference : System.Security.Cryptography.Xml.EncryptedReference @@ -26,6 +27,7 @@ public CipherReference(string uri) { } public CipherReference(string uri, System.Security.Cryptography.Xml.TransformChain transformChain) { } public override System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public override void LoadXml(System.Xml.XmlElement value) { } } public partial class DataObject @@ -60,6 +62,7 @@ public sealed partial class EncryptedData : System.Security.Cryptography.Xml.Enc public EncryptedData() { } public override System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public override void LoadXml(System.Xml.XmlElement value) { } } public sealed partial class EncryptedKey : System.Security.Cryptography.Xml.EncryptedType @@ -73,6 +76,7 @@ public void AddReference(System.Security.Cryptography.Xml.DataReference dataRefe public void AddReference(System.Security.Cryptography.Xml.KeyReference keyReference) { } public override System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public override void LoadXml(System.Xml.XmlElement value) { } } public abstract partial class EncryptedReference @@ -87,6 +91,7 @@ protected EncryptedReference(string uri, System.Security.Cryptography.Xml.Transf public void AddTransform(System.Security.Cryptography.Xml.Transform transform) { } public virtual System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public virtual void LoadXml(System.Xml.XmlElement value) { } } public abstract partial class EncryptedType @@ -104,6 +109,7 @@ protected EncryptedType() { } public void AddProperty(System.Security.Cryptography.Xml.EncryptionProperty ep) { } public abstract System.Xml.XmlElement GetXml(); [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public abstract void LoadXml(System.Xml.XmlElement value); } public partial class EncryptedXml @@ -126,10 +132,13 @@ public partial class EncryptedXml public const string XmlEncTripleDESKeyWrapUrl = "http://www.w3.org/2001/04/xmlenc#kw-tripledes"; public const string XmlEncTripleDESUrl = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"; [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public EncryptedXml() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public EncryptedXml(System.Xml.XmlDocument document) { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public EncryptedXml(System.Xml.XmlDocument document, System.Security.Policy.Evidence? evidence) { } public System.Security.Policy.Evidence? DocumentEvidence { get { throw null; } set { } } public System.Text.Encoding Encoding { get { throw null; } set { } } @@ -219,6 +228,7 @@ public void AddClause(System.Security.Cryptography.Xml.KeyInfoClause clause) { } public System.Collections.IEnumerator GetEnumerator() { throw null; } public System.Collections.IEnumerator GetEnumerator(System.Type requestedObjectType) { throw null; } public System.Xml.XmlElement GetXml() { throw null; } + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public void LoadXml(System.Xml.XmlElement value) { } } public abstract partial class KeyInfoClause @@ -228,6 +238,7 @@ protected KeyInfoClause() { } public abstract void LoadXml(System.Xml.XmlElement element); } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public partial class KeyInfoEncryptedKey : System.Security.Cryptography.Xml.KeyInfoClause { public KeyInfoEncryptedKey() { } @@ -301,6 +312,7 @@ public Reference(string? uri) { } public void AddTransform(System.Security.Cryptography.Xml.Transform transform) { } public System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public void LoadXml(System.Xml.XmlElement value) { } } public sealed partial class ReferenceList : System.Collections.ICollection, System.Collections.IEnumerable, System.Collections.IList @@ -344,9 +356,11 @@ public Signature() { } public void AddObject(System.Security.Cryptography.Xml.DataObject dataObject) { } public System.Xml.XmlElement GetXml() { throw null; } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public void LoadXml(System.Xml.XmlElement value) { } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public partial class SignedInfo : System.Collections.ICollection, System.Collections.IEnumerable { public SignedInfo() { } @@ -396,10 +410,13 @@ public partial class SignedXml public const string XmlDsigXsltTransformUrl = "http://www.w3.org/TR/1999/REC-xslt-19991116"; public const string XmlLicenseTransformUrl = "urn:mpeg:mpeg21:2003:01-REL-R-NS:licenseTransform"; [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public SignedXml() { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public SignedXml(System.Xml.XmlDocument document) { } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public SignedXml(System.Xml.XmlElement elem) { } [System.Diagnostics.CodeAnalysis.AllowNullAttribute] public System.Security.Cryptography.Xml.EncryptedXml EncryptedXml { get { throw null; } set { } } @@ -454,6 +471,7 @@ public void Add(System.Security.Cryptography.Xml.Transform transform) { } public System.Collections.IEnumerator GetEnumerator() { throw null; } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public partial class XmlDecryptionTransform : System.Security.Cryptography.Xml.Transform { public XmlDecryptionTransform() { } @@ -554,6 +572,7 @@ public override void LoadInnerXml(System.Xml.XmlNodeList nodeList) { } public override void LoadInput(object obj) { } } [System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute("XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code.")] + [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute("The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application.")] public partial class XmlLicenseTransform : System.Security.Cryptography.Xml.Transform { public XmlLicenseTransform() { } diff --git a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj index 899bc64c16e318..3974bdf58e004d 100644 --- a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj @@ -9,6 +9,10 @@ + + + + diff --git a/src/libraries/System.Security.Cryptography.Xml/src/ILLink/ILLink.Suppressions.xml b/src/libraries/System.Security.Cryptography.Xml/src/ILLink/ILLink.Suppressions.xml deleted file mode 100644 index d1b8e66a585313..00000000000000 --- a/src/libraries/System.Security.Cryptography.Xml/src/ILLink/ILLink.Suppressions.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.CryptoHelpers.CreateFromName``1(System.String) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.DSASignatureDescription.CreateDeformatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.DSASignatureDescription.CreateFormatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.RSAPKCS1SignatureDescription.CreateDeformatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.RSAPKCS1SignatureDescription.CreateFormatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.SignedXml.CheckSignedInfo(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2026 - member - M:System.Security.Cryptography.Xml.SignedXml.ComputeSignature - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.DSASignatureDescription.CreateDeformatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.DSASignatureDescription.CreateDigest - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.DSASignatureDescription.CreateFormatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.RSAPKCS1SignatureDescription.CreateDeformatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.RSAPKCS1SignatureDescription.CreateDigest - - - ILLink - IL2046 - member - M:System.Security.Cryptography.Xml.RSAPKCS1SignatureDescription.CreateFormatter(System.Security.Cryptography.AsymmetricAlgorithm) - - - ILLink - IL2057 - member - M:System.Security.Cryptography.Xml.SignedXml.CheckSignedInfo(System.Security.Cryptography.AsymmetricAlgorithm) - - - \ No newline at end of file diff --git a/src/libraries/System.Security.Cryptography.Xml/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Xml/src/Resources/Strings.resx index 2bd8ecd0fe14bb..924132bd04547e 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Xml/src/Resources/Strings.resx @@ -136,7 +136,7 @@ A Cipher Data element should have either a CipherValue or a CipherReference element. - Could not create hash algorithm object. + Could not create hash algorithm object. If the application has been trimmed, ensure the required algorithm implementations are preserved. Could not create the XML transformation identified by the URI {0}. @@ -184,7 +184,7 @@ Signing key is not loaded. - Symmetric algorithm is not specified. + Symmetric algorithm is not specified. If the application has been trimmed, ensure the required algorithm implementations are preserved. Cipher data is not specified. diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj b/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj index 7d3013c1c01bda..5aea1a156c97a4 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/src/System.Security.Cryptography.Xml.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) true @@ -138,6 +138,7 @@ System.Security.Cryptography.Xml.XmlLicenseTransform + diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherData.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherData.cs index 4e84778c2e7bdc..ebc7b1980d2b2a 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherData.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherData.cs @@ -95,6 +95,7 @@ internal XmlElement GetXml(XmlDocument document) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherReference.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherReference.cs index de5033266679e6..14741e3c069892 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherReference.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CipherReference.cs @@ -67,6 +67,7 @@ public override XmlElement GetXml() } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public override void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CryptoHelpers.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CryptoHelpers.cs index 40cdea30bd3504..6ea4154ca27790 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CryptoHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/CryptoHelpers.cs @@ -9,11 +9,13 @@ namespace System.Security.Cryptography.Xml { internal static class CryptoHelpers { + internal const string CreateFromNameUnreferencedCodeMessage = "The algorithm implementations referenced in the XML payload might be removed. Ensure the required algorithm implementations are preserved in your application."; internal const string XsltRequiresDynamicCodeMessage = "XmlDsigXsltTransform uses XslCompiledTransform which requires dynamic code."; private static readonly char[] _invalidChars = new char[] { ',', '`', '[', '*', '&' }; [RequiresDynamicCode(XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CreateFromNameUnreferencedCodeMessage)] private static object? CreateFromKnownName(string name) => name switch { @@ -60,6 +62,7 @@ private static XmlDsigXsltTransform CreateXmlDsigXsltTransform() } [RequiresDynamicCode(XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CreateFromNameUnreferencedCodeMessage)] public static T? CreateFromName(string? name) where T : class { if (name == null || name.IndexOfAny(_invalidChars) >= 0) @@ -76,6 +79,7 @@ private static XmlDsigXsltTransform CreateXmlDsigXsltTransform() } } + [RequiresUnreferencedCode(CreateFromNameUnreferencedCodeMessage)] [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCodeAttribute", Justification = "Only XmlDsigXsltTransform requires dynamic code. This method asserts that T is not a Transform.")] public static T? CreateNonTransformFromName(string? name) where T : class diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/DSASignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/DSASignatureDescription.cs index 2b423e681e0fbc..22b1c4c355a79b 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/DSASignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/DSASignatureDescription.cs @@ -17,6 +17,9 @@ public DSASignatureDescription() DigestAlgorithm = "SHA1"; } +#if NETCOREAPP + [RequiresUnreferencedCode("CreateDeformatter is not trim compatible because the algorithm implementation referenced by DeformatterAlgorithm might be removed.")] +#endif public sealed override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { var item = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm!)!; @@ -25,6 +28,9 @@ public sealed override AsymmetricSignatureDeformatter CreateDeformatter(Asymmetr return item; } +#if NETCOREAPP + [RequiresUnreferencedCode("CreateFormatter is not trim compatible because the algorithm implementation referenced by FormatterAlgorithm might be removed.")] +#endif public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) { var item = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm!)!; @@ -34,6 +40,8 @@ public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAl } [SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 needed for compat.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:AnnotationsMustMatchBase", + Justification = "This derived implementation doesn't require unreferenced code, like the base does.")] public sealed override HashAlgorithm CreateDigest() { return SHA1.Create(); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs index df2c077483b4ae..3de83fe10ebc08 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedData.cs @@ -9,6 +9,7 @@ namespace System.Security.Cryptography.Xml public sealed class EncryptedData : EncryptedType { [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public override void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs index 3a46f0e5bf07cd..3cd2a7bc0a35ee 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedKey.cs @@ -48,6 +48,7 @@ public void AddReference(KeyReference keyReference) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public override void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedReference.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedReference.cs index 81ccbce3b702e0..159bc6ac0b5ea9 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedReference.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedReference.cs @@ -103,6 +103,7 @@ internal XmlElement GetXml(XmlDocument document) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public virtual void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs index 85b82dd8d0d112..29aa30afacfec7 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedType.cs @@ -105,6 +105,7 @@ public virtual CipherData CipherData } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public abstract void LoadXml(XmlElement value); public abstract XmlElement GetXml(); } diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs index 9c9d3337196d9f..1e42b3a73ac9ee 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/EncryptedXml.cs @@ -77,12 +77,15 @@ public class EncryptedXml // public constructors // [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public EncryptedXml() : this(new XmlDocument()) { } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public EncryptedXml(XmlDocument document) : this(document, null) { } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public EncryptedXml(XmlDocument document, Evidence? evidence) { _document = document; @@ -303,6 +306,7 @@ public virtual byte[] GetDecryptionIV(EncryptedData encryptedData, string? symme // default behaviour is to look for keys defined by an EncryptedKey clause // either directly or through a KeyInfoRetrievalMethod, and key names in the key mapping [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public virtual SymmetricAlgorithm? GetDecryptionKey(EncryptedData encryptedData, string? symmetricAlgorithmUri) { if (encryptedData is null) @@ -391,6 +395,7 @@ public virtual byte[] GetDecryptionIV(EncryptedData encryptedData, string? symme // Try to decrypt the EncryptedKey given the key mapping [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public virtual byte[]? DecryptEncryptedKey(EncryptedKey encryptedKey) { if (encryptedKey is null) @@ -537,6 +542,7 @@ public void ClearKeyNameMappings() // Encrypts the given element with the certificate specified. The certificate is added as // an X509Data KeyInfo to an EncryptedKey (AES session key) generated randomly. [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public EncryptedData Encrypt(XmlElement inputElement, X509Certificate2 certificate) { if (inputElement is null) @@ -582,6 +588,7 @@ public EncryptedData Encrypt(XmlElement inputElement, X509Certificate2 certifica // has to be defined before calling this method. The key name is added as // a KeyNameInfo KeyInfo to an EncryptedKey (AES session key) generated randomly. [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public EncryptedData Encrypt(XmlElement inputElement, string keyName) { if (inputElement is null) @@ -665,6 +672,7 @@ public EncryptedData Encrypt(XmlElement inputElement, string keyName) // The behaviour of this method can be extended because GetDecryptionKey is virtual // the document is decrypted in place [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public void DecryptDocument() { // Look for all EncryptedData elements and decrypt them diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs index d439382ea13ee7..2beaa3eb31dbbb 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfo.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; +using System.Diagnostics.CodeAnalysis; using System.Xml; namespace System.Security.Cryptography.Xml @@ -58,6 +59,7 @@ internal XmlElement GetXml(XmlDocument xmlDocument) return keyInfoElement; } + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoEncryptedKey.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoEncryptedKey.cs index 0826866fd9874b..45329ded66a947 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoEncryptedKey.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/KeyInfoEncryptedKey.cs @@ -7,6 +7,7 @@ namespace System.Security.Cryptography.Xml { [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public class KeyInfoEncryptedKey : KeyInfoClause { private EncryptedKey? _encryptedKey; diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA1SignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA1SignatureDescription.cs index 82de982f9cd3af..e181cde89608a7 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA1SignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA1SignatureDescription.cs @@ -12,6 +12,8 @@ public RSAPKCS1SHA1SignatureDescription() : base("SHA1") } [SuppressMessage("Microsoft.Security", "CA5350", Justification = "SHA1 needed for compat.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:AnnotationsMustMatchBase", + Justification = "This derived implementation doesn't require unreferenced code, like the base does.")] public sealed override HashAlgorithm CreateDigest() { return SHA1.Create(); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA256SignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA256SignatureDescription.cs index 21c8967f563b13..08f9620e200c01 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA256SignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA256SignatureDescription.cs @@ -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. +using System.Diagnostics.CodeAnalysis; + namespace System.Security.Cryptography.Xml { internal sealed class RSAPKCS1SHA256SignatureDescription : RSAPKCS1SignatureDescription @@ -9,6 +11,8 @@ public RSAPKCS1SHA256SignatureDescription() : base("SHA256") { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:AnnotationsMustMatchBase", + Justification = "This derived implementation doesn't require unreferenced code, like the base does.")] public sealed override HashAlgorithm CreateDigest() { return SHA256.Create(); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA384SignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA384SignatureDescription.cs index 9d472c896646ff..92c7a24d6d8d80 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA384SignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA384SignatureDescription.cs @@ -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. +using System.Diagnostics.CodeAnalysis; + namespace System.Security.Cryptography.Xml { internal sealed class RSAPKCS1SHA384SignatureDescription : RSAPKCS1SignatureDescription @@ -9,6 +11,8 @@ public RSAPKCS1SHA384SignatureDescription() : base("SHA384") { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:AnnotationsMustMatchBase", + Justification = "This derived implementation doesn't require unreferenced code, like the base does.")] public sealed override HashAlgorithm CreateDigest() { return SHA384.Create(); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA512SignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA512SignatureDescription.cs index 0bc99fcc6c1b6e..3be4740315353a 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA512SignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SHA512SignatureDescription.cs @@ -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. +using System.Diagnostics.CodeAnalysis; + namespace System.Security.Cryptography.Xml { internal sealed class RSAPKCS1SHA512SignatureDescription : RSAPKCS1SignatureDescription @@ -9,6 +11,8 @@ public RSAPKCS1SHA512SignatureDescription() : base("SHA512") { } + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2046:AnnotationsMustMatchBase", + Justification = "This derived implementation doesn't require unreferenced code, like the base does.")] public sealed override HashAlgorithm CreateDigest() { return SHA512.Create(); diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SignatureDescription.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SignatureDescription.cs index 9c48c3172d45fe..6d5a8fd733e03a 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SignatureDescription.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/RSAPKCS1SignatureDescription.cs @@ -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. +using System.Diagnostics.CodeAnalysis; + namespace System.Security.Cryptography.Xml { internal abstract class RSAPKCS1SignatureDescription : SignatureDescription @@ -13,6 +15,9 @@ public RSAPKCS1SignatureDescription(string hashAlgorithmName) DigestAlgorithm = hashAlgorithmName; } +#if NETCOREAPP + [RequiresUnreferencedCode("CreateDeformatter is not trim compatible because the algorithm implementation referenced by DeformatterAlgorithm might be removed.")] +#endif public sealed override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { var item = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm!)!; @@ -21,6 +26,9 @@ public sealed override AsymmetricSignatureDeformatter CreateDeformatter(Asymmetr return item; } +#if NETCOREAPP + [RequiresUnreferencedCode("CreateFormatter is not trim compatible because the algorithm implementation referenced by FormatterAlgorithm might be removed.")] +#endif public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) { var item = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm!)!; @@ -29,6 +37,9 @@ public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAl return item; } +#if NETCOREAPP + [RequiresUnreferencedCode("CreateDigest is not trim compatible because the algorithm implementation referenced by DigestAlgorithm might be removed.")] +#endif public abstract override HashAlgorithm CreateDigest(); } } diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs index 1cf008b3f468ee..a0dc3399730e19 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Reference.cs @@ -203,6 +203,7 @@ internal XmlElement GetXml(XmlDocument document) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public void LoadXml(XmlElement value) { if (value is null) @@ -333,6 +334,7 @@ public void AddTransform(Transform transform) TransformChain.Add(transform); } + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal void UpdateHashValue(XmlDocument document, CanonicalXmlNodeList refList) { DigestValue = CalculateHashValue(document, refList); @@ -340,6 +342,7 @@ internal void UpdateHashValue(XmlDocument document, CanonicalXmlNodeList refList // What we want to do is pump the input through the TransformChain and then // hash the output of the chain document is the document context for resolving relative references + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal byte[]? CalculateHashValue(XmlDocument document, CanonicalXmlNodeList refList) { // refList is a list of elements that might be targets of references diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Signature.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Signature.cs index 50d7e67c659d69..89485f83f534b8 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Signature.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Signature.cs @@ -130,6 +130,7 @@ internal XmlElement GetXml(XmlDocument document) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedInfo.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedInfo.cs index 654e4787ed1ecb..20b55828d594e0 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedInfo.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedInfo.cs @@ -8,6 +8,7 @@ namespace System.Security.Cryptography.Xml { [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public class SignedInfo : ICollection { private string? _id; diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs index d5048385e07ee6..50e13fde40d102 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXml.cs @@ -88,12 +88,14 @@ public class SignedXml // [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public SignedXml() { Initialize(null); } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public SignedXml(XmlDocument document) { if (document is null) @@ -105,6 +107,7 @@ public SignedXml(XmlDocument document) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public SignedXml(XmlElement elem) { if (elem is null) @@ -118,6 +121,7 @@ public SignedXml(XmlElement elem) [MemberNotNull(nameof(m_signature))] [MemberNotNull(nameof(_safeCanonicalizationMethods))] [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] private void Initialize(XmlElement? element) { _containingDocument = element?.OwnerDocument; @@ -178,6 +182,7 @@ public AsymmetricAlgorithm? SigningKey public EncryptedXml EncryptedXml { [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] get => _exml ??= new EncryptedXml(_containingDocument!); // default processing rules set => _exml = value; } @@ -223,6 +228,7 @@ public XmlElement GetXml() } [UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RUC")] public void LoadXml(XmlElement value) { if (value is null) @@ -380,6 +386,7 @@ public bool CheckSignature(X509Certificate2 certificate, bool verifySignatureOnl return true; } + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] public void ComputeSignature() { SignedXmlDebugLog.LogBeginSignatureComputation(this, _context!); @@ -636,6 +643,7 @@ private static bool DefaultSignatureFormatValidator(SignedXml signedXml) // Validation function to see if the current signature is signed with a truncated HMAC - one which // has a signature length of fewer bits than the whole HMAC output. + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] private bool DoesSignatureUseTruncatedHmac() { // If we're not using the SignatureLength property, then we're not truncating the signature length @@ -780,6 +788,7 @@ private static IList DefaultSafeTransformMethods } } + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] private byte[] GetC14NDigest(HashAlgorithm hash) { bool isKeyedHashAlgorithm = hash is KeyedHashAlgorithm; @@ -879,6 +888,7 @@ public int Compare(object? a, object? b) } } + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] private void BuildDigestedReferences() { // Default the DigestMethod and Canonicalization @@ -916,6 +926,7 @@ private void BuildDigestedReferences() } } + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] private bool CheckDigestedReferences() { ArrayList references = m_signature.SignedInfo!.References; @@ -1004,6 +1015,8 @@ private bool CheckSignatureFormat() return formatValid; } + [UnconditionalSuppressMessage("ILLink", "IL2026:RequiresUnreferencedCode", Justification = "ctors are marked as RDC")] + [UnconditionalSuppressMessage("ILLink", "IL2057:UnrecognizedReflectionPattern", Justification = "ctors are marked as RDC")] private bool CheckSignedInfo(AsymmetricAlgorithm key) { if (key is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs index 334491e4c3147d..ae73934b343584 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs @@ -677,6 +677,7 @@ internal static void LogSigning(SignedXml signedXml, KeyedHashAlgorithm key) /// /// SignedXml object driving the signature /// Reference being hashed + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal static void LogSigningReference(SignedXml signedXml, Reference reference) { Debug.Assert(signedXml != null, "signedXml != null"); @@ -807,6 +808,7 @@ internal static void LogVerifyReference(SignedXml signedXml, Reference reference /// reference being verified /// actual hash value of the reference /// hash value the signature expected the reference to have + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal static void LogVerifyReferenceHash(SignedXml signedXml, Reference reference, byte[]? actualHash, @@ -1025,6 +1027,7 @@ internal static void LogVerifyX509Chain(SignedXml signedXml, X509Chain chain, X5 /// /// SignedXml object verifying the signature /// reference being verified + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal static void LogSignedXmlRecursionLimit(SignedXml signedXml, Reference reference) { diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/TransformChain.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/TransformChain.cs index 00998dde429856..8022ba73c8f879 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/TransformChain.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/TransformChain.cs @@ -168,6 +168,7 @@ internal XmlElement GetXml(XmlDocument document, string ns) } [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] internal void LoadXml(XmlElement value) { if (value is null) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs index a844a0937b18ae..ff57f6e7170303 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlDecryptionTransform.cs @@ -12,6 +12,7 @@ namespace System.Security.Cryptography.Xml // and XML Encryption when performed on the same document. [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public class XmlDecryptionTransform : Transform { private readonly Type[] _inputTypes = { typeof(Stream), typeof(XmlDocument) }; @@ -21,7 +22,12 @@ public class XmlDecryptionTransform : Transform private EncryptedXml? _exml; // defines the XML encryption processing rules private XmlDocument? _containingDocument; private XmlNamespaceManager? _nsm; - private const string XmlDecryptionTransformNamespaceUrl = "http://www.w3.org/2002/07/decrypt#"; + + // work around https://github.com/dotnet/runtime/issues/81864 by splitting this into a separate class. + internal static class Consts + { + internal const string XmlDecryptionTransformNamespaceUrl = "http://www.w3.org/2002/07/decrypt#"; + } public XmlDecryptionTransform() { @@ -90,10 +96,10 @@ public override void LoadInnerXml(XmlNodeList nodeList) XmlElement? elem = node as XmlElement; if (elem != null) { - if (elem.LocalName == "Except" && elem.NamespaceURI == XmlDecryptionTransformNamespaceUrl) + if (elem.LocalName == "Except" && elem.NamespaceURI == Consts.XmlDecryptionTransformNamespaceUrl) { // the Uri is required - string? uri = Utils.GetAttribute(elem, "URI", XmlDecryptionTransformNamespaceUrl); + string? uri = Utils.GetAttribute(elem, "URI", Consts.XmlDecryptionTransformNamespaceUrl); if (uri == null || uri.Length == 0 || uri[0] != '#') throw new CryptographicException(SR.Cryptography_Xml_UriRequired); if (!Utils.VerifyAttributes(elem, "URI")) @@ -121,7 +127,7 @@ public override void LoadInnerXml(XmlNodeList nodeList) element.SetAttribute("Algorithm", Algorithm); foreach (string uri in ExceptUris) { - XmlElement exceptUriElement = document.CreateElement("Except", XmlDecryptionTransformNamespaceUrl); + XmlElement exceptUriElement = document.CreateElement("Except", Consts.XmlDecryptionTransformNamespaceUrl); exceptUriElement.SetAttribute("URI", uri); element.AppendChild(exceptUriElement); } diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs index 536dc9f2e6b22a..e58d6c4df95f96 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/XmlLicenseTransform.cs @@ -8,6 +8,7 @@ namespace System.Security.Cryptography.Xml { [RequiresDynamicCode(CryptoHelpers.XsltRequiresDynamicCodeMessage)] + [RequiresUnreferencedCode(CryptoHelpers.CreateFromNameUnreferencedCodeMessage)] public class XmlLicenseTransform : Transform { private readonly Type[] _inputTypes = { typeof(XmlDocument) }; @@ -15,8 +16,13 @@ public class XmlLicenseTransform : Transform private XmlNamespaceManager? _namespaceManager; private XmlDocument? _license; private IRelDecryptor? _relDecryptor; - private const string ElementIssuer = "issuer"; - private const string NamespaceUriCore = "urn:mpeg:mpeg21:2003:01-REL-R-NS"; + + // work around https://github.com/dotnet/runtime/issues/81864 by splitting these into a separate class. + internal static class Consts + { + internal const string ElementIssuer = "issuer"; + internal const string NamespaceUriCore = "urn:mpeg:mpeg21:2003:01-REL-R-NS"; + } public XmlLicenseTransform() { @@ -131,7 +137,7 @@ public override void LoadInput(object obj) _namespaceManager = new XmlNamespaceManager(_license.NameTable); _namespaceManager.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl); _namespaceManager.AddNamespace("enc", EncryptedXml.XmlEncNamespaceUrl); - _namespaceManager.AddNamespace("r", NamespaceUriCore); + _namespaceManager.AddNamespace("r", Consts.NamespaceUriCore); XmlElement? currentIssuerContext; XmlElement? currentLicenseContext; @@ -158,8 +164,8 @@ public override void LoadInput(object obj) if (issuerList[i]! == currentIssuerContext) continue; - if ((issuerList[i]!.LocalName == ElementIssuer) && - (issuerList[i]!.NamespaceURI == NamespaceUriCore)) + if ((issuerList[i]!.LocalName == Consts.ElementIssuer) && + (issuerList[i]!.NamespaceURI == Consts.NamespaceUriCore)) issuerList[i]!.ParentNode!.RemoveChild(issuerList[i]!); } From 3be7ac129bc35931f6987e0303b5d8e6b9c74ee2 Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 12 Apr 2023 13:26:40 -0700 Subject: [PATCH 13/21] Reduce test projects and remove usage of Newtonsoft.Json in StartupHook tests (#84652) --- .../PortableApp/PortableApp.csproj | 4 - .../TestProjects/PortableApp/Program.cs | 14 +- .../PortableAppWithMissingRef.csproj | 23 ---- .../PortableAppWithMissingRef/Program.cs | 20 --- .../SharedLibrary/ReferenceLibrary.csproj | 10 -- .../SharedLibrary/SharedLibrary.cs | 14 -- .../StartupHookWithAssemblyResolver.cs | 41 ++++-- .../StartupHookWithDependency.cs | 18 --- .../StartupHookWithDependency.csproj | 12 -- .../HostActivation.Tests/StartupHooks.cs | 129 ++++-------------- 10 files changed, 66 insertions(+), 219 deletions(-) delete mode 100644 src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj delete mode 100644 src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/Program.cs delete mode 100644 src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj delete mode 100644 src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/SharedLibrary.cs delete mode 100644 src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.cs delete mode 100644 src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj diff --git a/src/installer/tests/Assets/TestProjects/PortableApp/PortableApp.csproj b/src/installer/tests/Assets/TestProjects/PortableApp/PortableApp.csproj index 9cf6012fd61b7c..f413febe3ff59a 100644 --- a/src/installer/tests/Assets/TestProjects/PortableApp/PortableApp.csproj +++ b/src/installer/tests/Assets/TestProjects/PortableApp/PortableApp.csproj @@ -6,8 +6,4 @@ $(MNAVersion) - - - - diff --git a/src/installer/tests/Assets/TestProjects/PortableApp/Program.cs b/src/installer/tests/Assets/TestProjects/PortableApp/Program.cs index bde1de9cb84e2c..7931560f6c44b8 100644 --- a/src/installer/tests/Assets/TestProjects/PortableApp/Program.cs +++ b/src/installer/tests/Assets/TestProjects/PortableApp/Program.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Loader; namespace PortableApp { @@ -14,9 +16,15 @@ public static void Main(string[] args) Console.WriteLine(string.Join(Environment.NewLine, args)); Console.WriteLine(RuntimeInformation.FrameworkDescription); - // A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly - var t = typeof(Newtonsoft.Json.JsonReader); - System.Diagnostics.Trace.WriteLine(t); + if (args.Length == 0) + return; + + if (args[0] == "load_shared_library") + { + var asm = AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName("SharedLibrary")); + FieldInfo field = asm.GetType("SharedLibrary.SharedType").GetField("Value"); + Console.WriteLine($"SharedLibrary.SharedType.Value={field.GetValue(null)}"); + } } } } diff --git a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj b/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj deleted file mode 100644 index 17d3f0556923de..00000000000000 --- a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/PortableAppWithMissingRef.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - $(NetCoreAppCurrent) - Exe - $(MNAVersion) - false - - - - - - - - - - False - - - - diff --git a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/Program.cs b/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/Program.cs deleted file mode 100644 index 249ff017708af7..00000000000000 --- a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/Program.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using SharedLibrary; - -namespace PortableApp -{ - public static class Program - { - public static int Main(string[] args) - { - // Returns 1 if using the reference assembly, and 2 if - // using the assembly injected by the startup hook. This - // should never actually use the reference assembly, which - // is not published with the app. - return SharedType.Value; - } - } -} diff --git a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj b/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj deleted file mode 100644 index 715eb5425edb00..00000000000000 --- a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/ReferenceLibrary.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - $(NetCoreAppCurrent) - Library - $(MNAVersion) - SharedLibrary - - - diff --git a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/SharedLibrary.cs b/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/SharedLibrary.cs deleted file mode 100644 index b13fad58d26b6d..00000000000000 --- a/src/installer/tests/Assets/TestProjects/PortableAppWithMissingRef/SharedLibrary/SharedLibrary.cs +++ /dev/null @@ -1,14 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace SharedLibrary -{ - public class SharedType - { - // This is only used as a reference library for a portable - // app. It will never be called. - public static int Value = 1; - } -} diff --git a/src/installer/tests/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.cs b/src/installer/tests/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.cs index 78dd0a00496864..473f0174f6f4bb 100644 --- a/src/installer/tests/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.cs +++ b/src/installer/tests/Assets/TestProjects/StartupHookWithAssemblyResolver/StartupHookWithAssemblyResolver.cs @@ -4,29 +4,42 @@ using System; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.Loader; internal class StartupHook { public static void Initialize() { - AssemblyLoadContext.Default.Resolving += SharedHostPolicy.SharedAssemblyResolver.Resolve; + Console.WriteLine($"Hello from startup hook in {(typeof(StartupHook).Assembly.GetName().Name)}!"); + + bool addResolver = Environment.GetEnvironmentVariable("TEST_STARTUPHOOK_ADD_RESOLVER") == true.ToString(); + if (addResolver) + { + AssemblyLoadContext.Default.Resolving += OnResolving; + } + + bool useDependency = Environment.GetEnvironmentVariable("TEST_STARTUPHOOK_USE_DEPENDENCY") == true.ToString(); + if (useDependency) + { + UseDependency(); + } } -} -namespace SharedHostPolicy -{ - public class SharedAssemblyResolver + [MethodImpl(MethodImplOptions.NoInlining)] + private static void UseDependency() { - public static Assembly Resolve(AssemblyLoadContext context, AssemblyName assemblyName) - { - if (assemblyName.Name == "SharedLibrary") - { - string startupHookDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - string sharedLibrary = Path.GetFullPath(Path.Combine(startupHookDirectory, "SharedLibrary.dll")); - return AssemblyLoadContext.Default.LoadFromAssemblyPath(sharedLibrary); - } + Console.WriteLine($"SharedLibrary.Value: {SharedLibrary.SharedType.Value}"); + } + + private static Assembly OnResolving(AssemblyLoadContext context, AssemblyName assemblyName) + { + if (assemblyName.Name != "SharedLibrary") return null; - } + + Console.WriteLine($"Resolving {assemblyName.Name} in startup hook"); + string startupHookDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + string sharedLibrary = Path.GetFullPath(Path.Combine(startupHookDirectory, "SharedLibrary.dll")); + return AssemblyLoadContext.Default.LoadFromAssemblyPath(sharedLibrary); } } diff --git a/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.cs b/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.cs deleted file mode 100644 index dddc9580c3b747..00000000000000 --- a/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -internal class StartupHook -{ - public static void Initialize() - { - // This startup hook can pass or fail depending on whether the - // app comes with Newtonsoft.Json. - Console.WriteLine("Hello from startup hook with dependency!"); - - // A small operation involving NewtonSoft.Json to ensure the assembly is loaded properly - var t = typeof(Newtonsoft.Json.JsonReader); - System.Diagnostics.Trace.WriteLine(t); - } -} diff --git a/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj b/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj deleted file mode 100644 index 48714afea7d924..00000000000000 --- a/src/installer/tests/Assets/TestProjects/StartupHookWithDependency/StartupHookWithDependency.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - $(NetCoreAppCurrent) - $(MNAVersion) - - - - - - - diff --git a/src/installer/tests/HostActivation.Tests/StartupHooks.cs b/src/installer/tests/HostActivation.Tests/StartupHooks.cs index 61b6c24cc4fe52..10f1093dbf820d 100644 --- a/src/installer/tests/HostActivation.Tests/StartupHooks.cs +++ b/src/installer/tests/HostActivation.Tests/StartupHooks.cs @@ -28,7 +28,7 @@ public void Muxer_activation_of_RuntimeConfig_StartupHook_Succeeds() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - var startupHookFixture = sharedTestState.StartupHookFixture.Copy(); + var startupHookFixture = sharedTestState.StartupHookFixture; var startupHookDll = startupHookFixture.TestProject.AppDll; RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson) @@ -52,14 +52,14 @@ public void Muxer_activation_of_RuntimeConfig_And_Environment_StartupHooks_Succe var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - var startupHookFixture = sharedTestState.StartupHookFixture.Copy(); + var startupHookFixture = sharedTestState.StartupHookFixture; var startupHookDll = startupHookFixture.TestProject.AppDll; RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson) .WithProperty(startupHookRuntimeConfigName, startupHookDll) .Save(); - var startupHook2Fixture = sharedTestState.StartupHookWithDependencyFixture.Copy(); + var startupHook2Fixture = sharedTestState.StartupHookWithAssemblyResolver; var startupHook2Dll = startupHook2Fixture.TestProject.AppDll; // include any char to counter output from other threads such as in #57243 @@ -72,9 +72,9 @@ public void Muxer_activation_of_RuntimeConfig_And_Environment_StartupHooks_Succe .CaptureStdErr() .Execute() .Should().Pass() - .And.HaveStdOutMatching("Hello from startup hook with dependency!" + + .And.HaveStdOutMatching($"Hello from startup hook in {startupHook2Fixture.TestProject.AssemblyName}!" + wildcardPattern + - "Hello from startup hook!" + + $"Hello from startup hook!" + wildcardPattern + "Hello World"); } @@ -83,7 +83,7 @@ public void Muxer_activation_of_RuntimeConfig_And_Environment_StartupHooks_Succe [Fact] public void Muxer_activation_of_Empty_StartupHook_Variable_Succeeds() { - var fixture = sharedTestState.PortableAppFixture.Copy(); + var fixture = sharedTestState.PortableAppFixture; var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; @@ -102,90 +102,47 @@ public void Muxer_activation_of_Empty_StartupHook_Variable_Succeeds() [Fact] public void Muxer_activation_of_StartupHook_With_Missing_Dependencies_Fails() { - var fixture = sharedTestState.PortableAppWithExceptionFixture.Copy(); + var fixture = sharedTestState.PortableAppFixture; var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - var startupHookFixture = sharedTestState.StartupHookWithDependencyFixture.Copy(); + var startupHookFixture = sharedTestState.StartupHookWithAssemblyResolver; var startupHookDll = startupHookFixture.TestProject.AppDll; // Startup hook has a dependency not on the TPA list dotnet.Exec(appDll) .EnvironmentVariable(startupHookVarName, startupHookDll) + // Indicate that the startup hook should try to use a dependency + .EnvironmentVariable("TEST_STARTUPHOOK_USE_DEPENDENCY", true.ToString()) .CaptureStdOut() .CaptureStdErr() .Execute(expectedToFail: true) .Should().Fail() - .And.HaveStdErrContaining("System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json"); - } - - private static void RemoveLibraryFromDepsJson(string depsJsonPath, string libraryName) - { - DependencyContext context; - using (FileStream fileStream = File.Open(depsJsonPath, FileMode.Open)) - { - using (DependencyContextJsonReader reader = new DependencyContextJsonReader()) - { - context = reader.Read(fileStream); - } - } - - context = new DependencyContext(context.Target, - context.CompilationOptions, - context.CompileLibraries, - context.RuntimeLibraries.Select(lib => new RuntimeLibrary( - lib.Type, - lib.Name, - lib.Version, - lib.Hash, - lib.RuntimeAssemblyGroups.Select(assemblyGroup => new RuntimeAssetGroup( - assemblyGroup.Runtime, - assemblyGroup.RuntimeFiles.Where(f => !f.Path.EndsWith("SharedLibrary.dll")))).ToList().AsReadOnly(), - lib.NativeLibraryGroups, - lib.ResourceAssemblies, - lib.Dependencies, - lib.Serviceable, - lib.Path, - lib.HashPath, - lib.RuntimeStoreManifestName)), - context.RuntimeGraph); - - using (FileStream fileStream = File.Open(depsJsonPath, FileMode.Truncate, FileAccess.Write)) - { - DependencyContextWriter writer = new DependencyContextWriter(); - writer.Write(context, fileStream); - } + .And.HaveStdErrContaining("System.IO.FileNotFoundException: Could not load file or assembly 'SharedLibrary"); } // Run startup hook that adds an assembly resolver [Fact] public void Muxer_activation_of_StartupHook_With_Assembly_Resolver() { - var fixture = sharedTestState.PortableAppWithMissingRefFixture.Copy(); + var fixture = sharedTestState.PortableAppFixture; var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - var appDepsJson = Path.Combine(Path.GetDirectoryName(appDll), Path.GetFileNameWithoutExtension(appDll) + ".deps.json"); - RemoveLibraryFromDepsJson(appDepsJson, "SharedLibrary.dll"); - var startupHookFixture = sharedTestState.StartupHookWithAssemblyResolver.Copy(); + var startupHookFixture = sharedTestState.StartupHookWithAssemblyResolver; var startupHookDll = startupHookFixture.TestProject.AppDll; - // No startup hook results in failure due to missing app dependency - dotnet.Exec(appDll) - .CaptureStdOut() - .CaptureStdErr() - .Execute(expectedToFail: true) - .Should().Fail() - .And.HaveStdErrContaining("FileNotFoundException: Could not load file or assembly 'SharedLibrary"); - - // Startup hook with assembly resolver results in use of injected dependency (which has value 2) - dotnet.Exec(appDll) + // Startup hook with assembly resolver results in use of injected dependency + dotnet.Exec(appDll, "load_shared_library") .EnvironmentVariable(startupHookVarName, startupHookDll) + // Indicate that the startup hook should add an assembly resolver + .EnvironmentVariable("TEST_STARTUPHOOK_ADD_RESOLVER", true.ToString()) .CaptureStdOut() .CaptureStdErr() - .Execute(expectedToFail: true) - .Should().Fail() - .And.ExitWith(2); + .Execute() + .Should().Pass() + .And.HaveStdOutContaining("Resolving SharedLibrary in startup hook") + .And.HaveStdOutContaining("SharedLibrary.SharedType.Value=2"); } [Fact] @@ -195,7 +152,7 @@ public void Muxer_activation_of_StartupHook_With_IsSupported_False() var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - var startupHookFixture = sharedTestState.StartupHookFixture.Copy(); + var startupHookFixture = sharedTestState.StartupHookFixture; var startupHookDll = startupHookFixture.TestProject.AppDll; RuntimeConfig.FromFile(fixture.TestProject.RuntimeConfigJson) @@ -216,19 +173,13 @@ public void Muxer_activation_of_StartupHook_With_IsSupported_False() public class SharedTestState : IDisposable { - // Entry point projects + // Entry point project public TestProjectFixture PortableAppFixture { get; } - public TestProjectFixture PortableAppWithExceptionFixture { get; } - // Entry point with missing reference assembly - public TestProjectFixture PortableAppWithMissingRefFixture { get; } - // Correct startup hooks + // Correct startup hook public TestProjectFixture StartupHookFixture { get; } - // Valid startup hooks with incorrect behavior - public TestProjectFixture StartupHookWithDependencyFixture { get; } - - // Startup hook with an assembly resolver + // Startup hook that can be configured to add an assembly resolver or use a dependency public TestProjectFixture StartupHookWithAssemblyResolver { get; } public RepoDirectoriesProvider RepoDirectories { get; } @@ -237,30 +188,17 @@ public SharedTestState() { RepoDirectories = new RepoDirectoriesProvider(); - // Entry point projects + // Entry point project PortableAppFixture = new TestProjectFixture("PortableApp", RepoDirectories) .EnsureRestored() .PublishProject(); - PortableAppWithExceptionFixture = new TestProjectFixture("PortableAppWithException", RepoDirectories) - .EnsureRestored() - .PublishProject(); - // Entry point with missing reference assembly - PortableAppWithMissingRefFixture = new TestProjectFixture("PortableAppWithMissingRef", RepoDirectories) - .EnsureRestored() - .PublishProject(); - - // Correct startup hooks + // Correct startup hook StartupHookFixture = new TestProjectFixture("StartupHook", RepoDirectories) .EnsureRestored() .PublishProject(); - // Valid startup hooks with incorrect behavior - StartupHookWithDependencyFixture = new TestProjectFixture("StartupHookWithDependency", RepoDirectories) - .EnsureRestored() - .PublishProject(); - - // Startup hook with an assembly resolver + // Startup hook that can be configured to add an assembly resolver or use a dependency StartupHookWithAssemblyResolver = new TestProjectFixture("StartupHookWithAssemblyResolver", RepoDirectories) .EnsureRestored() .PublishProject(); @@ -268,19 +206,8 @@ public SharedTestState() public void Dispose() { - // Entry point projects PortableAppFixture.Dispose(); - PortableAppWithExceptionFixture.Dispose(); - // Entry point with missing reference assembly - PortableAppWithMissingRefFixture.Dispose(); - - // Correct startup hooks StartupHookFixture.Dispose(); - - // Valid startup hooks with incorrect behavior - StartupHookWithDependencyFixture.Dispose(); - - // Startup hook with an assembly resolver StartupHookWithAssemblyResolver.Dispose(); } } From 887c043eb94be364188e2b23a87efa214ea57f1e Mon Sep 17 00:00:00 2001 From: Sven Boemer Date: Wed, 12 Apr 2023 13:39:35 -0700 Subject: [PATCH 14/21] Build on CBL-mariner host with rootfs (#84148) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes the linux builds to use the new CBL-mariner build images. All of these builds are now cross-builds with a rootfs (including x64, and x64 musl). - The new images intentionally don't have binutils, so our build jobs have been updated to use llvm-based tools. This includes lld when we run nativeaot over our tests. This leads to a slight size regression, I believe due to ILCompiler not supporting `--gc-sections` with lld. - This change turns off PGO optimization because it was hitting a compiler crash when consuming and old version of profile data produced by clang9 instrumented builds (https://bugzilla.redhat.com/show_bug.cgi?id=1827282). The intention is to quickly flow the change into our optimization repo, then collect and ingest the new data so we can turn optimization back on. - The Mono LLVMAot test build is kept on the old build images, because they run the aot compiler which depends on binutils. We can probably move it to the same plan as the other legs, but I'm not familiar with the context here. cc @akoeplinger. We would at least need to fix `AS_NAME` here: https://github.com/dotnet/runtime/blob/1d2cd206f40306cbf06f3e2676e7cfa301077285/src/mono/mono/mini/aot-compiler.c#L13030 - Mono arm64 product build is kept on the old images due to https://github.com/dotnet/runtime/issues/84503. - Includes a temporary revert of https://github.com/dotnet/runtime/pull/84148/commits/d80a584ae1c1fc27d3fd24c03f755eccdd7baa99 which requires LLVM 13. - Sets arch for mono build, because our source-built LLVM doesn't target armv7a by default. Possibly related to https://salsa.debian.org/pkg-llvm-team/llvm-toolchain/-/commit/b7363248b115339c4fb838fcd3ae43671eedae0a - Allow text relocations. The lld defaults differ from ld, which will add text relocations on demand by default. See https://maskray.me/blog/2020-12-19-lld-and-gnu-linker-incompatibilities --------- Co-authored-by: Jan Vorlicek Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> Co-authored-by: Jeremy Koritzinsky Co-authored-by: Alexander Köplinger --- eng/Subsets.props | 10 +-- eng/common/cross/toolchain.cmake | 6 +- eng/liveBuilds.targets | 2 +- eng/native/build-commons.sh | 1 + eng/native/tryrun.cmake | 5 +- eng/nativepgo.targets | 3 +- eng/pipelines/common/global-build-job.yml | 10 +-- eng/pipelines/common/platform-matrix.yml | 64 +++++++++++++++++++ .../templates/pipeline-with-resources.yml | 30 +++++++-- .../build-runtime-tests-and-send-to-helix.yml | 2 +- .../templates/runtimes/build-test-job.yml | 21 ++---- .../coreclr/nativeaot-post-build-steps.yml | 2 +- .../coreclr/templates/build-jit-job.yml | 11 ---- eng/pipelines/coreclr/templates/build-job.yml | 15 +---- .../execute-trimming-tests-steps.yml | 2 +- eng/pipelines/mono/templates/build-job.yml | 4 +- .../mono/templates/xplat-pipeline-job.yml | 2 + eng/pipelines/runtime.yml | 10 +-- eng/testing/linker/project.csproj.template | 6 ++ eng/testing/tests.singlefile.targets | 3 +- src/coreclr/CMakeLists.txt | 4 ++ src/coreclr/build-runtime.sh | 2 +- src/coreclr/crossgen-corelib.proj | 8 +-- .../Microsoft.NETCore.Native.targets | 6 +- src/coreclr/pgosupport.cmake | 2 +- .../tools/aot/ILCompiler/ILCompiler.csproj | 57 +++++++++++++++++ .../tools/aot/crossgen2/crossgen2.csproj | 33 +++++++++- .../Microsoft.NETCore.App.Crossgen2.sfxproj | 6 +- .../Microsoft.NETCore.App/ReadyToRun.targets | 2 +- src/mono/CMakeLists.txt | 2 +- src/mono/mono.proj | 36 ++++++++++- .../CMakeLists.txt | 2 +- .../CMakeLists.txt | 4 +- src/tests/Directory.Build.targets | 3 + src/tests/build.proj | 1 + .../nativeaot/SmokeTests/DwarfDump/Program.cs | 6 +- .../SmokeTests/HardwareIntrinsics/Program.cs | 4 +- .../HardwareIntrinsics/X64Baseline.csproj | 3 - .../HardwareIntrinsics/x64NonVex.csproj | 3 - .../HardwareIntrinsics/x64Vex.csproj | 3 - 40 files changed, 281 insertions(+), 115 deletions(-) diff --git a/eng/Subsets.props b/eng/Subsets.props index 190a2cffa7ebe9..4af6e90f9172be 100644 --- a/eng/Subsets.props +++ b/eng/Subsets.props @@ -249,8 +249,8 @@ Category="clr" /> - - + + - + @@ -367,8 +367,8 @@ - - + + diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake index d813dde6de27ad..1c9d212d135926 100644 --- a/eng/common/cross/toolchain.cmake +++ b/eng/common/cross/toolchain.cmake @@ -76,7 +76,9 @@ elseif(TARGET_ARCH_NAME STREQUAL "s390x") set(TOOLCHAIN "s390x-linux-gnu") elseif(TARGET_ARCH_NAME STREQUAL "x64") set(CMAKE_SYSTEM_PROCESSOR x86_64) - if(LINUX) + if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl) + set(TOOLCHAIN "x86_64-alpine-linux-musl") + elseif(LINUX) set(TOOLCHAIN "x86_64-linux-gnu") if(TIZEN) set(TIZEN_TOOLCHAIN "x86_64-tizen-linux-gnu/9.2.0") @@ -279,7 +281,7 @@ endif() # Specify compile options -if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|ppc64le|riscv64|s390x)$" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU) +if((TARGET_ARCH_NAME MATCHES "^(arm|arm64|armel|armv6|ppc64le|riscv64|s390x|x64|x86)$" AND NOT ANDROID AND NOT FREEBSD) OR ILLUMOS OR HAIKU) set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN}) set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN}) diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets index 8b2e6e69893de4..286a5d9606d4e9 100644 --- a/eng/liveBuilds.targets +++ b/eng/liveBuilds.targets @@ -25,7 +25,7 @@ $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'sharedFramework')) $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'crossgen2')) $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'ilc-published')) - $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', '$(BuildArchitecture)', 'ilc')) + $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', '$(BuildArchitecture)', 'ilc')) $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'aotsdk')) $([MSBuild]::NormalizeDirectory('$(CoreCLRArtifactsPath)', 'build')) diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh index a1f8f550cdc8bb..905cc125f9286b 100755 --- a/eng/native/build-commons.sh +++ b/eng/native/build-commons.sh @@ -473,6 +473,7 @@ while :; do hostarch|-hostarch) if [[ -n "$2" ]]; then __HostArch="$2" + __ExplicitHostArch=1 shift else echo "ERROR: 'hostarch' requires a non-empty option argument" diff --git a/eng/native/tryrun.cmake b/eng/native/tryrun.cmake index 489f709d50683b..7ae283d7c10302 100644 --- a/eng/native/tryrun.cmake +++ b/eng/native/tryrun.cmake @@ -12,6 +12,7 @@ if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf OR EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/s390x-alpine-linux-musl OR EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/ppc64le-alpine-linux-musl OR EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/i586-alpine-linux-musl OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/x86_64-alpine-linux-musl OR EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/riscv64-alpine-linux-musl) set(ALPINE_LINUX 1) @@ -74,7 +75,7 @@ if(DARWIN) else() message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!") endif() -elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|armv6|arm64|loongarch64|riscv64|s390x|ppc64le|x86)$" OR FREEBSD OR ILLUMOS OR TIZEN) +elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|armv6|arm64|loongarch64|riscv64|s390x|ppc64le|x86|x64)$" OR FREEBSD OR ILLUMOS OR TIZEN) set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1) set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 0) set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0) @@ -160,6 +161,6 @@ else() message(FATAL_ERROR "Unsupported platform. OS: ${CMAKE_SYSTEM_NAME}, arch: ${TARGET_ARCH_NAME}") endif() -if(TARGET_ARCH_NAME MATCHES "^(x86|s390x|armv6|loongarch64|riscv64|ppc64le)$") +if(TARGET_ARCH_NAME MATCHES "^(x86|x64|s390x|armv6|loongarch64|riscv64|ppc64le)$") set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 0) endif() diff --git a/eng/nativepgo.targets b/eng/nativepgo.targets index 9f5984efdb6332..cfd41d5e975a8f 100644 --- a/eng/nativepgo.targets +++ b/eng/nativepgo.targets @@ -1,7 +1,8 @@ true - true + + false false false diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml index 80c263eea7c6b4..6124c13390ee6f 100644 --- a/eng/pipelines/common/global-build-job.yml +++ b/eng/pipelines/common/global-build-job.yml @@ -75,9 +75,11 @@ jobs: - name: _osParameter value: /p:RuntimeOS=linux-bionic - # Do not rename as it clashes with MSBuild property in libraries/build-native.proj - - name: _crossBuildPropertyArg - value: /p:CrossBuild=${{ parameters.crossBuild }} + - name: crossArg + value: '' + - ${{ if eq(parameters.crossBuild, true) }}: + - name: crossArg + value: '-cross' - ${{ if ne(parameters.jobParameters.crossrootfsDir, '') }}: # This is only required for cross builds. @@ -187,7 +189,7 @@ jobs: - task: CodeQL3000Init@0 displayName: Initialize CodeQL (manually-injected) - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) ${{ parameters.buildArgs }} $(_officialBuildParameter) $(_crossBuildPropertyArg) $(_cxx11Parameter) $(_buildDarwinFrameworksParameter) $(_overrideTestScriptWindowsCmdParameter) + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) $(crossArg) ${{ parameters.buildArgs }} $(_officialBuildParameter) $(_cxx11Parameter) $(_buildDarwinFrameworksParameter) $(_overrideTestScriptWindowsCmdParameter) displayName: Build product ${{ if eq(parameters.useContinueOnErrorDuringBuild, true) }}: continueOnError: ${{ parameters.shouldContinueOnError }} diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml index 6e7736b584fffa..7918cb0d137891 100644 --- a/eng/pipelines/common/platform-matrix.yml +++ b/eng/pipelines/common/platform-matrix.yml @@ -108,6 +108,7 @@ jobs: runtimeFlavor: ${{ parameters.runtimeFlavor }} buildConfig: ${{ parameters.buildConfig }} helixQueueGroup: ${{ parameters.helixQueueGroup }} + crossBuild: true ${{ insert }}: ${{ parameters.jobParameters }} # Linux musl arm @@ -222,6 +223,7 @@ jobs: runtimeFlavor: ${{ parameters.runtimeFlavor }} buildConfig: ${{ parameters.buildConfig }} helixQueueGroup: ${{ parameters.helixQueueGroup }} + crossBuild: true ${{ insert }}: ${{ parameters.jobParameters }} # Linux x86 @@ -316,6 +318,68 @@ jobs: isNonPortableSourceBuild: false ${{ insert }}: ${{ parameters.jobParameters }} +# GCC Linux x64 Build + +- ${{ if containsValue(parameters.platforms, 'gcc_linux_x64') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: linux + archType: x64 + targetRid: linux-x64 + platform: linux_x64 + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + container: debian-11-gcc12-amd64 + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + buildConfig: ${{ parameters.buildConfig }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + compilerName: gcc + ${{ insert }}: ${{ parameters.jobParameters }} + +# Mono Linux arm64 product build + +- ${{ if containsValue(parameters.platforms, 'mono_linux_arm64') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: linux + archType: arm64 + targetRid: linux-arm64 + platform: linux_arm64 + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + container: mono_linux_arm64 + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + buildConfig: ${{ parameters.buildConfig }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + crossBuild: true + ${{ insert }}: ${{ parameters.jobParameters }} + +# Mono LLVMAot test build + +- ${{ if containsValue(parameters.platforms, 'linux_x64_llvmaot') }}: + - template: xplat-setup.yml + parameters: + jobTemplate: ${{ parameters.jobTemplate }} + helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }} + variables: ${{ parameters.variables }} + osGroup: linux + archType: x64 + targetRid: linux-x64 + platform: linux_x64 + shouldContinueOnError: ${{ parameters.shouldContinueOnError }} + container: linux_x64_llvmaot + jobParameters: + runtimeFlavor: ${{ parameters.runtimeFlavor }} + buildConfig: ${{ parameters.buildConfig }} + helixQueueGroup: ${{ parameters.helixQueueGroup }} + ${{ insert }}: ${{ parameters.jobParameters }} + # Linux s390x - ${{ if containsValue(parameters.platforms, 'linux_s390x') }}: diff --git a/eng/pipelines/common/templates/pipeline-with-resources.yml b/eng/pipelines/common/templates/pipeline-with-resources.yml index de16160c88be75..d9222efc1a8dd0 100644 --- a/eng/pipelines/common/templates/pipeline-with-resources.yml +++ b/eng/pipelines/common/templates/pipeline-with-resources.yml @@ -5,7 +5,7 @@ parameters: resources: containers: - container: linux_arm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-arm + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm-20230410173854-290f679 env: ROOTFS_DIR: /crossrootfs/arm @@ -14,21 +14,29 @@ resources: env: ROOTFS_DIR: /crossrootfs/armv6 - - container: linux_arm64 + # Use old build images until we can avoid a clang-12 crash: https://github.com/dotnet/runtime/issues/84503 + - container: mono_linux_arm64 image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-20.04-cross-arm64 env: ROOTFS_DIR: /crossrootfs/arm64 + - container: linux_arm64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64-20230410173854-2288685 + env: + ROOTFS_DIR: /crossrootfs/arm64 + - container: linux_musl_x64 - image: mcr.microsoft.com/dotnet-buildtools/prereqs:alpine-3.13-WithNode + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-alpine-20230410173854-2288685 + env: + ROOTFS_DIR: /crossrootfs/x64 - container: linux_musl_arm - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-cross-arm-alpine + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm-alpine-20230410173854-290f679 env: ROOTFS_DIR: /crossrootfs/arm - container: linux_musl_arm64 - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-22.04-cross-arm64-alpine + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-arm64-alpine-20230410173854-2288685 env: ROOTFS_DIR: /crossrootfs/arm64 # This container contains all required toolsets to build for Android and for Linux with bionic libc. @@ -37,10 +45,12 @@ resources: image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-android - container: linux_x64 - image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-amd64-20230410173854-2288685 + env: + ROOTFS_DIR: /crossrootfs/x64 - container: linux_x86 - image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-x86-linux + image: mcr.microsoft.com/dotnet-buildtools/prereqs:cbl-mariner-2.0-cross-x86-20230410173854-2288685 env: ROOTFS_DIR: /crossrootfs/x86 @@ -59,6 +69,12 @@ resources: env: ROOTFS_DIR: /crossrootfs/ppc64le + - container: debian-11-gcc12-amd64 + image: mcr.microsoft.com/dotnet-buildtools/prereqs:debian-11-gcc12-amd64 + + - container: linux_x64_llvmaot + image: mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7 + - container: browser_wasm image: mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-webassembly-net8-20230322221728-80fdceb diff --git a/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml b/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml index 651ecdeed5b4f6..174832216912bd 100644 --- a/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml +++ b/eng/pipelines/common/templates/runtimes/build-runtime-tests-and-send-to-helix.yml @@ -33,7 +33,7 @@ steps: - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) ci ${{ parameters.archType }} $(buildConfigUpper) $(priorityArg) $(runtimeFlavorArgs) ${{ parameters.testBuildArgs }} $(runtimeVariantArg) /p:LibrariesConfiguration=${{ coalesce(parameters.liveLibrariesBuildConfig, parameters.buildConfig) }} displayName: Build Tests - ${{ if ne(parameters.osGroup, 'windows') }}: - - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) ci os ${{ parameters.osGroup }} ${{ parameters.archType }} $(buildConfigUpper) $(priorityArg) $(runtimeFlavorArgs) ${{ parameters.testBuildArgs }} $(runtimeVariantArg) /p:LibrariesConfiguration=${{ coalesce(parameters.liveLibrariesBuildConfig, parameters.buildConfig) }} + - script: $(Build.SourcesDirectory)/src/tests/build$(scriptExt) $(crossArg) ci os ${{ parameters.osGroup }} ${{ parameters.archType }} $(buildConfigUpper) $(priorityArg) $(runtimeFlavorArgs) ${{ parameters.testBuildArgs }} $(runtimeVariantArg) /p:LibrariesConfiguration=${{ coalesce(parameters.liveLibrariesBuildConfig, parameters.buildConfig) }} displayName: Build Tests diff --git a/eng/pipelines/common/templates/runtimes/build-test-job.yml b/eng/pipelines/common/templates/runtimes/build-test-job.yml index f5f306713fc8eb..2813c45915c5e3 100644 --- a/eng/pipelines/common/templates/runtimes/build-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/build-test-job.yml @@ -13,6 +13,7 @@ parameters: runtimeVariant: '' dependsOn: [] dependOnEvaluatePaths: false + crossBuild: false pgoType: '' ### Build managed test components (native components are getting built as part @@ -31,16 +32,13 @@ jobs: archType: ${{ parameters.archType }} osGroup: ${{ parameters.osGroup }} osSubgroup: ${{ parameters.osSubgroup }} + crossBuild: ${{ parameters.crossBuild }} container: ${{ parameters.container }} runtimeVariant: ${{ parameters.runtimeVariant }} testGroup: ${{ parameters.testGroup }} pool: ${{ parameters.pool }} dependOnEvaluatePaths: ${{ parameters.dependOnEvaluatePaths }} - - ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.compilerName, 'gcc'), not(and(eq(parameters.osGroup, 'linux'), eq(parameters.osSubgroup, '_musl'))), not(eq(parameters.osGroup, 'osx'))) }}: - compilerArg: '-clang9' - ${{ if not(and(ne(parameters.osGroup, 'windows'), ne(parameters.compilerName, 'gcc'), not(and(eq(parameters.osGroup, 'linux'), eq(parameters.osSubgroup, '_musl'))), not(eq(parameters.osGroup, 'osx')))) }}: - compilerArg: '' + compilerArg: '' # Test jobs should continue on error for internal builds ${{ if eq(variables['System.TeamProject'], 'internal') }}: @@ -74,17 +72,6 @@ jobs: value: 'libs.sfx+libs.oob+clr.iltools /p:RefOnly=true -c Release -ci' - name: compilerArg value: '' - - ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.compilerName, 'gcc')) }}: - - name: compilerArg - value: '-clang9' - # We need to use the stable version available on Alpine Linux - - ${{ if and(eq(parameters.osGroup, 'linux'), eq(parameters.osSubgroup, '_musl')) }}: - - name: compilerArg - value: '' - # AppleClang has different version scheme, so we let compiler introspection pick up the available clang from PATH - - ${{ if eq(parameters.osGroup, 'osx') }}: - - name: compilerArg - value: '' - name: runtimeFlavorArgs value: '' @@ -109,7 +96,7 @@ jobs: displayName: Install native dependencies # Build core/libraries dependencies of test build - - script: $(Build.SourcesDirectory)/build$(scriptExt) $(liveRuntimeBuildParams) $(compilerArg) + - script: $(Build.SourcesDirectory)/build$(scriptExt) $(liveRuntimeBuildParams) $(crossArg) $(compilerArg) displayName: Build coreclr/libs components needed by test build - ${{ if in(parameters.osGroup, 'osx', 'ios', 'tvos') }}: diff --git a/eng/pipelines/coreclr/nativeaot-post-build-steps.yml b/eng/pipelines/coreclr/nativeaot-post-build-steps.yml index c971d239edc9e4..491e663230fcb1 100644 --- a/eng/pipelines/coreclr/nativeaot-post-build-steps.yml +++ b/eng/pipelines/coreclr/nativeaot-post-build-steps.yml @@ -27,5 +27,5 @@ steps: # Publishing tooling doesn't support different configs between runtime and libs, so only run tests in Release config - ${{ if eq(parameters.buildConfig, 'release') }}: - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) /p:TestAssemblies=false /p:RunNativeAotTestApps=true $(_officialBuildParameter) $(_crossBuildPropertyArg) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/NativeAotTests.binlog ${{ parameters.extraTestArgs }} + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) $(crossArg) /p:TestAssemblies=false /p:RunNativeAotTestApps=true $(_officialBuildParameter) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/NativeAotTests.binlog ${{ parameters.extraTestArgs }} displayName: Run NativeAot Library Tests diff --git a/eng/pipelines/coreclr/templates/build-jit-job.yml b/eng/pipelines/coreclr/templates/build-jit-job.yml index 8aeaa489f9b1d8..1c4e4541876222 100644 --- a/eng/pipelines/coreclr/templates/build-jit-job.yml +++ b/eng/pipelines/coreclr/templates/build-jit-job.yml @@ -53,17 +53,6 @@ jobs: - name: compilerArg value: '' - - ${{ if ne(parameters.osGroup, 'windows') }}: - - name: compilerArg - value: '-clang9' - # We need to use the stable version available on Alpine Linux - - ${{ if and(eq(parameters.osGroup, 'linux'), eq(parameters.osSubgroup, '_musl')) }}: - - name: compilerArg - value: '' - # AppleClang has different version scheme, so we let compiler introspection pick up the available clang from PATH - - ${{ if eq(parameters.osGroup, 'osx') }}: - - name: compilerArg - value: '' - ${{ if eq(parameters.osGroup, 'windows') }}: - name: PythonScript diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index a7f68e34220559..e2e1e731c5fea9 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -86,17 +86,6 @@ jobs: value: '-gcc' - name: publishLogsArtifactPrefix value: 'BuildLogs_CoreCLR_GCC' - - ${{ if and(ne(parameters.osGroup, 'windows'), ne(parameters.compilerName, 'gcc')) }}: - - name: compilerArg - value: '-clang9' - # We need to use the stable version available on Alpine Linux - - ${{ if and(eq(parameters.osGroup, 'linux'), eq(parameters.osSubgroup, '_musl')) }}: - - name: compilerArg - value: '' - # AppleClang has different version scheme, so we let compiler introspection pick up the available clang from PATH - - ${{ if eq(parameters.osGroup, 'osx') }}: - - name: compilerArg - value: '' - ${{ if and(ne(variables['System.TeamProject'], 'public'), ne(variables['Build.Reason'], 'PullRequest')) }}: # Variables used to publish packages to blob feed - name: dotnetfeedUrl @@ -207,7 +196,7 @@ jobs: - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) -ci $(enforcePgoArg) $(pgoInstrumentArg) $(officialBuildIdArg) $(clrInterpreterBuildArg) $(CoreClrPgoDataArg) displayName: Build CoreCLR Runtime - - ${{ if ne(parameters.archType, 'x64') }}: + - ${{ if or(eq(parameters.crossBuild, 'true'), ne(parameters.archType, 'x64')) }}: - script: $(Build.SourcesDirectory)/src/coreclr/build-runtime$(scriptExt) $(buildConfig) $(archType) -hostarch x64 $(osArg) -ci $(compilerArg) -component crosscomponents -cmakeargs "-DCLR_CROSS_COMPONENTS_BUILD=1" $(officialBuildIdArg) $(clrRuntimePortableBuildArg) displayName: Build CoreCLR Cross-Arch Tools (Tools that run on x64 targeting x86) @@ -223,7 +212,7 @@ jobs: # Build CoreCLR Managed Components - ${{ if or(ne(parameters.osGroup, 'linux'), ne(parameters.archType, 'x86')) }}: - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.corelib+clr.nativecorelib+clr.nativeaotlibs+clr.tools+clr.packages+clr.paltestlist $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(pgoInstrumentArg) $(officialBuildIdArg) -ci + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.corelib+clr.nativecorelib+clr.nativeaotlibs+clr.tools+clr.packages+clr.paltestlist $(crossArg) $(compilerArg) -arch $(archType) $(osArg) -c $(buildConfig) $(pgoInstrumentArg) $(officialBuildIdArg) -ci displayName: Build managed product components and packages - ${{ if and(eq(parameters.osGroup, 'linux'), eq(parameters.archType, 'x86')) }}: - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.corelib $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(pgoInstrumentArg) $(officialBuildIdArg) -ci diff --git a/eng/pipelines/libraries/execute-trimming-tests-steps.yml b/eng/pipelines/libraries/execute-trimming-tests-steps.yml index a0172e2363428b..567abab0bb984e 100644 --- a/eng/pipelines/libraries/execute-trimming-tests-steps.yml +++ b/eng/pipelines/libraries/execute-trimming-tests-steps.yml @@ -4,5 +4,5 @@ parameters: steps: # Execute tests - - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) /p:TestAssemblies=false /p:TestTrimming=true $(_officialBuildParameter) $(_crossBuildPropertyArg) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/TrimmingTests.binlog ${{ parameters.extraTestArgs }} + - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -ci -arch ${{ parameters.archType }} $(_osParameter) -s libs.tests -c $(_BuildConfig) $(crossArg) /p:TestAssemblies=false /p:TestTrimming=true $(_officialBuildParameter) /bl:$(Build.SourcesDirectory)/artifacts/log/$(buildConfigUpper)/TrimmingTests.binlog ${{ parameters.extraTestArgs }} displayName: Run Trimming Tests diff --git a/eng/pipelines/mono/templates/build-job.yml b/eng/pipelines/mono/templates/build-job.yml index ddce3b6f0070ca..cdcf76143f5fdc 100644 --- a/eng/pipelines/mono/templates/build-job.yml +++ b/eng/pipelines/mono/templates/build-job.yml @@ -145,7 +145,7 @@ jobs: # Build - ${{ if ne(parameters.osGroup, 'windows') }}: - - script: ./build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) $(darwinFrameworks) + - script: ./build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts $(crossArg) -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) $(darwinFrameworks) displayName: Build product - ${{ if eq(parameters.osGroup, 'windows') }}: - script: build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) @@ -170,7 +170,7 @@ jobs: # Build packages - ${{ if ne(parameters.osGroup, 'windows') }}: - - script: ./build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) -pack $(OutputRidArg) + - script: ./build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts $(crossArg) -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) -pack $(OutputRidArg) displayName: Build nupkg - ${{ if eq(parameters.osGroup, 'windows') }}: - script: build$(scriptExt) -subset mono$(msCorDbi)+clr.hosts -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(aotCrossParameter) $(llvmParameter) -pack $(OutputRidArg) diff --git a/eng/pipelines/mono/templates/xplat-pipeline-job.yml b/eng/pipelines/mono/templates/xplat-pipeline-job.yml index addebb94903f03..2c369f71f30bb6 100644 --- a/eng/pipelines/mono/templates/xplat-pipeline-job.yml +++ b/eng/pipelines/mono/templates/xplat-pipeline-job.yml @@ -6,6 +6,7 @@ parameters: name: '' helixType: '(unspecified)' container: '' + crossBuild: false liveLibrariesBuildConfig: '' strategy: '' pool: '' @@ -34,6 +35,7 @@ jobs: name: ${{ parameters.name }} helixType: ${{ parameters.helixType }} container: ${{ parameters.container }} + crossBuild: ${{ parameters.crossBuild }} strategy: ${{ parameters.strategy }} pool: ${{ parameters.pool }} runtimeVariant: ${{ parameters.runtimeVariant }} diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml index c3903d3728b895..dfb06547eeb8af 100644 --- a/eng/pipelines/runtime.yml +++ b/eng/pipelines/runtime.yml @@ -100,11 +100,9 @@ extends: jobTemplate: /eng/pipelines/coreclr/templates/build-job.yml buildConfig: checked platforms: - - linux_x64 - container: debian-11-gcc12-amd64 + - gcc_linux_x64 jobParameters: testGroup: innerloop - compilerName: gcc condition: >- or( eq(dependencies.evaluate_paths.outputs['SetPathVars_coreclr.containsChange'], true), @@ -703,7 +701,9 @@ extends: - osx_x64 - osx_arm64 - linux_x64 - - linux_arm64 + # - linux_arm64 + # Remove once we can use linux_arm64: https://github.com/dotnet/runtime/issues/84503 + - mono_linux_arm64 # - linux_musl_arm64 - windows_x64 - windows_x86 @@ -1212,7 +1212,7 @@ extends: buildConfig: Release runtimeFlavor: mono platforms: - - linux_x64 + - linux_x64_llvmaot # Disabled pending outcome of https://github.com/dotnet/runtime/issues/60234 investigation #- linux_arm64 variables: diff --git a/eng/testing/linker/project.csproj.template b/eng/testing/linker/project.csproj.template index fe3d1ba28871e8..6dcd1c5754dd95 100644 --- a/eng/testing/linker/project.csproj.template +++ b/eng/testing/linker/project.csproj.template @@ -36,9 +36,15 @@ {IlcSdkPath} {IlcFrameworkPath} {IlcFrameworkNativePath} + lld + $(ROOTFS_DIR) {CoreCLRBuildIntegrationDir} + + + + {RuntimeHostConfigurationOptions} diff --git a/eng/testing/tests.singlefile.targets b/eng/testing/tests.singlefile.targets index 1ea8c014446c6c..821e8f93750b40 100644 --- a/eng/testing/tests.singlefile.targets +++ b/eng/testing/tests.singlefile.targets @@ -24,11 +24,12 @@ $(CoreCLRILCompilerDir) $(CoreCLRCrossILCompilerDir) - $(ROOTFS_DIR) + $(ROOTFS_DIR) $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll $(CoreCLRAotSdkDir) $(NetCoreAppCurrentTestHostSharedFrameworkPath) $(NetCoreAppCurrentTestHostSharedFrameworkPath) + lld $(NoWarn);IL1005;IL2105;IL3000;IL3001;IL3002;IL3003 partial true diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt index 67b773bf787876..d794641ebcd787 100644 --- a/src/coreclr/CMakeLists.txt +++ b/src/coreclr/CMakeLists.txt @@ -109,6 +109,10 @@ if(CLR_CMAKE_HOST_UNIX) endif() endif() + if(CLR_CMAKE_TARGET_LINUX AND CLR_CMAKE_TARGET_ARCH_I386) + add_linker_flag(-Wl,-z,notext) + endif() + if(NOT CLR_CMAKE_HOST_MACCATALYST AND NOT CLR_CMAKE_HOST_IOS AND NOT CLR_CMAKE_HOST_TVOS) add_subdirectory(pal) add_subdirectory(hosts) diff --git a/src/coreclr/build-runtime.sh b/src/coreclr/build-runtime.sh index 7399088f291d9d..2b99c9b9eed5f0 100755 --- a/src/coreclr/build-runtime.sh +++ b/src/coreclr/build-runtime.sh @@ -114,7 +114,7 @@ __IntermediatesDir="$__ArtifactsIntermediatesDir/$__ConfigTriplet" export __IntermediatesDir __ArtifactsIntermediatesDir -if [[ "$__TargetArch" != "$__HostArch" ]]; then +if [[ "$__ExplicitHostArch" == 1 ]]; then __IntermediatesDir="$__IntermediatesDir/$__HostArch" __BinDir="$__BinDir/$__HostArch" fi diff --git a/src/coreclr/crossgen-corelib.proj b/src/coreclr/crossgen-corelib.proj index 553eee0b38d37e..7c3ac1e3e47233 100644 --- a/src/coreclr/crossgen-corelib.proj +++ b/src/coreclr/crossgen-corelib.proj @@ -13,15 +13,9 @@ - - - x64 - $(BuildArchitecture) - + $(BuildArchitecture) - true - false false true diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets index 5b62b6f8906f0c..44703efeb45cdf 100644 --- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets +++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets @@ -318,8 +318,7 @@ The .NET Foundation licenses this file to you under the MIT license. - - + @@ -336,9 +335,6 @@ The .NET Foundation licenses this file to you under the MIT license. -x - - - diff --git a/src/coreclr/pgosupport.cmake b/src/coreclr/pgosupport.cmake index 71d90b49e94192..edcffea53954fb 100644 --- a/src/coreclr/pgosupport.cmake +++ b/src/coreclr/pgosupport.cmake @@ -6,7 +6,7 @@ if(NOT WIN32) # Function required to give CMAKE_REQUIRED_* local scope function(check_have_lto) set(CMAKE_REQUIRED_FLAGS -flto) - set(CMAKE_REQUIRED_LIBRARIES -flto -fuse-ld=gold) + set(CMAKE_REQUIRED_LIBRARIES -flto) check_cxx_source_compiles("int main() { return 0; }" HAVE_LTO) endfunction(check_have_lto) check_have_lto() diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj index db48433db73f85..7ffc15676e5253 100644 --- a/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler/ILCompiler.csproj @@ -13,11 +13,68 @@ false false true + $(ROOTFS_DIR) true true true + + + + <_hostOS>$(NETCoreSdkPortableRuntimeIdentifier.SubString(0, $(NETCoreSdkPortableRuntimeIdentifier.LastIndexOf('-')))) + $(_hostOS) + runtime.$(OSIdentifier)-$(IlcHostArch).Microsoft.DotNet.ILCompiler + + + + + + + + $(RuntimeIdentifier) + + + x86_64 + aarch64 + arm64 + + + $(CrossCompileArch)-linux-gnu + $(CrossCompileArch)-alpine-linux-musl + $(CrossCompileArch)-unknown-freebsd12 + + + + + + + + + + clang + + true + + + + + + + + + + + $(CoreCLRILCompilerDir) - $(CoreCLRCrossILCompilerDir) - $(ROOTFS_DIR) + $(CoreCLRCrossILCompilerDir) + $(ROOTFS_DIR) $(CoreCLRILCompilerDir)netstandard/ILCompiler.Build.Tasks.dll $(CoreCLRAotSdkDir) $(MicrosoftNetCoreAppRuntimePackRidLibTfmDir) @@ -39,6 +39,10 @@ false + + + + @@ -57,11 +61,36 @@ + + + + + $(RuntimeIdentifier) + + + x86_64 + aarch64 + arm64 + + + $(CrossCompileArch)-linux-gnu + $(CrossCompileArch)-alpine-linux-musl + $(CrossCompileArch)-unknown-freebsd12 + + + + + + + clang + lld true false - + false false - llvm-objcopy-15 - aarch64-linux-gnu-objcopy + Condition="'$(TargetOS)' == '$(HostOS)' and '$(TargetArchitecture)' == '$(BuildArchitecture)' and '$(CrossBuild)' != 'true'"> diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets b/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets index d29f12364fe24e..0b82891e6c42e4 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/ReadyToRun.targets @@ -15,7 +15,7 @@ - x64 + $(BuildArchitecture) $(CoreCLRArtifactsPath)\$(CrossDir)\crossgen2\crossgen2.dll true diff --git a/src/mono/CMakeLists.txt b/src/mono/CMakeLists.txt index 7b57776aa007c7..d9202a9cf196e5 100644 --- a/src/mono/CMakeLists.txt +++ b/src/mono/CMakeLists.txt @@ -712,7 +712,7 @@ elseif(HOST_ANDROID) elseif(HOST_LINUX) include(FindPkgConfig) if(CROSS_ROOTFS) - set(ENV{PKG_CONFIG_ICU_UC_INCLUDEDIR} "${CROSS_ROOTFS}/usr/include") + set(ENV{PKG_CONFIG_SYSROOT_DIR} "${CROSS_ROOTFS}") endif(CROSS_ROOTFS) pkg_check_modules(ICU icu-uc) set(ICU_FLAGS "-DTARGET_UNIX -DU_DISABLE_RENAMING -Wno-reserved-id-macro -Wno-documentation -Wno-documentation-unknown-command -Wno-switch-enum -Wno-covered-switch-default -Wno-extra-semi-stmt -Wno-unknown-warning-option -Wno-deprecated-declarations") diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 8e6d21c440d392..ec4168167b2834 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -105,7 +105,7 @@ - + @@ -314,6 +314,20 @@ <_MonoBuildEnv Include="PKG_CONFIG_PATH=$(MonoCrossDir)/lib/pkgconfig" /> + + + <_MonoCMakeArgs Include="-DCMAKE_TOOLCHAIN_FILE=$(CrossToolchainFile)" /> + <_MonoBuildEnv Include="TARGET_BUILD_ARCH=x64" /> + <_MonoBuildEnv Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/pkgconfig" /> + + + + + <_MonoCMakeArgs Include="-DCMAKE_TOOLCHAIN_FILE=$(CrossToolchainFile)" /> + <_MonoBuildEnv Include="TARGET_BUILD_ARCH=x86" /> + <_MonoBuildEnv Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/pkgconfig" /> + + <_MonoCMakeArgs Include="-DCMAKE_TOOLCHAIN_FILE=$(CrossToolchainFile)" /> @@ -546,11 +560,15 @@ <_MonoCFLAGS Include="-Wl,--build-id=sha1" /> + <_MonoCFLAGS Condition="'$(Platform)' == 'arm'" Include="-march=armv7-a" /> <_MonoCXXFLAGS Include="-Wl,--build-id=sha1" /> + <_MonoCXXFLAGS Condition="'$(Platform)' == 'arm'" Include="-march=armv7-a" /> <_MonoAOTCFLAGS Include="-Wl,--build-id=sha1" /> + <_MonoAOTCFLAGS Condition="'$(RealTargetArchitecture)' == 'arm'" Include="-march=armv7-a" /> <_MonoAOTCXXFLAGS Include="-Wl,--build-id=sha1" /> + <_MonoAOTCXXFLAGS Condition="'$(RealTargetArchitecture)' == 'arm'" Include="-march=armv7-a" /> @@ -659,7 +677,13 @@ <_ObjcopyPrefix Condition="'$(MonoCrossDir)' != '' and '$(Platform)' == 'riscv64' and $(_Objcopy) == ''">llvm-objcopy- - + + + + + <_Objcopy Condition="'$(_ObjcopyFound)' == '0'">llvm-objcopy + + @@ -818,6 +842,13 @@ + + + + <_MonoAotBuildEnv Include="TARGET_BUILD_ARCH=x64" /> + <_MonoAotBuildEnv Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/x86_64-linux-gnu/pkgconfig" /> + + @@ -856,6 +887,7 @@ <_MonoSkipInitCompiler Condition="'$(RealTargetArchitecture)' != '' and '$(RealTargetArchitecture)' != '$(BuildArchitecture)'">false + <_MonoSkipInitCompiler Condition="'$(CrossBuild)' == 'true'">false <_MonoAotCrossOffsetsCommand Condition="'$(MonoUseCrossTool)' == 'true'">$(PythonCmd) $(MonoProjectRoot)mono/tools/offsets-tool/offsets-tool.py @(MonoAotCrossOffsetsToolParams, ' ') <_MonoAotCMakeConfigureCommand>cmake @(MonoAOTCMakeArgs, ' ') $(MonoCMakeExtraArgs) "$(MonoProjectRoot.TrimEnd('\/'))" <_MonoAotCMakeConfigureCommand Condition="'$(_MonoSkipInitCompiler)' != 'true' and '$(HostOS)' != 'windows'">sh -c 'build_arch="$(_CompilerTargetArch)" compiler="$(MonoCCompiler)" . "$(RepositoryEngineeringCommonDir)native/init-compiler.sh" && @(_MonoAotBuildEnv, ' ') $(_MonoAotCMakeConfigureCommand)' diff --git a/src/native/libs/System.Globalization.Native/CMakeLists.txt b/src/native/libs/System.Globalization.Native/CMakeLists.txt index a895bb22755280..1614fa62b22e60 100644 --- a/src/native/libs/System.Globalization.Native/CMakeLists.txt +++ b/src/native/libs/System.Globalization.Native/CMakeLists.txt @@ -124,7 +124,7 @@ endif() install (TARGETS System.Globalization.Native-Static DESTINATION ${STATIC_LIB_DESTINATION} COMPONENT libs) -if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ANDROID) +if(NOT CLR_CMAKE_TARGET_APPLE AND NOT CLR_CMAKE_TARGET_ANDROID AND NOT CLR_CMAKE_TARGET_ALPINE_LINUX) if (GEN_SHARED_LIB) add_custom_command(TARGET System.Globalization.Native POST_BUILD COMMENT "Verifying System.Globalization.Native.so dependencies" diff --git a/src/native/libs/System.Security.Cryptography.Native/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native/CMakeLists.txt index 1b066e554ffe37..8eb0b88258ed65 100644 --- a/src/native/libs/System.Security.Cryptography.Native/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native/CMakeLists.txt @@ -98,12 +98,12 @@ set_target_properties(System.Security.Cryptography.Native.OpenSsl-Static PROPERT if (GEN_SHARED_LIB) if (FEATURE_DISTRO_AGNOSTIC_SSL) - # on macOS the link step fails with undefined symbols, and the script doesn't run. + # on macOS and Alpine the link step fails with undefined symbols, and the script doesn't run. # if the build succeeds, the script would succeed, except it uses a Linux-only command. # # on Linux, the build will succeed with undefined symbols, then the script reports them # and fails the build for us. - if (NOT APPLE) + if (NOT APPLE AND NOT CLR_CMAKE_TARGET_ALPINE_LINUX) add_custom_command(TARGET System.Security.Cryptography.Native.OpenSsl POST_BUILD COMMENT "Verifying System.Security.Cryptography.Native.OpenSsl.so dependencies" COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/../verify-so.sh diff --git a/src/tests/Directory.Build.targets b/src/tests/Directory.Build.targets index 7773f30703d562..cbeda81910e992 100644 --- a/src/tests/Directory.Build.targets +++ b/src/tests/Directory.Build.targets @@ -533,12 +533,15 @@ $(MicrosoftNetCoreAppRuntimePackNativeDir) $(OutputRid) + lld + $(ROOTFS_DIR) true true $(IlcSdkPath) + diff --git a/src/tests/build.proj b/src/tests/build.proj index 597ec67d803dab..8a00ffa945fe0c 100644 --- a/src/tests/build.proj +++ b/src/tests/build.proj @@ -486,6 +486,7 @@ $(GroupBuildCmd) /nodeReuse:false $(GroupBuildCmd) /maxcpucount $(GroupBuildCmd) /bl:$(ArtifactsDir)/log/$(Configuration)/InnerManagedTestBuild.$(__TestGroupToBuild).binlog + $(GroupBuildCmd) "/p:CrossBuild=true" $(GroupBuildCmd) "/p:DefaultBuildAllTarget=BuildNativeAot" $(GroupBuildCmd) "/p:IlcMultiModule=true" $(GroupBuildCmd) "/p:BuildNativeAotFrameworkObjects=true" diff --git a/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs b/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs index f0996dd070ea51..0096a28c92f1eb 100644 --- a/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs +++ b/src/tests/nativeaot/SmokeTests/DwarfDump/Program.cs @@ -51,11 +51,11 @@ public static int Main(string[] args) // Just count the number of warnings and errors. There are so many right now that it's not worth enumerating the list #if DEBUG - const int MinWarnings = 17000; + const int MinWarnings = 16500; const int MaxWarnings = 18500; #else - const int MinWarnings = 12000; - const int MaxWarnings = 13000; + const int MinWarnings = 9500; + const int MaxWarnings = 10500; #endif int count = 0; string line; diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs index 2cc750f188c91a..06f6a027c94dda 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/Program.cs @@ -30,12 +30,12 @@ static int Main() else { lowerBound = 1300 * 1024; // ~1.3 MB - upperBound = 1600 * 1024; // ~1.6 MB + upperBound = 1750 * 1024; // ~1.75 MB } if (fileSize < lowerBound || fileSize > upperBound) { - Console.WriteLine("BUG: File size is not in the expected range. Did a libraries change regress size of Hello World?"); + Console.WriteLine($"BUG: File size is not in the expected range ({lowerBound} to {upperBound} bytes). Did a libraries change regress size of Hello World?"); return 1; } diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj index 28fc56a41439c4..51ef171354befa 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/X64Baseline.csproj @@ -7,9 +7,6 @@ true $(DefineConstants);BASELINE_INTRINSICS true - - - objcopy diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj index c00af0ea752e47..86c1e23e9dfa51 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64NonVex.csproj @@ -7,9 +7,6 @@ true $(DefineConstants);NON_VEX_INTRINSICS true - - - objcopy diff --git a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj index 92ad8638993057..d485e9dae32cc8 100644 --- a/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj +++ b/src/tests/nativeaot/SmokeTests/HardwareIntrinsics/x64Vex.csproj @@ -7,9 +7,6 @@ true $(DefineConstants);VEX_INTRINSICS true - - - objcopy From 429105d1f194ff10e82cce35c509f609dcf8622c Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Wed, 12 Apr 2023 19:01:44 -0500 Subject: [PATCH 15/21] Revert "[wasm] Revert to using latest chrome for testing (#83150)" (#84732) This reverts commit f5fd94bef6478c143771221c19b947ac83fea870. --- eng/testing/ProvisioningVersions.props | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/eng/testing/ProvisioningVersions.props b/eng/testing/ProvisioningVersions.props index a3747316cd778c..74362b4665e659 100644 --- a/eng/testing/ProvisioningVersions.props +++ b/eng/testing/ProvisioningVersions.props @@ -41,16 +41,16 @@ these snapshot urls. --> - - - - - - - - - - + + 109.0.5414.119 + 1070088 + <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1070096 + + + 109.0.5414.120 + 1070088 + <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1070094 + 108.0.1 From fbcb1e78c9aa7c7c9895c269aa3dd5a4a299b54b Mon Sep 17 00:00:00 2001 From: Viktor Hofer Date: Thu, 13 Apr 2023 02:35:49 +0200 Subject: [PATCH 16/21] Fix source-build oob package orchestration (#84720) Regressed with https://github.com/dotnet/runtime/commit/e3c370086d9325d51eb96656dced208d9151bb0e. By replacing "net48" with `$(NetFrameworkCurrent)`, the condition became true (as both BuildTargetFramework and NetFrameworkCurrent are empty in source build) and projects were filtered out. --- src/libraries/oob-all.proj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/oob-all.proj b/src/libraries/oob-all.proj index 7974fa370604b0..1754c8b3d8a70c 100644 --- a/src/libraries/oob-all.proj +++ b/src/libraries/oob-all.proj @@ -1,6 +1,6 @@ - + $(BuildTargetFramework) true From 6875ba02dbde6477abe16f0863348e617cc03fcb Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 12 Apr 2023 17:57:56 -0700 Subject: [PATCH 17/21] Zlib: Update zlib to v1.2.13, intel-zlib to v1.2.13_jtk (#84602) --- THIRD-PARTY-NOTICES.TXT | 2 +- src/installer/pkg/THIRD-PARTY-NOTICES.TXT | 2 +- src/native/external/cgmanifest.json | 6 +- src/native/external/zlib-intel-version.txt | 21 +- src/native/external/zlib-intel/compress.c | 6 +- src/native/external/zlib-intel/crc32.c | 21 +- src/native/external/zlib-intel/deflate.c | 177 ++++++++------ .../external/zlib-intel/deflate_quick.c | 2 +- src/native/external/zlib-intel/inflate.c | 9 +- src/native/external/zlib-intel/inflate.h | 6 +- src/native/external/zlib-intel/inftrees.c | 4 +- src/native/external/zlib-intel/inftrees.h | 2 +- src/native/external/zlib-intel/trees.c | 184 ++++++++++----- src/native/external/zlib-intel/zconf.h | 19 +- src/native/external/zlib-intel/zlib.h | 22 +- src/native/external/zlib-intel/zutil.c | 16 +- src/native/external/zlib-intel/zutil.h | 1 + src/native/external/zlib-version.txt | 18 +- src/native/external/zlib/CMakeLists.txt | 42 +--- src/native/external/zlib/ChangeLog | 24 +- src/native/external/zlib/LICENSE | 22 ++ src/native/external/zlib/Makefile.in | 20 +- src/native/external/zlib/README | 4 +- src/native/external/zlib/compress.c | 6 +- src/native/external/zlib/configure | 97 ++++---- src/native/external/zlib/crc32.c | 21 +- src/native/external/zlib/deflate.c | 219 +++++++++--------- src/native/external/zlib/deflate.h | 4 +- src/native/external/zlib/gzlib.c | 2 +- src/native/external/zlib/gzread.c | 8 +- src/native/external/zlib/gzwrite.c | 2 +- src/native/external/zlib/infback.c | 17 +- src/native/external/zlib/inflate.c | 7 +- src/native/external/zlib/inftrees.c | 4 +- src/native/external/zlib/inftrees.h | 2 +- src/native/external/zlib/make_vms.com | 4 +- src/native/external/zlib/treebuild.xml | 4 +- src/native/external/zlib/trees.c | 123 +++++----- src/native/external/zlib/uncompr.c | 4 +- src/native/external/zlib/zconf.h | 19 +- src/native/external/zlib/zconf.h.cmakein | 19 +- src/native/external/zlib/zconf.h.in | 19 +- src/native/external/zlib/zlib.3 | 4 +- src/native/external/zlib/zlib.3.pdf | Bin 8848 -> 0 bytes src/native/external/zlib/zlib.h | 20 +- src/native/external/zlib/zlib2ansi | 4 +- src/native/external/zlib/zutil.c | 16 +- 47 files changed, 720 insertions(+), 535 deletions(-) create mode 100644 src/native/external/zlib/LICENSE delete mode 100644 src/native/external/zlib/zlib.3.pdf diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT index f60a240e7ee207..06c74d4c2547b4 100644 --- a/THIRD-PARTY-NOTICES.TXT +++ b/THIRD-PARTY-NOTICES.TXT @@ -73,7 +73,7 @@ https://github.com/madler/zlib https://zlib.net/zlib_license.html /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 27th, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler diff --git a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT index 1d5c53c71e550d..fcb519506d511e 100644 --- a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT +++ b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT @@ -72,7 +72,7 @@ https://github.com/madler/zlib https://zlib.net/zlib_license.html /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 27th, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler diff --git a/src/native/external/cgmanifest.json b/src/native/external/cgmanifest.json index 422a0d93aef8d1..632588412cfed0 100644 --- a/src/native/external/cgmanifest.json +++ b/src/native/external/cgmanifest.json @@ -46,7 +46,7 @@ "Type": "git", "Git": { "RepositoryUrl": "https://github.com/madler/zlib", - "CommitHash": "21767c654d31d2dccdde4330529775c6c5fd5389" + "CommitHash": "04f42ceca40f73e2978b50e93806c2a18c1281fc" } }, "DevelopmentDependency": false @@ -55,8 +55,8 @@ "Component": { "Type": "git", "Git": { - "RepositoryUrl": "https://github.com/jtkukunas/zlib", - "CommitHash": "bf55d56b068467329f5a6f29bee31bc80d694023" + "RepositoryUrl": "https://github.com/intel/zlib", + "CommitHash": "6160a8f20c3626aec2f8b0fda5bf2e65bfe31781" } }, "DevelopmentDependency": false diff --git a/src/native/external/zlib-intel-version.txt b/src/native/external/zlib-intel-version.txt index cd7dadc8cd9431..d406ffbcc459b3 100644 --- a/src/native/external/zlib-intel-version.txt +++ b/src/native/external/zlib-intel-version.txt @@ -1,13 +1,14 @@ -v1.2.12_jtk.1 -(bf55d56b068467329f5a6f29bee31bc80d694023) +v1.2.13_jtk +(6160a8f20c3626aec2f8b0fda5bf2e65bfe31781) -https://github.com/jtkukunas/zlib/releases/tag/v1.2.12_jtk.1 +https://github.com/intel/zlib/releases/tag/v1.2.13_jtk Note: This library does not use a standard release lifecycle. - We're pointing to the latest available tagged version at the time we forked the code. - -We have also cherry-picked into our local copy: -https://github.com/madler/zlib/commit/7ecf7c7458578d05a20fa481436dd5c58db112f7 - -And applied by hand the deflate_quick.c change from this commit: -https://github.com/dotnet/runtime/commit/60f6129b3eaef088f4b1ddc30d3320a68f396d85 + We're pointing to the latest available tagged version as of this writing. + +We do not pull in every file from the intel/zlib repo. Instead, some years ago, +somebody determined what they believed was the minimum set that needed to be +copied into our repo in order to build. Since then, we've just updated only +those files in-place, ignoring other files in the intel/zlib repo. If new files +are introduced which are necessary for building the product, feel free to bring +those down as well. diff --git a/src/native/external/zlib-intel/compress.c b/src/native/external/zlib-intel/compress.c index e2db404abf888b..2ad5326c14ec04 100644 --- a/src/native/external/zlib-intel/compress.c +++ b/src/native/external/zlib-intel/compress.c @@ -19,7 +19,7 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) +int ZEXPORT compress2(dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) /* =========================================================================== */ -int ZEXPORT compress (dest, destLen, source, sourceLen) +int ZEXPORT compress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen) If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -uLong ZEXPORT compressBound (sourceLen) +uLong ZEXPORT compressBound(sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + diff --git a/src/native/external/zlib-intel/crc32.c b/src/native/external/zlib-intel/crc32.c index b5de91f991bae1..49c4f1b828e525 100644 --- a/src/native/external/zlib-intel/crc32.c +++ b/src/native/external/zlib-intel/crc32.c @@ -98,13 +98,22 @@ # endif #endif +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + /* Local functions. */ local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); -/* If available, use the ARM processor CRC32 instruction. */ -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 -# define ARMCRC32 +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) @@ -645,8 +654,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x - instruction per cycle. Each CRC is calcuated on Z_BATCH words. The three - CRCs are combined into a single CRC after each set of batches. */ + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; @@ -1107,7 +1116,7 @@ uLong ZEXPORT crc32_combine_gen(len2) } /* ========================================================================= */ -uLong crc32_combine_op(crc1, crc2, op) +uLong ZEXPORT crc32_combine_op(crc1, crc2, op) uLong crc1; uLong crc2; uLong op; diff --git a/src/native/external/zlib-intel/deflate.c b/src/native/external/zlib-intel/deflate.c index 2dbd71ebf26e56..bd5e95774a689a 100644 --- a/src/native/external/zlib-intel/deflate.c +++ b/src/native/external/zlib-intel/deflate.c @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.12.1 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -88,6 +88,7 @@ local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +ZLIB_INTERNAL void fill_window(deflate_state *s); /* =========================================================================== @@ -154,6 +155,27 @@ local const config configuration_table[10] = { /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ #define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif /* =========================================================================== * Initialize the hash table (avoiding 64K overflow for 16 bit systems). @@ -161,9 +183,9 @@ local const config configuration_table[10] = { */ #define CLEAR_HASH(s) \ do { \ - s->head[s->hash_size-1] = NIL; \ + s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ - (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== @@ -271,6 +293,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -305,7 +329,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); #if defined(USE_PCLMUL_CRC) window_padding = 8; @@ -335,11 +359,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is @@ -385,7 +409,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) +local int deflateStateCheck(strm) z_streamp strm; { deflate_state *s; @@ -408,7 +432,7 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; @@ -477,7 +501,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; @@ -499,7 +523,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) +int ZEXPORT deflateResetKeep(strm) z_streamp strm; { deflate_state *s; @@ -543,7 +567,7 @@ int ZEXPORT deflateResetKeep (strm) } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) +int ZEXPORT deflateReset(strm) z_streamp strm; { int ret; @@ -555,7 +579,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) +int ZEXPORT deflateSetHeader(strm, head) z_streamp strm; gz_headerp head; { @@ -566,7 +590,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) +int ZEXPORT deflatePending(strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; @@ -580,7 +604,7 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) +int ZEXPORT deflatePrime(strm, bits, value) z_streamp strm; int bits; int value; @@ -675,36 +699,50 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -741,11 +779,12 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits ? fixedlen : storelen) + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -755,7 +794,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) +local void putShortMSB(s, b) deflate_state *s; uInt b; { @@ -802,7 +841,7 @@ ZLIB_INTERNAL void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) +int ZEXPORT deflate(strm, flush) z_streamp strm; int flush; { @@ -857,7 +896,7 @@ int ZEXPORT deflate (strm, flush) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1128,7 +1167,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) +int ZEXPORT deflateEnd(strm) z_streamp strm; { int status; @@ -1154,7 +1193,7 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) +int ZEXPORT deflateCopy(dest, source) z_streamp dest; z_streamp source; { @@ -1252,7 +1291,7 @@ local unsigned read_buf(strm, buf, size) /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -local void lm_init (s) +local void lm_init(s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; @@ -1273,11 +1312,6 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif } #ifdef ZLIB_DEBUG @@ -1304,7 +1338,7 @@ ZLIB_INTERNAL void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1348,9 +1382,9 @@ ZLIB_INTERNAL void fill_window(s) /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ - if (s->strstart >= wsize+MAX_DIST(s)) { + if (s->strstart >= wsize + MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; @@ -1467,7 +1501,7 @@ ZLIB_INTERNAL void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; @@ -1677,7 +1711,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1725,15 +1759,15 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; #ifdef USE_CRC_HASH - if (!x86_cpu_has_sse42) + if (!x86_cpu_has_sse42) #endif - { + { s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif - } + } /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not * matter since it will be recomputed at next deflate call. */ @@ -1741,7 +1775,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1785,7 +1819,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1827,17 +1861,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -1855,8 +1889,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -1874,8 +1908,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -1932,7 +1966,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -1947,7 +1982,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1987,7 +2022,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); diff --git a/src/native/external/zlib-intel/deflate_quick.c b/src/native/external/zlib-intel/deflate_quick.c index 13815281bec8d8..1a6e4f89810bbb 100644 --- a/src/native/external/zlib-intel/deflate_quick.c +++ b/src/native/external/zlib-intel/deflate_quick.c @@ -44,7 +44,7 @@ local inline long compare258(z_const unsigned char *z_const src0, "cmp $256 + 16, %[ax]\n\t" "jb 1b\n\t" -#ifdef TARGET_X86 +#ifdef X86 "movzwl -16(%[src0], %[ax]), %[dx]\n\t" #else "movzwq -16(%[src0], %[ax]), %[dx]\n\t" diff --git a/src/native/external/zlib-intel/inflate.c b/src/native/external/zlib-intel/inflate.c index 39de2fbf401827..96306ef76570b7 100644 --- a/src/native/external/zlib-intel/inflate.c +++ b/src/native/external/zlib-intel/inflate.c @@ -167,6 +167,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -797,8 +799,9 @@ int flush; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); @@ -1282,7 +1285,7 @@ int flush; out = left; #ifdef USE_PCLMUL_CRC - if ((state->wrap) & 2 && x86_cpu_has_pclmul) + if (state->flags > 0 && x86_cpu_has_pclmul) strm->adler = state->check = crc_fold_512to32(state->crc); #endif diff --git a/src/native/external/zlib-intel/inflate.h b/src/native/external/zlib-intel/inflate.h index d2c672310e75a5..a7bc6246c77970 100644 --- a/src/native/external/zlib-intel/inflate.h +++ b/src/native/external/zlib-intel/inflate.h @@ -138,7 +138,7 @@ static inline void inf_crc_copy(z_streamp strm, unsigned char FAR *const dst, struct inflate_state *const state = (struct inflate_state *const)strm->state; #if !defined(NO_GZIP) && defined(USE_PCLMUL_CRC) - if ((state->wrap & 2) && x86_cpu_has_pclmul) { + if (state->flags > 0 && x86_cpu_has_pclmul) { crc_fold_copy(state->crc, dst, src, len); return; } @@ -147,11 +147,11 @@ static inline void inf_crc_copy(z_streamp strm, unsigned char FAR *const dst, zmemcpy(dst, src, len); #if !defined(NO_GZIP) - if ((state->wrap & 2)) + if (state->flags > 0) strm->adler = state->check = crc32(state->check, dst, len); else #endif - if ((state->wrap & 1)) + if (state->flags == 0) strm->adler = state->check = adler32(state->check, dst, len); } diff --git a/src/native/external/zlib-intel/inftrees.c b/src/native/external/zlib-intel/inftrees.c index 3fb7bba14e8ecb..57d2793bec931f 100644 --- a/src/native/external/zlib-intel/inftrees.c +++ b/src/native/external/zlib-intel/inftrees.c @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.12.1 Copyright 1995-2022 Mark Adler "; + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 76, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/src/native/external/zlib-intel/inftrees.h b/src/native/external/zlib-intel/inftrees.h index baa53a0b1a199c..f53665311c1624 100644 --- a/src/native/external/zlib-intel/inftrees.h +++ b/src/native/external/zlib-intel/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. diff --git a/src/native/external/zlib-intel/trees.c b/src/native/external/zlib-intel/trees.c index 3c35e19f276c3e..35462a1313aa83 100644 --- a/src/native/external/zlib-intel/trees.c +++ b/src/native/external/zlib-intel/trees.c @@ -153,6 +153,75 @@ local void bi_flush OF((deflate_state *s)); local void gen_trees_header OF((void)); #endif +#ifndef ZLIB_DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* !ZLIB_DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef ZLIB_DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !ZLIB_DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = (int)value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* ZLIB_DEBUG */ + + +/* the arguments must not have side effects */ + /* =========================================================================== * Initialize the various 'constant' tables. */ @@ -183,7 +252,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -239,7 +308,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -248,7 +317,7 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header() { @@ -385,7 +454,7 @@ local void pqdownheap(s, tree, k) while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -434,7 +503,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -445,7 +514,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -457,10 +526,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -496,7 +565,7 @@ local void gen_bitlen(s, desc) * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -local void gen_codes (tree, max_code, bl_count) +local void gen_codes(tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ @@ -510,13 +579,13 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ - Assert (code + bl_count[MAX_BITS]-1 == (1<heap_len = 0, s->heap_max = HEAP_SIZE; @@ -579,7 +648,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -627,7 +696,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) +local void scan_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -641,10 +710,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -672,7 +741,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) +local void send_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -685,11 +754,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -700,13 +769,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -734,8 +803,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -746,7 +815,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -768,19 +837,19 @@ local void send_all_trees(s, lcodes, dcodes, blcodes) Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } @@ -793,7 +862,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); @@ -804,7 +873,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } @@ -870,14 +939,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -887,7 +959,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -898,21 +970,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -931,18 +999,18 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) +int ZLIB_INTERNAL _tr_tally(s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ { s->sym_buf[s->sym_next++] = (uch)dist; s->sym_buf[s->sym_next++] = (uch)(dist >> 8); @@ -958,7 +1026,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); @@ -988,7 +1056,7 @@ local void compress_block(s, ltree, dtree) } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ + send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; @@ -1104,6 +1172,6 @@ ZLIB_INTERNAL void bi_windup(s) s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; + s->bits_sent = (s->bits_sent + 7) & ~7; #endif } diff --git a/src/native/external/zlib-intel/zconf.h b/src/native/external/zlib-intel/zconf.h index 5e1d68a004e974..bf977d3e70adef 100644 --- a/src/native/external/zlib-intel/zconf.h +++ b/src/native/external/zlib-intel/zconf.h @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -349,6 +352,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +473,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/src/native/external/zlib-intel/zlib.h b/src/native/external/zlib-intel/zlib.h index eb8751700eb742..953cb5012dc203 100644 --- a/src/native/external/zlib-intel/zlib.h +++ b/src/native/external/zlib-intel/zlib.h @@ -1,5 +1,5 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12.1, March xxth, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler @@ -37,12 +37,12 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.12.1-motley" -#define ZLIB_VERNUM 0x12c1 +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 -#define ZLIB_VER_SUBREVISION 1 +#define ZLIB_VER_REVISION 13 +#define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -660,7 +660,7 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -915,7 +915,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. @@ -1437,12 +1437,12 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); @@ -1913,7 +1913,7 @@ ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) diff --git a/src/native/external/zlib-intel/zutil.c b/src/native/external/zlib-intel/zutil.c index dcab28a0d5177a..9543ae825e3250 100644 --- a/src/native/external/zlib-intel/zutil.c +++ b/src/native/external/zlib-intel/zutil.c @@ -61,9 +61,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,7 +121,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) +void ZLIB_INTERNAL z_error(m) char *m; { fprintf(stderr, "%s\n", m); @@ -214,7 +216,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,7 +242,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; @@ -277,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); @@ -302,7 +304,7 @@ extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) +voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) voidpf opaque; unsigned items; unsigned size; @@ -312,7 +314,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) +void ZLIB_INTERNAL zcfree(opaque, ptr) voidpf opaque; voidpf ptr; { diff --git a/src/native/external/zlib-intel/zutil.h b/src/native/external/zlib-intel/zutil.h index 01b68b6d15ccf5..056a2b0c36063d 100644 --- a/src/native/external/zlib-intel/zutil.h +++ b/src/native/external/zlib-intel/zutil.h @@ -216,6 +216,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); #endif /* common defaults */ diff --git a/src/native/external/zlib-version.txt b/src/native/external/zlib-version.txt index 86d276b4a51ba2..00ce7fdbb2cd32 100644 --- a/src/native/external/zlib-version.txt +++ b/src/native/external/zlib-version.txt @@ -1,11 +1,15 @@ -v1.2.12 -(21767c654d31d2dccdde4330529775c6c5fd5389) +v1.2.13 +(04f42ceca40f73e2978b50e93806c2a18c1281fc) -https://github.com/madler/zlib/releases/tag/v1.2.12 +https://github.com/madler/zlib/releases/tag/v1.2.13 + +We have removed zlib.3.pdf from our local copy, as it is a binary file which is +not needed for our compilation. We have also cherry-picked into our local copy: -https://github.com/madler/zlib/commit/ec3df00224d4b396e2ac6586ab5d25f673caa4c2 -https://github.com/madler/zlib/commit/7ecf7c7458578d05a20fa481436dd5c58db112f7 -And we have inserted into our local copy of zutil.h, line 196, the following declaration: - ZEXTERN uLong ZEXPORT crc32_combine_gen64 OF((z_off_t)); +- https://github.com/madler/zlib/commit/e554695638228b846d49657f31eeff0ca4680e8a + + This patch only affects memLevel 9 compression. .NET doesn't currently use this + memLevel, but we'll take this patch out of an abundance of caution just in case + we enable this functionality in a future release. diff --git a/src/native/external/zlib/CMakeLists.txt b/src/native/external/zlib/CMakeLists.txt index e6fbb37d105f6d..b412dc7feb732a 100644 --- a/src/native/external/zlib/CMakeLists.txt +++ b/src/native/external/zlib/CMakeLists.txt @@ -3,10 +3,7 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) project(zlib C) -set(VERSION "1.2.12") - -option(ASM686 "Enable building i686 assembly implementation") -option(AMD64 "Enable building amd64 assembly implementation") +set(VERSION "1.2.13") set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") @@ -129,39 +126,6 @@ if(NOT MINGW) ) endif() -if(CMAKE_COMPILER_IS_GNUCC) - if(ASM686) - set(ZLIB_ASMS contrib/asm686/match.S) - elseif (AMD64) - set(ZLIB_ASMS contrib/amd64/amd64-match.S) - endif () - - if(ZLIB_ASMS) - add_definitions(-DASMV) - set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) - endif() -endif() - -if(MSVC) - if(ASM686) - ENABLE_LANGUAGE(ASM_MASM) - set(ZLIB_ASMS - contrib/masmx86/inffas32.asm - contrib/masmx86/match686.asm - ) - elseif (AMD64) - ENABLE_LANGUAGE(ASM_MASM) - set(ZLIB_ASMS - contrib/masmx64/gvmat64.asm - contrib/masmx64/inffasx64.asm - ) - endif() - - if(ZLIB_ASMS) - add_definitions(-DASMV -DASMINF) - endif() -endif() - # parse the full version number from zlib.h and include in ZLIB_FULL_VERSION file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" @@ -183,8 +147,8 @@ if(MINGW) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) -add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) -add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) set_target_properties(zlib PROPERTIES SOVERSION 1) diff --git a/src/native/external/zlib/ChangeLog b/src/native/external/zlib/ChangeLog index f0b0e6180921ba..457526bc6a51f5 100644 --- a/src/native/external/zlib/ChangeLog +++ b/src/native/external/zlib/ChangeLog @@ -1,6 +1,18 @@ ChangeLog file for zlib +Changes in 1.2.13 (13 Oct 2022) +- Fix configure issue that discarded provided CC definition +- Correct incorrect inputs provided to the CRC functions +- Repair prototypes and exporting of new CRC functions +- Fix inflateBack to detect invalid input with distances too far +- Have infback() deliver all of the available output up to any error +- Fix a bug when getting a gzip header extra field with inflate() +- Fix bug in block type selection when Z_FIXED used +- Tighten deflateBound bounds +- Remove deleted assembler code references +- Various portability and appearance improvements + Changes in 1.2.12 (27 Mar 2022) - Cygwin does not have _wopen(), so do not create gzopen_w() there - Permit a deflateParams() parameter change as soon as possible @@ -159,7 +171,7 @@ Changes in 1.2.7.1 (24 Mar 2013) - Fix types in contrib/minizip to match result of get_crc_table() - Simplify contrib/vstudio/vc10 with 'd' suffix - Add TOP support to win32/Makefile.msc -- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Support i686 and amd64 assembler builds in CMakeLists.txt - Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h - Add vc11 and vc12 build files to contrib/vstudio - Add gzvprintf() as an undocumented function in zlib @@ -359,14 +371,14 @@ Changes in 1.2.5.1 (10 Sep 2011) - Use u4 type for crc_table to avoid conversion warnings - Apply casts in zlib.h to avoid conversion warnings - Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] -- Improve inflateSync() documentation to note indeterminancy +- Improve inflateSync() documentation to note indeterminacy - Add deflatePending() function to return the amount of pending output - Correct the spelling of "specification" in FAQ [Randers-Pehrson] - Add a check in configure for stdarg.h, use for gzprintf() - Check that pointers fit in ints when gzprint() compiled old style - Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] - Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] -- Add debug records in assmebler code [Londer] +- Add debug records in assembler code [Londer] - Update RFC references to use http://tools.ietf.org/html/... [Li] - Add --archs option, use of libtool to configure for Mac OS X [Borstel] @@ -1033,7 +1045,7 @@ Changes in 1.2.0.1 (17 March 2003) - Include additional header file on VMS for off_t typedef - Try to use _vsnprintf where it supplants vsprintf [Vollant] - Add some casts in inffast.c -- Enchance comments in zlib.h on what happens if gzprintf() tries to +- Enhance comments in zlib.h on what happens if gzprintf() tries to write more than 4095 bytes before compression - Remove unused state from inflateBackEnd() - Remove exit(0) from minigzip.c, example.c @@ -1211,7 +1223,7 @@ Changes in 1.0.9 (17 Feb 1998) - Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 - in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) - in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with - the declaration of FAR (Gilles VOllant) + the declaration of FAR (Gilles Vollant) - install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) - read_buf buf parameter of type Bytef* instead of charf* - zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) @@ -1567,7 +1579,7 @@ Changes in 0.4: - renamed deflateOptions as deflateInit2, call one or the other but not both - added the method parameter for deflateInit2 - added inflateInit2 -- simplied considerably deflateInit and inflateInit by not supporting +- simplified considerably deflateInit and inflateInit by not supporting user-provided history buffer. This is supported only in deflateInit2 and inflateInit2 diff --git a/src/native/external/zlib/LICENSE b/src/native/external/zlib/LICENSE new file mode 100644 index 00000000000000..ab8ee6f71428c3 --- /dev/null +++ b/src/native/external/zlib/LICENSE @@ -0,0 +1,22 @@ +Copyright notice: + + (C) 1995-2022 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu diff --git a/src/native/external/zlib/Makefile.in b/src/native/external/zlib/Makefile.in index 3d858aa3a246df..7d2713f4c574a9 100644 --- a/src/native/external/zlib/Makefile.in +++ b/src/native/external/zlib/Makefile.in @@ -7,10 +7,6 @@ # Normally configure builds both a static and a shared library. # If you want to build just a static library, use: ./configure --static -# To use the asm code, type: -# cp contrib/asm?86/match.S ./match.S -# make LOC=-DASMV OBJA=match.o - # To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: # make install # To install in $HOME instead of /usr/local, use: @@ -26,13 +22,13 @@ CFLAGS=-O SFLAGS=-O LDFLAGS= -TEST_LDFLAGS=-L. libz.a +TEST_LDFLAGS=$(LDFLAGS) -L. libz.a LDSHARED=$(CC) CPP=$(CC) -E STATICLIB=libz.a SHAREDLIB=libz.so -SHAREDLIBV=libz.so.1.2.12 +SHAREDLIBV=libz.so.1.2.13 SHAREDLIBM=libz.so.1 LIBS=$(STATICLIB) $(SHAREDLIBV) @@ -87,7 +83,7 @@ test: all teststatic testshared teststatic: static @TMPST=tmpst_$$; \ - if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \ + if echo hello world | ${QEMU_RUN} ./minigzip | ${QEMU_RUN} ./minigzip -d && ${QEMU_RUN} ./example $$TMPST ; then \ echo ' *** zlib test OK ***'; \ else \ echo ' *** zlib test FAILED ***'; false; \ @@ -100,7 +96,7 @@ testshared: shared DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ TMPSH=tmpsh_$$; \ - if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \ + if echo hello world | ${QEMU_RUN} ./minigzipsh | ${QEMU_RUN} ./minigzipsh -d && ${QEMU_RUN} ./examplesh $$TMPSH; then \ echo ' *** zlib shared test OK ***'; \ else \ echo ' *** zlib shared test FAILED ***'; false; \ @@ -109,7 +105,7 @@ testshared: shared test64: all64 @TMP64=tmp64_$$; \ - if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \ + if echo hello world | ${QEMU_RUN} ./minigzip64 | ${QEMU_RUN} ./minigzip64 -d && ${QEMU_RUN} ./example64 $$TMP64; then \ echo ' *** zlib 64-bit test OK ***'; \ else \ echo ' *** zlib 64-bit test FAILED ***'; false; \ @@ -124,7 +120,7 @@ infcover: infcover.o libz.a cover: infcover rm -f *.gcda - ./infcover + ${QEMU_RUN} ./infcover gcov inf*.c libz.a: $(OBJS) @@ -292,10 +288,10 @@ minigzip$(EXE): minigzip.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) examplesh$(EXE): example.o $(SHAREDLIBV) - $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) -L. $(SHAREDLIBV) minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) - $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) -L. $(SHAREDLIBV) example64$(EXE): example64.o $(STATICLIB) $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) diff --git a/src/native/external/zlib/README b/src/native/external/zlib/README index 024b79d3d8c8b8..ba34d1894a9b4a 100644 --- a/src/native/external/zlib/README +++ b/src/native/external/zlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.12 is a general purpose data compression library. All the code is +zlib 1.2.13 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and @@ -31,7 +31,7 @@ Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . -The changes made in version 1.2.12 are documented in the file ChangeLog. +The changes made in version 1.2.13 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . diff --git a/src/native/external/zlib/compress.c b/src/native/external/zlib/compress.c index e2db404abf888b..2ad5326c14ec04 100644 --- a/src/native/external/zlib/compress.c +++ b/src/native/external/zlib/compress.c @@ -19,7 +19,7 @@ memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) +int ZEXPORT compress2(dest, destLen, source, sourceLen, level) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -65,7 +65,7 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) /* =========================================================================== */ -int ZEXPORT compress (dest, destLen, source, sourceLen) +int ZEXPORT compress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -78,7 +78,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen) If the default memLevel or windowBits for deflateInit() is changed, then this function needs to be updated. */ -uLong ZEXPORT compressBound (sourceLen) +uLong ZEXPORT compressBound(sourceLen) uLong sourceLen; { return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + diff --git a/src/native/external/zlib/configure b/src/native/external/zlib/configure index 52ff4a04ea8998..fa4d5daaba99f4 100644 --- a/src/native/external/zlib/configure +++ b/src/native/external/zlib/configure @@ -32,8 +32,11 @@ fi # set command prefix for cross-compilation if [ -n "${CHOST}" ]; then - uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`" + uname=${CHOST} + mname=${CHOST} CROSS_PREFIX="${CHOST}-" +else + mname=`(uname -a || echo unknown) 2>/dev/null` fi # destination name for static library @@ -174,9 +177,10 @@ if test -z "$CC"; then else cc=${CROSS_PREFIX}cc fi +else + cc=${CC} fi -cflags=${CFLAGS-"-O3"} -# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure + case "$cc" in *gcc*) gcc=1 ;; *clang*) gcc=1 ;; @@ -202,13 +206,13 @@ if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then fi if test "$warn" -eq 1; then if test "$zconst" -eq 1; then - CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST" + CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -DZLIB_CONST" else - CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" + CFLAGS="${CFLAGS} -Wall -Wextra" fi fi if test $sanitize -eq 1; then - CFLAGS="${CFLAGS} -fsanitize=address" + CFLAGS="${CFLAGS} -g -fsanitize=address" fi if test $debug -eq 1; then CFLAGS="${CFLAGS} -DZLIB_DEBUG" @@ -218,47 +222,52 @@ if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then uname=`(uname -s || echo unknown) 2>/dev/null` fi case "$uname" in - Linux* | linux* | GNU | GNU/* | solaris*) + Linux* | linux* | *-linux* | GNU | GNU/* | solaris*) + case "$mname" in + *sparc*) + LDFLAGS="${LDFLAGS} -Wl,--no-warn-rwx-segments" ;; + esac LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} ;; *BSD | *bsd* | DragonFly) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,${SRCDIR}zlib.map"} LDCONFIG="ldconfig -m" ;; - CYGWIN* | Cygwin* | cygwin* | OS/2*) + CYGWIN* | Cygwin* | cygwin* | *-cygwin* | OS/2*) EXE='.exe' ;; - MINGW* | mingw*) -# temporary bypass + MINGW* | mingw* | *-mingw*) rm -f $test.[co] $test $test$shared_ext - echo "Please use win32/Makefile.gcc instead." | tee -a configure.log - leave 1 + echo "If this doesn't work for you, try win32/Makefile.gcc." | tee -a configure.log LDSHARED=${LDSHARED-"$cc -shared"} LDSHAREDLIBC="" EXE='.exe' ;; - QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 - # (alain.bonnefoy@icbt.com) - LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; HP-UX*) - LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} - case `(uname -m || echo unknown) 2>/dev/null` in - ia64) - shared_ext='.so' - SHAREDLIB='libz.so' ;; - *) - shared_ext='.sl' - SHAREDLIB='libz.sl' ;; - esac ;; - Darwin* | darwin*) - shared_ext='.dylib' - SHAREDLIB=libz$shared_ext - SHAREDLIBV=libz.$VER$shared_ext - SHAREDLIBM=libz.$VER1$shared_ext - LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} - if libtool -V 2>&1 | grep Apple > /dev/null; then - AR="libtool" - else - AR="/usr/bin/libtool" - fi - ARFLAGS="-o" ;; - *) LDSHARED=${LDSHARED-"$cc -shared"} ;; + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + AIX*) + LDFLAGS="${LDFLAGS} -Wl,-brtl" ;; + Darwin* | darwin* | *-darwin*) + shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} + if libtool -V 2>&1 | grep Apple > /dev/null; then + AR="libtool" + else + AR="/usr/bin/libtool" + fi + ARFLAGS="-o" ;; + *) + LDSHARED=${LDSHARED-"$cc -shared"} ;; esac else # find system name and corresponding cc options @@ -450,20 +459,6 @@ else TEST="all teststatic testshared" fi -# check for underscores in external names for use by assembler code -CPP=${CPP-"$CC -E"} -case $CFLAGS in - *ASMV*) - echo >> configure.log - show "$NM $test.o | grep _hello" - if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then - CPP="$CPP -DNO_UNDERLINE" - echo Checking for underline in external names... No. | tee -a configure.log - else - echo Checking for underline in external names... Yes. | tee -a configure.log - fi ;; -esac - echo >> configure.log # check for size_t diff --git a/src/native/external/zlib/crc32.c b/src/native/external/zlib/crc32.c index 3b7122a3aed90f..f8357b083f7636 100644 --- a/src/native/external/zlib/crc32.c +++ b/src/native/external/zlib/crc32.c @@ -98,13 +98,22 @@ # endif #endif +/* If available, use the ARM processor CRC32 instruction. */ +#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 +# define ARMCRC32 +#endif + /* Local functions. */ local z_crc_t multmodp OF((z_crc_t a, z_crc_t b)); local z_crc_t x2nmodp OF((z_off64_t n, unsigned k)); -/* If available, use the ARM processor CRC32 instruction. */ -#if defined(__aarch64__) && defined(__ARM_FEATURE_CRC32) && W == 8 -# define ARMCRC32 +#if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) + local z_word_t byte_swap OF((z_word_t word)); +#endif + +#if defined(W) && !defined(ARMCRC32) + local z_crc_t crc_word OF((z_word_t data)); + local z_word_t crc_word_big OF((z_word_t data)); #endif #if defined(W) && (!defined(ARMCRC32) || defined(DYNAMIC_CRC_TABLE)) @@ -645,8 +654,8 @@ unsigned long ZEXPORT crc32_z(crc, buf, len) len &= 7; /* Do three interleaved CRCs to realize the throughput of one crc32x - instruction per cycle. Each CRC is calcuated on Z_BATCH words. The three - CRCs are combined into a single CRC after each set of batches. */ + instruction per cycle. Each CRC is calculated on Z_BATCH words. The + three CRCs are combined into a single CRC after each set of batches. */ while (num >= 3 * Z_BATCH) { crc1 = 0; crc2 = 0; @@ -1107,7 +1116,7 @@ uLong ZEXPORT crc32_combine_gen(len2) } /* ========================================================================= */ -uLong crc32_combine_op(crc1, crc2, op) +uLong ZEXPORT crc32_combine_op(crc1, crc2, op) uLong crc1; uLong crc2; uLong op; diff --git a/src/native/external/zlib/deflate.c b/src/native/external/zlib/deflate.c index 799fb93cc04ba8..d2e1106ef5d07d 100644 --- a/src/native/external/zlib/deflate.c +++ b/src/native/external/zlib/deflate.c @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.12 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.13 Copyright 1995-2022 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -87,13 +87,7 @@ local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif #ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, @@ -160,7 +154,7 @@ local const config configuration_table[10] = { * characters, so that a running hash key can be computed from the previous * key instead of complete recalculation each time. */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) +#define UPDATE_HASH(s,h,c) (h = (((h) << s->hash_shift) ^ (c)) & s->hash_mask) /* =========================================================================== @@ -191,9 +185,9 @@ local const config configuration_table[10] = { */ #define CLEAR_HASH(s) \ do { \ - s->head[s->hash_size-1] = NIL; \ + s->head[s->hash_size - 1] = NIL; \ zmemzero((Bytef *)s->head, \ - (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + (unsigned)(s->hash_size - 1)*sizeof(*s->head)); \ } while (0) /* =========================================================================== @@ -285,6 +279,8 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (windowBits < 0) { /* suppress zlib wrapper */ wrap = 0; + if (windowBits < -15) + return Z_STREAM_ERROR; windowBits = -windowBits; } #ifdef GZIP @@ -314,7 +310,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + s->hash_shift = ((s->hash_bits + MIN_MATCH-1) / MIN_MATCH); s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); @@ -340,11 +336,11 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, * sym_buf value to read moves forward three bytes. From that symbol, up to * 31 bits are written to pending_buf. The closest the written pending_buf * bits gets to the next sym_buf symbol to read is just before the last - * code is written. At that time, 31*(n-2) bits have been written, just - * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at - * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * code is written. At that time, 31*(n - 2) bits have been written, just + * after 24*(n - 2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n - 1 * symbols are written.) The closest the writing gets to what is unread is - * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * then n + 14 bits. Here n is lit_bufsize, which is 16384 by default, and * can range from 128 to 32768. * * Therefore, at a minimum, there are 142 bits of space between what is @@ -390,7 +386,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, /* ========================================================================= * Check for a valid deflate stream state. Return 0 if ok, 1 if not. */ -local int deflateStateCheck (strm) +local int deflateStateCheck(strm) z_streamp strm; { deflate_state *s; @@ -413,7 +409,7 @@ local int deflateStateCheck (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; @@ -482,7 +478,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) +int ZEXPORT deflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; @@ -504,7 +500,7 @@ int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) } /* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) +int ZEXPORT deflateResetKeep(strm) z_streamp strm; { deflate_state *s; @@ -542,7 +538,7 @@ int ZEXPORT deflateResetKeep (strm) } /* ========================================================================= */ -int ZEXPORT deflateReset (strm) +int ZEXPORT deflateReset(strm) z_streamp strm; { int ret; @@ -554,7 +550,7 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) +int ZEXPORT deflateSetHeader(strm, head) z_streamp strm; gz_headerp head; { @@ -565,7 +561,7 @@ int ZEXPORT deflateSetHeader (strm, head) } /* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) +int ZEXPORT deflatePending(strm, pending, bits) unsigned *pending; int *bits; z_streamp strm; @@ -579,7 +575,7 @@ int ZEXPORT deflatePending (strm, pending, bits) } /* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) +int ZEXPORT deflatePrime(strm, bits, value) z_streamp strm; int bits; int value; @@ -674,36 +670,50 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) } /* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. + * For the default windowBits of 15 and memLevel of 8, this function returns a + * close to exact, as well as small, upper bound on the compressed size. This + * is an expansion of ~0.03%, plus a small constant. + * + * For any setting other than those defaults for windowBits and memLevel, one + * of two worst case bounds is returned. This is at most an expansion of ~4% or + * ~13%, plus a small constant. * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. + * Both the 0.03% and 4% derive from the overhead of stored blocks. The first + * one is for stored blocks of 16383 bytes (memLevel == 8), whereas the second + * is for stored blocks of 127 bytes (the worst case memLevel == 1). The + * expansion results from five bytes of header for each stored block. * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. + * The larger expansion of 13% results from a window size less than or equal to + * the symbols buffer size (windowBits <= memLevel + 7). In that case some of + * the data being compressed may have slid out of the sliding window, impeding + * a stored block from being emitted. Then the only choice is a fixed or + * dynamic block, where a fixed block limits the maximum expansion to 9 bits + * per 8-bit byte, plus 10 bits for every block. The smallest block size for + * which this can occur is 255 (memLevel == 2). + * + * Shifts are used to approximate divisions, for speed. */ uLong ZEXPORT deflateBound(strm, sourceLen) z_streamp strm; uLong sourceLen; { deflate_state *s; - uLong complen, wraplen; + uLong fixedlen, storelen, wraplen; + + /* upper bound for fixed blocks with 9-bit literals and length 255 + (memLevel == 2, which is the lowest that may not use stored blocks) -- + ~13% overhead plus a small constant */ + fixedlen = sourceLen + (sourceLen >> 3) + (sourceLen >> 8) + + (sourceLen >> 9) + 4; - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + /* upper bound for stored blocks with length 127 (memLevel == 1) -- + ~4% overhead plus a small constant */ + storelen = sourceLen + (sourceLen >> 5) + (sourceLen >> 7) + + (sourceLen >> 11) + 7; - /* if can't get parameters, return conservative bound plus zlib wrapper */ + /* if can't get parameters, return larger bound plus a zlib wrapper */ if (deflateStateCheck(strm)) - return complen + 6; + return (fixedlen > storelen ? fixedlen : storelen) + 6; /* compute wrapper length */ s = strm->state; @@ -740,11 +750,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen = 6; } - /* if not default parameters, return conservative bound */ + /* if not default parameters, return one of the conservative bounds */ if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; + return (s->w_bits <= s->hash_bits && s->level ? fixedlen : storelen) + + wraplen; - /* default settings: return tight bound for that case */ + /* default settings: return tight bound for that case -- ~0.03% overhead + plus a small constant */ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + (sourceLen >> 25) + 13 - 6 + wraplen; } @@ -754,7 +766,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) +local void putShortMSB(s, b) deflate_state *s; uInt b; { @@ -801,7 +813,7 @@ local void flush_pending(strm) } while (0) /* ========================================================================= */ -int ZEXPORT deflate (strm, flush) +int ZEXPORT deflate(strm, flush) z_streamp strm; int flush; { @@ -856,7 +868,7 @@ int ZEXPORT deflate (strm, flush) s->status = BUSY_STATE; if (s->status == INIT_STATE) { /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt header = (Z_DEFLATED + ((s->w_bits - 8) << 4)) << 8; uInt level_flags; if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) @@ -1116,7 +1128,7 @@ int ZEXPORT deflate (strm, flush) } /* ========================================================================= */ -int ZEXPORT deflateEnd (strm) +int ZEXPORT deflateEnd(strm) z_streamp strm; { int status; @@ -1142,7 +1154,7 @@ int ZEXPORT deflateEnd (strm) * To simplify the source, this is not supported for 16-bit MSDOS (which * doesn't have enough memory anyway to duplicate compression states). */ -int ZEXPORT deflateCopy (dest, source) +int ZEXPORT deflateCopy(dest, source) z_streamp dest; z_streamp source; { @@ -1231,7 +1243,7 @@ local unsigned read_buf(strm, buf, size) /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -local void lm_init (s) +local void lm_init(s) deflate_state *s; { s->window_size = (ulg)2L*s->w_size; @@ -1252,11 +1264,6 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif } #ifndef FASTEST @@ -1269,10 +1276,6 @@ local void lm_init (s) * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 * OUT assertion: the match length is not greater than s->lookahead. */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ local uInt longest_match(s, cur_match) deflate_state *s; IPos cur_match; /* current match */ @@ -1297,10 +1300,10 @@ local uInt longest_match(s, cur_match) */ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register ush scan_end = *(ushf*)(scan + best_len - 1); #else register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end1 = scan[best_len - 1]; register Byte scan_end = scan[best_len]; #endif @@ -1318,7 +1321,8 @@ local uInt longest_match(s, cur_match) */ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); do { Assert(cur_match < s->strstart, "no future"); @@ -1336,43 +1340,44 @@ local uInt longest_match(s, cur_match) /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || + if (*(ushf*)(match + best_len - 1) != scan_end || *(ushf*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient + * strstart + 3, + 5, up to strstart + 257. We check for insufficient * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * at strstart + 257. If MAX_MATCH-2 is not a multiple of 8, it is * necessary to put more guard bytes at the end of the window, or * to check more often for insufficient lookahead. */ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && + *(ushf*)(scan += 2) == *(ushf*)(match += 2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + /* Here, scan <= window + strstart + 257 */ + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); if (*scan == *match) scan++; - len = (MAX_MATCH - 1) - (int)(strend-scan); + len = (MAX_MATCH - 1) - (int)(strend - scan); scan = strend - (MAX_MATCH-1); #else /* UNALIGNED_OK */ - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; + if (match[best_len] != scan_end || + match[best_len - 1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1382,7 +1387,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1391,7 +1396,8 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), + "wild scan"); len = MAX_MATCH - (int)(strend - scan); scan = strend - MAX_MATCH; @@ -1403,9 +1409,9 @@ local uInt longest_match(s, cur_match) best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ushf*)(scan + best_len - 1); #else - scan_end1 = scan[best_len-1]; + scan_end1 = scan[best_len - 1]; scan_end = scan[best_len]; #endif } @@ -1415,7 +1421,6 @@ local uInt longest_match(s, cur_match) if ((uInt)best_len <= s->lookahead) return (uInt)best_len; return s->lookahead; } -#endif /* ASMV */ #else /* FASTEST */ @@ -1436,7 +1441,8 @@ local uInt longest_match(s, cur_match) */ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "need lookahead"); Assert(cur_match < s->strstart, "no future"); @@ -1446,7 +1452,7 @@ local uInt longest_match(s, cur_match) */ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - /* The check at best_len-1 can be removed because it will be made + /* The check at best_len - 1 can be removed because it will be made * again later. (This heuristic is not always a win.) * It is not necessary to compare scan[2] and match[2] since they * are always equal when the other bytes match, given that @@ -1456,7 +1462,7 @@ local uInt longest_match(s, cur_match) Assert(*scan == *match, "match[2]?"); /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. + * the 256th check will be made at strstart + 258. */ do { } while (*++scan == *++match && *++scan == *++match && @@ -1465,7 +1471,7 @@ local uInt longest_match(s, cur_match) *++scan == *++match && *++scan == *++match && scan < strend); - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (unsigned)(s->window_size - 1), "wild scan"); len = MAX_MATCH - (int)(strend - scan); @@ -1501,7 +1507,7 @@ local void check_match(s, start, match, length) z_error("invalid match"); } if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); + fprintf(stderr,"\\[%d,%d]", start - match, length); do { putc(s->window[start++], stderr); } while (--length != 0); } } @@ -1547,9 +1553,9 @@ local void fill_window(s) /* If the window is almost full and there is insufficient lookahead, * move the upper half to the lower one to make room in the upper half. */ - if (s->strstart >= wsize+MAX_DIST(s)) { + if (s->strstart >= wsize + MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); + zmemcpy(s->window, s->window + wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; @@ -1680,7 +1686,7 @@ local void fill_window(s) * * deflate_stored() is written to minimize the number of times an input byte is * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. + * maximizes the opportunities to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; @@ -1890,7 +1896,7 @@ local block_state deflate_fast(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -1938,7 +1944,7 @@ local block_state deflate_fast(s, flush) s->strstart += s->match_length; s->match_length = 0; s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); + UPDATE_HASH(s, s->ins_h, s->window[s->strstart + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif @@ -1949,7 +1955,7 @@ local block_state deflate_fast(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -1993,7 +1999,7 @@ local block_state deflate_slow(s, flush) if (s->lookahead == 0) break; /* flush the current block */ } - /* Insert the string window[strstart .. strstart+2] in the + /* Insert the string window[strstart .. strstart + 2] in the * dictionary, and set hash_head to the head of the hash chain: */ hash_head = NIL; @@ -2035,17 +2041,17 @@ local block_state deflate_slow(s, flush) uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; /* Do not insert strings in hash table beyond this. */ - check_match(s, s->strstart-1, s->prev_match, s->prev_length); + check_match(s, s->strstart - 1, s->prev_match, s->prev_length); - _tr_tally_dist(s, s->strstart -1 - s->prev_match, + _tr_tally_dist(s, s->strstart - 1 - s->prev_match, s->prev_length - MIN_MATCH, bflush); /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not + * strstart - 1 and strstart are already inserted. If there is not * enough lookahead, the last two strings are not inserted in * the hash table. */ - s->lookahead -= s->prev_length-1; + s->lookahead -= s->prev_length - 1; s->prev_length -= 2; do { if (++s->strstart <= max_insert) { @@ -2063,8 +2069,8 @@ local block_state deflate_slow(s, flush) * single literal. If there was a match but the current match * is longer, truncate the previous match to a single literal. */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); if (bflush) { FLUSH_BLOCK_ONLY(s, 0); } @@ -2082,8 +2088,8 @@ local block_state deflate_slow(s, flush) } Assert (flush != Z_NO_FLUSH, "no flush?"); if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); + Tracevv((stderr,"%c", s->window[s->strstart - 1])); + _tr_tally_lit(s, s->window[s->strstart - 1], bflush); s->match_available = 0; } s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; @@ -2140,7 +2146,8 @@ local block_state deflate_rle(s, flush) if (s->match_length > s->lookahead) s->match_length = s->lookahead; } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + Assert(scan <= s->window + (uInt)(s->window_size - 1), + "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */ @@ -2155,7 +2162,7 @@ local block_state deflate_rle(s, flush) } else { /* No match, output a literal byte */ Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; } @@ -2195,7 +2202,7 @@ local block_state deflate_huff(s, flush) /* Output a literal byte */ s->match_length = 0; Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); + _tr_tally_lit(s, s->window[s->strstart], bflush); s->lookahead--; s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); diff --git a/src/native/external/zlib/deflate.h b/src/native/external/zlib/deflate.h index 17c226113b08d6..1a06cd5f25d107 100644 --- a/src/native/external/zlib/deflate.h +++ b/src/native/external/zlib/deflate.h @@ -329,8 +329,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ - s->sym_buf[s->sym_next++] = dist; \ - s->sym_buf[s->sym_next++] = dist >> 8; \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ diff --git a/src/native/external/zlib/gzlib.c b/src/native/external/zlib/gzlib.c index dddaf2687303eb..55da46a453fd18 100644 --- a/src/native/external/zlib/gzlib.c +++ b/src/native/external/zlib/gzlib.c @@ -30,7 +30,7 @@ local gzFile gz_open OF((const void *, int, const char *)); The gz_strwinerror function does not change the current setting of GetLastError. */ -char ZLIB_INTERNAL *gz_strwinerror (error) +char ZLIB_INTERNAL *gz_strwinerror(error) DWORD error; { static char buf[1024]; diff --git a/src/native/external/zlib/gzread.c b/src/native/external/zlib/gzread.c index 884c9bfe4cfb8d..dd77381596cbc0 100644 --- a/src/native/external/zlib/gzread.c +++ b/src/native/external/zlib/gzread.c @@ -157,11 +157,9 @@ local int gz_look(state) the output buffer is larger than the input buffer, which also assures space for gzungetc() */ state->x.next = state->out; - if (strm->avail_in) { - memcpy(state->x.next, strm->next_in, strm->avail_in); - state->x.have = strm->avail_in; - strm->avail_in = 0; - } + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; state->how = COPY; state->direct = 1; return 0; diff --git a/src/native/external/zlib/gzwrite.c b/src/native/external/zlib/gzwrite.c index a8ffc8f53da703..eb8a0e5893ff6a 100644 --- a/src/native/external/zlib/gzwrite.c +++ b/src/native/external/zlib/gzwrite.c @@ -474,7 +474,7 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) #else /* !STDC && !Z_HAVE_STDARG_H */ /* -- see zlib.h -- */ -int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, +int ZEXPORTVA gzprintf(file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) gzFile file; const char *format; diff --git a/src/native/external/zlib/infback.c b/src/native/external/zlib/infback.c index a390c58e816f5b..babeaf1806f98f 100644 --- a/src/native/external/zlib/infback.c +++ b/src/native/external/zlib/infback.c @@ -66,6 +66,7 @@ int stream_size; state->window = window; state->wnext = 0; state->whave = 0; + state->sane = 1; return Z_OK; } @@ -605,25 +606,27 @@ void FAR *out_desc; break; case DONE: - /* inflate stream terminated properly -- write leftover output */ + /* inflate stream terminated properly */ ret = Z_STREAM_END; - if (left < state->wsize) { - if (out(out_desc, state->window, state->wsize - left)) - ret = Z_BUF_ERROR; - } goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; - default: /* can't happen, but makes compilers happy */ + default: + /* can't happen, but makes compilers happy */ ret = Z_STREAM_ERROR; goto inf_leave; } - /* Return unused input */ + /* Write leftover output and return unused input */ inf_leave: + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left) && + ret == Z_STREAM_END) + ret = Z_BUF_ERROR; + } strm->next_in = next; strm->avail_in = have; return ret; diff --git a/src/native/external/zlib/inflate.c b/src/native/external/zlib/inflate.c index 7be8c63662a7f4..8acbef44e993ba 100644 --- a/src/native/external/zlib/inflate.c +++ b/src/native/external/zlib/inflate.c @@ -168,6 +168,8 @@ int windowBits; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { + if (windowBits < -15) + return Z_STREAM_ERROR; wrap = 0; windowBits = -windowBits; } @@ -764,8 +766,9 @@ int flush; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; + state->head->extra != Z_NULL && + (len = state->head->extra_len - state->length) < + state->head->extra_max) { zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); diff --git a/src/native/external/zlib/inftrees.c b/src/native/external/zlib/inftrees.c index 09462a740b12c1..57d2793bec931f 100644 --- a/src/native/external/zlib/inftrees.c +++ b/src/native/external/zlib/inftrees.c @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.12 Copyright 1995-2022 Mark Adler "; + " inflate 1.2.13 Copyright 1995-2022 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 202}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 194, 65}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, diff --git a/src/native/external/zlib/inftrees.h b/src/native/external/zlib/inftrees.h index baa53a0b1a199c..f53665311c1624 100644 --- a/src/native/external/zlib/inftrees.h +++ b/src/native/external/zlib/inftrees.h @@ -38,7 +38,7 @@ typedef struct { /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that + examples/enough.c found in the zlib distribution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. diff --git a/src/native/external/zlib/make_vms.com b/src/native/external/zlib/make_vms.com index 65e9d0cbc8e1dd..4dc8a891355980 100644 --- a/src/native/external/zlib/make_vms.com +++ b/src/native/external/zlib/make_vms.com @@ -14,9 +14,9 @@ $! 0.02 20061008 Adapt to new Makefile.in $! 0.03 20091224 Add support for large file check $! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite $! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in -$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new exmples +$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new examples $! subdir path, update module search in makefile.in -$! 0.07 20120115 Triggered by work done by Alexey Chupahin completly redesigned +$! 0.07 20120115 Triggered by work done by Alexey Chupahin completely redesigned $! shared image creation $! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared $! image diff --git a/src/native/external/zlib/treebuild.xml b/src/native/external/zlib/treebuild.xml index 781b4c98cc23ad..0017a45d3c5cbf 100644 --- a/src/native/external/zlib/treebuild.xml +++ b/src/native/external/zlib/treebuild.xml @@ -1,6 +1,6 @@ - - + + zip compression library diff --git a/src/native/external/zlib/trees.c b/src/native/external/zlib/trees.c index f73fd99c37bdb2..5f305c47221e90 100644 --- a/src/native/external/zlib/trees.c +++ b/src/native/external/zlib/trees.c @@ -193,7 +193,7 @@ local void send_bits(s, value, length) s->bits_sent += (ulg)length; /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid)) * unused bits in value. */ if (s->bi_valid > (int)Buf_size - length) { @@ -256,7 +256,7 @@ local void tr_static_init() length = 0; for (code = 0; code < LENGTH_CODES-1; code++) { base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ dist = 0; for (code = 0 ; code < 16; code++) { base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ for ( ; code < D_CODES; code++) { base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { _dist_code[256 + dist++] = (uch)code; } } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); + Assert (dist == 256, "tr_static_init: 256 + dist != 512"); /* Construct the codes of the static literal tree */ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; @@ -312,7 +312,7 @@ local void tr_static_init() } /* =========================================================================== - * Genererate the file trees.h describing the static trees. + * Generate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H # ifndef ZLIB_DEBUG @@ -321,7 +321,7 @@ local void tr_static_init() # define SEPARATOR(i, last, width) \ ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) + ((i) % (width) == (width) - 1 ? ",\n" : ", ")) void gen_trees_header() { @@ -458,7 +458,7 @@ local void pqdownheap(s, tree, k) while (j <= s->heap_len) { /* Set j to the smallest of the two sons: */ if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) { j++; } /* Exit if v is smaller than both sons */ @@ -507,7 +507,7 @@ local void gen_bitlen(s, desc) */ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + for (h = s->heap_max + 1; h < HEAP_SIZE; h++) { n = s->heap[h]; bits = tree[tree[n].Dad].Len + 1; if (bits > max_length) bits = max_length, overflow++; @@ -518,7 +518,7 @@ local void gen_bitlen(s, desc) s->bl_count[bits]++; xbits = 0; - if (n >= base) xbits = extra[n-base]; + if (n >= base) xbits = extra[n - base]; f = tree[n].Freq; s->opt_len += (ulg)f * (unsigned)(bits + xbits); if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); @@ -530,10 +530,10 @@ local void gen_bitlen(s, desc) /* Find the first bit length which could increase: */ do { - bits = max_length-1; + bits = max_length - 1; while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */ s->bl_count[max_length]--; /* The brother of the overflow item also moves one step up, * but this does not affect bl_count[max_length] @@ -569,7 +569,7 @@ local void gen_bitlen(s, desc) * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -local void gen_codes (tree, max_code, bl_count) +local void gen_codes(tree, max_code, bl_count) ct_data *tree; /* the tree to decorate */ int max_code; /* largest code with non zero frequency */ ushf *bl_count; /* number of codes at each bit length */ @@ -583,13 +583,13 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits - 1]) << 1; next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. */ - Assert (code + bl_count[MAX_BITS]-1 == (1<heap_len = 0, s->heap_max = HEAP_SIZE; @@ -652,7 +652,7 @@ local void build_tree(s, desc) } desc->max_code = max_code; - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + /* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree, * establish sub-heaps of increasing lengths: */ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); @@ -700,7 +700,7 @@ local void build_tree(s, desc) * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) +local void scan_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -714,10 +714,10 @@ local void scan_tree (s, tree, max_code) int min_count = 4; /* min repeat count */ if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ + tree[max_code + 1].Len = (ush)0xffff; /* guard */ for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -745,7 +745,7 @@ local void scan_tree (s, tree, max_code) * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) +local void send_tree(s, tree, max_code) deflate_state *s; ct_data *tree; /* the tree to be scanned */ int max_code; /* and its largest code of non zero frequency */ @@ -758,11 +758,11 @@ local void send_tree (s, tree, max_code) int max_count = 7; /* max repeat count */ int min_count = 4; /* min repeat count */ - /* tree[max_code+1].Len = -1; */ /* guard already set */ + /* tree[max_code + 1].Len = -1; */ /* guard already set */ if (nextlen == 0) max_count = 138, min_count = 3; for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; + curlen = nextlen; nextlen = tree[n + 1].Len; if (++count < max_count && curlen == nextlen) { continue; } else if (count < min_count) { @@ -773,13 +773,13 @@ local void send_tree (s, tree, max_code) send_code(s, curlen, s->bl_tree); count--; } Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2); } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3); } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7); } count = 0; prevlen = curlen; if (nextlen == 0) { @@ -807,8 +807,8 @@ local int build_bl_tree(s) /* Build the bit length tree: */ build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + /* opt_len now includes the length of the tree representations, except the + * lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts. */ /* Determine the number of bit length codes to send. The pkzip format @@ -819,7 +819,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -841,19 +841,19 @@ local void send_all_trees(s, lcodes, dcodes, blcodes) Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, "too many codes"); Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes - 1, 5); + send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */ for (rank = 0; rank < blcodes; rank++) { Tracev((stderr, "\nbl code %2d ", bl_order[rank])); send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); } Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); } @@ -866,7 +866,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) ulg stored_len; /* length of input block */ int last; /* one if this is the last block for a file */ { - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ + send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */ bi_windup(s); /* align on byte boundary */ put_short(s, (ush)stored_len); put_short(s, (ush)~stored_len); @@ -877,7 +877,7 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; + s->bits_sent += stored_len << 3; #endif } @@ -943,14 +943,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex = build_bl_tree(s); /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; + opt_lenb = (s->opt_len + 3 + 7) >> 3; + static_lenb = (s->static_len + 3 + 7) >> 3; Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, s->sym_next / 3)); - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; +#ifndef FORCE_STATIC + if (static_lenb <= opt_lenb || s->strategy == Z_FIXED) +#endif + opt_lenb = static_lenb; } else { Assert(buf != (char*)0, "lost buf"); @@ -960,7 +963,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) #ifdef FORCE_STORED if (buf != (char*)0) { /* force stored block */ #else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { + if (stored_len + 4 <= opt_lenb && buf != (char*)0) { /* 4: two words for the lengths */ #endif /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. @@ -971,21 +974,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) */ _tr_stored_block(s, buf, stored_len, last); -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); + } else if (static_lenb == opt_lenb) { + send_bits(s, (STATIC_TREES<<1) + last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); #ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); + send_bits(s, (DYN_TREES<<1) + last, 3); + send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1, + max_blindex + 1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); #ifdef ZLIB_DEBUG @@ -1004,22 +1003,22 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) s->compressed_len += 7; /* align on byte boundary */ #endif } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3, + s->compressed_len - 7*last)); } /* =========================================================================== * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) +int ZLIB_INTERNAL _tr_tally(s, dist, lc) deflate_state *s; unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ + unsigned lc; /* match length - MIN_MATCH or unmatched char (dist==0) */ { - s->sym_buf[s->sym_next++] = dist; - s->sym_buf[s->sym_next++] = dist >> 8; - s->sym_buf[s->sym_next++] = lc; + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1031,7 +1030,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } return (s->sym_next == s->sym_end); @@ -1061,7 +1060,7 @@ local void compress_block(s, ltree, dtree) } else { /* Here, lc is the match length - MIN_MATCH */ code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ + send_code(s, code + LITERALS + 1, ltree); /* send length code */ extra = extra_lbits[code]; if (extra != 0) { lc -= base_length[code]; @@ -1177,6 +1176,6 @@ local void bi_windup(s) s->bi_buf = 0; s->bi_valid = 0; #ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; + s->bits_sent = (s->bits_sent + 7) & ~7; #endif } diff --git a/src/native/external/zlib/uncompr.c b/src/native/external/zlib/uncompr.c index f03a1a865e347d..f9532f46c1a69f 100644 --- a/src/native/external/zlib/uncompr.c +++ b/src/native/external/zlib/uncompr.c @@ -24,7 +24,7 @@ Z_DATA_ERROR if the input data was corrupted, including if the input data is an incomplete zlib stream. */ -int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) +int ZEXPORT uncompress2(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; @@ -83,7 +83,7 @@ int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) err; } -int ZEXPORT uncompress (dest, destLen, source, sourceLen) +int ZEXPORT uncompress(dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; diff --git a/src/native/external/zlib/zconf.h b/src/native/external/zlib/zconf.h index 5e1d68a004e974..bf977d3e70adef 100644 --- a/src/native/external/zlib/zconf.h +++ b/src/native/external/zlib/zconf.h @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -349,6 +352,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +473,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/src/native/external/zlib/zconf.h.cmakein b/src/native/external/zlib/zconf.h.cmakein index a7f24cce60ff7a..247ba2461dd09e 100644 --- a/src/native/external/zlib/zconf.h.cmakein +++ b/src/native/external/zlib/zconf.h.cmakein @@ -40,6 +40,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -351,6 +354,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -469,11 +475,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/src/native/external/zlib/zconf.h.in b/src/native/external/zlib/zconf.h.in index 5e1d68a004e974..bf977d3e70adef 100644 --- a/src/native/external/zlib/zconf.h.in +++ b/src/native/external/zlib/zconf.h.in @@ -38,6 +38,9 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_combine_gen z_crc32_combine_gen +# define crc32_combine_gen64 z_crc32_combine_gen64 +# define crc32_combine_op z_crc32_combine_op # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound @@ -349,6 +352,9 @@ # ifdef FAR # undef FAR # endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ @@ -467,11 +473,18 @@ typedef uLong FAR uLongf; # undef _LARGEFILE64_SOURCE #endif -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H +#ifndef Z_HAVE_UNISTD_H +# ifdef __WATCOMC__ +# define Z_HAVE_UNISTD_H +# endif +#endif +#ifndef Z_HAVE_UNISTD_H +# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32) +# define Z_HAVE_UNISTD_H +# endif #endif #ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# if defined(Z_HAVE_UNISTD_H) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ diff --git a/src/native/external/zlib/zlib.3 b/src/native/external/zlib/zlib.3 index bcaebd9f02cda1..6f6e91404dff19 100644 --- a/src/native/external/zlib/zlib.3 +++ b/src/native/external/zlib/zlib.3 @@ -1,4 +1,4 @@ -.TH ZLIB 3 "27 Mar 2022" +.TH ZLIB 3 "13 Oct 2022" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS @@ -105,7 +105,7 @@ before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS AND LICENSE -Version 1.2.12 +Version 1.2.13 .LP Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler .LP diff --git a/src/native/external/zlib/zlib.3.pdf b/src/native/external/zlib/zlib.3.pdf deleted file mode 100644 index 54d677ab01708639e04f9972ef20c52b00ba432d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8848 zcmch7c|4Ts8+S?46e6i)8M0=X88c(7BL*RpUDg<8tiv!f_K>YCQOKUHEXf{PEQQFH zkYp)aq3oiNqW2lqIi1t_y}#f4`JB)D{NtYMxvuNJ*8Be6_d`%uRb2umi2w<<%w4$w zLV}@Sl8qBcK>?yoaJ8p8fTaP7K1AJ-NF|WL5OpGsN>C-(lJEpH8bqOz2{;#!_w`(} zSL9dfZ2tXcpPJX7a1TBDIzDOr27X?j*sM=*?$>e&5)iP#(jj)5B|gHf8LaZIeS8hQ zAYydK{7eF2XY%wk+JA$pgRZ!`kK;M-${N{^yvk?mHLTgXa0Z>p_~~lOqeS!7WlqS% z$Eev?2REawQ}Cu-6|?i2h7$@6I%~oWqmYr>+Pyc@j#895OTI;v?mOQZ70MB=@9FQ( zR_phn?SarONbqot!6Pcb~@v$^+DwSBG~eh{E^-^Ee3t>XGfyAR{H=BdH0#Eh^F<&2s= z?ZW$ zH{VzCCB;^ps5sJGBTLAmr)aWgAhRx zz3LrrLI{izo zk3rkVkskhoMeUpIe0AYV`a+o>oLLVwn%VZ(C?ZbNX|^z1R@qEG^qrC6k5h=yM(j?q z+j%{IrHew0e@yOdk8vqwFDIM^t{= zed^lvPaU|^pCZfAOFJUM%VAjAwJXLPKJC4&JX4jc%RD5;G`&tT#bhTGT3X6ZBo^tn z-4tL=l)1Q@EyL7qhIfE$DPezOOf93SAwQ<-9=!zCP>*x@$QdYFr5>4KT~^NPmVNCl z=)49L7o@!iO26ChJkgSra=HAHc(7CHnc}q%%W(Qi@pSGW*JlKN2K=cFcdvo@A;sB* zMVmGX>lr4-A-k3Op*+qHjdy4I=Oc&d3ui_rE%;R8TAsVd21PANxA)lyMUdn8Wj+># zP5K$TE|~F~T`#<9s=GETv1EC>*JPC=YgNU}OUXJxJf9G(^(dc?AAaSe5<}sk+GM0>@E!L1MRt*MQ3_*nuKW=XH1^mWR*04JKj$N9lE`F!L8=Xj zywD~$=74!+C~rKwByu82?*7;UGpv8p1GUZU-5!e-;|^8eO^!IrE7JvMO1vWSCksQ}}9b+M}n z9TAUOGdny3FlF(CGA5 zu0-J>tE$u8CO2L5XOB+{&j+96i^eajQm)ZC4(7;5ddr1ci?>I~RCx=U(0Q3HgolAvU7W*e2Gv* z$V$6|@P85%UQEdv6gi^s5^KS6`28+^;i20lO7Oco=!Q7XimpFDP~>3+63BbLL1!A6 z<1d!ORUE^SW30_(iYtF{EL2J+y@Z9E`}88>IeSFRa98US=(FHRhe9|tHQu62hzcL%Ara6Ff6}f$6$at5@C2!JL9lLy*qR%G+ywcSzWxC4D)>J*{`o z)Oe;JKFv!;H;C!ZaElv<;jY$}m&L73?@zg=8o`n~Yyk1=8Hp~|=|)B1o@8n1J;1n5r%2ZBt?yY-6kX0)aw#>yK#jgAGM!*kV7CeGV!Jqe&St}dXm7*5_ue?i!W&X9$g$ZPq*lXF>?Ytp6_4{_8>6ARrs&$d?wsG+7iLo&h zqegT8dwPA63_|~EJ0*5UxuWzcPu`81Zr}aj%Wn(x-lK6n%z`%U)9*246u8XCzCk+f zQFd{n_1TJQXPQwoBe$hi!mxAe> z18YyI4K&v6O1a?VYL}1ra>6nrnNRPTZGNSelHU2rUH)}$A$uy*3E%31Vz|6YuPXUJ z`m!}Qx3v|Jn7mxSCq(;vTUG_>@TWJQ>~4aN^g+0Xxnv#W`^vi0Pgt$Jil&R0vC~dD z+H&iHof`*>-lfKQ*7dMg1l8nQ_XcA#oGgrOG&_s2I40(+yCXaCtyqoWL=U(ciwYXQ z?Edo19;;au>yJH9&X-%lUOd#r^LP#I)~-#T_0O_??(UzqbeO|=-&$z9Etqq?K6|k7 z*bBF^BVIBi6QTOAwK=urFB#n36Is4HNnn^K^7wlxl@}k~uzi_>e91~0dski{J)8!L z%yr9ZFU8w(JERhrgC7__bsDPfuCvHE(YNpBK9rNs`%P7>e}R183y19ajh1fRb*pbZ zeCJDY)(7m6p=+cgSxmEGau+j-lPNjtnoZI+EWBUkf^#iwS9-;uotI`-cHWLpk!3K` z^js0P?l`Q*7OaZhVQ?LJ=80)ADknd`dNIM^io3?>-Ly0DCi?WXB^x_MYllbE zStYK|laicz)9N4hoRcVZO@Ao@MeL-%7&<>;y6=B7*h*YC3+1$OXSz&29mVNz=KGZ^pfF-;z7yt#qyZ)w9emNU5>1QUi`R z`@i&{bMl6bT4z~pt7YY?OTsv9^f@69;iAODt@Buo?mES-y2B}tGmw*0mtyy_&Ug!1 zypyfw5`CS8cJMNItQfn|jsDO#UvAD7V$hfzEoy|~?rqT$JT$}nNk`+51E1AxRo&*6 z0}gD2(HRsuy(OcyUs5cq z10M$ZxNmjz^3|wP?#OC@K2KBkGf#K6J@1(e-!h<= z7gH~y3mzI(>1ZKyuls5t2U&)WU#*`HDi#jcdfzBc?&ohb+<*)WL4q`;EET#@hYT4W z9Z`!7D>+@Vx)FJT1F`qS#eEODUyG!PRYg!@FX$y>NmB&~ougtsw>2KEha^$r)ZeY{ zjCNRqpF;X&=8W?zQ1C3dmk_xTM5yFpc__#d+*nrqS6IlY0#NFgsawE_t`| zed|~_m|I)$;ueEQ)vQwm96p$%YbnYVANF{6L*GEUC&Lj##!P*xQ}0$CJ?v*s{tU1<+?_=cK zaSjE^kSS?uYx)o~SzKJT7KFhG_=@OHHAjAB8Vnri-Jz_1$8rUnO3yi*uaoJzesJG? z>z$j?kD76x9{V?X4xg~D>B~=m@(!*Wa1H1j6W5q-o^mIwF(zsxhVs4QGCpzICp5pe z{Y%$yVJ6ypCZsD*IB>!fDtt$3E84}%)7*d8h;%ze528fxVe{-H{?KV>m3J) zU7~{|xzc_kIM*P=$JEF^vEO|4)JW>Q0!%NQeqHTmpw7LDw|p$avo5)v8C8a&ER%D^ z^~NEaexwSB{7dAO&9;`8;sz;6_fp3v%U#Y}A7dQ%m%QiOkuf=3J(n?DW-z#zmVL>5 zD-iXlSf%8el>PDi6i`cVm+!RUHPJ5_&+cY@^&oommop4-#TZ2#JX3jmpZC?A6w6JX zkxFzNFTLr^q(`9iDIp6+N>1b99VnhQtJt7H-my#(`&%WOx}uW31J0G@bn2}Rm27*; zxr)!9li_g_q+82gVD&XB4hy)`MFCf+A+p5Z>}yXLISyv%UCFBjnWxPOV z)=BoD{;Bu`_H27c8Rh+)ADPB&P#x|RHXTzm>hR}?^nDuTd3Ef5fojevN6eHqq$<9p zmh%?GW#1j%*&?{qL)|fxLcdp;SwdbqJ*ce*n&Rkf@T|u&+u(3tS+4e>&he~QH=c?m z@-}Q$5!j!_$MYQWVG*ez42oUrx_&wBe9C^94^*oBuC8&Ndc-GnHM2U2nt%zWab5Jf zO(_07Qo@f|Rq`yU@-kb_5ciP8_!W*N78YKQp57GIhTUC-w?A;}>98w;9$CfRg9dFq zW;4(iKdB7jiN`e?L{*OwZBOf{-MXZ4u0ve2t)%Ew3O2a4P5f*Vp>e`ot${f}J?2*H zvFeOItWL9^NR4s4sw4m8l{tk&?(hNbl*_%2r}QQT`_7HjBpeVgQmDd~M&pymR1o3N zWb)U9MW4wxlv{E-K?Ho0k2cm$3nMr-QM6z8WXfK0r(dOPWkfKv3wtR_@9X%8N4d$# z_SDH2JMLn7MlZ;SLoUN&Lo3jVeR&7QO{EXND|r5Dc<0qvrW*|oVJ>NnWQ#nJn{!%- zJwrC{V}!s$*ZDGA=|MStB8Q$|G}Y?4Fea@$I-`TxYj>s5j@{?Qoe2533iA{6E~?02 zCWP9hQ|wnRP&>OhQvFv6_=C5wvx`?r{UIWwOVi=heuvII;bpUe4AVz2!D0!*r;SS- zrao&G-+fTZo@&J5V~KhPdWsD(eD<(_^@dHLte| zSU{kgBHG?umX$M_d5OcE>(URk^=FXqyR1vs?>l|APRnzVd8V%|B`-@pC&E+g7N)ve zmFgbHX=)><$s`~HTD?4=c~#Op=5oJn#?b(FArbpPjy?MW=h|eBxQ_=vN}rM!Q8HV9 zfkMaiysLraPTS%xejdnHslA&Xj+$pSZNw?3tJy!eJr+p<6UZ96&4t0OS(D=a5GwL&lnAA3BVROAVu>V<28~u@t<~D?A zZ3@;pQopU~vcGBh=*rf|rfcq8V#h3-5`Gg$>5B3DC zm7Lt%pEfJTbE!f9f<fZY z!Ur|Ie7m?T)mp#JnbBKkox|lCFL=5&8QJFS8m6bib~as57a!K7vZXzTT1nE2Pmjc->J@y&Y8^hFG@MB zE+2n`1lxN(4HLj*QOKW|;1@_>=;KC!=;G`N5G(=jh*KeXgUz7;JdlP-fl;zjmLP~e zi3;3BgP{NynczwV!)f3FAQLDg53((R0$gG1l1a7(1gbd%xa0;y3<=&;Ku*n@ddgs1 z6bAb)qD}(D0lhSN;8q)g0e%A-Dd259LL>deEVMa(T#x^MF>w3x9R&GqAnJDmw?Wjl z(LXHw(?GyqAcWxU7*fEH(~fuw*c?QQus#U(Jyw=rz*P^xcd1`}{Hu!q3yz8-lI(wK z`VnRAU`pn{_iXjy=05Qv@x zs-rDVLdS;a=#5VS?5E`6&qoM@Xa5KaK_pO5ScbTW10lY(ubjbX62yta&61cEl?R zpG9J!ST_v8!BNAPOfc|0V`%H^Y%7ZwRziamlyE@p5G1^DZW4Ce-=rvD0>xI5AEU3W z&QD|Tmh*OTa{;Oo?CnByrO0_J3U7CKyu2j6;F2V=Jp?8z zD+_^2L8PQ401gR?k1G}DE#XQz4$QZ0h@;6LVy+a)ZJQ)*NiGma69`Na3i&yaD&P*; z(T(azas|^S#@UcOsEWcK9*%f9s4Pkfijam$5TxNU5-^w@N&*Tz5;z$o!iGSQg+Xm# zKc{p1#mv9V2fP3#gadH^MsmOsiTAK2kQIeb>1u;dIglvS@AHFYC8c1(kRR^(k1DXhqotrgNTF~EDU=}$DF>65g91NMa!{xO;5_{M+%u zxnZ&Y_lUW;&`O%dC#OoX^>6`pE=|?{mxB4XbBwqB!(cZLGI6^*@U{>FkwCMJ0;CxR zSd6!ovm=pRa6oP2+}w!3ib^Ya2vC#4Xa(RU)sadhptpNZnMnOUAUe`|NsfqfwO17O zmcSG2a2`aeFxtpUbe%UgA_O-}AwY4aKacErv1f13up{z`*FX(02jG`O_PZ!~EsDF8YAl}{Qe4eZ)~rvaAzoraJC zaK+#Fq@@3WCi@!=DGUG2W;hD^n|(+W5=iXd=71x9(QXj5<^m{ogq(X@HYL#gVDog&`v)iv$S@s_CeM{tv?$gG~Sc diff --git a/src/native/external/zlib/zlib.h b/src/native/external/zlib/zlib.h index 4a98e38bf34c82..953cb5012dc203 100644 --- a/src/native/external/zlib/zlib.h +++ b/src/native/external/zlib/zlib.h @@ -1,5 +1,5 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.12, March 11th, 2022 + version 1.2.13, October 13th, 2022 Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler @@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.12" -#define ZLIB_VERNUM 0x12c0 +#define ZLIB_VERSION "1.2.13" +#define ZLIB_VERNUM 0x12d0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 12 +#define ZLIB_VER_REVISION 13 #define ZLIB_VER_SUBREVISION 0 /* @@ -276,7 +276,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput + which can be used if desired to determine whether or not there is more output in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to @@ -660,7 +660,7 @@ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up @@ -915,7 +915,7 @@ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. + Similarly, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. @@ -1437,12 +1437,12 @@ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf + multiple of size, then the final partial item is nevertheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. + file, resetting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); @@ -1913,7 +1913,7 @@ ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) diff --git a/src/native/external/zlib/zlib2ansi b/src/native/external/zlib/zlib2ansi index 15e3e165f37dec..23b2a1d5a3ec2f 100644 --- a/src/native/external/zlib/zlib2ansi +++ b/src/native/external/zlib/zlib2ansi @@ -8,7 +8,7 @@ # TODO # -# Asumes no function pointer parameters. unless they are typedefed. +# Assumes no function pointer parameters. unless they are typedefed. # Assumes no literal strings that look like function definitions # Assumes functions start at the beginning of a line @@ -104,7 +104,7 @@ sub StripComments no warnings; - # Strip C & C++ coments + # Strip C & C++ comments # From the perlfaq $_[0] =~ diff --git a/src/native/external/zlib/zutil.c b/src/native/external/zlib/zutil.c index dcab28a0d5177a..9543ae825e3250 100644 --- a/src/native/external/zlib/zutil.c +++ b/src/native/external/zlib/zutil.c @@ -61,9 +61,11 @@ uLong ZEXPORT zlibCompileFlags() #ifdef ZLIB_DEBUG flags += 1 << 8; #endif + /* #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif + */ #ifdef ZLIB_WINAPI flags += 1 << 10; #endif @@ -119,7 +121,7 @@ uLong ZEXPORT zlibCompileFlags() # endif int ZLIB_INTERNAL z_verbose = verbose; -void ZLIB_INTERNAL z_error (m) +void ZLIB_INTERNAL z_error(m) char *m; { fprintf(stderr, "%s\n", m); @@ -214,7 +216,7 @@ local ptr_table table[MAX_PTR]; * a protected system like OS/2. Use Microsoft C instead. */ -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; @@ -240,7 +242,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) return buf; } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { int n; @@ -277,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) # define _hfree hfree #endif -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); @@ -302,7 +304,7 @@ extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) +voidpf ZLIB_INTERNAL zcalloc(opaque, items, size) voidpf opaque; unsigned items; unsigned size; @@ -312,7 +314,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) (voidpf)calloc(items, size); } -void ZLIB_INTERNAL zcfree (opaque, ptr) +void ZLIB_INTERNAL zcfree(opaque, ptr) voidpf opaque; voidpf ptr; { From 0ac097f594f62b7a13ca9bd3354a9fb94566878a Mon Sep 17 00:00:00 2001 From: Elinor Fung Date: Wed, 12 Apr 2023 22:05:11 -0700 Subject: [PATCH 18/21] Implement `load_assembly_bytes` delegate for hosting API (#84650) --- .../ComponentWithNoDependencies/Component.cs | 1 + .../FunctionPointerResultExtensions.cs | 5 + .../NativeHosting/LoadAssembly.cs | 130 ++++++++++++----- .../ILLink.Descriptors.LibraryBuild.xml | 1 + .../src/ILLink/ILLink.Descriptors.Shared.xml | 1 + .../InteropServices/ComponentActivator.cs | 50 +++++++ src/native/corehost/coreclr_delegates.h | 8 + .../corehost/corehost_context_contract.h | 1 + src/native/corehost/fxr/hostfxr.cpp | 2 + src/native/corehost/hostfxr.h | 1 + src/native/corehost/hostpolicy/hostpolicy.cpp | 6 + .../test/nativehost/host_context_test.cpp | 138 +++++++++++++++++- .../test/nativehost/host_context_test.h | 11 ++ .../corehost/test/nativehost/nativehost.cpp | 51 +++++++ 14 files changed, 365 insertions(+), 41 deletions(-) diff --git a/src/installer/tests/Assets/TestProjects/ComponentWithNoDependencies/Component.cs b/src/installer/tests/Assets/TestProjects/ComponentWithNoDependencies/Component.cs index 8620ad949cab88..1216e1ecf43105 100644 --- a/src/installer/tests/Assets/TestProjects/ComponentWithNoDependencies/Component.cs +++ b/src/installer/tests/Assets/TestProjects/ComponentWithNoDependencies/Component.cs @@ -19,6 +19,7 @@ static Component() { Assembly asm = Assembly.GetExecutingAssembly(); Console.WriteLine($"{asm.GetName().Name}: AssemblyLoadContext = {AssemblyLoadContext.GetLoadContext(asm)}"); + Console.WriteLine($"{asm.GetName().Name}: Location = '{asm.Location}'"); } private static void PrintComponentCallLog(string name, IntPtr arg, int size) diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/FunctionPointerResultExtensions.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/FunctionPointerResultExtensions.cs index fca93813528aa5..09fdc52bc186bf 100644 --- a/src/installer/tests/HostActivation.Tests/NativeHosting/FunctionPointerResultExtensions.cs +++ b/src/installer/tests/HostActivation.Tests/NativeHosting/FunctionPointerResultExtensions.cs @@ -42,5 +42,10 @@ public static FluentAssertions.AndConstraint ExecuteInD { return assertion.HaveStdOutContaining($"{assemblyName}: AssemblyLoadContext = \"Default\" System.Runtime.Loader.DefaultAssemblyLoadContext"); } + + public static FluentAssertions.AndConstraint ExecuteWithLocation(this CommandResultAssertions assertion, string assemblyName, string location) + { + return assertion.HaveStdOutContaining($"{assemblyName}: Location = '{location}'"); + } } } diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssembly.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssembly.cs index b5e4c748eaa6be..28e7044525c1ee 100644 --- a/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssembly.cs +++ b/src/installer/tests/HostActivation.Tests/NativeHosting/LoadAssembly.cs @@ -11,11 +11,14 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHosting { - public partial class LoadAssembly : IClassFixture + public class LoadAssembly : IClassFixture { private const string AppLoadAssemblyArg = "app_load_assembly"; private const string ComponentLoadAssemblyArg = "component_load_assembly"; + private const string AppLoadAssemblyBytesArg = "app_load_assembly_bytes"; + private const string ComponentLoadAssemblyBytesArg = "component_load_assembly_bytes"; + private readonly SharedTestState sharedState; public LoadAssembly(SharedTestState sharedTestState) @@ -23,77 +26,113 @@ public LoadAssembly(SharedTestState sharedTestState) sharedState = sharedTestState; } - [Fact] - public void ApplicationContext() + private void ApplicationContext(bool loadAssemblyBytes, bool loadSymbolBytes) { - var appProject = sharedState.Application; - var componentProject = sharedState.ComponentWithNoDependenciesFixture.TestProject; - string[] args = + var app = sharedState.Application; + var component = sharedState.Component; + IEnumerable args = new[] { - AppLoadAssemblyArg, + loadAssemblyBytes ? AppLoadAssemblyBytesArg : AppLoadAssemblyArg, sharedState.HostFxrPath, - appProject.AppDll, - componentProject.AppDll, - sharedState.ComponentTypeName, - sharedState.ComponentEntryPoint1, - }; + app.AppDll + }.Concat(sharedState.GetComponentLoadArgs(loadAssemblyBytes, loadSymbolBytes)); + CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot) .Execute(); result.Should().Pass() - .And.InitializeContextForApp(appProject.AppDll) + .And.InitializeContextForApp(app.AppDll) .And.ExecuteSelfContained(selfContained: false) - .And.ExecuteInDefaultContext(componentProject.AssemblyName) + .And.ExecuteInDefaultContext(component.AssemblyName) + .And.ExecuteWithLocation(component.AssemblyName, loadAssemblyBytes ? string.Empty : component.AppDll) .And.ExecuteFunctionPointer(sharedState.ComponentEntryPoint1, 1, 1); } [Fact] - public void ComponentContext() + public void ApplicationContext_FilePath() + { + ApplicationContext(loadAssemblyBytes: false, loadSymbolBytes: false); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ApplicationContext_Bytes(bool loadSymbolBytes) + { + ApplicationContext(loadAssemblyBytes: true, loadSymbolBytes); + } + + private void ComponentContext(bool loadAssemblyBytes, bool loadSymbolBytes) { - var appProject = sharedState.Application; - var componentProject = sharedState.ComponentWithNoDependenciesFixture.TestProject; - string[] args = + var app = sharedState.Application; + var component = sharedState.Component; + IEnumerable args = new[] { - ComponentLoadAssemblyArg, + loadAssemblyBytes ? ComponentLoadAssemblyBytesArg : ComponentLoadAssemblyArg, sharedState.HostFxrPath, - componentProject.RuntimeConfigJson, - componentProject.AppDll, - sharedState.ComponentTypeName, - sharedState.ComponentEntryPoint1, - }; + component.RuntimeConfigJson + }.Concat(sharedState.GetComponentLoadArgs(loadAssemblyBytes, loadSymbolBytes)); + CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot) .Execute(); result.Should().Pass() - .And.InitializeContextForConfig(componentProject.RuntimeConfigJson) - .And.ExecuteInDefaultContext(componentProject.AssemblyName) + .And.InitializeContextForConfig(component.RuntimeConfigJson) + .And.ExecuteInDefaultContext(component.AssemblyName) + .And.ExecuteWithLocation(component.AssemblyName, loadAssemblyBytes ? string.Empty : component.AppDll) .And.ExecuteFunctionPointer(sharedState.ComponentEntryPoint1, 1, 1); } [Fact] - public void SelfContainedApplicationContext() + public void ComponentContext_FilePath() + { + ComponentContext(loadAssemblyBytes: false, loadSymbolBytes: false); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ComponentContext_Bytes(bool loadSymbolBytes) + { + ComponentContext(loadAssemblyBytes: true, loadSymbolBytes); + } + + private void SelfContainedApplicationContext(bool loadAssemblyBytes, bool loadSymbolBytes) { - var appProject = sharedState.SelfContainedApplication; - var componentProject = sharedState.ComponentWithNoDependenciesFixture.TestProject; - string[] args = + var app = sharedState.SelfContainedApplication; + var component = sharedState.Component; + IEnumerable args = new[] { - AppLoadAssemblyArg, - appProject.HostFxrDll, - appProject.AppDll, - componentProject.AppDll, - sharedState.ComponentTypeName, - sharedState.ComponentEntryPoint1 - }; + loadAssemblyBytes ? AppLoadAssemblyBytesArg : AppLoadAssemblyArg, + app.HostFxrDll, + app.AppDll + }.Concat(sharedState.GetComponentLoadArgs(loadAssemblyBytes, loadSymbolBytes)); + CommandResult result = sharedState.CreateNativeHostCommand(args, sharedState.DotNetRoot) .Execute(); result.Should().Pass() - .And.InitializeContextForApp(appProject.AppDll) + .And.InitializeContextForApp(app.AppDll) .And.ExecuteSelfContained(selfContained: true) - .And.ExecuteInDefaultContext(componentProject.AssemblyName) + .And.ExecuteInDefaultContext(component.AssemblyName) + .And.ExecuteWithLocation(component.AssemblyName, loadAssemblyBytes ? string.Empty : component.AppDll) .And.ExecuteFunctionPointer(sharedState.ComponentEntryPoint1, 1, 1); } + [Fact] + public void SelfContainedApplicationContext_FilePath() + { + SelfContainedApplicationContext(loadAssemblyBytes: false, loadSymbolBytes: false); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void SelfContainedApplicationContext_Bytes(bool loadSymbolBytes) + { + SelfContainedApplicationContext(loadAssemblyBytes: true, loadSymbolBytes); + } + public class SharedTestState : SharedTestStateBase { public string HostFxrPath { get; } @@ -103,10 +142,10 @@ public class SharedTestState : SharedTestStateBase public TestApp SelfContainedApplication { get; } public TestProjectFixture ComponentWithNoDependenciesFixture { get; } + public TestApp Component => ComponentWithNoDependenciesFixture.TestProject.BuiltApp; public string ComponentTypeName { get; } public string ComponentEntryPoint1 => "ComponentEntryPoint1"; - public string UnmanagedFunctionPointerEntryPoint1 => "UnmanagedFunctionPointerEntryPoint1"; public SharedTestState() { @@ -127,6 +166,17 @@ public SharedTestState() ComponentTypeName = $"Component.Component, {ComponentWithNoDependenciesFixture.TestProject.AssemblyName}"; } + internal IEnumerable GetComponentLoadArgs(bool loadAssemblyBytes, bool loadSymbolBytes) + { + List args = new List() { Component.AppDll }; + if (loadAssemblyBytes) + args.Add(loadSymbolBytes ? $"{Path.GetFileNameWithoutExtension(Component.AppDll)}.pdb" : "nullptr"); + + args.Add(ComponentTypeName); + args.Add(ComponentEntryPoint1); + return args; + } + protected override void Dispose(bool disposing) { if (Application != null) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml index 849584a3e812d7..2cafb97358f18a 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.xml @@ -31,6 +31,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml index 71e5ac5adac0ee..a6c2ad4619d923 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.Shared.xml @@ -16,6 +16,7 @@ --> + diff --git a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs index d543fc8c5d7916..fefb25b18855cf 100644 --- a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs +++ b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComponentActivator.cs @@ -160,6 +160,56 @@ private static void LoadAssemblyImpl(string assemblyPath) } } + /// + /// Native hosting entry point for loading an assembly from a byte array + /// + /// Bytes of the assembly to load + /// Byte length of the assembly to load + /// Optional. Bytes of the symbols for the assembly + /// Optional. Byte length of the symbols for the assembly + /// Extensibility parameter (currently unused) + /// Extensibility parameter (currently unused) + [RequiresDynamicCode(NativeAOTIncompatibleWarningMessage)] + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("maccatalyst")] + [UnsupportedOSPlatform("tvos")] + [UnmanagedCallersOnly] + public static unsafe int LoadAssemblyBytes(byte* assembly, nint assemblyByteLength, byte* symbols, nint symbolsByteLength, IntPtr loadContext, IntPtr reserved) + { + if (!IsSupported) + return HostFeatureDisabled; + + try + { + ArgumentNullException.ThrowIfNull(assembly); + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(assemblyByteLength); + ArgumentOutOfRangeException.ThrowIfGreaterThan(assemblyByteLength, int.MaxValue); + ArgumentOutOfRangeException.ThrowIfNotEqual(loadContext, IntPtr.Zero); + ArgumentOutOfRangeException.ThrowIfNotEqual(reserved, IntPtr.Zero); + + ReadOnlySpan assemblySpan = new ReadOnlySpan(assembly, (int)assemblyByteLength); + ReadOnlySpan symbolsSpan = default; + if (symbols != null && symbolsByteLength > 0) + { + symbolsSpan = new ReadOnlySpan(symbols, (int)symbolsByteLength); + } + + LoadAssemblyBytesLocal(assemblySpan, symbolsSpan); + } + catch (Exception e) + { + return e.HResult; + } + + return 0; + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The same feature switch applies to GetFunctionPointer and this function. We rely on the warning from GetFunctionPointer.")] + static void LoadAssemblyBytesLocal(ReadOnlySpan assemblyBytes, ReadOnlySpan symbolsBytes) => AssemblyLoadContext.Default.InternalLoad(assemblyBytes, symbolsBytes); + } + /// /// Native hosting entry point for creating a native delegate /// diff --git a/src/native/corehost/coreclr_delegates.h b/src/native/corehost/coreclr_delegates.h index 03b1f814cde181..550badf135097b 100644 --- a/src/native/corehost/coreclr_delegates.h +++ b/src/native/corehost/coreclr_delegates.h @@ -49,4 +49,12 @@ typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_fn)( void *load_context /* Extensibility parameter (currently unused and must be 0) */, void *reserved /* Extensibility parameter (currently unused and must be 0) */); +typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_bytes_fn)( + const void *assembly_bytes /* Bytes of the assembly to load */, + size_t assembly_bytes_len /* Byte length of the assembly to load */, + const void *symbols_bytes /* Optional. Bytes of the symbols for the assembly */, + size_t symbols_bytes_len /* Optional. Byte length of the symbols for the assembly */, + void *load_context /* Extensibility parameter (currently unused and must be 0) */, + void *reserved /* Extensibility parameter (currently unused and must be 0) */); + #endif // __CORECLR_DELEGATES_H__ diff --git a/src/native/corehost/corehost_context_contract.h b/src/native/corehost/corehost_context_contract.h index 7426b72a3525b7..124a05a21cbd1e 100644 --- a/src/native/corehost/corehost_context_contract.h +++ b/src/native/corehost/corehost_context_contract.h @@ -29,6 +29,7 @@ enum class coreclr_delegate_type load_assembly_and_get_function_pointer, get_function_pointer, load_assembly, + load_assembly_bytes, __last, // Sentinel value for determining the last known delegate type }; diff --git a/src/native/corehost/fxr/hostfxr.cpp b/src/native/corehost/fxr/hostfxr.cpp index e16cee8d74f9f9..0df1b24cda77f4 100644 --- a/src/native/corehost/fxr/hostfxr.cpp +++ b/src/native/corehost/fxr/hostfxr.cpp @@ -669,6 +669,8 @@ namespace return coreclr_delegate_type::get_function_pointer; case hostfxr_delegate_type::hdt_load_assembly: return coreclr_delegate_type::load_assembly; + case hostfxr_delegate_type::hdt_load_assembly_bytes: + return coreclr_delegate_type::load_assembly_bytes; } return coreclr_delegate_type::invalid; } diff --git a/src/native/corehost/hostfxr.h b/src/native/corehost/hostfxr.h index 36bc4b835b279c..a19636b9e3fd08 100644 --- a/src/native/corehost/hostfxr.h +++ b/src/native/corehost/hostfxr.h @@ -29,6 +29,7 @@ enum hostfxr_delegate_type hdt_load_assembly_and_get_function_pointer, hdt_get_function_pointer, hdt_load_assembly, + hdt_load_assembly_bytes, }; typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv); diff --git a/src/native/corehost/hostpolicy/hostpolicy.cpp b/src/native/corehost/hostpolicy/hostpolicy.cpp index 440ae4f04f93f0..6173b1ae368ff5 100644 --- a/src/native/corehost/hostpolicy/hostpolicy.cpp +++ b/src/native/corehost/hostpolicy/hostpolicy.cpp @@ -543,6 +543,12 @@ namespace "Internal.Runtime.InteropServices.ComponentActivator", "LoadAssembly", delegate); + case coreclr_delegate_type::load_assembly_bytes: + return coreclr->create_delegate( + "System.Private.CoreLib", + "Internal.Runtime.InteropServices.ComponentActivator", + "LoadAssemblyBytes", + delegate); default: return StatusCode::LibHostInvalidArgs; } diff --git a/src/native/corehost/test/nativehost/host_context_test.cpp b/src/native/corehost/test/nativehost/host_context_test.cpp index 264a8f6369a9ae..24b649515d685a 100644 --- a/src/native/corehost/test/nativehost/host_context_test.cpp +++ b/src/native/corehost/test/nativehost/host_context_test.cpp @@ -373,6 +373,42 @@ namespace return success; } + bool call_load_assembly_bytes( + load_assembly_bytes_fn load_assembly_bytes, + const pal::char_t *assembly_path, + const pal::char_t *symbols_path, + const pal::char_t *log_prefix, + pal::stringstream_t &test_output) + { + std::ifstream assembly_file(assembly_path, std::ios::binary); + std::vector assembly_bytes { std::istreambuf_iterator(assembly_file), std::istreambuf_iterator() }; + assembly_file.close(); + + std::vector symbols_bytes; + if (pal::strcmp(symbols_path, _X("nullptr")) != 0) + { + std::ifstream symbols_file(symbols_path, std::ios::binary); + symbols_bytes = std::vector((std::istreambuf_iterator(symbols_file)), (std::istreambuf_iterator())); + symbols_file.close(); + } + + test_output << log_prefix << _X("calling load_assembly_bytes(") + << std::hex << (size_t)(assembly_bytes.data()) << _X(", ") << assembly_bytes.size() << _X(", ") + << std::hex << (size_t)(symbols_bytes.data()) << _X(", ") << symbols_bytes.size() + << _X(")") << std::endl; + + int rc = load_assembly_bytes( + (unsigned char *)assembly_bytes.data(), + assembly_bytes.size(), + symbols_bytes.empty() ? nullptr : (unsigned char *)symbols_bytes.data(), + symbols_bytes.size(), + nullptr /* load_context */, + nullptr /* reserved */); + bool success = rc == StatusCode::Success; + test_output << log_prefix << _X("load_assembly_bytes ") << (success ? _X("succeeded: ") : _X("failed: ")) << std::hex << std::showbase << rc << std::endl; + return success; + } + bool component_load_assembly_test( const hostfxr_exports &hostfxr, const pal::char_t *config_path, @@ -436,7 +472,7 @@ namespace { const pal::char_t *assembly_path = argv[i]; success &= call_load_assembly(load_assembly, assembly_path, log_prefix, test_output); - + const pal::char_t *type_name = argv[i + 1]; const pal::char_t *method_name = argv[i + 2]; success &= call_get_function_pointer_flavour(get_function_pointer, type_name, method_name, log_prefix, test_output); @@ -448,6 +484,83 @@ namespace return success && rcClose == StatusCode::Success; } + bool component_load_assembly_bytes_test( + const hostfxr_exports &hostfxr, + const pal::char_t *config_path, + int argc, + const pal::char_t *argv[], + const pal::char_t *log_prefix, + pal::stringstream_t &test_output) + { + hostfxr_handle handle; + if (!init_for_config(hostfxr, config_path, &handle, log_prefix, test_output)) + return false; + + load_assembly_bytes_fn load_assembly_bytes = nullptr; + hostfxr_delegate_type hdt = hostfxr_delegate_type::hdt_load_assembly_bytes; + bool success = get_runtime_delegate(hostfxr, handle, hdt, (void **)&load_assembly_bytes, log_prefix, test_output); + + get_function_pointer_fn get_function_pointer = nullptr; + hdt = hostfxr_delegate_type::hdt_get_function_pointer; + success &= get_runtime_delegate(hostfxr, handle, hdt, (void **)&get_function_pointer, log_prefix, test_output); + if (success) + { + for (int i = 0; i <= argc - 4; i += 4) + { + const pal::char_t *assembly_path = argv[i]; + const pal::char_t *symbols_path = argv[i + 1]; + success &= call_load_assembly_bytes(load_assembly_bytes, assembly_path, symbols_path, log_prefix, test_output); + + const pal::char_t *type_name = argv[i + 2]; + const pal::char_t *method_name = argv[i + 3]; + success &= call_get_function_pointer_flavour(get_function_pointer, type_name, method_name, log_prefix, test_output); + } + } + + int rcClose = hostfxr.close(handle); + if (rcClose != StatusCode::Success) + test_output << log_prefix << _X("hostfxr_close failed: ") << std::hex << std::showbase << rcClose << std::endl; + + return success && rcClose == StatusCode::Success; + } + + bool app_load_assembly_bytes_test( + const hostfxr_exports &hostfxr, + int argc, + const pal::char_t *argv[], + const pal::char_t *log_prefix, + pal::stringstream_t &test_output) + { + hostfxr_handle handle; + if (!init_for_command_line(hostfxr, argc, argv, &handle, log_prefix, test_output)) + return false; + + load_assembly_bytes_fn load_assembly_bytes = nullptr; + hostfxr_delegate_type hdt = hostfxr_delegate_type::hdt_load_assembly_bytes; + bool success = get_runtime_delegate(hostfxr, handle, hdt, (void **)&load_assembly_bytes, log_prefix, test_output); + + get_function_pointer_fn get_function_pointer = nullptr; + hdt = hostfxr_delegate_type::hdt_get_function_pointer; + success &= get_runtime_delegate(hostfxr, handle, hdt, (void **)&get_function_pointer, log_prefix, test_output); + if (success) + { + for (int i = 1; i <= argc - 4; i += 4) + { + const pal::char_t *assembly_path = argv[i]; + const pal::char_t *symbols_path = argv[i + 1]; + success &= call_load_assembly_bytes(load_assembly_bytes, assembly_path, symbols_path, log_prefix, test_output); + + const pal::char_t *type_name = argv[i + 2]; + const pal::char_t *method_name = argv[i + 3]; + success &= call_get_function_pointer_flavour(get_function_pointer, type_name, method_name, log_prefix, test_output); + } + } + int rcClose = hostfxr.close(handle); + if (rcClose != StatusCode::Success) + test_output << log_prefix << _X("hostfxr_close failed: ") << std::hex << std::showbase << rcClose << std::endl; + return success && rcClose == StatusCode::Success; + } + bool component_load_assembly_and_get_function_pointer_test( const hostfxr_exports &hostfxr, const pal::char_t *config_path, @@ -819,6 +932,29 @@ bool host_context_test::app_load_assembly( return app_load_assembly_test(hostfxr, argc, argv, config_log_prefix, test_output); } +bool host_context_test::component_load_assembly_bytes( + const pal::string_t &hostfxr_path, + const pal::char_t *config_path, + int argc, + const pal::char_t *argv[], + pal::stringstream_t &test_output) +{ + hostfxr_exports hostfxr{ hostfxr_path }; + + return component_load_assembly_bytes_test(hostfxr, config_path, argc, argv, config_log_prefix, test_output); +} + +bool host_context_test::app_load_assembly_bytes( + const pal::string_t &hostfxr_path, + int argc, + const pal::char_t *argv[], + pal::stringstream_t &test_output) +{ + hostfxr_exports hostfxr{ hostfxr_path }; + + return app_load_assembly_bytes_test(hostfxr, argc, argv, config_log_prefix, test_output); +} + bool host_context_test::component_load_assembly_and_get_function_pointer( const pal::string_t &hostfxr_path, const pal::char_t *config_path, diff --git a/src/native/corehost/test/nativehost/host_context_test.h b/src/native/corehost/test/nativehost/host_context_test.h index fe48dc33a33ca1..4d6b5d0cf74788 100644 --- a/src/native/corehost/test/nativehost/host_context_test.h +++ b/src/native/corehost/test/nativehost/host_context_test.h @@ -70,6 +70,17 @@ namespace host_context_test int argc, const pal::char_t *argv[], pal::stringstream_t &test_output); + bool component_load_assembly_bytes( + const pal::string_t &hostfxr_path, + const pal::char_t *config_path, + int argc, + const pal::char_t *argv[], + pal::stringstream_t &test_output); + bool app_load_assembly_bytes( + const pal::string_t &hostfxr_path, + int argc, + const pal::char_t *argv[], + pal::stringstream_t &test_output); bool component_load_assembly_and_get_function_pointer( const pal::string_t &hostfxr_path, const pal::char_t *config_path, diff --git a/src/native/corehost/test/nativehost/nativehost.cpp b/src/native/corehost/test/nativehost/nativehost.cpp index c317ed09dc4e3d..b53db3a65eaa93 100644 --- a/src/native/corehost/test/nativehost/nativehost.cpp +++ b/src/native/corehost/test/nativehost/nativehost.cpp @@ -267,6 +267,57 @@ int main(const int argc, const pal::char_t *argv[]) std::cout << tostr(test_output.str()).data() << std::endl; return success ? EXIT_SUCCESS : EXIT_FAILURE; } + else if (pal::strcmp(command, _X("component_load_assembly_bytes")) == 0) + { + // args: ... [ ...] + const int min_argc = 4; + if (argc < min_argc + 4) + { + std::cerr << "Invalid arguments" << std::endl; + return -1; + } + + const pal::string_t hostfxr_path = argv[2]; + const pal::char_t *config_path = argv[3]; + + int remaining_argc = argc - min_argc; + const pal::char_t **remaining_argv = nullptr; + if (argc > min_argc) + remaining_argv = &argv[min_argc]; + + pal::stringstream_t test_output; + bool success = false; + + success = host_context_test::component_load_assembly_bytes(hostfxr_path, config_path, remaining_argc, remaining_argv, test_output); + + std::cout << tostr(test_output.str()).data() << std::endl; + return success ? EXIT_SUCCESS : EXIT_FAILURE; + } + else if (pal::strcmp(command, _X("app_load_assembly_bytes")) == 0) + { + // args: ... [ ...] + const int min_argc = 3; + if (argc < min_argc + 5) + { + std::cerr << "Invalid arguments" << std::endl; + return -1; + } + + const pal::string_t hostfxr_path = argv[2]; + + int remaining_argc = argc - min_argc; + const pal::char_t **remaining_argv = nullptr; + if (argc > min_argc) + remaining_argv = &argv[min_argc]; + + pal::stringstream_t test_output; + bool success = false; + + success = host_context_test::app_load_assembly_bytes(hostfxr_path, remaining_argc, remaining_argv, test_output); + + std::cout << tostr(test_output.str()).data() << std::endl; + return success ? EXIT_SUCCESS : EXIT_FAILURE; + } else if (pal::strcmp(command, _X("component_load_assembly_and_get_function_pointer")) == 0) { // args: ... [ ...] From 1311b8aaf2bd03c2e6c64bd8fdc00c44120b7e7f Mon Sep 17 00:00:00 2001 From: Vlad-Alexandru Ionescu <114913836+LeVladIonescu@users.noreply.github.com> Date: Thu, 13 Apr 2023 08:19:05 +0300 Subject: [PATCH 19/21] [mono][jit] Added AndNot and ConditionalSelect intrinsics (#84744) Signed-off-by: Vlad - Alexandru Ionescu Co-authored-by: Vlad - Alexandru Ionescu --- src/mono/mono/arch/arm64/arm64-codegen.h | 6 ++++-- src/mono/mono/mini/cpu-arm64.mdesc | 2 ++ src/mono/mono/mini/mini-arm64.c | 8 ++++++++ src/mono/mono/mini/simd-intrinsics.c | 2 -- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/arch/arm64/arm64-codegen.h b/src/mono/mono/arch/arm64/arm64-codegen.h index 49dc27294832a8..20796854c42ff0 100644 --- a/src/mono/mono/arch/arm64/arm64-codegen.h +++ b/src/mono/mono/arch/arm64/arm64-codegen.h @@ -1825,6 +1825,8 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_orr(p, width, rd, rn, rm) arm_neon_3svec_opcode ((p), (width), 0b0, 0b10, 0b00011, (rd), (rn), (rm)) #define arm_neon_eor(p, width, rd, rn, rm) arm_neon_3svec_opcode ((p), (width), 0b1, 0b00, 0b00011, (rd), (rn), (rm)) #define arm_neon_bif(p, width, rd, rn, rm) arm_neon_3svec_opcode ((p), (width), 0b1, 0b11, 0b00011, (rd), (rn), (rm)) +#define arm_neon_bic(p, width, rd, rn, rm) arm_neon_3svec_opcode ((p), (width), 0b0, 0b01, 0b00011, (rd), (rn), (rm)) +#define arm_neon_bsl(p, width, rd, rn, rm) arm_neon_3svec_opcode ((p), (width), 0b1, 0b01, 0b00011, (rd), (rn), (rm)) // Specific macros: #define arm_neon_shadd_8b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_LOW, 0b0, SIZE_1, 0b00000, (rd), (rn), (rm)) @@ -2245,8 +2247,8 @@ arm_encode_arith_imm (int imm, guint32 *shift) #define arm_neon_eor_8b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_LOW, 0b1, 0b00, 0b00011, (rd), (rn), (rm)) #define arm_neon_eor_16b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_FULL, 0b1, 0b00, 0b00011, (rd), (rn), (rm)) -#define arm_neon_bsl_8b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_LOW, 0b1, 0b00, 0b00011, (rd), (rn), (rm)) -#define arm_neon_bsl_16b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_FULL, 0b1, 0b00, 0b00011, (rd), (rn), (rm)) +#define arm_neon_bsl_8b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_LOW, 0b1, 0b01, 0b00011, (rd), (rn), (rm)) +#define arm_neon_bsl_16b(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_FULL, 0b1, 0b01, 0b00011, (rd), (rn), (rm)) #define arm_neon_fminnmp_2s(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_LOW, 0b1, 0b10 | SIZE_1, 0b11000, (rd), (rn), (rm)) #define arm_neon_fminnmp_4s(p, rd, rn, rm) arm_neon_3svec_opcode ((p), VREG_FULL, 0b1, 0b10 | SIZE_1, 0b11000, (rd), (rn), (rm)) diff --git a/src/mono/mono/mini/cpu-arm64.mdesc b/src/mono/mono/mini/cpu-arm64.mdesc index 8da7174c0fd58c..7176dd6309186a 100644 --- a/src/mono/mono/mini/cpu-arm64.mdesc +++ b/src/mono/mono/mini/cpu-arm64.mdesc @@ -531,6 +531,8 @@ create_scalar_int: dest:x src1:i len:8 create_scalar_float: dest:x src1:f len:12 create_scalar_unsafe_int: dest:x src1:i len:4 create_scalar_unsafe_float: dest:x src1:f len:4 +arm64_bic: dest:x src1:x src2:x len:4 +bitwise_select: dest:x src1:x src2:x src3:x len:12 generic_class_init: src1:a len:44 clob:c gc_safe_point: src1:i len:12 clob:c diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 3d23bc27da4ba2..a97237a9f9fdb2 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -3731,6 +3731,14 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) arm_neon_neg (code, get_vector_size_macro (ins), get_type_size_macro (ins->inst_c1), dreg, sreg1); } break; + case OP_ARM64_BIC: + arm_neon_bic (code, get_vector_size_macro (ins), dreg, sreg1, sreg2); + break; + case OP_BSL: + arm_neon_mov (code, NEON_TMP_REG, sreg1); + arm_neon_bsl (code, get_vector_size_macro (ins), NEON_TMP_REG, sreg2, ins->sreg3); + arm_neon_mov (code, dreg, NEON_TMP_REG); + break; case OP_XBINOP: switch (ins->inst_c0) { case OP_IMAX: diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 7e89aba8d6981e..cd4d498f0b740e 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1226,8 +1226,6 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi if (!(!strcmp (m_class_get_name (cmethod->klass), "Vector128") || !strcmp (m_class_get_name (cmethod->klass), "Vector"))) return NULL; switch (id) { - case SN_AndNot: - case SN_ConditionalSelect: case SN_ConvertToDouble: case SN_ConvertToInt32: case SN_ConvertToInt64: From d0a287a56fda74f610e2ada174e64512dc596130 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Thu, 13 Apr 2023 03:06:05 -0500 Subject: [PATCH 20/21] Revert "[browser] Wasm SDK packed as a nuget package (#84082)" (#84743) This reverts commit 063adfe9f2925c5c6c74e5d30d04a7d5a085e144. --- .../Sdk/Sdk.props | 2 +- .../Sdk/Sdk.targets.in | 2 +- ...Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj | 14 - ...icrosoft.NET.Sdk.WebAssembly.Browser.props | 43 -- ...rosoft.NET.Sdk.WebAssembly.Browser.targets | 493 -------------- .../Microsoft.NET.Sdk.WebAssembly.Pack.props | 20 - ...Microsoft.NET.Sdk.WebAssembly.Pack.targets | 12 - .../build/Wasm.web.config | 44 -- .../WorkloadManifest.targets.in | 6 +- src/mono/nuget/mono-packages.proj | 1 - .../AssetsComputingHelper.cs | 86 --- .../BootJsonData.cs | 157 ----- .../ComputeWasmBuildAssets.cs | 266 -------- .../ComputeWasmPublishAssets.cs | 628 ------------------ .../FileHasher.cs | 35 - .../GenerateWasmBootJson.cs | 341 ---------- ...soft.NET.Sdk.WebAssembly.Pack.Tasks.csproj | 32 - 17 files changed, 4 insertions(+), 2178 deletions(-) delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets delete mode 100644 src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs delete mode 100644 src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj diff --git a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props index dae0b088f16071..2890daaf708283 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props +++ b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.props @@ -1,5 +1,5 @@ - + wasm browser true diff --git a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in index 60d993f9c1a531..0f9edfb14f10d3 100644 --- a/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in +++ b/src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in @@ -9,7 +9,7 @@ $([MSBuild]::NormalizeDirectory($(MSBuildThisFileDirectory), '..', 'WasmAppHost')) - true + true diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj deleted file mode 100644 index 32b0ded6b35fd7..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/Microsoft.NET.Sdk.WebAssembly.Pack.pkgproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SDK for building and publishing WebAssembly applications. - - - - - - - - - diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props deleted file mode 100644 index dc074e761f24e1..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.props +++ /dev/null @@ -1,43 +0,0 @@ - - - - - false - - exe - - false - - false - - - false - - - true - partial - false - - - / - Root - $(StaticWebAssetsAdditionalBuildPropertiesToRemove);RuntimeIdentifier;SelfContained - ComputeFilesToPublish;GetCurrentProjectPublishStaticWebAssetItems - $(StaticWebAssetsAdditionalPublishProperties);BuildProjectReferences=false;ResolveAssemblyReferencesFindRelatedSatellites=true - $(StaticWebAssetsAdditionalPublishPropertiesToRemove);NoBuild;RuntimeIdentifier - - - - - - diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets deleted file mode 100644 index 3fe69f51c2e0ed..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ /dev/null @@ -1,493 +0,0 @@ - - - - - true - - - true - - - - - - - $(MSBuildThisFileDirectory)..\ - <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' == 'Core'">net8.0 - <_WebAssemblySdkTasksTFM Condition=" '$(MSBuildRuntimeType)' != 'Core'">net472 - <_WebAssemblySdkTasksAssembly>$(WebAssemblySdkDirectoryRoot)tools\$(_WebAssemblySdkTasksTFM)\Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.dll - - - - - - - - true - true - - - false - false - true - false - false - false - <_AggressiveAttributeTrimming Condition="'$(_AggressiveAttributeTrimming)' == ''">true - false - true - false - - - false - false - false - false - true - - - - false - - false - _GatherWasmFilesToPublish;$(WasmNestedPublishAppDependsOn) - <_WasmNestedPublishAppPreTarget>ComputeFilesToPublish - - - - - - - - - - - - $(ResolveStaticWebAssetsInputsDependsOn); - _AddWasmStaticWebAssets; - - - - _GenerateBuildWasmBootJson; - $(StaticWebAssetsPrepareForRunDependsOn) - - - - $(ResolvePublishStaticWebAssetsDependsOn); - ProcessPublishFilesForWasm; - ComputeWasmExtensions; - _AddPublishWasmBootJsonToStaticWebAssets; - - - - $(GenerateStaticWebAssetsPublishManifestDependsOn); - GeneratePublishWasmBootJson; - - - - $(AddWasmStaticWebAssetsDependsOn); - ResolveWasmOutputs; - - - $(GenerateBuildWasmBootJsonDependsOn); - ResolveStaticWebAssetsInputs; - - - $(GeneratePublishWasmBootJsonDependsOn); - - - - - - - - - - - - - - - - - - - - <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(InvariantGlobalization)' != 'true'">$(BlazorWebAssemblyLoadAllGlobalizationData) - <_BlazorWebAssemblyLoadAllGlobalizationData Condition="'$(_BlazorWebAssemblyLoadAllGlobalizationData)' == ''">false - <_BlazorIcuDataFileName Condition="'$(InvariantGlobalization)' != 'true' AND '$(BlazorWebAssemblyLoadAllGlobalizationData)' != 'true'">$(BlazorIcuDataFileName) - <_LoadCustomIcuData>false - <_LoadCustomIcuData Condition="'$(_BlazorIcuDataFileName)' != ''">true - - - - - - <_BlazorEnableTimeZoneSupport>$(BlazorEnableTimeZoneSupport) - <_BlazorEnableTimeZoneSupport Condition="'$(_BlazorEnableTimeZoneSupport)' == ''">true - <_WasmInvariantGlobalization>$(InvariantGlobalization) - <_WasmInvariantGlobalization Condition="'$(_WasmInvariantGlobalization)' == ''">true - <_WasmCopyOutputSymbolsToOutputDirectory>$(CopyOutputSymbolsToOutputDirectory) - <_WasmCopyOutputSymbolsToOutputDirectory Condition="'$(_WasmCopyOutputSymbolsToOutputDirectory)'==''">true - <_BlazorWebAssemblyStartupMemoryCache>$(BlazorWebAssemblyStartupMemoryCache) - <_BlazorWebAssemblyJiterpreter>$(BlazorWebAssemblyJiterpreter) - <_BlazorWebAssemblyRuntimeOptions>$(BlazorWebAssemblyRuntimeOptions) - - - $(OutputPath)$(PublishDirName)\ - - - - - - - - <_WasmConfigFileCandidates Include="@(StaticWebAsset)" Condition="'%(SourceType)' == 'Discovered'" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_WasmBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json - - - - <_BuildWasmBootJson - Include="$(_WasmBuildBootJsonPath)" - RelativePath="_framework/blazor.boot.json" /> - - - - - - - - - - - - - - - - - <_WasmBuildBootJsonPath>$(IntermediateOutputPath)blazor.boot.json - - - - <_WasmJsModuleCandidatesForBuild - Include="@(StaticWebAsset)" - Condition="'%(StaticWebAsset.AssetTraitName)' == 'JSModule' and '%(StaticWebAsset.AssetTraitValue)' == 'JSLibraryModule' and '%(AssetKind)' != 'Publish'" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_WasmPublishPrefilteredAssets - Include="@(StaticWebAsset)" - Condition="'%(StaticWebAsset.AssetTraitName)' == 'WasmResource' or '%(StaticWebAsset.AssetTraitName)' == 'Culture' or '%(AssetRole)' == 'Alternative'" /> - - - - <_DotNetJsItem Include="@(ResolvedFileToPublish)" Condition="'%(ResolvedFileToPublish.DestinationSubPath)' == 'dotnet.js' AND '%(ResolvedFileToPublish.AssetType)' == 'native'" /> - - - - <_DotNetJsVersion>%(_DotNetJsItem.NuGetPackageVersion) - - - - - - - - - - - - - - - - - - - <_BlazorExtensionsCandidate Include="@(BlazorPublishExtension->'%(FullPath)')"> - $(PackageId) - Computed - $(PublishDir)wwwroot - $(StaticWebAssetBasePath) - %(BlazorPublishExtension.RelativePath) - Publish - All - Primary - WasmResource - extension:%(BlazorPublishExtension.ExtensionName) - Never - PreserveNewest - %(BlazorPublishExtension.Identity) - - - - - - - - - - - - - - - - - - <_PublishWasmBootJson - Include="$(IntermediateOutputPath)blazor.publish.boot.json" - RelativePath="_framework/blazor.boot.json" /> - - - - - - - - - - - <_WasmPublishAsset - Include="@(StaticWebAsset)" - Condition="'%(AssetKind)' != 'Build' and '%(StaticWebAsset.AssetTraitValue)' != 'manifest' and ('%(StaticWebAsset.AssetTraitName)' == 'WasmResource' or '%(StaticWebAsset.AssetTraitName)' == 'Culture') and '%(StaticWebAsset.AssetTraitValue)' != 'boot'" /> - - <_WasmPublishConfigFile - Include="@(StaticWebAsset)" - Condition="'%(StaticWebAsset.AssetTraitName)' == 'WasmResource' and '%(StaticWebAsset.AssetTraitValue)' == 'settings'"/> - - <_WasmJsModuleCandidatesForPublish - Include="@(StaticWebAsset)" - Condition="'%(StaticWebAsset.AssetTraitName)' == 'JSModule' and '%(StaticWebAsset.AssetTraitValue)' == 'JSLibraryModule' and '%(AssetKind)' != 'Build'" /> - - - <_WasmPublishAsset Remove="@(_BlazorExtensionsCandidatesForPublish)" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props deleted file mode 100644 index a41609b5c15a65..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - browser-wasm - - - <_WebAssemblyPropsFile>$(MSBuildThisFileDirectory)\Microsoft.NET.Sdk.WebAssembly.Browser.props - <_WebAssemblyTargetsFile>$(MSBuildThisFileDirectory)\Microsoft.NET.Sdk.WebAssembly.Browser.targets - - diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets deleted file mode 100644 index df15f880ba1b39..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Pack.targets +++ /dev/null @@ -1,12 +0,0 @@ - - diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config deleted file mode 100644 index 586d3565ed1eb4..00000000000000 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Wasm.web.config +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in index b42b351e97ac2f..c9a2c7494450fd 100644 --- a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in +++ b/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in @@ -20,8 +20,6 @@ <_BrowserWorkloadNotSupportedForTFM Condition="$([MSBuild]::VersionLessThan($(TargetFrameworkVersion), '6.0'))">true <_BrowserWorkloadDisabled>$(_BrowserWorkloadNotSupportedForTFM) - <_UsingBlazorOrWasmSdk Condition="'$(UsingMicrosoftNETSdkBlazorWebAssembly)' == 'true' or '$(UsingMicrosoftNETSdkWebAssembly)' == 'true'">true - @@ -41,7 +39,7 @@ <_WasmNativeWorkloadNeeded Condition="'$(RunAOTCompilation)' == 'true' or '$(WasmEnableSIMD)' == 'true' or '$(WasmBuildNative)' == 'true' or - '$(WasmGenerateAppBundle)' == 'true' or '$(_UsingBlazorOrWasmSdk)' != 'true'" >true + '$(WasmGenerateAppBundle)' == 'true' or '$(UsingMicrosoftNETSdkBlazorWebAssembly)' != 'true'" >true false true @@ -61,7 +59,7 @@ true - + false true diff --git a/src/mono/nuget/mono-packages.proj b/src/mono/nuget/mono-packages.proj index 438ec97ace3e1a..6a2ddff782b75e 100644 --- a/src/mono/nuget/mono-packages.proj +++ b/src/mono/nuget/mono-packages.proj @@ -8,7 +8,6 @@ - diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs deleted file mode 100644 index 2854594ae10547..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/AssetsComputingHelper.cs +++ /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. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; - -namespace Microsoft.NET.Sdk.WebAssembly; - -public class AssetsComputingHelper -{ - public static bool ShouldFilterCandidate( - ITaskItem candidate, - bool timezoneSupport, - bool invariantGlobalization, - bool copySymbols, - string customIcuCandidateFilename, - out string reason) - { - var extension = candidate.GetMetadata("Extension"); - var fileName = candidate.GetMetadata("FileName"); - var assetType = candidate.GetMetadata("AssetType"); - var fromMonoPackage = string.Equals( - candidate.GetMetadata("NuGetPackageId"), - "Microsoft.NETCore.App.Runtime.Mono.browser-wasm", - StringComparison.Ordinal); - - reason = extension switch - { - ".a" when fromMonoPackage => "extension is .a is not supported.", - ".c" when fromMonoPackage => "extension is .c is not supported.", - ".h" when fromMonoPackage => "extension is .h is not supported.", - // It is safe to filter out all XML files since we are not interested in any XML file from the list - // of ResolvedFilesToPublish to become a static web asset. Things like this include XML doc files and - // so on. - ".xml" => "it is a documentation file", - ".rsp" when fromMonoPackage => "extension is .rsp is not supported.", - ".props" when fromMonoPackage => "extension is .props is not supported.", - ".blat" when !timezoneSupport => "timezone support is not enabled.", - ".dat" when invariantGlobalization && fileName.StartsWith("icudt") => "invariant globalization is enabled", - ".dat" when !string.IsNullOrEmpty(customIcuCandidateFilename) && fileName != customIcuCandidateFilename => "custom icu file will be used instead of icu from the runtime pack", - ".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor", - ".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor", - ".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor", - ".js" when assetType == "native" && fileName != "dotnet" => $"{fileName}{extension} is not used by Blazor", - ".pdb" when !copySymbols => "copying symbols is disabled", - ".symbols" when fromMonoPackage => "extension .symbols is not required.", - _ => null - }; - - return reason != null; - } - - public static string GetCandidateRelativePath(ITaskItem candidate) - { - var destinationSubPath = candidate.GetMetadata("DestinationSubPath"); - if (!string.IsNullOrEmpty(destinationSubPath)) - return $"_framework/{destinationSubPath}"; - - var relativePath = candidate.GetMetadata("FileName") + candidate.GetMetadata("Extension"); - return $"_framework/{relativePath}"; - } - - public static ITaskItem GetCustomIcuAsset(ITaskItem candidate) - { - var customIcuCandidate = new TaskItem(candidate); - var relativePath = GetCandidateRelativePath(customIcuCandidate); - customIcuCandidate.SetMetadata("RelativePath", relativePath); - customIcuCandidate.SetMetadata("AssetTraitName", "BlazorWebAssemblyResource"); - customIcuCandidate.SetMetadata("AssetTraitValue", "native"); - customIcuCandidate.SetMetadata("AssetType", "native"); - return customIcuCandidate; - } - - public static bool TryGetAssetFilename(ITaskItem candidate, out string filename) - { - bool candidateIsValid = candidate != null && !string.IsNullOrEmpty(candidate.ItemSpec); - filename = candidateIsValid ? - $"{candidate.GetMetadata("FileName")}" : - ""; - return candidateIsValid; - } -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs deleted file mode 100644 index 282d5cf6d0a580..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/BootJsonData.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Runtime.Serialization; -using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary; - -namespace Microsoft.NET.Sdk.WebAssembly; - -/// -/// Defines the structure of a Blazor boot JSON file -/// -public class BootJsonData -{ - /// - /// Gets the name of the assembly with the application entry point - /// - public string entryAssembly { get; set; } - - /// - /// Gets the set of resources needed to boot the application. This includes the transitive - /// closure of .NET assemblies (including the entrypoint assembly), the dotnet.wasm file, - /// and any PDBs to be loaded. - /// - /// Within , dictionary keys are resource names, - /// and values are SHA-256 hashes formatted in prefixed base-64 style (e.g., 'sha256-abcdefg...') - /// as used for subresource integrity checking. - /// - public ResourcesData resources { get; set; } = new ResourcesData(); - - /// - /// Gets a value that determines whether to enable caching of the - /// inside a CacheStorage instance within the browser. - /// - public bool cacheBootResources { get; set; } - - /// - /// Gets a value that determines if this is a debug build. - /// - public bool debugBuild { get; set; } - - /// - /// Gets a value that determines if the linker is enabled. - /// - public bool linkerEnabled { get; set; } - - /// - /// Config files for the application - /// - public List config { get; set; } - - /// - /// Gets or sets the that determines how icu files are loaded. - /// - public ICUDataMode icuDataMode { get; set; } - - /// - /// Gets or sets a value that determines if the caching startup memory is enabled. - /// - public bool? startupMemoryCache { get; set; } - - /// - /// Gets a value for mono runtime options. - /// - public string[] runtimeOptions { get; set; } - - /// - /// Gets or sets configuration extensions. - /// - public Dictionary> extensions { get; set; } -} - -public class ResourcesData -{ - /// - /// .NET Wasm runtime resources (dotnet.wasm, dotnet.js) etc. - /// - public ResourceHashesByNameDictionary runtime { get; set; } = new ResourceHashesByNameDictionary(); - - /// - /// "assembly" (.dll) resources - /// - public ResourceHashesByNameDictionary assembly { get; set; } = new ResourceHashesByNameDictionary(); - - /// - /// "debug" (.pdb) resources - /// - [DataMember(EmitDefaultValue = false)] - public ResourceHashesByNameDictionary pdb { get; set; } - - /// - /// localization (.satellite resx) resources - /// - [DataMember(EmitDefaultValue = false)] - public Dictionary satelliteResources { get; set; } - - /// - /// Assembly (.dll) resources that are loaded lazily during runtime - /// - [DataMember(EmitDefaultValue = false)] - public ResourceHashesByNameDictionary lazyAssembly { get; set; } - - /// - /// JavaScript module initializers that Blazor will be in charge of loading. - /// - [DataMember(EmitDefaultValue = false)] - public ResourceHashesByNameDictionary libraryInitializers { get; set; } - - /// - /// Extensions created by users customizing the initialization process. The format of the file(s) - /// is up to the user. - /// - [DataMember(EmitDefaultValue = false)] - public Dictionary extensions { get; set; } - - /// - /// Additional assets that the runtime consumes as part of the boot process. - /// - [DataMember(EmitDefaultValue = false)] - public Dictionary runtimeAssets { get; set; } - -} - -public enum ICUDataMode : int -{ - // Note that the numeric values are serialized and used in JS code, so don't change them without also updating the JS code - - /// - /// Load optimized icu data file based on the user's locale - /// - Sharded = 0, - - /// - /// Use the combined icudt.dat file - /// - All = 1, - - /// - /// Do not load any icu data files. - /// - Invariant = 2, - - /// - /// Load custom icu file provided by the developer. - /// - Custom = 3, -} - -[DataContract] -public class AdditionalAsset -{ - [DataMember(Name = "hash")] - public string Hash { get; set; } - - [DataMember(Name = "behavior")] - public string Behavior { get; set; } -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs deleted file mode 100644 index 68a563322f613e..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmBuildAssets.cs +++ /dev/null @@ -1,266 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Microsoft.NET.Sdk.WebAssembly; - -namespace Microsoft.NET.Sdk.WebAssembly; - -// This task does the build work of processing the project inputs and producing a set of pseudo-static web assets. -public class ComputeWasmBuildAssets : Task -{ - [Required] - public ITaskItem[] Candidates { get; set; } - - public ITaskItem CustomIcuCandidate { get; set; } - - [Required] - public ITaskItem[] ProjectAssembly { get; set; } - - [Required] - public ITaskItem[] ProjectDebugSymbols { get; set; } - - [Required] - public ITaskItem[] SatelliteAssemblies { get; set; } - - [Required] - public ITaskItem[] ProjectSatelliteAssemblies { get; set; } - - [Required] - public string OutputPath { get; set; } - - [Required] - public bool TimeZoneSupport { get; set; } - - [Required] - public bool InvariantGlobalization { get; set; } - - [Required] - public bool CopySymbols { get; set; } - - public bool FingerprintDotNetJs { get; set; } - - [Output] - public ITaskItem[] AssetCandidates { get; set; } - - [Output] - public ITaskItem[] FilesToRemove { get; set; } - - public override bool Execute() - { - var filesToRemove = new List(); - var assetCandidates = new List(); - - try - { - if (ProjectAssembly.Length != 1) - { - Log.LogError("Invalid number of project assemblies '{0}'", string.Join("," + Environment.NewLine, ProjectAssembly.Select(a => a.ItemSpec))); - return true; - } - - if (ProjectDebugSymbols.Length > 1) - { - Log.LogError("Invalid number of symbol assemblies '{0}'", string.Join("," + Environment.NewLine, ProjectDebugSymbols.Select(a => a.ItemSpec))); - return true; - } - - if (AssetsComputingHelper.TryGetAssetFilename(CustomIcuCandidate, out string customIcuCandidateFilename)) - { - var customIcuCandidate = AssetsComputingHelper.GetCustomIcuAsset(CustomIcuCandidate); - assetCandidates.Add(customIcuCandidate); - } - - for (int i = 0; i < Candidates.Length; i++) - { - var candidate = Candidates[i]; - if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason)) - { - Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); - filesToRemove.Add(candidate); - continue; - } - - var satelliteAssembly = SatelliteAssemblies.FirstOrDefault(s => s.ItemSpec == candidate.ItemSpec); - if (satelliteAssembly != null) - { - var inferredCulture = satelliteAssembly.GetMetadata("DestinationSubDirectory").Trim('\\', '/'); - Log.LogMessage(MessageImportance.Low, "Found satellite assembly '{0}' asset for candidate '{1}' with inferred culture '{2}'", satelliteAssembly.ItemSpec, candidate.ItemSpec, inferredCulture); - - var assetCandidate = new TaskItem(satelliteAssembly); - assetCandidate.SetMetadata("AssetKind", "Build"); - assetCandidate.SetMetadata("AssetRole", "Related"); - assetCandidate.SetMetadata("AssetTraitName", "Culture"); - assetCandidate.SetMetadata("AssetTraitValue", inferredCulture); - assetCandidate.SetMetadata("RelativePath", $"_framework/{inferredCulture}/{satelliteAssembly.GetMetadata("FileName")}{satelliteAssembly.GetMetadata("Extension")}"); - assetCandidate.SetMetadata("RelatedAsset", Path.GetFullPath(Path.Combine(OutputPath, "wwwroot", "_framework", Path.GetFileName(assetCandidate.GetMetadata("ResolvedFrom"))))); - - assetCandidates.Add(assetCandidate); - continue; - } - - if (candidate.GetMetadata("FileName") == "dotnet" && candidate.GetMetadata("Extension") == ".js") - { - string newDotnetJSFileName = null; - string newDotNetJSFullPath = null; - if (FingerprintDotNetJs) - { - var itemHash = FileHasher.GetFileHash(candidate.ItemSpec); - newDotnetJSFileName = $"dotnet.{candidate.GetMetadata("NuGetPackageVersion")}.{itemHash}.js"; - - var originalFileFullPath = Path.GetFullPath(candidate.ItemSpec); - var originalFileDirectory = Path.GetDirectoryName(originalFileFullPath); - - newDotNetJSFullPath = Path.Combine(originalFileDirectory, newDotnetJSFileName); - } - else - { - newDotNetJSFullPath = candidate.ItemSpec; - newDotnetJSFileName = Path.GetFileName(newDotNetJSFullPath); - } - - var newDotNetJs = new TaskItem(newDotNetJSFullPath, candidate.CloneCustomMetadata()); - newDotNetJs.SetMetadata("OriginalItemSpec", candidate.ItemSpec); - - var newRelativePath = $"_framework/{newDotnetJSFileName}"; - newDotNetJs.SetMetadata("RelativePath", newRelativePath); - - newDotNetJs.SetMetadata("AssetTraitName", "WasmResource"); - newDotNetJs.SetMetadata("AssetTraitValue", "native"); - - assetCandidates.Add(newDotNetJs); - continue; - } - else - { - string relativePath = AssetsComputingHelper.GetCandidateRelativePath(candidate); - candidate.SetMetadata("RelativePath", relativePath); - } - - // Workaround for https://github.com/dotnet/aspnetcore/issues/37574. - // For items added as "Reference" in project references, the OriginalItemSpec is incorrect. - // Ignore it, and use the FullPath instead. - if (candidate.GetMetadata("ReferenceSourceTarget") == "ProjectReference") - { - candidate.SetMetadata("OriginalItemSpec", candidate.ItemSpec); - } - - var culture = candidate.GetMetadata("Culture"); - if (!string.IsNullOrEmpty(culture)) - { - candidate.SetMetadata("AssetKind", "Build"); - candidate.SetMetadata("AssetRole", "Related"); - candidate.SetMetadata("AssetTraitName", "Culture"); - candidate.SetMetadata("AssetTraitValue", culture); - var fileName = candidate.GetMetadata("FileName"); - var suffixIndex = fileName.Length - ".resources".Length; - var relatedAssetPath = Path.GetFullPath(Path.Combine( - OutputPath, - "wwwroot", - "_framework", - fileName.Substring(0, suffixIndex) + ProjectAssembly[0].GetMetadata("Extension"))); - - candidate.SetMetadata("RelatedAsset", relatedAssetPath); - - Log.LogMessage(MessageImportance.Low, "Found satellite assembly '{0}' asset for inferred candidate '{1}' with culture '{2}'", candidate.ItemSpec, relatedAssetPath, culture); - } - - assetCandidates.Add(candidate); - } - - var intermediateAssembly = new TaskItem(ProjectAssembly[0]); - intermediateAssembly.SetMetadata("RelativePath", $"_framework/{intermediateAssembly.GetMetadata("FileName")}{intermediateAssembly.GetMetadata("Extension")}"); - assetCandidates.Add(intermediateAssembly); - - if (ProjectDebugSymbols.Length > 0) - { - var debugSymbols = new TaskItem(ProjectDebugSymbols[0]); - debugSymbols.SetMetadata("RelativePath", $"_framework/{debugSymbols.GetMetadata("FileName")}{debugSymbols.GetMetadata("Extension")}"); - assetCandidates.Add(debugSymbols); - } - - for (int i = 0; i < ProjectSatelliteAssemblies.Length; i++) - { - var projectSatelliteAssembly = ProjectSatelliteAssemblies[i]; - var candidateCulture = projectSatelliteAssembly.GetMetadata("Culture"); - Log.LogMessage( - "Found satellite assembly '{0}' asset for project '{1}' with culture '{2}'", - projectSatelliteAssembly.ItemSpec, - intermediateAssembly.ItemSpec, - candidateCulture); - - var assetCandidate = new TaskItem(Path.GetFullPath(projectSatelliteAssembly.ItemSpec), projectSatelliteAssembly.CloneCustomMetadata()); - var projectAssemblyAssetPath = Path.GetFullPath(Path.Combine( - OutputPath, - "wwwroot", - "_framework", - ProjectAssembly[0].GetMetadata("FileName") + ProjectAssembly[0].GetMetadata("Extension"))); - - var normalizedPath = assetCandidate.GetMetadata("TargetPath").Replace('\\', '/'); - - assetCandidate.SetMetadata("AssetKind", "Build"); - assetCandidate.SetMetadata("AssetRole", "Related"); - assetCandidate.SetMetadata("AssetTraitName", "Culture"); - assetCandidate.SetMetadata("AssetTraitValue", candidateCulture); - assetCandidate.SetMetadata("RelativePath", Path.Combine("_framework", normalizedPath)); - assetCandidate.SetMetadata("RelatedAsset", projectAssemblyAssetPath); - - assetCandidates.Add(assetCandidate); - } - - for (var i = 0; i < assetCandidates.Count; i++) - { - var candidate = assetCandidates[i]; - ApplyUniqueMetadataProperties(candidate); - } - } - catch (Exception ex) - { - Log.LogError(ex.ToString()); - return false; - } - - FilesToRemove = filesToRemove.ToArray(); - AssetCandidates = assetCandidates.ToArray(); - - return !Log.HasLoggedErrors; - } - - private static void ApplyUniqueMetadataProperties(ITaskItem candidate) - { - var extension = candidate.GetMetadata("Extension"); - var filename = candidate.GetMetadata("FileName"); - switch (extension) - { - case ".dll": - if (string.IsNullOrEmpty(candidate.GetMetadata("AssetTraitName"))) - { - candidate.SetMetadata("AssetTraitName", "WasmResource"); - candidate.SetMetadata("AssetTraitValue", "runtime"); - } - if (string.Equals(candidate.GetMetadata("ResolvedFrom"), "{HintPathFromItem}", StringComparison.Ordinal)) - { - candidate.RemoveMetadata("OriginalItemSpec"); - } - break; - case ".wasm": - case ".blat": - case ".dat" when filename.StartsWith("icudt"): - candidate.SetMetadata("AssetTraitName", "WasmResource"); - candidate.SetMetadata("AssetTraitValue", "native"); - break; - case ".pdb": - candidate.SetMetadata("AssetTraitName", "WasmResource"); - candidate.SetMetadata("AssetTraitValue", "symbol"); - candidate.RemoveMetadata("OriginalItemSpec"); - break; - default: - break; - } - } -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs deleted file mode 100644 index d622db24a31a5e..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ComputeWasmPublishAssets.cs +++ /dev/null @@ -1,628 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using Microsoft.NET.Sdk.WebAssembly; - -namespace Microsoft.NET.Sdk.WebAssembly; - -// This target computes the list of publish static web assets based on the changes that happen during publish and the list of build static -// web assets. -// In this target we need to do 2 things: -// * Harmonize the list of dlls produced at build time with the list of resolved files to publish. -// * We iterate over the list of existing static web assets and do as follows: -// * If we find the assembly in the resolved files to publish and points to the original assembly (linker disabled or assembly not linked) -// we create a new "Publish" static web asset for the assembly. -// * If we find the assembly in the resolved files to publish and points to a new location, we assume this assembly has been updated (as part of linking) -// and we create a new "Publish" static web asset for the asembly pointing to the new location. -// * If we don't find the assembly on the resolved files to publish it has been linked out from the app, so we don't add any new static web asset and we -// also avoid adding any existing related static web asset (satellite assemblies and compressed versions). -// * We update static web assets for satellite assemblies and compressed assets accordingly. -// * Look at the list of "native" assets and determine whether we need to create new publish assets for the current build assets or if we need to -// update the native assets because the app was ahead of time compiled. -public class ComputeWasmPublishAssets : Task -{ - [Required] - public ITaskItem[] ResolvedFilesToPublish { get; set; } - - public ITaskItem CustomIcuCandidate { get; set; } - - [Required] - public ITaskItem[] WasmAotAssets { get; set; } - - [Required] - public ITaskItem[] ExistingAssets { get; set; } - - [Required] - public bool TimeZoneSupport { get; set; } - - [Required] - public bool InvariantGlobalization { get; set; } - - [Required] - public bool CopySymbols { get; set; } - - [Required] - public string PublishPath { get; set; } - - [Required] - public string DotNetJsVersion { get; set; } - - public bool FingerprintDotNetJs { get; set; } - - [Output] - public ITaskItem[] NewCandidates { get; set; } - - [Output] - public ITaskItem[] FilesToRemove { get; set; } - - public override bool Execute() - { - var filesToRemove = new List(); - var newAssets = new List(); - - try - { - // We'll do a first pass over the resolved files to publish to figure out what files need to be removed - // as well as categorize resolved files into different groups. - var resolvedFilesToPublishToRemove = new Dictionary(StringComparer.Ordinal); - - // These assemblies are keyed of the assembly name "computed" based on the relative path, which must be - // unique. - var resolvedAssembliesToPublish = new Dictionary(StringComparer.Ordinal); - var resolvedSymbolsToPublish = new Dictionary(StringComparer.Ordinal); - var satelliteAssemblyToPublish = new Dictionary<(string, string), ITaskItem>(EqualityComparer<(string, string)>.Default); - var resolvedNativeAssetToPublish = new Dictionary(StringComparer.Ordinal); - GroupResolvedFilesToPublish( - resolvedFilesToPublishToRemove, - resolvedAssembliesToPublish, - satelliteAssemblyToPublish, - resolvedSymbolsToPublish, - resolvedNativeAssetToPublish); - - // Group candidate static web assets - var assemblyAssets = new Dictionary(); - var symbolAssets = new Dictionary(); - var nativeAssets = new Dictionary(); - var satelliteAssemblyAssets = new Dictionary(); - var compressedRepresentations = new Dictionary(); - GroupExistingStaticWebAssets( - assemblyAssets, - nativeAssets, - satelliteAssemblyAssets, - symbolAssets, - compressedRepresentations); - - var newStaticWebAssets = ComputeUpdatedAssemblies( - satelliteAssemblyToPublish, - filesToRemove, - resolvedAssembliesToPublish, - assemblyAssets, - satelliteAssemblyAssets, - compressedRepresentations); - - newAssets.AddRange(newStaticWebAssets); - - var nativeStaticWebAssets = ProcessNativeAssets( - nativeAssets, - resolvedFilesToPublishToRemove, - resolvedNativeAssetToPublish, - compressedRepresentations, - filesToRemove); - - newAssets.AddRange(nativeStaticWebAssets); - - var symbolStaticWebAssets = ProcessSymbolAssets( - symbolAssets, - compressedRepresentations, - resolvedFilesToPublishToRemove, - resolvedSymbolsToPublish, - filesToRemove); - - newAssets.AddRange(symbolStaticWebAssets); - - foreach (var kvp in resolvedFilesToPublishToRemove) - { - var resolvedPublishFileToRemove = kvp.Value; - filesToRemove.Add(resolvedPublishFileToRemove); - } - } - catch (Exception ex) - { - Log.LogError(ex.ToString()); - return false; - } - - FilesToRemove = filesToRemove.ToArray(); - NewCandidates = newAssets.ToArray(); - - return !Log.HasLoggedErrors; - } - - private List ProcessNativeAssets( - Dictionary nativeAssets, - IDictionary resolvedPublishFilesToRemove, - Dictionary resolvedNativeAssetToPublish, - Dictionary compressedRepresentations, - List filesToRemove) - { - var nativeStaticWebAssets = new List(); - - // Keep track of the updated assets to determine what compressed assets we can reuse - var updateMap = new Dictionary(); - - foreach (var kvp in nativeAssets) - { - var key = kvp.Key; - var asset = kvp.Value; - var isDotNetJs = IsDotNetJs(key); - var isDotNetWasm = IsDotNetWasm(key); - if (!isDotNetJs && !isDotNetWasm) - { - if (resolvedNativeAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing)) - { - if (!resolvedPublishFilesToRemove.TryGetValue(existing.ItemSpec, out var removed)) - { - // This is a native asset like timezones.blat or similar that was not filtered and that needs to be updated - // to a publish asset. - var newAsset = new TaskItem(asset); - ApplyPublishProperties(newAsset); - nativeStaticWebAssets.Add(newAsset); - filesToRemove.Add(existing); - updateMap.Add(asset.ItemSpec, newAsset); - Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); - } - else - { - Log.LogMessage(MessageImportance.Low, "Removing asset '{0}'.", existing.ItemSpec); - // This was a file that was filtered, so just remove it, we don't need to add any publish static web asset - filesToRemove.Add(removed); - - // Remove the file from the list to avoid double processing later when we process other files we filtered. - resolvedPublishFilesToRemove.Remove(existing.ItemSpec); - } - } - - continue; - } - - if (isDotNetJs) - { - var aotDotNetJs = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.js"); - ITaskItem newDotNetJs = null; - if (aotDotNetJs != null && FingerprintDotNetJs) - { - newDotNetJs = new TaskItem(Path.GetFullPath(aotDotNetJs.ItemSpec), asset.CloneCustomMetadata()); - newDotNetJs.SetMetadata("OriginalItemSpec", aotDotNetJs.ItemSpec); - newDotNetJs.SetMetadata("RelativePath", $"_framework/{$"dotnet.{DotNetJsVersion}.{FileHasher.GetFileHash(aotDotNetJs.ItemSpec)}.js"}"); - - updateMap.Add(asset.ItemSpec, newDotNetJs); - Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetJs.ItemSpec); - } - else - { - newDotNetJs = new TaskItem(asset); - Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); - } - - ApplyPublishProperties(newDotNetJs); - nativeStaticWebAssets.Add(newDotNetJs); - if (resolvedNativeAssetToPublish.TryGetValue("dotnet.js", out var resolved)) - { - filesToRemove.Add(resolved); - } - continue; - } - - if (isDotNetWasm) - { - var aotDotNetWasm = WasmAotAssets.SingleOrDefault(a => $"{a.GetMetadata("FileName")}{a.GetMetadata("Extension")}" == "dotnet.wasm"); - ITaskItem newDotNetWasm = null; - if (aotDotNetWasm != null) - { - newDotNetWasm = new TaskItem(Path.GetFullPath(aotDotNetWasm.ItemSpec), asset.CloneCustomMetadata()); - newDotNetWasm.SetMetadata("OriginalItemSpec", aotDotNetWasm.ItemSpec); - updateMap.Add(asset.ItemSpec, newDotNetWasm); - Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with AoT version '{1}'", asset.ItemSpec, newDotNetWasm.ItemSpec); - } - else - { - newDotNetWasm = new TaskItem(asset); - Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); - } - - ApplyPublishProperties(newDotNetWasm); - nativeStaticWebAssets.Add(newDotNetWasm); - if (resolvedNativeAssetToPublish.TryGetValue("dotnet.wasm", out var resolved)) - { - filesToRemove.Add(resolved); - } - continue; - } - } - - var compressedUpdatedFiles = ProcessCompressedAssets(compressedRepresentations, nativeAssets, updateMap); - foreach (var f in compressedUpdatedFiles) - { - nativeStaticWebAssets.Add(f); - } - - return nativeStaticWebAssets; - - static bool IsDotNetJs(string key) - { - var fileName = Path.GetFileName(key); - return fileName.StartsWith("dotnet.", StringComparison.Ordinal) && fileName.EndsWith(".js", StringComparison.Ordinal) && !fileName.Contains("worker"); - } - - static bool IsDotNetWasm(string key) => string.Equals("dotnet.wasm", Path.GetFileName(key), StringComparison.Ordinal); - } - - private List ProcessSymbolAssets( - Dictionary symbolAssets, - Dictionary compressedRepresentations, - Dictionary resolvedPublishFilesToRemove, - Dictionary resolvedSymbolAssetToPublish, - List filesToRemove) - { - var symbolStaticWebAssets = new List(); - var updateMap = new Dictionary(); - - foreach (var kvp in symbolAssets) - { - var asset = kvp.Value; - if (resolvedSymbolAssetToPublish.TryGetValue(Path.GetFileName(asset.GetMetadata("OriginalItemSpec")), out var existing)) - { - if (!resolvedPublishFilesToRemove.TryGetValue(existing.ItemSpec, out var removed)) - { - // This is a symbol asset like classlibrary.pdb or similar that was not filtered and that needs to be updated - // to a publish asset. - var newAsset = new TaskItem(asset); - ApplyPublishProperties(newAsset); - symbolStaticWebAssets.Add(newAsset); - updateMap.Add(newAsset.ItemSpec, newAsset); - filesToRemove.Add(existing); - Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); - } - else - { - // This was a file that was filtered, so just remove it, we don't need to add any publish static web asset - filesToRemove.Add(removed); - - // Remove the file from the list to avoid double processing later when we process other files we filtered. - resolvedPublishFilesToRemove.Remove(existing.ItemSpec); - } - } - } - - var compressedFiles = ProcessCompressedAssets(compressedRepresentations, symbolAssets, updateMap); - - foreach (var file in compressedFiles) - { - symbolStaticWebAssets.Add(file); - } - - return symbolStaticWebAssets; - } - - private List ComputeUpdatedAssemblies( - IDictionary<(string, string assemblyName), ITaskItem> satelliteAssemblies, - List filesToRemove, - Dictionary resolvedAssembliesToPublish, - Dictionary assemblyAssets, - Dictionary satelliteAssemblyAssets, - Dictionary compressedRepresentations) - { - // All assemblies, satellite assemblies and gzip files are initially defined as build assets. - // We need to update them to publish assets when they haven't changed or when they have been linked. - // For satellite assemblies and compressed files, we won't include them in the list of assets to update - // when the original assembly they depend on has been linked out. - var assetsToUpdate = new Dictionary(); - var linkedAssets = new Dictionary(); - - foreach (var kvp in assemblyAssets) - { - var asset = kvp.Value; - var fileName = Path.GetFileName(asset.GetMetadata("RelativePath")); - if (resolvedAssembliesToPublish.TryGetValue(fileName, out var existing)) - { - // We found the assembly, so it'll have to be updated. - assetsToUpdate.Add(asset.ItemSpec, asset); - filesToRemove.Add(existing); - if (!string.Equals(asset.ItemSpec, existing.GetMetadata("FullPath"), StringComparison.Ordinal)) - { - linkedAssets.Add(asset.ItemSpec, existing); - } - } - } - - foreach (var kvp in satelliteAssemblyAssets) - { - var satelliteAssembly = kvp.Value; - var relatedAsset = satelliteAssembly.GetMetadata("RelatedAsset"); - if (assetsToUpdate.ContainsKey(relatedAsset)) - { - assetsToUpdate.Add(satelliteAssembly.ItemSpec, satelliteAssembly); - var culture = satelliteAssembly.GetMetadata("AssetTraitValue"); - var fileName = Path.GetFileName(satelliteAssembly.GetMetadata("RelativePath")); - if (satelliteAssemblies.TryGetValue((culture, fileName), out var existing)) - { - filesToRemove.Add(existing); - } - else - { - var message = $"Can't find the original satellite assembly in the list of resolved files to " + - $"publish for asset '{satelliteAssembly.ItemSpec}'."; - throw new InvalidOperationException(message); - } - } - } - - var compressedFiles = ProcessCompressedAssets(compressedRepresentations, assetsToUpdate, linkedAssets); - - foreach (var file in compressedFiles) - { - assetsToUpdate.Add(file.ItemSpec, file); - } - - var updatedAssetsMap = new Dictionary(StringComparer.Ordinal); - foreach (var asset in assetsToUpdate.Select(a => a.Value).OrderBy(a => a.GetMetadata("AssetRole"), Comparer.Create(OrderByAssetRole))) - { - var assetTraitName = asset.GetMetadata("AssetTraitName"); - switch (assetTraitName) - { - case "WasmResource": - ITaskItem newAsemblyAsset = null; - if (linkedAssets.TryGetValue(asset.ItemSpec, out var linked)) - { - newAsemblyAsset = new TaskItem(linked.GetMetadata("FullPath"), asset.CloneCustomMetadata()); - newAsemblyAsset.SetMetadata("OriginalItemSpec", linked.ItemSpec); - Log.LogMessage(MessageImportance.Low, "Replacing asset '{0}' with linked version '{1}'", - asset.ItemSpec, - newAsemblyAsset.ItemSpec); - } - else - { - Log.LogMessage(MessageImportance.Low, "Linked asset not found for asset '{0}'", asset.ItemSpec); - newAsemblyAsset = new TaskItem(asset); - } - ApplyPublishProperties(newAsemblyAsset); - - updatedAssetsMap.Add(asset.ItemSpec, newAsemblyAsset); - break; - default: - // Satellite assembliess and compressed assets - var dependentAsset = new TaskItem(asset); - ApplyPublishProperties(dependentAsset); - UpdateRelatedAssetProperty(asset, dependentAsset, updatedAssetsMap); - Log.LogMessage(MessageImportance.Low, "Promoting asset '{0}' to Publish asset.", asset.ItemSpec); - - updatedAssetsMap.Add(asset.ItemSpec, dependentAsset); - break; - } - } - - return updatedAssetsMap.Values.ToList(); - } - - private List ProcessCompressedAssets( - Dictionary compressedRepresentations, - Dictionary assetsToUpdate, - Dictionary updatedAssets) - { - var processed = new List(); - var runtimeAssetsToUpdate = new List(); - foreach (var kvp in compressedRepresentations) - { - var compressedAsset = kvp.Value; - var relatedAsset = compressedAsset.GetMetadata("RelatedAsset"); - if (assetsToUpdate.ContainsKey(relatedAsset)) - { - if (!updatedAssets.ContainsKey(relatedAsset)) - { - Log.LogMessage(MessageImportance.Low, "Related assembly for '{0}' was not updated and the compressed asset can be reused.", relatedAsset); - var newCompressedAsset = new TaskItem(compressedAsset); - ApplyPublishProperties(newCompressedAsset); - runtimeAssetsToUpdate.Add(newCompressedAsset); - } - else - { - Log.LogMessage(MessageImportance.Low, "Related assembly for '{0}' was updated and the compressed asset will be discarded.", relatedAsset); - } - - processed.Add(kvp.Key); - } - } - - // Remove all the elements we've found to avoid having to iterate over them when we process other assets. - foreach (var element in processed) - { - compressedRepresentations.Remove(element); - } - - return runtimeAssetsToUpdate; - } - - private static void UpdateRelatedAssetProperty(ITaskItem asset, TaskItem newAsset, Dictionary updatedAssetsMap) - { - if (!updatedAssetsMap.TryGetValue(asset.GetMetadata("RelatedAsset"), out var updatedRelatedAsset)) - { - throw new InvalidOperationException("Related asset not found."); - } - - newAsset.SetMetadata("RelatedAsset", updatedRelatedAsset.ItemSpec); - } - - private int OrderByAssetRole(string left, string right) - { - var leftScore = GetScore(left); - var rightScore = GetScore(right); - - return leftScore - rightScore; - - static int GetScore(string candidate) => candidate switch - { - "Primary" => 0, - "Related" => 1, - "Alternative" => 2, - _ => throw new InvalidOperationException("Invalid asset role"), - }; - } - - private void ApplyPublishProperties(ITaskItem newAsemblyAsset) - { - newAsemblyAsset.SetMetadata("AssetKind", "Publish"); - newAsemblyAsset.SetMetadata("ContentRoot", Path.Combine(PublishPath, "wwwroot")); - newAsemblyAsset.SetMetadata("CopyToOutputDirectory", "Never"); - newAsemblyAsset.SetMetadata("CopyToPublishDirectory", "PreserveNewest"); - } - - private void GroupExistingStaticWebAssets( - Dictionary assemblyAssets, - Dictionary nativeAssets, - Dictionary satelliteAssemblyAssets, - Dictionary symbolAssets, - Dictionary compressedRepresentations) - { - foreach (var asset in ExistingAssets) - { - var traitName = asset.GetMetadata("AssetTraitName"); - if (IsWebAssemblyResource(traitName)) - { - var traitValue = asset.GetMetadata("AssetTraitValue"); - if (IsRuntimeAsset(traitValue)) - { - assemblyAssets.Add(asset.ItemSpec, asset); - } - else if (IsNativeAsset(traitValue)) - { - nativeAssets.Add(asset.ItemSpec, asset); - } - else if (IsSymbolAsset(traitValue)) - { - symbolAssets.Add(asset.ItemSpec, asset); - } - } - else if (IsCulture(traitName)) - { - satelliteAssemblyAssets.Add(asset.ItemSpec, asset); - } - else if (IsAlternative(asset)) - { - compressedRepresentations.Add(asset.ItemSpec, asset); - } - } - } - - private void GroupResolvedFilesToPublish( - Dictionary resolvedFilesToPublishToRemove, - Dictionary resolvedAssemblyToPublish, - Dictionary<(string, string), ITaskItem> satelliteAssemblyToPublish, - Dictionary resolvedSymbolsToPublish, - Dictionary resolvedNativeAssetToPublish) - { - var resolvedFilesToPublish = ResolvedFilesToPublish.ToList(); - if (AssetsComputingHelper.TryGetAssetFilename(CustomIcuCandidate, out string customIcuCandidateFilename)) - { - var customIcuCandidate = AssetsComputingHelper.GetCustomIcuAsset(CustomIcuCandidate); - resolvedFilesToPublish.Add(customIcuCandidate); - } - - foreach (var candidate in resolvedFilesToPublish) - { - if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, out var reason)) - { - Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason); - if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec)) - { - resolvedFilesToPublishToRemove.Add(candidate.ItemSpec, candidate); - } - else - { - Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); - } - continue; - } - - var extension = candidate.GetMetadata("Extension"); - if (string.Equals(extension, ".dll", StringComparison.Ordinal)) - { - var culture = candidate.GetMetadata("Culture"); - var inferredCulture = candidate.GetMetadata("DestinationSubDirectory").Replace("\\", "/").Trim('/'); - if (!string.IsNullOrEmpty(culture) || !string.IsNullOrEmpty(inferredCulture)) - { - var finalCulture = !string.IsNullOrEmpty(culture) ? culture : inferredCulture; - var assemblyName = Path.GetFileName(candidate.GetMetadata("RelativePath").Replace("\\", "/")); - if (!satelliteAssemblyToPublish.ContainsKey((finalCulture, assemblyName))) - { - satelliteAssemblyToPublish.Add((finalCulture, assemblyName), candidate); - } - else - { - Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); - } - continue; - } - - var candidateName = Path.GetFileName(candidate.GetMetadata("RelativePath")); - if (!resolvedAssemblyToPublish.ContainsKey(candidateName)) - { - resolvedAssemblyToPublish.Add(candidateName, candidate); - } - else - { - Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); - } - - continue; - } - - if (string.Equals(extension, ".pdb", StringComparison.Ordinal)) - { - var candidateName = Path.GetFileName(candidate.GetMetadata("RelativePath")); - if (!resolvedSymbolsToPublish.ContainsKey(candidateName)) - { - resolvedSymbolsToPublish.Add(candidateName, candidate); - } - else - { - Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); - } - - continue; - } - - // Capture all the native unfiltered assets since we need to process them to determine what static web assets need to get - // upgraded - if (string.Equals(candidate.GetMetadata("AssetType"), "native", StringComparison.Ordinal)) - { - var candidateName = $"{candidate.GetMetadata("FileName")}{extension}"; - if (!resolvedNativeAssetToPublish.ContainsKey(candidateName)) - { - resolvedNativeAssetToPublish.Add(candidateName, candidate); - } - else - { - Log.LogMessage(MessageImportance.Low, "Duplicate candidate '{0}' found in ResolvedFilesToPublish", candidate.ItemSpec); - } - continue; - } - } - } - - private static bool IsNativeAsset(string traitValue) => string.Equals(traitValue, "native", StringComparison.Ordinal); - - private static bool IsRuntimeAsset(string traitValue) => string.Equals(traitValue, "runtime", StringComparison.Ordinal); - private static bool IsSymbolAsset(string traitValue) => string.Equals(traitValue, "symbol", StringComparison.Ordinal); - - private static bool IsAlternative(ITaskItem asset) => string.Equals(asset.GetMetadata("AssetRole"), "Alternative", StringComparison.Ordinal); - - private static bool IsCulture(string traitName) => string.Equals(traitName, "Culture", StringComparison.Ordinal); - - private static bool IsWebAssemblyResource(string traitName) => string.Equals(traitName, "WasmResource", StringComparison.Ordinal); -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs deleted file mode 100644 index c264a1b42a4617..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/FileHasher.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Numerics; -using System.Security.Cryptography; -using System.Text; - -namespace Microsoft.NET.Sdk.WebAssembly; - -public static class FileHasher -{ - public static string GetFileHash(string filePath) - { - using var hash = SHA256.Create(); - var bytes = Encoding.UTF8.GetBytes(filePath); - var hashBytes = hash.ComputeHash(bytes); - return ToBase36(hashBytes); - } - - private static string ToBase36(byte[] hash) - { - const string chars = "0123456789abcdefghijklmnopqrstuvwxyz"; - - var result = new char[10]; - var dividend = BigInteger.Abs(new BigInteger(hash.AsSpan().Slice(0, 9).ToArray())); - for (var i = 0; i < 10; i++) - { - dividend = BigInteger.DivRem(dividend, 36, out var remainder); - result[i] = chars[(int)remainder]; - } - - return new string(result); - } -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs deleted file mode 100644 index d8a5a3d2ae9e6a..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/GenerateWasmBootJson.cs +++ /dev/null @@ -1,341 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Json; -using System.Text; -using System.Xml; -using Microsoft.Build.Framework; -using Microsoft.Build.Utilities; -using ResourceHashesByNameDictionary = System.Collections.Generic.Dictionary; - -namespace Microsoft.NET.Sdk.WebAssembly; - -public class GenerateWasmBootJson : Task -{ - private static readonly string[] jiterpreterOptions = new[] { "jiterpreter-traces-enabled", "jiterpreter-interp-entry-enabled", "jiterpreter-jit-call-enabled" }; - - [Required] - public string AssemblyPath { get; set; } - - [Required] - public ITaskItem[] Resources { get; set; } - - [Required] - public bool DebugBuild { get; set; } - - [Required] - public bool LinkerEnabled { get; set; } - - [Required] - public bool CacheBootResources { get; set; } - - public bool LoadAllICUData { get; set; } - - public bool LoadCustomIcuData { get; set; } - - public string InvariantGlobalization { get; set; } - - public ITaskItem[] ConfigurationFiles { get; set; } - - public ITaskItem[] Extensions { get; set; } - - public string StartupMemoryCache { get; set; } - - public string Jiterpreter { get; set; } - - public string RuntimeOptions { get; set; } - - [Required] - public string OutputPath { get; set; } - - public ITaskItem[] LazyLoadedAssemblies { get; set; } - - public override bool Execute() - { - using var fileStream = File.Create(OutputPath); - var entryAssemblyName = AssemblyName.GetAssemblyName(AssemblyPath).Name; - - try - { - WriteBootJson(fileStream, entryAssemblyName); - } - catch (Exception ex) - { - Log.LogError(ex.ToString()); - } - - return !Log.HasLoggedErrors; - } - - // Internal for tests - public void WriteBootJson(Stream output, string entryAssemblyName) - { - var icuDataMode = ICUDataMode.Sharded; - - if (string.Equals(InvariantGlobalization, "true", StringComparison.OrdinalIgnoreCase)) - { - icuDataMode = ICUDataMode.Invariant; - } - else if (LoadAllICUData) - { - icuDataMode = ICUDataMode.All; - } - else if (LoadCustomIcuData) - { - icuDataMode = ICUDataMode.Custom; - } - - var result = new BootJsonData - { - entryAssembly = entryAssemblyName, - cacheBootResources = CacheBootResources, - debugBuild = DebugBuild, - linkerEnabled = LinkerEnabled, - resources = new ResourcesData(), - config = new List(), - icuDataMode = icuDataMode, - startupMemoryCache = ParseOptionalBool(StartupMemoryCache), - }; - - if (!string.IsNullOrEmpty(RuntimeOptions)) - { - string[] runtimeOptions = RuntimeOptions.Split(' '); - result.runtimeOptions = runtimeOptions; - } - - bool? jiterpreter = ParseOptionalBool(Jiterpreter); - if (jiterpreter != null) - { - var runtimeOptions = result.runtimeOptions?.ToHashSet() ?? new HashSet(3); - foreach (var jiterpreterOption in jiterpreterOptions) - { - if (jiterpreter == true) - { - if (!runtimeOptions.Contains($"--no-{jiterpreterOption}")) - runtimeOptions.Add($"--{jiterpreterOption}"); - } - else - { - if (!runtimeOptions.Contains($"--{jiterpreterOption}")) - runtimeOptions.Add($"--no-{jiterpreterOption}"); - } - } - - result.runtimeOptions = runtimeOptions.ToArray(); - } - - // Build a two-level dictionary of the form: - // - assembly: - // - UriPath (e.g., "System.Text.Json.dll") - // - ContentHash (e.g., "4548fa2e9cf52986") - // - runtime: - // - UriPath (e.g., "dotnet.js") - // - ContentHash (e.g., "3448f339acf512448") - if (Resources != null) - { - var remainingLazyLoadAssemblies = new List(LazyLoadedAssemblies ?? Array.Empty()); - var resourceData = result.resources; - foreach (var resource in Resources) - { - ResourceHashesByNameDictionary resourceList = null; - - string behavior = null; - var fileName = resource.GetMetadata("FileName"); - var fileExtension = resource.GetMetadata("Extension"); - var assetTraitName = resource.GetMetadata("AssetTraitName"); - var assetTraitValue = resource.GetMetadata("AssetTraitValue"); - var resourceName = Path.GetFileName(resource.GetMetadata("RelativePath")); - - if (TryGetLazyLoadedAssembly(resourceName, out var lazyLoad)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a lazy loaded assembly.", resource.ItemSpec); - remainingLazyLoadAssemblies.Remove(lazyLoad); - resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary(); - resourceList = resourceData.lazyAssembly; - } - else if (string.Equals("Culture", assetTraitName, StringComparison.OrdinalIgnoreCase)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as satellite assembly with culture '{1}'.", resource.ItemSpec, assetTraitValue); - resourceData.satelliteResources ??= new Dictionary(StringComparer.OrdinalIgnoreCase); - resourceName = assetTraitValue + "/" + resourceName; - - if (!resourceData.satelliteResources.TryGetValue(assetTraitValue, out resourceList)) - { - resourceList = new ResourceHashesByNameDictionary(); - resourceData.satelliteResources.Add(assetTraitValue, resourceList); - } - } - else if (string.Equals("symbol", assetTraitValue, StringComparison.OrdinalIgnoreCase)) - { - if (TryGetLazyLoadedAssembly($"{fileName}.dll", out _)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a lazy loaded symbols file.", resource.ItemSpec); - resourceData.lazyAssembly ??= new ResourceHashesByNameDictionary(); - resourceList = resourceData.lazyAssembly; - } - else - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as symbols file.", resource.ItemSpec); - resourceData.pdb ??= new ResourceHashesByNameDictionary(); - resourceList = resourceData.pdb; - } - } - else if (string.Equals("runtime", assetTraitValue, StringComparison.OrdinalIgnoreCase)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as an app assembly.", resource.ItemSpec); - resourceList = resourceData.assembly; - } - else if (string.Equals(assetTraitName, "WasmResource", StringComparison.OrdinalIgnoreCase) && - string.Equals(assetTraitValue, "native", StringComparison.OrdinalIgnoreCase)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a native application resource.", resource.ItemSpec); - if (string.Equals(fileName, "dotnet", StringComparison.OrdinalIgnoreCase) && - string.Equals(fileExtension, ".wasm", StringComparison.OrdinalIgnoreCase)) - { - behavior = "dotnetwasm"; - } - - resourceList = resourceData.runtime; - } - else if (string.Equals("JSModule", assetTraitName, StringComparison.OrdinalIgnoreCase) && - string.Equals(assetTraitValue, "JSLibraryModule", StringComparison.OrdinalIgnoreCase)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as a library initializer resource.", resource.ItemSpec); - resourceData.libraryInitializers ??= new(); - resourceList = resourceData.libraryInitializers; - var targetPath = resource.GetMetadata("TargetPath"); - Debug.Assert(!string.IsNullOrEmpty(targetPath), "Target path for '{0}' must exist.", resource.ItemSpec); - AddResourceToList(resource, resourceList, targetPath); - continue; - } - else if (string.Equals("WasmResource", assetTraitName, StringComparison.OrdinalIgnoreCase) && - assetTraitValue.StartsWith("extension:", StringComparison.OrdinalIgnoreCase)) - { - Log.LogMessage(MessageImportance.Low, "Candidate '{0}' is defined as an extension resource '{1}'.", resource.ItemSpec, assetTraitValue); - var extensionName = assetTraitValue.Substring("extension:".Length); - resourceData.extensions ??= new(); - if (!resourceData.extensions.TryGetValue(extensionName, out resourceList)) - { - resourceList = new(); - resourceData.extensions[extensionName] = resourceList; - } - var targetPath = resource.GetMetadata("TargetPath"); - Debug.Assert(!string.IsNullOrEmpty(targetPath), "Target path for '{0}' must exist.", resource.ItemSpec); - AddResourceToList(resource, resourceList, targetPath); - continue; - } - else - { - Log.LogMessage(MessageImportance.Low, "Skipping resource '{0}' since it doesn't belong to a defined category.", resource.ItemSpec); - // This should include items such as XML doc files, which do not need to be recorded in the manifest. - continue; - } - - if (resourceList != null) - { - AddResourceToList(resource, resourceList, resourceName); - } - - if (!string.IsNullOrEmpty(behavior)) - { - resourceData.runtimeAssets ??= new Dictionary(); - AddToAdditionalResources(resource, resourceData.runtimeAssets, resourceName, behavior); - } - } - - if (remainingLazyLoadAssemblies.Count > 0) - { - const string message = "Unable to find '{0}' to be lazy loaded later. Confirm that project or " + - "package references are included and the reference is used in the project."; - - Log.LogError( - subcategory: null, - errorCode: "BLAZORSDK1001", - helpKeyword: null, - file: null, - lineNumber: 0, - columnNumber: 0, - endLineNumber: 0, - endColumnNumber: 0, - message: message, - string.Join(";", LazyLoadedAssemblies.Select(a => a.ItemSpec))); - - return; - } - } - - if (ConfigurationFiles != null) - { - foreach (var configFile in ConfigurationFiles) - { - result.config.Add(Path.GetFileName(configFile.ItemSpec)); - } - } - - if (Extensions != null && Extensions.Length > 0) - { - var configSerializer = new DataContractJsonSerializer(typeof(Dictionary), new DataContractJsonSerializerSettings - { - UseSimpleDictionaryFormat = true - }); - - result.extensions = new Dictionary> (); - foreach (var configExtension in Extensions) - { - var key = configExtension.GetMetadata("key"); - var config = (Dictionary)configSerializer.ReadObject(File.OpenRead(configExtension.ItemSpec)); - result.extensions[key] = config; - } - } - - var serializer = new DataContractJsonSerializer(typeof(BootJsonData), new DataContractJsonSerializerSettings - { - UseSimpleDictionaryFormat = true - }); - - using var writer = JsonReaderWriterFactory.CreateJsonWriter(output, Encoding.UTF8, ownsStream: false, indent: true); - serializer.WriteObject(writer, result); - - void AddResourceToList(ITaskItem resource, ResourceHashesByNameDictionary resourceList, string resourceKey) - { - if (!resourceList.ContainsKey(resourceKey)) - { - Log.LogMessage(MessageImportance.Low, "Added resource '{0}' to the manifest.", resource.ItemSpec); - resourceList.Add(resourceKey, $"sha256-{resource.GetMetadata("FileHash")}"); - } - } - } - - private static bool? ParseOptionalBool(string value) - { - if (string.IsNullOrEmpty(value) || !bool.TryParse(value, out var boolValue)) - return null; - - return boolValue; - } - - private void AddToAdditionalResources(ITaskItem resource, Dictionary additionalResources, string resourceName, string behavior) - { - if (!additionalResources.ContainsKey(resourceName)) - { - Log.LogMessage(MessageImportance.Low, "Added resource '{0}' to the list of additional assets in the manifest.", resource.ItemSpec); - additionalResources.Add(resourceName, new AdditionalAsset - { - Hash = $"sha256-{resource.GetMetadata("FileHash")}", - Behavior = behavior - }); - } - } - - private bool TryGetLazyLoadedAssembly(string fileName, out ITaskItem lazyLoadedAssembly) - { - return (lazyLoadedAssembly = LazyLoadedAssemblies?.SingleOrDefault(a => a.ItemSpec == fileName)) != null; - } -} diff --git a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj b/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj deleted file mode 100644 index e56ee68e46a5eb..00000000000000 --- a/src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - $(TargetFrameworkForNETCoreTasks);$(TargetFrameworkForNETFrameworkTasks) - $(NoWarn),CA1050,CA1850,CA1845,CA1859,NU5128 - Microsoft.NET.Sdk.WebAssembly - true - true - - - - - All - true - - - - - - - - - - - <_PublishFramework Remove="@(_PublishFramework)" /> - <_PublishFramework Include="$(TargetFrameworks)" /> - - - - - - From 42c6bcf2076a52d256afcab5080caddb1fbeea98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Laban?= Date: Thu, 13 Apr 2023 07:26:46 -0400 Subject: [PATCH 21/21] fix: Ensure that JSImport/JSExport use fully qualified name for DebuggerNonUserCode (#84725) --- .../gen/JSImportGenerator/Constants.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs index aab379d936ba2a..520eeba3ec4e87 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/gen/JSImportGenerator/Constants.cs @@ -10,7 +10,7 @@ internal static class Constants public const string JSImportAttribute = "System.Runtime.InteropServices.JavaScript.JSImportAttribute"; public const string JSExportAttribute = "System.Runtime.InteropServices.JavaScript.JSExportAttribute"; public const string JavaScriptMarshal = "System.Runtime.InteropServices.JavaScript.JavaScriptMarshal"; - public const string DebuggerNonUserCodeAttribute = "System.Diagnostics.DebuggerNonUserCode"; + public const string DebuggerNonUserCodeAttribute = "global::System.Diagnostics.DebuggerNonUserCode"; public const string JSFunctionSignatureGlobal = "global::System.Runtime.InteropServices.JavaScript.JSFunctionBinding"; public const string JSMarshalerArgumentGlobal = "global::System.Runtime.InteropServices.JavaScript.JSMarshalerArgument";