File: Actions\GrammarActions.Instructions.References.cs
Web Access
Project: ILAssembler.csproj (ILAssembler)
// 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 System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using Antlr4.Runtime;

namespace ILAssembler;

internal sealed partial class GrammarActions
{
    internal void EmitMethodReferenceInstruction(IToken opcodeToken, CILParser.MethodRefContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        ILOpCode opcode = instruction.OpCode;
        CurrentMethodContext method = instruction.Method;
        bool expectInstance = opcode is ILOpCode.Callvirt or ILOpCode.Newobj;
        _expectInstance = expectInstance;
        try
        {
            method.Definition.MethodBody.OpCode(opcode);
            WriteInstructionToken(method, MaterializeMethodReference(context));
        }
        finally
        {
            if (expectInstance)
            {
                _expectInstance = false;
            }
        }
    }

    internal void EmitFieldReferenceInstruction(IToken opcodeToken, CILParser.FieldRefContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        instruction.Method.Definition.MethodBody.OpCode(instruction.OpCode);
        WriteInstructionToken(instruction.Method, MaterializeFieldReference(context));
    }

    internal void EmitMetadataTokenInstruction(IToken opcodeToken, CILParser.MdtokenContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        instruction.Method.Definition.MethodBody.OpCode(instruction.OpCode);
        WriteInstructionToken(instruction.Method, ResolveMetadataToken(context));
    }

    internal void EmitTypeReferenceInstruction(IToken opcodeToken, CILParser.TypeSpecContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        instruction.Method.Definition.MethodBody.OpCode(instruction.OpCode);
        WriteInstructionToken(instruction.Method, ResolveTypeSpecification(context));
    }

    internal void EmitCalliInstruction(IToken opcodeToken, CILParser.CalliSignatureContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        Debug.Assert(instruction.OpCode == ILOpCode.Calli);
        instruction.Method.Definition.MethodBody.OpCode(instruction.OpCode);
        instruction.Method.Definition.MethodBody.Token(
            _entityRegistry.GetOrCreateStandaloneSignature(
                MaterializeCalliSignature(context.Value)).Handle);
    }

    internal void EmitOwnerTokenInstruction(IToken opcodeToken, CILParser.OwnerTypeContext context)
    {
        if (StartInstruction(opcodeToken) is not { } instruction || context.HasSyntaxError)
        {
            return;
        }

        instruction.Method.Definition.MethodBody.OpCode(instruction.OpCode);
        WriteInstructionToken(instruction.Method, MaterializeOwnerType(context));
    }

    private static void WriteInstructionToken(CurrentMethodContext method, EntityRegistry.EntityBase entity)
    {
        if (entity is EntityRegistry.TypeReferenceEntity typeReference)
        {
            typeReference.RecordBlobToWriteResolvedToken(
                method.Definition.MethodBody.CodeBuilder.ReserveBytes(sizeof(int)));
        }
        else if (entity is EntityRegistry.MemberReferenceEntity memberReference)
        {
            memberReference.RecordBlobToWriteResolvedHandle(
                method.Definition.MethodBody.CodeBuilder.ReserveBytes(sizeof(int)));
        }
        else
        {
            method.Definition.MethodBody.Token(entity.Handle);
        }
    }

}