谁在何时调用describeConstable()? [英] Who calls describeConstable(), and when?
问题描述
I have stumbled somewhat happily into Constable
and the like in JDK 15. I mostly understand.
在研究了所有编译器理论并且甚至理解了一点点之后,我仍然发现这个问题:谁调用了 Constable
的 describeConstable()
方法,何时?? Brian的演示似乎暗示了它是在编译时以某种方式访问的.对于此类事情幼稚,我期望它出现在
After frolicking through all the compiler theory and even understanding a little bit of it, I find I still have this question: Who calls a Constable
's describeConstable()
method, and when? Brian's presentation seemed to imply it is somehow accessed at compile time. Being naïve about such things, I was expecting it to show up in the usage page under jdk.compiler
or something. Instead, the only consumption seems to be in the jdk.incubator.foreign
package. (Obviously I understand it may be used by some private machinery somewhere that isn't exposed by the usage page; hence my question.)
我将 Thread.dumpStack()
放在实现 Constable
并返回 Optional.ofNullable(null)
只是为了查看会发生什么,而…在编译或运行时什么都没有发生.
I placed a Thread.dumpStack()
in a describeConstable()
implementation of a dumb class that implements Constable
and that returns Optional.ofNullable(null)
just to see what would happen and…nothing happened at compile- or runtime.
(我确实知道,直到JDK 12之前,如果您想编写动态常量,就必须使用ASM或ByteBuddy或类似的东西.但是,我天真地看起来,就像 Constable
一样,允许您的用户类插入" Java编译器并允许 it 为您进行常量编写.我也知道 java.lang.constant
主要是为编译器作者准备的,但是在我看来 Constable
有点例外,最后,我显然明白 I 可以随时调用此方法我希望,但这显然不是它的目的.)
(I do know that until JDK 12 if you wanted to write dynamic constants you had to use ASM or ByteBuddy or something similar. To my naïve eyes it looks, though, like Constable
is there to allow your user class to "plug into" the Java compiler and allow it to do the constant writing for you. I am also aware that the classes and methods in java.lang.constant
are primarily intended for compiler writers, but Constable
seemed to me to be a bit of an exception. Finally, I obviously understand that I can call this method any time I wish, but that's clearly not what it's intended for.)
编辑:非常感谢以下一些非常有帮助和耐心的回答和评论,我想我已经开始了解它了(我不是一个编译器人员,因此点应该很明显).虽然我知道一旦 X实例实现Constable
存在,那么 ContantDesc
就会从其 describeConstable()
返回必须由其他常量描述符组成(本身),而据我了解,常量工厂"(例如 ClassDesc#of()
等)可能会在编译时调用,并且显然必须仅接受其他常量作为它们可能需要的任何参数,我仍然不清楚如何任意 X实现Constable
首先在编译过程中实例化,同时…正在被编译(!),使得 describeConstable()可以在编译时对其进行调用.
EDIT: Thanks (very much) to some of the extremely helpful and patient answers and comments below, I think I'm starting to get it (I'm not a compiler guy which by this point should be quite obvious). While I understand that once an instance of X implements Constable
exists then the ContantDesc
it returns from its describeConstable()
must be made (itself) of other constant descriptors, and while I understand that "constant factories" (such as ClassDesc#of()
and so on) may be called at compile time and obviously must accept only other constants as any arguments they might require, I'm still not clear on how an arbitrary X implements Constable
is instantiated during compilation in the first place while…it is being compiled (!) such that describeConstable()
can be called on it at compile time.
请牢记这个问题的答案可能是我在总体上缺少关于编译器的基本知识,或者是它们在静态分析过程中遇到的麻烦.我只是看到一个实例方法( describeConstable()
),该实例方法需要在对象的实例( X实现Constable
)上调用,并具有对象有人必须调用其构造函数.我不清楚Java编译器如何知道如何使用其任意的,可能是多参数的构造函数构造 X实现Constable
,以便随后可以在其上调用 describeConstable()
它.
Please kindly bear in mind the answer to this question may be something rudimentary that I'm missing about compilers in general, or the sorts of hijinks they get up to during static analysis. I just see an instance method (describeConstable()
) that needs to be invoked on an instance of an object (X implements Constable
) and in order to have an instance of an object someone has to call its constructor. It's unclear to me how the Java compiler could know how to construct my X implements Constable
with its arbitrary, possibly multi-argument constructor so that it could then call describeConstable()
on it.
推荐答案
到目前为止,我将说出我的理解和了解.这确实是一个有趣的功能.
I will say what I understood and know, so far. It is indeed an interesting feature.
谁调用了Constable的describeConstable()
Who calls a Constable's describeConstable()
javac
将.
什么时候?
首次调用/需要时.
更详细的说明.您知道lambda是如何编译的吗?如果没有,这是其中的简短介绍(稍后会有所帮助):
A more detailed explanation. Do you know how lambdas are compiled? If not, here is the very short intro in that (it will help a lot later):
Runnable r = () -> {System.out.println("easy, peasy");};
r.run();
如果您查看字节码,将会有一个 invokedynamic
调用:
if you look at the bytecode, there is going to be an invokedynamic
call:
invokedynamic #7, 0 // InvokeDynamic #0:run:()Ljava/lang/Runnable;
依次将其称为引导程序".方法:
this, in turn, will call a "bootstrap" method:
BootstrapMethods:
0: #39 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
-
引导方法的名称是:
LambdaMetafactory :: metafactory
.作为输入,它需要一个
Lookup
(由JVM提供)As input, it takes a
Lookup
(provided by the JVM)除其他外,
javac
提供了MethodType
(它描述了方法的返回类型和方法参数类型,在本例中为从
)Runnable
运行Among other things,
javac
provides aMethodType
(it describes the return type and method argument types of the method, in this case it isrun
fromRunnable
)它将返回一个
CallSite
(在这种情况下,它实际上是一个ConstantCallSite
).It will return a
CallSite
(in this case it is actually aConstantCallSite
).因此,用非常简单的话语(很可能有点错误),
invokedynamic
将调用绑定到ConstantCallSite
,该调用在内部将调用委派给实现具有您提供的run
方法的Runnable
(内部将其委托给定义lambda的"de-sugared"私有方法).这种情况仅发生一次,在第一次调用时,所有后续调用都不会经历这种痛苦.我以其他方式(例如此处)提供了更多详细信息.So, in rather very simple words (and most probably a bit wrong),
invokedynamic
binds the invocation to aConstantCallSite
, that internally delegates the call to an implementation ofRunnable
with arun
method that you have provided (internally it delegates to a "de-sugared" private method of where the lambda is defined). This happens only once, at the first invocation, all subsequent calls don't go through this pain. Somehow more details I provided in other answers, like here.相同的机制将用于动态常量(但必须使用
ldc
而不是invokedynamic
).机器"指的是机器".是 invokedynamic .The same mechanism will be used for dynamic constants (but it has to use
ldc
and notinvokedynamic
). The "machinery" was already provided in jdk-11. Notice the name of the class :ConstantBootstraps
, well we know why "bootstrap" and we know why "Constant". If you look at the arguments, it surely starts to make some sense, as it really resembles theinvokedynamic
for lambdas.现在您知道为什么需要
Constable/ConstantDesc
:这样bootstrap方法才能调用正确的实现.在上述情况下,javac
"knew"(推断/推断/等),lambda实际上是一个Runnable
.就恒定动态"而言,该类将实现Constable
的事实将隐含此信息.这将是配方".如何建立你的常数;至少在我的理解中.Now you know why
Constable/ConstantDesc
is needed: so that the bootstrap method calls the proper implementation. In the case above,javac
"knew" (inferred/deducted/etc) that lambda is really aRunnable
. In the case of "constant dynamic" this information will be implied by the fact that the class implementsConstable
. This is going to be the "recipe" of how to build your constant; at least in my understanding.请注意,其他人已经在
JVM
:Scala的lazy
上做到了这一点(只是想法).但是他们只是简单地实现了双重检查锁定,有时您需要为volatile
读操作付费.当然,在JVM
上实现此操作将是有益的;这是非常有用的.在何种程度上以及确切地 如何被人们所知;,因为尚未在javac
中实现,至少在主流jdk中尚未实现.可能是这样的:Just note that others have already done this (just the idea) on the
JVM
: Scala'slazy
. But they simply implemented doubled check locking behind the curtains and you pay for thatvolatile
read, at times... Of course implementing this on theJVM
will be beneficial; to what degree and exactly how is yet to be known; as this is not implemented in thejavac
yet, at least in the mainstream jdk. May be it will be something along the lines of:// made-up syntax __@lazy__ private static final MyObject obj = null;
,它将最终委托给
Constable :: describeConstable
或可能是:and this will eventually delegate to
Constable::describeConstable
or may be :__@lazy(provider="myProvider")__ private static final MyObject obj = null; private MyObject myProvider(){....}
但是我敢打赌,比我聪明的人会想到我这里没有提到的有关如何使用它的想法.当这种情况发生时(我知道会发生),我将需要更新此帖子.
But I bet that people that are much smarter than me will come up with ideas on how to use this that I have not mentioned here. When that happens (and I know it will), I will need to update this post.
这篇关于谁在何时调用describeConstable()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!