Skip to content

Commit da7f6ba

Browse files
committed
Move the most recent changes about the ALC from SD to Github
1 parent 436b5c9 commit da7f6ba

6 files changed

Lines changed: 51 additions & 49 deletions

File tree

src/Microsoft.PowerShell.CoreCLR.AssemblyLoadContext/CoreCLR/CorePsAssemblyLoadContext.cs

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ private PowerShellAssemblyLoadContext(string basePaths, bool useResolvingHandler
175175
/// <summary>
176176
/// Singleton instance of PowerShellAssemblyLoadContext
177177
/// </summary>
178-
public static PowerShellAssemblyLoadContext Instance
178+
internal static PowerShellAssemblyLoadContext Instance
179179
{
180180
get; private set;
181181
}
@@ -376,7 +376,19 @@ internal IEnumerable<Assembly> GetAssemblies(string namespaceQualifiedTypeName)
376376
string tpaStrongName;
377377
if (coreClrTypeCatalog.TryGetValue(namespaceQualifiedTypeName, out tpaStrongName))
378378
{
379-
return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
379+
try
380+
{
381+
return new Assembly[] { GetTrustedPlatformAssembly(tpaStrongName) };
382+
}
383+
catch (FileNotFoundException)
384+
{
385+
// It's possible that the type catalog generated in OPS contains more entries than
386+
// the one generated in windows build. This is because in OPS we have more freedom
387+
// to control what packages to depend on, such as Json.NET.
388+
// If we deploy the PSALC.dll generated from OPS to NanoServer, then it's possible
389+
// that 'GetTrustedPlatformAssembly(tpaStrongName)' may fail for such entries. In
390+
// this case, we ignore the exception and return our cached assemblies.
391+
}
380392
}
381393
}
382394

@@ -459,6 +471,15 @@ internal IEnumerable<string> GetAvailableDotNetTypes()
459471
/// <summary>
460472
/// Set the profile optimization root on the appropriate load context
461473
/// </summary>
474+
/// <remarks>
475+
/// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
476+
/// This is because PS assemblies will be recorded in the profile, and the next time OPS
477+
/// starts up, the default context will load the PS assemblies pretty early to ngen them
478+
/// in another CPU core, so our Load override won't track the loading of them, and thus
479+
/// OPS will fail to work.
480+
/// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
481+
/// are not in TPA list, then we can enable profile optimization without a problem.
482+
/// </remarks>
462483
internal void SetProfileOptimizationRootImpl(string directoryPath)
463484
{
464485
if (this.useResolvingHandlerOnly)
@@ -468,6 +489,15 @@ internal void SetProfileOptimizationRootImpl(string directoryPath)
468489
/// <summary>
469490
/// Start the profile optimization on the appropriate load context
470491
/// </summary>
492+
/// <remarks>
493+
/// When using PS ALC as a full fledged ALC in OPS, we don't enable profile optimization.
494+
/// This is because PS assemblies will be recorded in the profile, and the next time OPS
495+
/// starts up, the default context will load the PS assemblies pretty early to ngen them
496+
/// in another CPU core, so our Load override won't track the loading of them, and thus
497+
/// OPS will fail to work.
498+
/// The root cause is that dotnet.exe put all PS assemblies in TPA list. If PS assemblies
499+
/// are not in TPA list, then we can enable profile optimization without a problem.
500+
/// </remarks>
471501
internal void StartProfileOptimizationImpl(string profile)
472502
{
473503
if (this.useResolvingHandlerOnly)
@@ -620,38 +650,15 @@ private bool IsAssemblyMatching(AssemblyName requestedAssembly, AssemblyName loa
620650
/// </param>
621651
private Assembly GetTrustedPlatformAssembly(string tpaStrongName)
622652
{
623-
Assembly asmLoaded;
653+
// We always depend on the default context to load the TPAs that are recorded in
654+
// the type catalog.
655+
// - If the requested TPA is already loaded, then 'Assembly.Load' will just get
656+
// it back from the cache of default context.
657+
// - If the requested TPA is not loaded yet, then 'Assembly.Load' will make the
658+
// default context to load it
624659
AssemblyName assemblyName = new AssemblyName(tpaStrongName);
625-
626-
// With the current standalone-app model of OPS, .NET Core libraries and PS assemblies are mixed together in one folder.
627-
// So when using PSALC as a full fledged ALC in OPS, some TPAs might be loaded by our Load override. In that case, if we
628-
// alwasy call Assembly.Load here to get a TPA, we might end up with a different Assembly instance of the the same TPA
629-
// loaded in the default load context. We want to use the same assembly instance for type resolution in PS to avoid creating
630-
// types and running .NET code from different assembly instances of the same DLL. Therefore, we try our cache first to see
631-
// if the requested TPA is already loaded. If so, we use that one. If not, we load it in default context using Assembly.Load.
632-
// Once a TPA is loaded in the default context, the same Assembly instance will always be used by custom ALC's when they attempt
633-
// to resolve an "Assembly.Load" request for the same TPA.
634-
//
635-
// For in-box PS of NanoServer/IoT and the share-framework host model of OPS, we don't have the mixed libraries/assemblies
636-
// problem, and TPAs are always resolved/loaded by the default context. In those cases, checking our cache would be unnecessary,
637-
// but it won't cause any problems.
638-
639-
// Probe the assembly cache
640-
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
641-
return asmLoaded;
642-
643-
// Prepare to load the assembly
644-
lock (syncObj)
645-
{
646-
// Probe the cache again in case it's already loaded
647-
if (TryGetAssemblyFromCache(assemblyName, out asmLoaded))
648-
return asmLoaded;
649-
650-
// The requested TPA is not loaded by PS ALC, so load it in the default load context using Assembly.Load.
651-
// There is no need to add it to our cache. It's cached in the default context.
652-
asmLoaded = Assembly.Load(assemblyName);
653-
return asmLoaded;
654-
}
660+
Assembly asmLoaded = Assembly.Load(assemblyName);
661+
return asmLoaded;
655662
}
656663

657664
/// <summary>

src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1818,7 +1818,7 @@ internal PSModuleInfo LoadModuleManifest(
18181818
DirectoryInfo parent = null;
18191819
try
18201820
{
1821-
parent = ClrFacade.GetParent(moduleManifestPath);
1821+
parent = Directory.GetParent(moduleManifestPath);
18221822
}
18231823
catch (IOException)
18241824
{

src/System.Management.Automation/engine/Modules/TestModuleManifestCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ protected override void ProcessRecord()
241241
DirectoryInfo parent = null;
242242
try
243243
{
244-
parent = ClrFacade.GetParent(filePath);
244+
parent = Directory.GetParent(filePath);
245245
}
246246
catch (IOException) { }
247247
catch (UnauthorizedAccessException) { }

src/System.Management.Automation/resources/ParserStrings.resx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,8 +1351,8 @@ ModuleVersion : Version of module to import. If used, ModuleName must represent
13511351
<data name="CantActivateDocumentInPowerShellCore" xml:space="preserve">
13521352
<value>Cannot run a document in PowerShell Core: {0}.</value>
13531353
</data>
1354-
<data name="InvalidAssemblyLoadContextInUse" xml:space="preserve">
1355-
<value>The default AssemblyLoadContext in use is invalid. The default AssemblyLoadContext for PowerShell Core should be of type 'PowerShellAssemblyLoader'.</value>
1354+
<data name="LoadContextNotInitialized" xml:space="preserve">
1355+
<value>'PowerShellAssemblyLoadContext' is not initialized.</value>
13561356
</data>
13571357
<data name="MultipleTypeConstraintsOnMethodParam" xml:space="preserve">
13581358
<value>Multiple type constraints are not allowed on a method parameter.</value>

src/System.Management.Automation/utils/ClrFacade.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,10 @@ private static PowerShellAssemblyLoadContext PSAssemblyLoadContext
344344
{
345345
get
346346
{
347+
if (PowerShellAssemblyLoadContext.Instance == null)
348+
{
349+
throw new InvalidOperationException(ParserStrings.LoadContextNotInitialized);
350+
}
347351
return PowerShellAssemblyLoadContext.Instance;
348352
}
349353
}
@@ -512,15 +516,6 @@ internal static bool IsTransparentProxy(object obj)
512516
#endif
513517
}
514518

515-
/// <summary>
516-
/// Facade for Directory.GetParent(string)
517-
/// </summary>
518-
internal static DirectoryInfo GetParent(string path)
519-
{
520-
// Porting note: this is in recent CoreCLR
521-
return Directory.GetParent(path);
522-
}
523-
524519
/// <summary>
525520
/// Facade for ManagementDateTimeConverter.ToDmtfDateTime(DateTime)
526521
/// </summary>

src/powershell-native/nativemsh/pwrshcommon/pwrshcommon.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,14 +1454,14 @@ namespace NativeMsh
14541454
props[nProps] = L"TRUSTED_PLATFORM_ASSEMBLIES";
14551455
std::wstring tempStr = assemblyList.str();
14561456
vals[nProps] = tempStr.c_str();
1457-
nProps++;
1457+
nProps++;
14581458

14591459
props[nProps] = L"APP_PATHS";
1460-
vals[nProps] = hostEnvironment.GetHostDirectoryPath();
1460+
vals[nProps] = L"";
14611461
nProps++;
14621462

14631463
props[nProps] = L"APP_NI_PATHS";
1464-
vals[nProps] = hostEnvironment.GetHostDirectoryPath();
1464+
vals[nProps] = L"";
14651465
nProps++;
14661466

14671467
// Create the customized AppDomainManager out of the SandboxHelper class

0 commit comments

Comments
 (0)