- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
考虑这个典型的方法跟踪代码(为了说明而简化):
type
IMethodTracer = interface
end;
TMethodTracer = class(TInterfacedObject, IMethodTracer)
private
FName: String;
FResultAddr: Pointer;
FResultType: PTypeInfo;
public
constructor Create(
const AName: String;
const AResultAddr: Pointer = nil;
const AResultType: PTypeInfo = nil);
destructor Destroy; override;
end;
constructor TMethodTracer.Create(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo);
begin
inherited Create();
FName := AName;
FResultAddr := AResultAddr;
FResultType := AResultType;
Writeln('Entering ' + FName);
end;
destructor TMethodTracer.Destroy;
var
lSuffix: String;
lResVal: TValue;
begin
lSuffix := '';
if FResultAddr <> nil then
begin
//there's probably a more straight-forward to doing this, without involving TValue:
TValue.Make(FResultAddr, FResultType, lResVal);
lSuffix := ' - Result = ' + lResVal.AsString;
end;
Writeln('Leaving ' + FName + lSuffix);
inherited Destroy;
end;
function TraceMethod(
const AName: String;
const AResultAddr: Pointer;
const AResultType: PTypeInfo): IMethodTracer;
begin
Result := TMethodTracer.Create(AName, AResultAddr, AResultType);
end;
//////
function F1: String;
begin
TraceMethod('F1', @Result, TypeInfo(String));
Writeln('Doing some stuff...');
Result := 'Booyah!';
end;
F1();
这正在按预期工作。输出为:
Entering F1
Doing some stuff...
Leaving F1 - Result = Booyah!
我现在正在寻找一种方法来最大限度地减少调用 TraceMethod()
所需的参数数量,理想情况下允许我完全跳过与 Result
相关的参数。我自己没有汇编程序或堆栈布局的经验,但如果我没有弄错的话,从我看到其他人所做的“魔术”来看,至少隐含魔术 Result
变量的内存地址应该是可以通过某种方式获得,不是吗?也许人们也可以从那里获取其类型信息?
当然,如果甚至可以确定“周围”函数本身的名称,那么就完全不需要将参数传递给 TraceMethod
...
我使用的是Delphi XE2,因此所有最近引入的语言/框架功能都可以使用。
在有人提到它之前:我的实际代码已经使用 CodeSite.EnterMethod
/ExitMethod
而不是 Writeln
调用。我还知道这个简化的示例无法处理复杂类型并且不执行任何错误处理。
最佳答案
你最好的选择就是直接传入@Result
。如果不这样做,则无法保证 Result
甚至有地址。返回简单类型(例如Integer
和Boolean
)的函数将结果放入EAX 寄存器中。如果结果没有理由具有地址,则编译器不会为其分配任何内存。使用表达式@Result
强制编译器为其提供一个地址。
不过,仅知道地址并不能获得返回类型。可能有一种方法可以通过 RTTI 来发现它。这将涉及三个步骤:
从方法名中提取类名。然后你就可以get the RTTI for that type 。这需要方法名称包含明确的类名称(包括单元名称)。
使用list of methods从该类型中找到该方法的 RTTI。由于名称不一定唯一标识一个方法,这将使情况变得复杂。重载将全部显示相同的名称。 (Rruz 在 how to deal with RTTI of overloaded methods 方法的上下文中显示 Invoke
。)此外,从调试信息中获取的方法名称不一定与 RTTI 名称匹配。
您可以循环遍历类的所有方法,搜索 CodeAddress
的方法,而不是尝试匹配名称。属性与调用者的地址匹配。不过,事实证明,确定如何获取调用者的开始地址(而不是返回地址)比我预期的更难找到。
获取 the method's return type并使用 Handle
属性最终获得您想要的 PTypeInfo
值。
关于Delphi 汇编器/RTTI 专家 : Can I obtain the memory address and type info of the implied Result variable in a function?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10819770/
我是一名优秀的程序员,十分优秀!