Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Agents/Xamarin.Interactive.DotNetCore/DotNetCoreAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,17 @@ sealed class DotNetCoreEvaluationContextManager : EvaluationContextManager
"CS1685"
};

readonly NetCoreEvaluationAssemblyContext evaluationAssemblyContext
= new NetCoreEvaluationAssemblyContext ();

internal DotNetCoreEvaluationContextManager (DotNetCoreAgent agent)
: base (agent.RepresentationManager, agent)
{
}

private protected override EvaluationAssemblyContextBase AssemblyContext
=> evaluationAssemblyContext;

protected override object CreateGlobalState ()
=> new EvaluationContextGlobalObject ((DotNetCoreAgent)Context);

Expand All @@ -76,12 +82,7 @@ internal override void LoadExternalDependencies (
foreach (var externalDep in externalDependencies) {
try {
Log.Debug (TAG, $"Loading external dependency from {externalDep.Location}…");
if (MacIntegration.IsMac) {
// Don't do anything for now on Mac, nothing we've tried
// so far works. :(
} else {
WindowsSupport.LoadLibrary (externalDep.Location);
}
evaluationAssemblyContext.Add (externalDep);
} catch (Exception e) {
Log.Error (TAG, "Could not load external dependency.", e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// Author:
// Bojan Rajkovic <brajkovic@xamarin.com>
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Reflection;
using System.IO;
using System.Runtime.Loader;

using Xamarin.Interactive.CodeAnalysis.Evaluating;
using Xamarin.Interactive.CodeAnalysis.Resolving;
using Xamarin.Interactive.Logging;

namespace Xamarin.Interactive.DotNetCore
{
sealed class NetCoreEvaluationAssemblyContext : EvaluationAssemblyContextBase
{
const string TAG = nameof (NetCoreEvaluationAssemblyContext);

readonly InteractiveAssemblyLoadContext assemblyLoadContext;

sealed class InteractiveAssemblyLoadContext : AssemblyLoadContext
{
const string TAG = nameof (InteractiveAssemblyLoadContext);

NetCoreEvaluationAssemblyContext evaluationAssemblyContext;

public InteractiveAssemblyLoadContext (NetCoreEvaluationAssemblyContext evaluationAssemblyContext)
=> this.evaluationAssemblyContext = evaluationAssemblyContext;

protected override Assembly Load (AssemblyName assemblyName)
{
Log.Info (TAG, $"Requested assembly load for {assemblyName}.");

if (evaluationAssemblyContext.CompilationAssemblyMap.TryGetValue (assemblyName, out var netAssembly))
return netAssembly;

if (evaluationAssemblyContext.ReferencedAssemblyMap.TryGetValue (assemblyName, out var assemblyDefinition))
return LoadAssemblyFromAssemblyDefinition (assemblyName, assemblyDefinition);

Log.Warning (
TAG,
$"Could not load assembly {assemblyName}, it wasn't present in any list of assemblies.");

return null;
}

Assembly LoadAssemblyFromAssemblyDefinition (AssemblyName assemblyName, AssemblyDefinition assemblyDefinition)
{
Assembly loadedAsm;

if (File.Exists (assemblyDefinition.Content.Location)) {
loadedAsm = LoadFromAssemblyPath (assemblyDefinition.Content.Location);
Log.Info (TAG, $"Loaded assembly {loadedAsm} from {assemblyDefinition.Content.Location}.");
} else if (assemblyDefinition.Content.PEImage != null) {
var imageStream = new MemoryStream (assemblyDefinition.Content.PEImage);
if (assemblyDefinition.Content.DebugSymbols != null) {
var symStream = new MemoryStream (assemblyDefinition.Content.DebugSymbols);
loadedAsm = LoadFromStream (imageStream, symStream);
}
loadedAsm = LoadFromStream (imageStream);
Log.Info (TAG, $"Loaded assembly {loadedAsm} from sent PE image.");
} else {
Log.Warning (
TAG,
$"Could not load assembly {assemblyName}, location {assemblyDefinition.Content.Location} did not " +
"exist and PEImage was not sent.");
return null;
}

evaluationAssemblyContext.AssemblyResolvedHandler?.Invoke (loadedAsm, assemblyDefinition);

return loadedAsm;
}

internal Assembly InternalLoadByName (AssemblyName assemblyName)
=> Load (assemblyName);

protected override IntPtr LoadUnmanagedDll (string unmanagedDllName)
{
Log.Info (TAG, $"Requested unmanaged DLL load for {unmanagedDllName}.");

if (!evaluationAssemblyContext.ExternalDependencyMap.ContainsKey (unmanagedDllName)) {
Log.Info (TAG, $"Don't know where to load this from, falling back to base.");
return base.LoadUnmanagedDll (unmanagedDllName);
}

string unmanagedPath = evaluationAssemblyContext.ExternalDependencyMap [unmanagedDllName];
Log.Info (TAG, $"Loading unmanaged DLL {unmanagedDllName} from {unmanagedPath}.");

var unmanagedHandle = LoadUnmanagedDllFromPath (unmanagedPath);
Log.Info (TAG, $"Loaded unmanaged DLL {unmanagedDllName} from {unmanagedPath}, handle is {unmanagedHandle}.");

return unmanagedHandle;
}

public IntPtr LoadExternalDependency (AssemblyDependency dependency)
=> LoadUnmanagedDllFromPath (dependency.Location.FullPath);
}

public NetCoreEvaluationAssemblyContext ()
{
assemblyLoadContext = new InteractiveAssemblyLoadContext (this);
AssemblyLoadContext.Default.Resolving += HandleAssemblyResolve;
}

protected override void Dispose (bool disposing)
{
base.Dispose (disposing);
AssemblyLoadContext.Default.Resolving -= HandleAssemblyResolve;
}

public IntPtr LoadExternalDependency (AssemblyDependency dependency)
=> assemblyLoadContext.LoadExternalDependency (dependency);

Assembly HandleAssemblyResolve (AssemblyLoadContext loadContext, AssemblyName assemblyName)
=> assemblyLoadContext.InternalLoadByName (assemblyName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
<ItemGroup>
<ProjectReference Include="..\Xamarin.Interactive\Xamarin.Interactive.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// Author:
// Aaron Bockover <abock@xamarin.com>
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Generic;
using System.Reflection;

namespace Xamarin.Interactive.CodeAnalysis.Evaluating
{
// Implement a custom AssemblyName comparer so that we don't have to insert
// multiple different varieties of the same assembly name into the dictionary.
// Different pieces of external code seem to look up our submission assemblies in
// different ways: JSON.NET uses bare names (see https://bugzilla.xamarin.com/show_bug.cgi?id=58801),
// most of the framework uses fully qualified assembly names, and ASP.NET Core
// seems to use fully-qualified-except-no-version names. As submission assemblies
// aren't versioned, don't have a culture, and don't have a public key token, treating
// the name in a case insensitive way is fine.
sealed class AssemblyNameInsensitiveNameOnlyComparer : IEqualityComparer<AssemblyName>, IComparer<AssemblyName>
{
public static bool Equals (string x, string y)
=> string.Equals (x, y, StringComparison.OrdinalIgnoreCase);

public static bool Equals (AssemblyName x, AssemblyName y)
=> Equals (x?.Name, y?.Name);

public static readonly IComparer<AssemblyName> Default
= new AssemblyNameInsensitiveNameOnlyComparer ();

bool IEqualityComparer<AssemblyName>.Equals (AssemblyName x, AssemblyName y)
=> Equals (x?.Name, y?.Name);

int IEqualityComparer<AssemblyName>.GetHashCode (AssemblyName obj)
=> obj?.Name == null ? 0 : obj.Name.GetHashCode ();

public int Compare (AssemblyName x, AssemblyName y)
=> string.Compare (x?.Name, y?.Name, StringComparison.OrdinalIgnoreCase);
}

sealed class AssemblyNameFullNameComparer : IEqualityComparer<AssemblyName>, IComparer<AssemblyName>
{
public static bool Equals (string x, string y)
=> string.Equals (x, y, StringComparison.OrdinalIgnoreCase);

public static bool Equals (AssemblyName x, AssemblyName y)
=> Equals (x?.Name, y?.Name);

public static readonly IComparer<AssemblyName> Default
= new AssemblyNameFullNameComparer ();

bool IEqualityComparer<AssemblyName>.Equals (AssemblyName x, AssemblyName y)
=> Equals (x?.FullName, y?.FullName);

int IEqualityComparer<AssemblyName>.GetHashCode (AssemblyName obj)
=> obj?.Name == null ? 0 : obj.Name.GetHashCode ();

public int Compare (AssemblyName x, AssemblyName y)
=> string.Compare (x?.FullName, y?.FullName);
}
}

This file was deleted.

Loading