问题标签 [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.
java - 为什么即使 MethodHandle 正常,我也会在 invokeExact 上得到 WrongMethodTypeException
我正在尝试调用一个调用方法,但有一个我无法解释的错误。我听说 Invoke Exact 方法必须返回,但即使在那时它也不起作用。
在此代码上程序崩溃
这是包含我要调用的方法的类
java - 如何在 ByteBuddy 中安装和使用常量 MethodHandle?
我正在使用ByteBuddy 对常量MethodHandle
s的支持。
我正在尝试(有效地)查找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()
它。MethodHandle
MethodHandle
我的第一个问题是:这是正确的食谱吗?
接下来,我将使用这个“字段设置器”在超类中设置的(愚蠢的)字段MethodHandle
被命名fortyTwo
并且类型为Integer
. 您可能会猜到我想将其值设置为什么。这一切都很好,显然(还)与 ByteBuddy 没有任何关系,但它会的。
一切都编译得很好。
当我运行我的代码时,在我有机会做任何事情之前,即在类加载期间,我得到了ClassFormatError
ByteBuddy 生成的生成子类。该错误抱怨此子类已尝试使用无效签名定义字段(!):
我没有定义这样一个领域。超类当然可以(见上文),并且如前所述,它的类型是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()
.
如果我误诊了,我深表歉意;我仍在学习。
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()
MethodHandle
private static final
invokeExact()
MethodHandle
因此,我的问题的另一种表述方式是:表示 a 的常量形式MethodHandle
是否能够存储其特权?或者是否有一些一次性的方法来“提高”给定MethodHandle
存储为常量的特权?或者一个给定的值被存储为一个常量这一事实是否MethodHandle
会阻止它在任何时候访问除传统可访问的 Java 构造之外的任何东西? 我在相关部分的 JVM 规范中没有看到任何非常明显的内容。
jvm - 如何使用`MethodHandle`模仿`tableswitch`?
上下文:我一直在对使用invokedynamic
和手动生成字节码之间的区别进行基准测试(这是在决定针对 JVM 的编译器是应该发出更详细的“传统”字节码还是仅仅invokedynamic
使用聪明的引导方法进行调用的上下文中)。MethodHandles
在这样做时,将字节码映射到至少同样快的组合器非常简单,除了tableswitch
.
问题:有模仿tableswitch
使用的技巧MethodHandle
吗?我试着用一个跳转表来模仿它:使用一个常量MethodHandle[]
,用 索引到它arrayElementGetter
,然后用 调用找到的句柄MethodHandles.invoker
。然而,当我通过 JMH 运行它时,它最终比原始字节码慢了大约 50%。
下面是生成方法句柄的代码:
这是初始字节码(我试图用一个invokedynamic
电话替换)
java - MethodHandle 强制转换返回类型
我尝试通过方法句柄将方法链接在一起,其中一些来自泛型类型。如果一个函数返回一个泛型类型,我必须为 MethodType 指定 Object.class,但我看不到将它转换回泛型类型参数类型的简单方法。在大多数情况下,这没有问题,因为invoke 似乎会自动转换它们,但我必须创建可以使用invokeExact 运行的mhs。没有简单的方法来使用方法句柄进行转换吗?
我的测试代码:
java - LambdaMetaFactory 装箱/拆箱参数和返回类型
我有以下两种方法:
包括以下两个接口:
这适用于所有类类型,包括用于原始类型的数字包装器,例如Integer
for int
。但是,如果我有一个接受 an 的 setterint
或一个返回 an 的 getter ìnt
,它会尝试传递/返回 Number-Wrapper,从而导致异常。
无需使用其他方法即可将其装箱/拆箱的正确方法是什么。这里的原因是保持 API 干净且易于使用。我愿意为这里的拳击/拆箱带来小小的性能损失。
java - 在 Java 中使用其他常量的常量
在我的课堂上,我需要一个以类为参数的 SLF4J Logger,以及一个简单的类名。logger 和 CLASS_NAME 常量都使用 MethodHandles.lookup()。我想知道拥有这样的东西是否更有意义/更有效:
或者只使用 MethodHandles.lookup() 两次:
java - LambdaMetaFactory 和私有方法
我想使用 LambdaMetaFactory 来有效地访问私有方法。
我知道这不是安全违规,因为以下代码有效:
但是,我尝试使用 LambdaMetaFactory 失败了:
显然m.setAccessible(true)
这里还不够。我尝试更改lookup
为MethodHandles.privateLookupIn(Foo.class, MethodHandles.lookup())
,这在我的玩具示例中确实解决了它......但在我的实际应用程序中没有,它会生成一个IllegalAccessException
说法,我的班级“没有完全特权访问”。我一直无法发现为什么我的应用程序“没有完全权限访问”,或者如何修复它。
我发现几乎可以工作的唯一一件事是:
只要我在VM选项中有我可以做到TRUSTED
的,它就允许我使用它。这会产生一个代替(说它找不到),这似乎很有希望......但我仍然无法弄清楚如何让它完全工作,只是产生这个错误而不是其他错误。lookup
--illegal-access=permit
NoClassDefFoundError
Foo
这里发生了什么,我该如何bar
访问LambdaMetaFactory
?