Code Monkey home page Code Monkey logo

iltrim's Introduction

Hi there

I'm Michal, I live in Slovakia, and I work remotely at the .NET Runtime team at Microsoft.

In my spare time I work on C#-related side projects that I find fun but don't particularly overlap with my day job. I maintain the bflat compiler - a C# compiler with Go-like tooling to build small and selfconained apps by default. You might also know me from my greatest hits such as "Let's make C# run on Windows 3.11!", "How about a snake game in C# running on DOS?". I also write articles such as the one on how I built a fully self-contained game in C# in 8 kilobytes.

You can follow me on Twitter to see what I'm up to: https://twitter.com/MStrehovsky

If you would like, leave me a tip in my tip jar at https://paypal.me/MichalStrehovsky

iltrim's People

Contributors

akoeplinger avatar andyayersms avatar bruceforstall avatar brzvlad avatar caroleidt avatar dotnet-bot avatar dotnet-maestro-bot avatar eerhardt avatar ericstj avatar gonzalop avatar hughbe avatar illupus avatar janvorli avatar jaykrell avatar jkotas avatar jonhanna avatar kumpera avatar lambdageek avatar luhenry avatar marek-safar avatar mellinoe avatar michalstrehovsky avatar migueldeicaza avatar pgavlin avatar safern avatar schani avatar stephentoub avatar vargaz avatar viktorhofer avatar weshaggard avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Forkers

baronfel

iltrim's Issues

Provide runtime implementation assemblies in ILTrim test infra

To repro the issue:
Add _ = ((EcmaType)_module.GetObject(_handle)).IsValueType to GetStaticDependencies of TypeDefinitionNode. Notice that iltrim now asserts/crashes.

This is because we need to provide two things for the type system to actually work - places where to resolve assemblies, and information about what assembly is the system module.

This should be done somewhere around here:

// TODO: we should set context.ReferenceFilePaths to a map of assembly simple name to file path
// and call ResolveAssembly instead to get an interned EcmaModule.
// Direct call to EcmaModule.Create creates an assembly out of thin air without registering
// it anywhere and once we deal with multiple assemblies that refer to each other, that's a problem.
EcmaModule module = EcmaModule.Create(context, pe, containingAssembly: null);
// TODO: need to context.SetSystemModule to get a usable type system context

We need to set the ReferenceFilePaths to a string -> string dictionary that maps assembly simple name (basically, just file name without extension) to the file path of the assembly.

Once that's provided, we should also call SetSystemModule with the module that represents the CoreLib and defines System.Object.

Add support for switch instruction

Find the test to repro this with below (note that simplifying the switches tends to NOT repro it, Roslyn will only use the switch instruction in some cases, for simple switches it tends to use if/else branches).

The problem is that switch instruction is of variable length. In the MethodBodyNode.WriteInternal we "copy" instructions over to the output, relying on Opcode helper to determine the length of the instruction. This doesn't work for switch. The fix is to parse the switch instruction manually and write it out manually as well.

Repro (just add a "Switch.cs" into Basic tests and paste the code below):

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Mono.Linker.Tests.Cases.Expectations.Assertions;

namespace Mono.Linker.Tests.Cases.Basic
{
    public class Switch
    {
        public static void Main()
        {
            TestSwitchStatement(1);
            TestSwitchExpression(1);
        }

        [Kept]
        public static void TestSwitchStatement(int p)
        {
            switch (p)
            {
                case 0: Case1(); break;
                case 1: Case1(); break;
                case 3: Case1(); break;
                case 4: Case1(); break;
                case 5: Case1(); break;
                case 6: Case1(); break;
                case 7: Case1(); break;
                case 8: Case1(); break;
                case 9: Case1(); break;
                case 10: Case1(); break;
                default:
                    Case2();
                    break;
            }
        }

        [Kept]
        public static void Case1() { }
        [Kept]
        public static void Case2() { }

        [Kept]
        public static int TestSwitchExpression(int p) =>
            p switch
            {
                0 => 1,
                1 => 2,
                2 => 3,
                3 => 4,
                4 => 5,
                5 => 6,
                6 => 7,
                7 => 8,
                8 => 9,
                9 => 10,
                _ => 0
            };
    }
}

Add support for method parameters

Repro:
Modify the signature of the Main method to have an string[] args parameter. Notice that if you trim it and disassemble the output, the method parameter name is missing.

Fix:

  • Add a new node type that represents the Param.
  • GetStaticDependencies of the node will be empty for now. In WriteInternal, copy the Name, Attributes and SequenceNumber from the original.
  • In GetStaticDependencies of the MethodDefinitionNode, do a foreach over methodDef.GetParameters() and add the ParamNode as a dependency for each.

You should now see the method parameter name show up in the disassembly of the trimmed output.

Keep static constructors

We should ensure static constructors are kept, ideally mirroring the rules for when the static constructor is triggered. E.g. if the type is beforefieldinit, we only need to keep the static constructor if any of the static fields are kept.

The type system might come handy because there are APIs to get/check whether the static constructor is there and get the actual method.

Add support for generic parameters

  • Implement nodes representing GenericParam and GenericParamConstraint.

I think it's not possible to write a nice C# repro case for this just yet (we need at least #3 to be done - if that's already done, just add a typeof(SomeGenericType<>) in your Main). In the meantime, just root a generic type by calling AddRoot from the IL Trimmer, same as in #5.

Support properties and events in descriptors

The ILLink.Descriptors.xml parser doesn't support events and properties. Adding the parser support is easy, but the type system doesn't provide functionality to resolve event/property by name given a type.

Will have to look into how the DataFlow support does this (as it's the same need as reflection GetProperty).

Add support for Events

This has a fair overlap with #39. Events should not be worked on until properties are done (or vice versa - just don't work on them concurrently).

Add support for type references and assembly references

Repro:
Update the program by changing the IProgram interface to be a class (this makes it derive from System.Object).

Fix:

  • Add a new dependency node type that represents a TypeReference. Introduce the new class, implement GetStaticDependencies (we depend on the ResolutionScope of the TypeReference), implement WriteInternal.
  • Hook up the new TypeReferenceNode in NodeFactory. Don't forget adding it to NodeFactory.GetNodeForToken.
  • Add a new dependency node type that represent AssemblyReference. Introduce the new class, implement GetStaticDependencies (there are no dependencies), implement WriteInternal.
  • Hook up the new AssemblyReferenceNode in NodeFactory as above.

Add support for MethodSpec signatures

(Can be worked on once #33 is merged.)

To repro, introduce a generic method in the app. Then call the generic method using a type that is otherwise unreferenced as a generic parameter.

To fix:
We're currently copying the signature blob that specifies the generic arguments verbatim, without analyzing or rewriting it:

// TODO: report dependencies from the signature
yield return new(factory.GetNodeForToken(_module, methodSpec.Method), "Instantiated method");
}
protected override EntityHandle WriteInternal(ModuleWritingContext writeContext)
{
MetadataReader reader = _module.MetadataReader;
MethodSpecification methodSpec = reader.GetMethodSpecification(Handle);
var builder = writeContext.MetadataBuilder;
// TODO: the signature blob might contain references to tokens we need to rewrite
var signatureBlob = reader.GetBlobBytes(methodSpec.Signature);

We'll want to do something similar to what was done to method signatures in f632a12 so that the blob is interpreted. The format of the blob is simple - header, followed by number of generic arguments (n), followed by n types.

Add support for mult-dim array signatures

(Can be worked on after #33 is merged.)

To repro, update the Main program to call a new method that has a multi-dimensional array of some otherwise unreferenced type.

The fix is in two spots: look for SignatureTypeCode.Array in EcmaSignatureAnalyzer and EcmaSignatureRewriter. One has to extract the element type and report a dependency on it. The other needs to mirror the MDArray structure and rewrite the token of the element.

Add support for constant fields

To repro:
Update repro program - add a const int SomeField = 123; somewhere. You'll need to make sure the field is rooted by following similar steps as in #5. Notice that after trimming, the default value is missing.

To fix:

  • Introduce a new node to represent entry in the Constant table.
  • In the implementation of the constant node, don't worry about the contents of the blob - just copy the byte[] over as we do for e.g. the field's signatureBlob.
  • In the field definition dependency node, if fieldDef.Attributes & System.Reflection.FieldAttributes.Literal, this is a literal (const in C#) field.
  • If this is a literal field, the field also depends on the node representing the Constant value. fieldDef.GetDefaultValue will give you the token of the constant value. Add a dependency on the new node.

Add support for class layout

To repro:
Update repro Program.cs - change interface IProgram to class Program and place [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] on top of the class.
Notice that after running ILTrim, the class is no longer marked Sequential.

To fix:
When generating TypeDefinition metadata and the source TypeDefinition has layout (TypeDefinition.GetLayout() is not default), add an entry to the ClassLayout table (AddTypeLayout).

Sort properties by type on output

#50 adds support for properties, but relies on the order of the property table of the input assembly being the same as the order of the typedef table. See:

// TODO: Make this work with properties that aren't sorted in the same order as the TypeDef table
// (for example by sorting properties by type before emitting them, or by saving PropertyMap rows
// in the same order as tehy were in the input assembly.)
PropertyDefinitionHandle propertyHandle = writeContext.TokenMap.MapTypePropertyList(Handle);

Add support for Fields

Repro:
No good way to repro this before we have support for scanning method bodies. At the spot where we're calling analyzer.AddRoot to root the entrypoint method, add a line that roots the first field in the repro project as well: analyzer.AddRoot(factory.GetNodeForToken(module, MetadataTokens.FieldDefinitionHandle(1)), "First field");.

Fix:

  • Add a new node type that represents a FieldDefinition. It will look similar to MethodDefinitionNode.
  • In GetStaticDependencies we depend on the declaring type and there will be a TODO to handle the signature, same as for methods (just make a TODO).
  • In WriteInternal, emit the field. Add a TODO about the signature and just copy the bytes from source for now.

Add support for Properties

This is a bit of freestyle issue because it involves multiple tables and I don't want to spend time coming up with a detailed implementation plan. We can discuss on Teams.

Properties are represented in multiple tables. There's the Property table that defines the property name. There's the PropertyMap table that assigns properties to their owning type. And there's MethodSemantics table that assigns accessor methods to properties. See the ECMA spec for some pictures.

I think we'll want to go for a strategy where placing a property into the dependency graph places all the accessors into the dependency graph. We don't currently have anything that would put a property into the graph in the first place, so for your test purposes just AddRoot a property to test things same as it was done for fields in #5.

The MethodSemantics table suffers from the same problems as fieldlist and methodlist, so you have to be ready to write code that deals with this:

// Set of methods that help with mapping various *List fields of metadata records.
// As an example of a *List field, consider the FieldList field on the TypeDef record.
//
// The value of the FieldList of a particular TypeDef record captures the FieldDef
// token of the first field of the type. If there's no field, the FieldList field
// captures the first token of a field of the following type.
//
// The number of fields on a type can be quickly calculated by subtracting the value
// of FieldList of the current type from the FieldList value of next type. For the last
// type, we look at number of record in the field table instead of FieldList of the next
// type.
//
// Field table
//
// TypeDef table +-----------+
// ---+___________| 1
// +----------------|---+ -------/ |___________| 2
// 1 |________________|_1_+--/ |___________| 3
// 2 |________________|_4_+--------------+___________| 4
// 3 |________________|_4_+----------/ |___________| 5
// 4 | | 7 +------\ |___________| 6
// +----------------|---+ -------+ | 7
// ^ +-----------+
// |
// |
// |
// FieldList column
//
// In the table above, TypeDef 1 owns fields 1, 2, 3. TypeDef 2 owns no fields,
// TypeDef 3 owns fields 4, 5, 6 and TypeDef 4 owns field 7.
//
// The problem with building a TokenMap for this is twofold:
// 1. We cannot simply call MapToken on the value in the FieldList record because
// the field in question might not have been marked and we don't have an output
// token for it. If that's the case, we need to find the next field record with
// a mapping.
// 2. System.Reflection.Metadata abstracts away the FieldList record and we can't get
// a token to begin with. We can enumerate the fields on the on the type, but if
// the type has no fields, we have no choice but to look at the fields of the next
// type until we find a field.

(Your code will likely be a heavy copypaste of what's already there, but I wanted to issue a fair warning.)

Preserve manifest resources

Managed resources should be copied to the output. Probably just make the module type depend on all manifest resources in the assembly.

MetadataReader.ManifestResources and .GetManifestResource are the related API.

We'll need to pipe a new stream with the resource data to the ManagedPEBuilder, similar to what we did for RVA static data here: #56.

Add support for TypeSpec signatures

(Can be worked on once #33 is merged.)

To repro, introduce a generic type in the app (class Foo<T> { }) and then make another type derive from it class Bar : Foo<SomeUnusedType> { }. Then reference Bar from somewhere.

To fix:
We're currently copying the signature blob that specifies the generic arguments verbatim, without analyzing or rewriting it:

// TODO: report dependencies from the signature
yield break;
}
protected override EntityHandle WriteInternal(ModuleWritingContext writeContext)
{
MetadataReader reader = _module.MetadataReader;
TypeSpecification typeSpec = reader.GetTypeSpecification(Handle);
var builder = writeContext.MetadataBuilder;
// TODO: the signature blob might contain references to tokens we need to rewrite
var signatureBlob = reader.GetBlobBytes(typeSpec.Signature);

We'll want to do something similar to what was done to method signatures in f632a12 so that the blob is interpreted.

The blob pretty much contains just a signature that RewriteType and AnalyzeType already understands, so this is a lot less work than the method signatures referenced above.

Keep all fields on enums

Enums are special and we should just keep all fields on them.

In the typedefintitionnode, get the type system representation of the type by calling _module.GetType(Handle). The check IsEnum to see if we're an enum.

Add support for nested types

Repro:
Update the repro program by nesting the IProgram interface under another interface.

Fix:

  • If a GetDeclaringType() of a TypeDefinition is not IsNil(), add a dependency on the declaring type.
  • When writing out the record, AddNestedType() the type and owning type to write out the relationship.

Add support for scanning method bodies

Repro:
Update the repro program by changing Main to return FirstMethod();.

Fix:

  • You'll work in MethodBodyNode.cs.
  • Use GetILBytes to get the bytes of the body block.
  • S.R.Metadata doesn't come with an IL instruction decoder. We have a basic one in the type system so add it as a link to the project from src\coreclr\tools\Common\TypeSystem\IL\ILReader.cs. You'll also need ILOpcode.cs and ILOpcodeHelper.cs but that should be all (if more is needed, use your own judgement to ifdef stuff out).
  • Update GetStaticDependencies to report all tokens from the method body as factory.GetNodeForToken(token).
  • Rewrite the tokens in the instruction stream (using the token map) before writing them out in WriteInternal. InstructionEncoder from S.R.Metadata might be handy but it's possible it will be easier to encode it ourselves.

S.R.Metadata has its own ILOpCode enum. The managed type system pre-dates S.R.Metadata having IL APIs so they're unfortunately different. I'm unclear which one would be better to use now. Type system should ideally embrace the one from S.R.Metadata but that's out of scope of the hackathon.

Optimization to remove unused method bodies

Recommended to look at #42 to understand how conditional dependencies work.

If we have:

class Foo
{
    public void DoSomethingExpensive() => new ExpensiveClass().OtherStuff();
}

and then:

Foo f = null;

// ...

if (f != null)
    f.DoSomethingExpensive();

We'll pull ExpensiveClass into the dependency graph even though it can practically be never reached (Foo was never allocated and the instance method is not actually reachable). It would be nice to do something about it.

We cannot remove the call to the method easily, but we're able to remove the method body.

We already know when a type was allocated thanks to #42 and the ConstructedTypeNode.

MethodDefinition currently unconditionally depends on the method body. For instance methods on reference types (the type system can be used to answer those two questions), we should make the dependency conditional on a ConstructedTypeNode being present in the graph.

When we're in the the writing phase of the MethodDefinition, grab the method body node, and find out if it's Marked property is false. If the body wasn't marked, instead of int rva = bodyNode.Write(writeContext);, we should ask the writing context what the RVA of a throwing method is - writing context should generate a method body whose only instructions are ldnull/throw, remember the RVA, and return that - this will be a new API on writing context.

Add support for scanning exception regions

Valid once #16 is merged.

Repro:
Update the repro program by changing Main to contain try/catch/finally and calling some new methods from the catch and finally regions.

Fix:

  • Work is done in MethodBodyNode.cs
  • Use bodyBlock.ExceptionRegions to get to the exception regions in the original method
  • Update GetStaticDependencies to report the catch clause type token dependency
  • Include exception regions when rewriting the method body in Write.
    • The code already uses InstructionEncoder so just add a ControlFlowBuilder to it
    • Use the ControlFlowBuilder to add labels for the try/catch/finally blocks
    • Add exception regions
    • Remap the catch clause type tokens

Don't forget (or add an issue for) about filter blocks.

Handle generic types inheriting from generic types

The static dependency scanning of generic types needs to handle substituted base types. The following example should reproduce the problem:

using Mono.Linker.Tests.Cases.Expectations.Assertions;

namespace Mono.Linker.Tests.Cases.Basic
{
    [Kept]
    class GenericType
    {
        [Kept]
        public static void Main()
        {
            var c = new C();
        }
    }

    class A<T>
    {

    }
    class B<T> : A<string>
    {

    }
    class C : B<int>
    {
    }
}

Handling of unresolvable references

We'll need to look at places that go up into type system from metadata - type system tends to throw if things don't resolve so we need to be crisp on where it's okay to throw. Generally, missing references are an exceptional case so I'm not too worried about the throws, but we need to have catches in place.

One of the places that we'll need to revisit is the representation of AssemblyRefs from #105 - we can't get an EcmaModule to an assembly that doesn't resolve.

Add support for function pointer signatures

(Can be worked on after #33 is merged.)

To repro, update the Main program to call a new method that has a function pointer as an argument (i.e. delegate*<SomeType, SomeOtherType> in C#).

The fix is in two spots: look for SignatureTypeCode.FunctionPointer in EcmaSignatureAnalyzer and EcmaSignatureRewriter. One has to extract all the types referenced from the method signature report a dependency on them. The other needs to mirror the function pointer structure and rewrite the tokens of the parameter types.

Add support for field signatures

To repro, add a new field of some otherwise not kept type and e.g. assign a null to it in Main.

In the FieldDefinitionNode we currently just copy the signature blob over, which means we don't analyze/rewrite what the field type refers to. The fix will look similar to f632a12, except field signatures are simpler (there's just one type).

Please hook up MemberReference too, same as in the above commit (you can test it by e.g. reading the String.Empty field in Main).

For reference, field signatures are described in II.23.2.4 FieldSig of the ECMA-335 spec.

Add support for field RVA data

class Program
{
    static ReadOnlySpan<byte> Bytes => new byte[] { 1, 2, 3 };

    static int Main() => Bytes[0];
}

Be able to write out the magic field that underlies the Bytes property.

Keep virtual methods which are required by the base class

The logic which keeps virtual methods if the type is constructed and if the virtual method is used only works on constructed types (as expected). But if there's a non-constructed type which implements an abstract method, such method has to be kept in order for the metadata to be consistent. Currently we don't keep such a method.

To test, modify the VirtualMethods test to look like this:

    [Kept]
    public class VirtualMethods
    {
        [Kept]
        static void Main()
        {
            BaseType b = new DerivedType();
            b.Method1();

            NonConstructedType.DoSomethingStatic();
        }
    }

    [Kept]
    abstract class BaseType
    {
        [Kept]
        public BaseType() { }
        [Kept]
        public abstract void Method1();
        public abstract void Method2();
    }

    [Kept]
    [KeptBaseType(typeof(BaseType))]
    class DerivedType : BaseType
    {
        [Kept]
        public DerivedType() { }
        [Kept]
        public override void Method1() { }
        public override void Method2() { }
    }

    [Kept]
    [KeptBaseType(typeof(BaseType))]
    class NonConstructedType : BaseType
    {
        [Kept]
        public static void DoSomethingStatic() { }

        [Kept] // <- This fails - we don't keep Method1, even though we do keep the abstract method on the base class
        public override void Method1() { }
        public override void Method2() { }
    }

/cc @MichalStrehovsky

Keep instance fields on types with layout

If a TypeDefinition with a Sequential or Explicit layout is marked, we should mark all the instance fields on it.

As a possible additional optimization, we can postpone this on reference types until the type is allocated (i.e. until we have a ConstructedTypeNode for it in the system).

Parallelize method body scanning

In MethodBodyNode class:

  • We need to stop doing scanning work in GetStaticDependencies of MethodBodyNode. Instead, introduce a new method (e.g. ComputeDependencies) that computes the dependencies and stores them in a DependencyList-typed field.
    • This is the method we're going to call in parallel.
  • GetStaticDependencies will be changed to just return the value of the DependencyList-typed field.
  • StaticDependenciesAreComputed will be changed to return whether the DependencyList is non-null.

In the Trimmer class:

  • Install a ComputeDependencyRoutine callback (e.g. analyzer.ComputeDependencyRoutine += ComputeDependencyNodeDependencies;)
  • This is the callback we'll get with a list of all the nodes that reported StaticDependenciesAreComputed == false. Make it so that we scan all the method bodies in this list in parallel (e.g. with a Parallell.ForEach).

For inspiration, this is where crossgen2 does it, but ours can be much simpler (ignore all those "deferred phase stuff, etc. - we really just want a parallel foreach with a call to scan the method for each element of the list provided as an argument):

protected override void ComputeDependencyNodeDependencies(List<DependencyNodeCore<NodeFactory>> obj)
{
using (PerfEventSource.StartStopEvents.JitEvents())
{
Action<DependencyNodeCore<NodeFactory>> compileOneMethod = (DependencyNodeCore<NodeFactory> dependency) =>
{
MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo;
if (methodCodeNodeNeedingCode == null)
{
if (dependency is DeferredTillPhaseNode deferredPhaseNode)
{
if (Logger.IsVerbose)
_logger.Writer.WriteLine($"Moved to phase {_nodeFactory.CompilationCurrentPhase}");
deferredPhaseNode.NotifyCurrentPhase(_nodeFactory.CompilationCurrentPhase);
return;
}
}
Debug.Assert((_nodeFactory.CompilationCurrentPhase == 0) || ((_nodeFactory.CompilationCurrentPhase == 2) && !_finishedFirstCompilationRunInPhase2));
MethodDesc method = methodCodeNodeNeedingCode.Method;
if (Logger.IsVerbose)
{
string methodName = method.ToString();
Logger.Writer.WriteLine("Compiling " + methodName);
}
if (_printReproInstructions != null)
{
Logger.Writer.WriteLine($"Single method repro args:{_printReproInstructions(method)}");
}
try
{
using (PerfEventSource.StartStopEvents.JitMethodEvents())
{
// Create only 1 CorInfoImpl per thread.
// This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this));
corInfoImpl.CompileMethod(methodCodeNodeNeedingCode, Logger);
}
}
catch (TypeSystemException ex)
{
// If compilation fails, don't emit code for this method. It will be Jitted at runtime
if (Logger.IsVerbose)
Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}");
}
catch (RequiresRuntimeJitException ex)
{
if (Logger.IsVerbose)
Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
}
catch (CodeGenerationFailedException ex) when (_resilient)
{
if (Logger.IsVerbose)
Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT");
}
};
// Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle
if (Logger.IsVerbose)
Logger.Writer.WriteLine($"Processing {obj.Count} dependencies");
if (_parallelism == 1)
{
foreach (var dependency in obj)
compileOneMethod(dependency);
}
else
{
ParallelOptions options = new ParallelOptions
{
MaxDegreeOfParallelism = _parallelism
};
Parallel.ForEach(obj, options, compileOneMethod);
}
}
if (_methodILCache.Count > 1000)
{
_methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup);
}
if (_nodeFactory.CompilationCurrentPhase == 2)
{
_finishedFirstCompilationRunInPhase2 = true;
}
}

Please make it possible to run this still singlethreaded (same as crossgen2), because debugging a multithreaded app is a pain (breakpoints hit in all threads).

Type references don't mark the target

If there's a type reference to a type in a different module, we don't mark the type, only the module.
So for example:

static void Main()
{
    var t = typeof(TypeFromDifferentAssembly);
}

This will not preserve the type and the type ref in the original assembly is unresolvable.
Probably related #90.

Add support for rewriting signatures

Repro:
Update the repro program by adding a local variable in Main (a line with IAnortherType mylocal = default;).

Fix:

  • We'll want to introduce a new helper struct because rewriting signatures is a common theme. The helper struct should take a BlobReader with the signature, a BlobWriter to write the signature out, and the token map. The helper will read the signature, replace the tokens in it, and write it out. There might be another helper that just parses the signature and collects what the signature depends on.
  • Structurally we'll end up with something similar to src\coreclr\tools\Common\TypeSystem\Ecma\EcmaSignatureParser.cs - you can refer to that file to see how to read stuff out of the blob. Instead of constructing type system entities we'll use BlobEncoder from S.R.Metadata to encode a new blob, replacing any tokens in it with mapped tokens.
  • Use the new helper struct to implement GetStaticDependencies and WriteInternal on StandaloneSignatureNode.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.