【问题标题】:Update method attributes during JIT?在 JIT 期间更新方法属性?
【发布时间】:2016-09-12 19:56:31
【问题描述】:

我正在寻找在不创建新方法定义的情况下更新现有方法的属性的方法。

这是我目前的代码:

HRESULT STDMETHODCALLTYPE Weaver::JITCompilationStarted( 
        FunctionID functionId, BOOL fIsSafeToBlock) 
{
    HRESULT status = S_OK;
    MethodInfo methodInfo = GetMethodInfo(functionId);
    if (!IsMdVirtual(methodInfo.Attributes) && !IsMdStatic(methodInfo.Attributes)
        && !IsMdPrivate(methodInfo.Attributes) && !IsMdSpecialName(methodInfo.Attributes))
    {
        CComPtr<IMetaDataEmit> metaDataEmit;
        status = m_profilerInfo3->GetModuleMetaData(methodInfo.Module,
            ofRead | ofWrite, IID_IMetaDataEmit, (IUnknown**)&metaDataEmit);

        // TODO: get module metadata and update method attributes to:  methodInfo.Attributes | mdVirtual
        status = metaDataEmit->ApplyEditAndContinue(metaDataEmit /*?*/);
    }

    return status;
}

如您所见,我缺少检索函数元数据和内联修改的方法。这个方法的MSDN帮助很薄,找不到ApplyEditAndContinue的使用例子。

【问题讨论】:

  • 我投票要求对任何(或至少是第一个)反对票进行强制评论...省去了我们这些菜鸟们试图找出原因的麻烦。
  • JITCompilationStarted 更改属性为时已晚,可以在调用或 JIT 方法之前检查属性。元数据只能通过ModuleLoadFinished 回调进行修改。为什么要使用 ApplyEditAndContinue 添加属性而不是 DefineCustomAttribute?你到底想达到什么目的。 (不,我不是投反对票的人)
  • @BrianReichle,感谢您的提醒,基本上我想将常规类方法更改为虚拟方法,以便在单元测试期间可以模拟它们。这意味着我需要更改现有属性。基本上非虚拟方法是难以对我们的遗留代码进行单元测试的最常见原因。我想避免修改磁盘上的程序集(例如通过Fody'sVirtuosity
  • 啊,那也许你用SetMethodProps在dwMethodFlags中设置mdVirtual

标签: c++ .net jit cil


【解决方案1】:

在 cmets 中接受 Brian 的回答:

JITCompilationStarted 更改属性为时已晚,可以在调用或 JIT 方法之前检查属性。元数据只能从 ModuleLoadFinished 回调中修改。

翻译成代码如下(大大减少):

HRESULT Weaver::ModuleLoadFinished(ModuleID moduleId, HRESULT hrStatus)
{
    HRESULT status = S_OK;
    // Filter module

    // Enum & filter types in module
        // Enum & filter methods in type
            DWORD attributes, implFlags; ULONG codeRva;
            status = pMetaImport->GetMethodProps(tkMethod, NULL, NULL, NULL, NULL, &attributes, NULL, NULL, &codeRva, &implFlags);
            status = pMetaEmit->SetMethodProps(tkMethod, attributes | mdVirtual, codeRva, implFlags);

    return status;
}

这将允许在 .NET 中模拟非虚拟成员,例如:

public class Foo {
    public string Hello() => "test";
}

// ...
var fake = A.Fake<Foo>();
A.CallTo(() => fake.Hello()).Returns("faked");
Assert.Equals("faked", fake.Hello());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-23
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 2012-07-28
    • 2019-03-08
    • 1970-01-01
    相关资源
    最近更新 更多