问题标签 [methodhandle]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
106 浏览

java - 为什么即使 MethodHandle 正常,我也会在 invokeExact 上得到 WrongMethodTypeException

我正在尝试调用一个调用方法,但有一个我无法解释的错误。我听说 Invoke Exact 方法必须返回,但即使在那时它也不起作用。

在此代码上程序崩溃

这是包含我要调用的方法的类

0 投票
1 回答
100 浏览

java - 如何在 ByteBuddy 中安装和使用常量 MethodHandle?

我正在使用ByteBuddy 对常量MethodHandles的支持。

我正在尝试(有效地)查找MethodHandle一个类,然后从 ByteBuddy 生成的子类中使用它。

(我知道我可以使用静态MethodHandle字段和类型初始化器来做到这一点,但我想尝试使用这种常量支持。)

我有一个FieldDescription.Token代表头等舱的字段和TypeDescription代表头等舱的字段。从这些我可以得到FieldDescription.InDefinedShape这样的:new FieldDescription.Latent(typeDescription, fieldDescriptionToken)。从那我可以得到一个这样JavaConstant.MethodHandle的:JavaConstant.MethodHandle.ofSetter(fieldDescriptionLatent)。这工作正常。

然后我这样做:

通过这样做,我使用了on带 a 的重载,StackManipulation在这种情况下,JavaConstantValue它包装了 a JavaConstant,它是 的超类JavaConstant.MethodHandle。如您所见,我试图在希望将其存储为常量的地方调用invokeExact()它。MethodHandleMethodHandle

我的第一个问题是:这是正确的食谱吗?

接下来,我将使用这个“字段设置器”在超类中设置的(愚蠢的)字段MethodHandle被命名fortyTwo并且类型为Integer. 您可能会猜到我想将其值设置为什么。这一切都很好,显然(还)与 ByteBuddy 没有任何关系,但它会的。

一切都编译得很好。

当我运行我的代码时,在我有机会做任何事情之前,即在类加载期间,我得到了ClassFormatErrorByteBuddy 生成的生成子类。该错误抱怨此子类已尝试使用无效签名定义字段(!):

我没有定义这样一个领域。超类当然可以(见上文),并且如前所述,它的类型是java.lang.Integer. 字段的访问级别无关紧要。

我已经查看了TypeDescription包含的DynamicType.Unloaded(显然是在加载之前)并且没有fieldTokens,即 ByteBuddy 确实没有尝试在子类中实际定义一个字段。看来我正在使用的配方中的某些东西使它看起来像是……呃,验证者?我猜?真的不知道?由常量表示MethodHandle的 试图操纵子类上的字段,当然不存在这样的字段(我猜“ V”是字节码签名,void可能是默认值)。

所以我的最后一个问题是:为什么这种情况下使用字段设置MethodHandle常量会使ByteBuddy看起来像是试图在子类中定义一个字段? 就好像在定义或存储常量时删除了该字段的所属类型。

我认为这一切都与 ByteBuddy 如何支持常量有关MethodHandle。难道是 ByteBuddyMethodHandle在常量池中没有正确表示这种常量?或者这是(也许只是字段设置)本身的某种固有问题MethodHandle

我确实注意到在有问题的 ByteBuddy 代码中有一个引用(间接地)void。这对我来说有一定的意义:如果你要合成一个设置字段的方法句柄,那么它的返回类型将是void. 不过,我想知道(天真地)这是否实际上是在此处传递的正确类型,或者这是否可能靠近问题所在。

另一方面,似乎为了解析(在这种情况下)是“字段设置器”的方法句柄常量,或者类型 1 到 4(包括)的方法句柄,解析必须根据 JVM 的规则进行场分辨率。这些规则似乎(对于这个天真的读者)表明使用的描述符应该是字段的描述符。我认为,相反,ByteBuddy正在使用合成方法句柄的描述符,在这种情况下将是V(或void)。我的幼稚阅读使我认为至少在“字段设置器”的情况下,返回值getDescriptor()应该是返回值中存在的唯一参数的类型getParameterTypes().

如果我误诊了,我深表歉意;我仍在学习。

0 投票
1 回答
339 浏览

java - 可以使用 MethodHandle 常量绕过访问控制吗?

我正在使用 JDK 15。(我正在使用 ByteBuddy 1.10.16 生成一些类,但我认为它在这里几乎无关紧要,除了作为背景信息。)

在其中一个生成的类中,我调用invokeExact()了一个我设法存储在生成的类中的MethodHandle 常量。它是通过 获得的“字段设置器” MethodHandles.Lookup#findSetter

(在下文中,我知道该MethodHandles.privateLookupIn()方法。)

我注意到MethodHandle当它代表一个字段时,有问题的“字段设置器”会失败private。在大多数层面上,这并不让我感到惊讶:直接MethodHandle是,嗯,直接:虽然我不假装对所有这些东西的内部了解很多,但在我看来,它肯定只是包装了一些没有的低级字节码访问检查。

但是鉴于privateLookupIn()which 的存在表明在某些情况下可以绕过访问检查,是否有一条路径可以让我MethodHandle从 A 类中“收获”一个可以读取private字段的“字段设置器”,然后将其作为常量存储在另一个B类这样invokeExact()就可以成功?

我相信我过去做过类似的事情(必须检查)涉及private方法,但在那些情况下,我没有使用MethodHandle 常量,即我在使用和存储结果时获取MethodHandle类初始化时间并将结果存储在一个字段中,然后调用该字段的内容。如果我必须继续走这条路,我会的,但这里的常量似乎很有吸引力,如果可以的话,使用它们会很好。<clinit>privateLookupIn()MethodHandleprivate static finalinvokeExact()MethodHandle

因此,我的问题的另一种表述方式是:表示 a 的常量形式MethodHandle是否能够存储其特权?或者是否有一些一次性的方法来“提高”给定MethodHandle存储为常量的特权?或者一个给定的值被存储为一个常量这一事实是否MethodHandle会阻止它在任何时候访问除传统可访问的 Java 构造之外的任何东西? 我在相关部分的 JVM 规范中没有看到任何非常明显的内容。

0 投票
3 回答
175 浏览

jvm - 如何使用`MethodHandle`模仿`tableswitch`?

上下文:我一直在对使用invokedynamic和手动生成字节码之间的区别进行基准测试(这是在决定针对 JVM 的编译器是应该发出更详细的“传统”字节码还是仅仅invokedynamic使用聪明的引导方法进行调用的上下文中)。MethodHandles在这样做时,将字节码映射到至少同样快的组合器非常简单,除了tableswitch.

问题:有模仿tableswitch使用的技巧MethodHandle吗?我试着用一个跳转表来模仿它:使用一个常量MethodHandle[],用 索引到它arrayElementGetter,然后用 调用找到的句柄MethodHandles.invoker。然而,当我通过 JMH 运行它时,它最终比原始字节码慢了大约 50%。

下面是生成方法句柄的代码:

这是初始字节码(我试图用一个invokedynamic电话替换)

0 投票
1 回答
83 浏览

java - MethodHandle 强制转换返回类型

我尝试通过方法句柄将方法链接在一起,其中一些来自泛型类型。如果一个函数返回一个泛型类型,我必须为 MethodType 指定 Object.class,但我看不到将它转换回泛型类型参数类型的简单方法。在大多数情况下,这没有问题,因为invoke 似乎会自动转换它们,但我必须创建可以使用invokeExact 运行的mhs。没有简单的方法来使用方法句柄进行转换吗?

我的测试代码:

0 投票
2 回答
66 浏览

java - LambdaMetaFactory 装箱/拆箱参数和返回类型

我有以下两种方法:

包括以下两个接口:

这适用于所有类类型,包括用于原始类型的数字包装器,例如Integerfor int。但是,如果我有一个接受 an 的 setterint或一个返回 an 的 getter ìnt,它会尝试传递/返回 Number-Wrapper,从而导致异常。

无需使用其他方法即可将其装箱/拆箱的正确方法是什么。这里的原因是保持 API 干净且易于使用。我愿意为这里的拳击/拆箱带来小小的性能损失。

0 投票
1 回答
69 浏览

java - 在 Java 中使用其他常量的常量

在我的课堂上,我需要一个以类为参数的 SLF4J Logger,以及一个简单的类名。logger 和 CLASS_NAME 常量都使用 MethodHandles.lookup()。我想知道拥有这样的东西是否更有意义/更有效:

或者只使用 MethodHandles.lookup() 两次:

0 投票
1 回答
104 浏览

java - LambdaMetaFactory 和私有方法

我想使用 LambdaMetaFactory 来有效地访问私有方法。

我知道这不是安全违规,因为以下代码有效:

但是,我尝试使用 LambdaMetaFactory 失败了:

显然m.setAccessible(true)这里还不够。我尝试更改lookupMethodHandles.privateLookupIn(Foo.class, MethodHandles.lookup()),这在我的玩具示例中确实解决了它......但在我的实际应用程序中没有,它会生成一个IllegalAccessException说法,我的班级“没有完全特权访问”。我一直无法发现为什么我的应用程序“没有完全权限访问”,或者如何修复它。

我发现几乎可以工作的唯一一件事是:

只要我在VM选项中有我可以做到TRUSTED的,它就允许我使用它。这会产生一个代替(说它找不到),这似乎很有希望......但我仍然无法弄清楚如何让它完全工作,只是产生这个错误而不是其他错误。lookup--illegal-access=permitNoClassDefFoundErrorFoo

这里发生了什么,我该如何bar访问LambdaMetaFactory