Re: null checks vs. class resolution, and translation strategy for casts
> De: "Brian Goetz" > À: "Remi Forax" > Cc: "Frederic Parain" , "valhalla-spec-experts" > > Envoyé: Mardi 14 Avril 2020 15:56:06 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts >> How it is better than a new opcode "unbox" with exactly the same semantics ? > For one, an “unbox” opcode assumes that the VM understands the fictitious > relationship between the val and ref projections. But these are language > fictions; the VM sees only classes related by extension and sealing. No, your assuming that the semantics of unbox implies that the verifier will check for 'sealness', this is not the case, unbox <==> checkcast restricted to inline type (so with eager loading). You're free to unbox an Object to a Point, by example. Rémi
Re: null checks vs. class resolution, and translation strategy for casts
Then it’s a terrible and confusing name for an opcode :) > On Apr 14, 2020, at 10:08 AM, fo...@univ-mlv.fr wrote: > > > > De: "Brian Goetz" > À: "Remi Forax" > Cc: "Frederic Parain" , "valhalla-spec-experts" > > Envoyé: Mardi 14 Avril 2020 15:56:06 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts > > How it is better than a new opcode "unbox" with exactly the same semantics ? > > For one, an “unbox” opcode assumes that the VM understands the fictitious > relationship between the val and ref projections. But these are language > fictions; the VM sees only classes related by extension and sealing. > > No, > your assuming that the semantics of unbox implies that the verifier will > check for 'sealness', this is not the case, unbox <==> checkcast restricted > to inline type (so with eager loading). > > You're free to unbox an Object to a Point, by example. > > Rémi >
Re: null checks vs. class resolution, and translation strategy for casts
> > How it is better than a new opcode "unbox" with exactly the same semantics ? For one, an “unbox” opcode assumes that the VM understands the fictitious relationship between the val and ref projections. But these are language fictions; the VM sees only classes related by extension and sealing.
Re: null checks vs. class resolution, and translation strategy for casts
- Mail original - > De: "Frederic Parain" > À: "valhalla-spec-experts" > Envoyé: Lundi 13 Avril 2020 15:24:18 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts >> On Apr 8, 2020, at 14:43, John Rose wrote: >> >> I have a proposal for a translation strategy: >> >> 1. Translate casts to inline classes differently from “classic” >> casts. Add an extra step of null hostility. For very low-level >> reasons, I suggest using “ldc X” followed by Class::cast. >> >> Generally speaking, it’s a reasonable move to use reflective >> API points (like Class::cast) on constant metadata (like X.class) >> to implement language semantics. > > > There’s an alternative way to implement this: > > Casts to inline classes C can be translated to >#ldc C >#checkcast C > > with this new definition of checkast: > > "If objectref is null then: > - if type C has not been loaded yet, the operand stack is unchanged, > - if type C has already been loaded: > - if type C is not an inline type, the operand stack is unchanged > - otherwise the checkcast instruction throws a ClassCastException so it's more: #ldc C #checkcast 0<--- > > Otherwise, the named class, array, or interface type is resolved (§5.4.3.1). > If > objectref can be cast to the resolved class, array, or interface type, the > operand stack is unchanged; otherwise, the checkcast instruction throws a > ClassCastException." > > > This new definition doesn’t change the behavior of checkcast for old class > files, > and doesn’t change the behavior nor the translation strategy for casts to > non-inline types. > > In new class files, javac will use the ldc/checkcast sequence whenever a cast > to > an > inline type is required. Note that in many cases, type C would have already be > loaded > before ldc is executed (by pre-loading or eager loading). > > With migrated types, an old class file can still have a standalone checkcast > (without ldc) > referencing a type which is now an inline type, causing the null reference to > pass the checkcast > successfully. This is not a new issue. The same situation can be created by > reading a field > declared as ‘LC;’, getfield would simply read the field (only possible value > is > null) and push > it on the stack without checking if C is an inline type or not. This ’null’ > reference to an > invalid type can only be used by code that have the wrong information about > type > C, and this > is in fact the only possible value for this type (any attempt to create a real > instance of > ‘LC;’ would fail). In order to use this reference as a legitimate reference to > the real > type ‘QC;’, another checkcast, using the proper sequence above, would be > required and would > throw an exception. > > Ill formed or malicious class files could be aware that C is an inline type, > but > use a > single checkcast instruction (without preceding ldc) anyway. This is part of a > bigger > problem that has not been discussed yet: L/Q consistency inside a class file. > the SoV > document stipules that the value projection only exists in the Q-form and the > reference > projection only exists in the L-form. As of today, there’s no verification of > such kind > performed on class files. Nothing prevent a class file from declaring a field > of > type > ‘LC;’ and another of type ‘QC;’, and the same remark applies to method > arguments. > > > Going back to the modified specification of checkcast, new tests are easy to > implement > in the interpreter, and can easily be optimized by JIT compilers (most types > would be > loaded at compilation time), and there’s no bootstrapping issues. > How it is better than a new opcode "unbox" with exactly the same semantics ? > Fred Rémi
Re: null checks vs. class resolution, and translation strategy for casts
There’s an alternative way to implement this: Casts to inline classes C can be translated to #ldc C #checkcast C And, the ldc can be hoisted statically if desired, to the top of the method, or even into a static initializer.
Re: null checks vs. class resolution, and translation strategy for casts
> On Apr 8, 2020, at 14:43, John Rose wrote: > > I have a proposal for a translation strategy: > > 1. Translate casts to inline classes differently from “classic” > casts. Add an extra step of null hostility. For very low-level > reasons, I suggest using “ldc X” followed by Class::cast. > > Generally speaking, it’s a reasonable move to use reflective > API points (like Class::cast) on constant metadata (like X.class) > to implement language semantics. There’s an alternative way to implement this: Casts to inline classes C can be translated to #ldc C #checkcast C with this new definition of checkast: "If objectref is null then: - if type C has not been loaded yet, the operand stack is unchanged, - if type C has already been loaded: - if type C is not an inline type, the operand stack is unchanged - otherwise the checkcast instruction throws a ClassCastException Otherwise, the named class, array, or interface type is resolved (§5.4.3.1). If objectref can be cast to the resolved class, array, or interface type, the operand stack is unchanged; otherwise, the checkcast instruction throws a ClassCastException." This new definition doesn’t change the behavior of checkcast for old class files, and doesn’t change the behavior nor the translation strategy for casts to non-inline types. In new class files, javac will use the ldc/checkcast sequence whenever a cast to an inline type is required. Note that in many cases, type C would have already be loaded before ldc is executed (by pre-loading or eager loading). With migrated types, an old class file can still have a standalone checkcast (without ldc) referencing a type which is now an inline type, causing the null reference to pass the checkcast successfully. This is not a new issue. The same situation can be created by reading a field declared as ‘LC;’, getfield would simply read the field (only possible value is null) and push it on the stack without checking if C is an inline type or not. This ’null’ reference to an invalid type can only be used by code that have the wrong information about type C, and this is in fact the only possible value for this type (any attempt to create a real instance of ‘LC;’ would fail). In order to use this reference as a legitimate reference to the real type ‘QC;’, another checkcast, using the proper sequence above, would be required and would throw an exception. Ill formed or malicious class files could be aware that C is an inline type, but use a single checkcast instruction (without preceding ldc) anyway. This is part of a bigger problem that has not been discussed yet: L/Q consistency inside a class file. the SoV document stipules that the value projection only exists in the Q-form and the reference projection only exists in the L-form. As of today, there’s no verification of such kind performed on class files. Nothing prevent a class file from declaring a field of type ‘LC;’ and another of type ‘QC;’, and the same remark applies to method arguments. Going back to the modified specification of checkcast, new tests are easy to implement in the interpreter, and can easily be optimized by JIT compilers (most types would be loaded at compilation time), and there’s no bootstrapping issues. Fred
Re: null checks vs. class resolution, and translation strategy for casts
> De: "John Rose" > À: "Remi Forax" > Cc: "Brian Goetz" , "valhalla-spec-experts" > > Envoyé: Samedi 11 Avril 2020 07:43:28 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts > On Apr 10, 2020, at 4:19 AM, [ mailto:fo...@univ-mlv.fr | fo...@univ-mlv.fr ] > wrote: >>> So, here’s a recommendation: Use indy, and use a clunkier >>> fallback in the same places that today use a clunkier fallback >>> for string concatenation. And, record a line item of technical >>> debt that we should further explore indy intrinsics, after we >>> figure out what javac intrinsics look like. >> What is not clear to me is that javac can replace unbox by a nullcheck, for >> the >> VM, the input is an interface and the output is an inline type, given that >> interfaces are not checked until runtime, how the VM can validate that only a >> nullcheck is enough ? > It can’t; that’s why I’m saying javac needs to ask for a null check, > *and* somehow affirm the inline type (subtype of interface). > This is two bytecodes, invokestatic Objects.requireNN, plus > checkcast C. Ok, >> Also it's still not clear to me what indy provide in this case. > It provides both of the above effects in one bytecode. The bytecode, > in turn, can expand to some internal JVM intrinsic which the runtime > will optimize better than a back-to-back combo of the two standard > instructions. That intrinsic never has to be admitted to by any spec. >> So i still think that doing a checkcast (reusing checkcast being a trick to >> avoid to introduce a new bytecode) or having a special unbox opcode is a >> better >> idea. > Changing opcode behaviors and/or adding new opcodes is always > more expensive than appealing to indy, even if we have to add secret > optimizations to indy. Specs are almost always harder to change than > optimizations. Why do we have the new opcodes defaultvalue and withfield in that case ? In both case, the semantics "new inline type" and "unbox inline type" can be express with an indy, but for the former we have chosen to go with 2 new bytecodes and for the later you want to use indy, that doesn't seem logical. I understand why you want to use indy but from my armchair it seems like paying the cost upfront (with a new bytecode) or later (when optimizing). Indy is good when the linking is complex, for lambdas when you need to create a proxy class out of thin air, for the string concatenation or for the pattern matching because you have a lot of code shapes to link together. Indy has three major drawbacks, calling the BSM is slow, it's only fully inlined by c2 and you can not use it before it has been bootstraped. Those issues are all severe in our case, i don't see how we can use an inline type to express the entry (the pair of K,V) of a HashMap without being stopped by these issues. I heard you about the cost, but here indy is not the silver bullet, it's a shiny tool with its own weaknesses. And yes, adding a new opcode has a more upfront cost. > — John Rémi
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 10, 2020, at 4:19 AM, fo...@univ-mlv.fr wrote: > >> So, here’s a recommendation: Use indy, and use a clunkier >> fallback in the same places that today use a clunkier fallback >> for string concatenation. And, record a line item of technical >> debt that we should further explore indy intrinsics, after we >> figure out what javac intrinsics look like. > > What is not clear to me is that javac can replace unbox by a nullcheck, for > the VM, the input is an interface and the output is an inline type, given > that interfaces are not checked until runtime, how the VM can validate that > only a nullcheck is enough ? It can’t; that’s why I’m saying javac needs to ask for a null check, *and* somehow affirm the inline type (subtype of interface). This is two bytecodes, invokestatic Objects.requireNN, plus checkcast C. > Also it's still not clear to me what indy provide in this case. It provides both of the above effects in one bytecode. The bytecode, in turn, can expand to some internal JVM intrinsic which the runtime will optimize better than a back-to-back combo of the two standard instructions. That intrinsic never has to be admitted to by any spec. > So i still think that doing a checkcast (reusing checkcast being a trick to > avoid to introduce a new bytecode) or having a special unbox opcode is a > better idea. Changing opcode behaviors and/or adding new opcodes is always more expensive than appealing to indy, even if we have to add secret optimizations to indy. Specs are almost always harder to change than optimizations. — John
Re: null checks vs. class resolution, and translation strategy for casts
- Mail original - > De: "John Rose" > À: "Remi Forax" > Cc: "Brian Goetz" , "valhalla-spec-experts" > > Envoyé: Jeudi 9 Avril 2020 23:56:45 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts > On Apr 9, 2020, at 2:31 PM, fo...@univ-mlv.fr wrote: >> >> yes, indy is a way to create any new bytecode, but it also has some >> restrictions, >> the major one being that you can not using it before it has been >> bootstrapped. > > Good point; we found that with string concatenation, didn’t we? > If we use indy for this, we’ll run into similar bootstrapping issues. Replacing an inner class by a lambda when calling AccessController.doPrivileged early in the boot process was my first encounter with this issue. > > Which reminds me that Brian has been pondering javac intrinsics > for some time, as a way of replacing method calls that would > ordinarily be linked and run the normal way, with preferable > alternative implementations. This game could also be played > (very carefully) with BSMs. That (like javac intrinsics) would > sidestep the usual bootstrapping orders. javac intrinsics doesn't work well because of profile pollution, by example with String.valueOf(), if the format is a constant, you can transform the format (if it is non Locale sensitive) to a string concatenation, but there is no way to express "if it's a constant" at indy level. Either you capture the format string and hope you will see the same, here you have a profile pollution issue or you have a magic combinator that say if it's constant use this method handle and not the other one but in that case, the method handle called if the argument is a constant has never been called and so has no profile further down. > > So, here’s a recommendation: Use indy, and use a clunkier > fallback in the same places that today use a clunkier fallback > for string concatenation. And, record a line item of technical > debt that we should further explore indy intrinsics, after we > figure out what javac intrinsics look like. What is not clear to me is that javac can replace unbox by a nullcheck, for the VM, the input is an interface and the output is an inline type, given that interfaces are not checked until runtime, how the VM can validate that only a nullcheck is enough ? Also it's still not clear to me what indy provide in this case. So i still think that doing a checkcast (reusing checkcast being a trick to avoid to introduce a new bytecode) or having a special unbox opcode is a better idea. > > — John Rémi
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 2:31 PM, fo...@univ-mlv.fr wrote: > > yes, indy is a way to create any new bytecode, but it also has some > restrictions, > the major one being that you can not using it before it has been bootstrapped. Good point; we found that with string concatenation, didn’t we? If we use indy for this, we’ll run into similar bootstrapping issues. Which reminds me that Brian has been pondering javac intrinsics for some time, as a way of replacing method calls that would ordinarily be linked and run the normal way, with preferable alternative implementations. This game could also be played (very carefully) with BSMs. That (like javac intrinsics) would sidestep the usual bootstrapping orders. So, here’s a recommendation: Use indy, and use a clunkier fallback in the same places that today use a clunkier fallback for string concatenation. And, record a line item of technical debt that we should further explore indy intrinsics, after we figure out what javac intrinsics look like. — John
Re: null checks vs. class resolution, and translation strategy for casts
> De: "John Rose" > À: "Remi Forax" > Cc: "Brian Goetz" , "valhalla-spec-experts" > > Envoyé: Jeudi 9 Avril 2020 23:07:10 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts > On Apr 9, 2020, at 1:58 PM, Remi Forax < [ mailto:fo...@univ-mlv.fr | > fo...@univ-mlv.fr ] > wrote: >> I don't fully understand why not using checkcast because from the user POV >> the >> message will be better than just NPE. > When today I try unbox an Integer but encounter a null, > my experience is “NPE” rather than a more informative > “failed to unbox this int because you handed me a null”. > I agree, generally speaking, that messages should be more > informative. But surely the bar is low here, and “NPE” is > not out of bounds? Not if JEP 358 is enable, you have a NPE on Integer.intValue(). Anyway, it's not because error message can be improved in an area that it should not be there in another area. Users on the Java side are writing a cast, so having a class cast exception because the value is null seems to be a good error message. > That said, an indy-based solution has full information > about the use site, and can be coaxed to generate whatever > user experience we desire. And so would intrinsic based > solutions, of which I am favorable to some but not all. > Perhaps we want another (intrinsically optimized) version > of Objects::requireNonNull, which takes a second argument > that assists in generating a better diagnostic. yes, indy is a way to create any new bytecode, but it also has some restrictions, the major one being that you can not using it before it has been bootstrapped. > — John Rémi
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 2:07 PM, John Rose wrote: > > Perhaps we want another (intrinsically optimized) version > of Objects::requireNonNull, which takes a second argument > that assists in generating a better diagnostic. (D’oh; there it stands in the the JDK already.)
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 1:58 PM, Remi Forax wrote: > > I don't fully understand why not using checkcast because from the user POV > the message will be better than just NPE. When today I try unbox an Integer but encounter a null, my experience is “NPE” rather than a more informative “failed to unbox this int because you handed me a null”. I agree, generally speaking, that messages should be more informative. But surely the bar is low here, and “NPE” is not out of bounds? That said, an indy-based solution has full information about the use site, and can be coaxed to generate whatever user experience we desire. And so would intrinsic based solutions, of which I am favorable to some but not all. Perhaps we want another (intrinsically optimized) version of Objects::requireNonNull, which takes a second argument that assists in generating a better diagnostic. — John
Re: null checks vs. class resolution, and translation strategy for casts
I don't fully understand why not using checkcast because from the user POV the message will be better than just NPE. Rémi - Mail original - > De: "John Rose" > À: "Brian Goetz" > Cc: "valhalla-spec-experts" > Envoyé: Jeudi 9 Avril 2020 22:16:06 > Objet: Re: null checks vs. class resolution, and translation strategy for > casts > On Apr 9, 2020, at 1:03 PM, Brian Goetz wrote: >> >> >>> I have a proposal for a translation strategy: >> >> Casts to inline classes from their reference projections will be frequent. >> Because the reference projection is sealed to permit only the value >> projection, a cast is morally equivalent to a null check. We want to preserve >> this performance model, because otherwise we're reinventing boxing. >> >> Going through `ldc X.class / invokevirtual Class.cast` will surely be slow in >> the interpreter, but also risks being slow elsewhere (as do many of the other >> options.) >> >> So let me add to your list: is it time for a `checknonnull` bytecode, which >> throws NPE if null, or some other more flexible checking bytecode? >> (Alternatively, if we're saving bytecodes: `invokevirtual >> Object.`), where is a fake method that always links >> to a >> no-op, but invokevirtual NPEs on a null receiver.) > > Um, this feels a lot like a premature optimization. Let’s not add > `checknonnull` intrinsics to the interpreter (the very most > expensive way to do it) until we have tried the other alternatives > (Objects.requireNonNull, etc.) and have proven that the costs > are noticeable. And a spec EG is not the place to evaluate such > questions; it has to be demonstrated in a prototype. > > I see now why you are angling for verifier rules that know about > sealing relations. I think that also is premature optimizations. > Actually, verifier rules (not interpreter bytecodes) are the most > costly way to get anything done. > > Sorry to be a party pooper here, but that’s how it looks right now. > > — John
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 1:20 PM, John Rose wrote: > > No specs were harmed in making this proposal. P.P.S. Although there’s no precedent yet for it except static code rewriters, we could also intrinsify certain indy instructions in the same way, as early as the interpreter. Then we’d have customized verifier rules, based on each indy instruction signature, at no runtime cost, even at startup, thanks to the intrinsification logic. There are lots of ways to skin this… orange.
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 1:16 PM, John Rose wrote: > > On Apr 9, 2020, at 1:03 PM, Brian Goetz wrote: >> >> >>> I have a proposal for a translation strategy: >> >> Casts to inline classes from their reference projections will be frequent. >> Because the reference projection is sealed to permit only the value >> projection, a cast is morally equivalent to a null check. We want to >> preserve this performance model, because otherwise we're reinventing boxing. >> >> Going through `ldc X.class / invokevirtual Class.cast` will surely be slow >> in the interpreter, but also risks being slow elsewhere (as do many of the >> other options.) >> >> So let me add to your list: is it time for a `checknonnull` bytecode, which >> throws NPE if null, or some other more flexible checking bytecode? >> (Alternatively, if we're saving bytecodes: `invokevirtual >> Object.`), where is a fake method that always links >> to a no-op, but invokevirtual NPEs on a null receiver.) > > Um, this feels a lot like a premature optimization. Let’s not add > `checknonnull` intrinsics to the interpreter (the very most > expensive way to do it) until we have tried the other alternatives > (Objects.requireNonNull, etc.) and have proven that the costs > are noticeable. And a spec EG is not the place to evaluate such > questions; it has to be demonstrated in a prototype. > > I see now why you are angling for verifier rules that know about > sealing relations. I think that also is premature optimizations. > Actually, verifier rules (not interpreter bytecodes) are the most > costly way to get anything done. > > Sorry to be a party pooper here, but that’s how it looks right now. > > — John P.S. The Object. idea is clever, and we have done things like that in the past; the interpreter has special fast entry points for certain math functions. These were added due to certain benchmarks being slow >20 years ago; who knows if they are still relevant. We could do the same for Objects.requireNonNull; that would be a less intrusive (more sneaky) version of Object.. No specs were harmed in making this proposal.
Re: null checks vs. class resolution, and translation strategy for casts
On Apr 9, 2020, at 1:03 PM, Brian Goetz wrote: > > >> I have a proposal for a translation strategy: > > Casts to inline classes from their reference projections will be frequent. > Because the reference projection is sealed to permit only the value > projection, a cast is morally equivalent to a null check. We want to preserve > this performance model, because otherwise we're reinventing boxing. > > Going through `ldc X.class / invokevirtual Class.cast` will surely be slow in > the interpreter, but also risks being slow elsewhere (as do many of the other > options.) > > So let me add to your list: is it time for a `checknonnull` bytecode, which > throws NPE if null, or some other more flexible checking bytecode? > (Alternatively, if we're saving bytecodes: `invokevirtual > Object.`), where is a fake method that always links to > a no-op, but invokevirtual NPEs on a null receiver.) Um, this feels a lot like a premature optimization. Let’s not add `checknonnull` intrinsics to the interpreter (the very most expensive way to do it) until we have tried the other alternatives (Objects.requireNonNull, etc.) and have proven that the costs are noticeable. And a spec EG is not the place to evaluate such questions; it has to be demonstrated in a prototype. I see now why you are angling for verifier rules that know about sealing relations. I think that also is premature optimizations. Actually, verifier rules (not interpreter bytecodes) are the most costly way to get anything done. Sorry to be a party pooper here, but that’s how it looks right now. — John
Re: null checks vs. class resolution, and translation strategy for casts
I have a proposal for a translation strategy: Casts to inline classes from their reference projections will be frequent. Because the reference projection is sealed to permit only the value projection, a cast is morally equivalent to a null check. We want to preserve this performance model, because otherwise we're reinventing boxing. Going through `ldc X.class / invokevirtual Class.cast` will surely be slow in the interpreter, but also risks being slow elsewhere (as do many of the other options.) So let me add to your list: is it time for a `checknonnull` bytecode, which throws NPE if null, or some other more flexible checking bytecode? (Alternatively, if we're saving bytecodes: `invokevirtual Object.`), where is a fake method that always links to a no-op, but invokevirtual NPEs on a null receiver.)
Re: null checks vs. class resolution, and translation strategy for casts
Correction… The recommended reflective approach has a flaw (easily fixed), which makes indy my real recommendation. On Apr 8, 2020, at 11:43 AM, John Rose wrote: > … > I have a proposal for a translation strategy: > > 1. Translate casts to inline classes differently from “classic” > casts. Add an extra step of null hostility. For very low-level > reasons, I suggest using “ldc X” followed by Class::cast. > > Generally speaking, it’s a reasonable move to use reflective > API points (like Class::cast) on constant metadata (like X.class) > to implement language semantics. This suggestion is incomplete. If the result of the cast is going to be used as type X, then the verifier must be pacified by adding `checkcast X`. Basically, you have to do both reflective and intrinsic cast operations, if you need to get the verifier on board, as well as do a null check. That tips me over to recommending indy instead, which was #2. Indy, that Swiss army knife of an instruction, can get it done in one. > The following alternatives are also possible; I present them > in decreasing order of preference: > > 2. Use invokedynamic to roll our own instruction. It will > be a trivial BSM since we are really just doing an asType > operation. But I think this is probably overkill, despite > my fondness for indy. For a conversion to type X, where X may be a null-hostile inline type (or any type whose semantics is not exactly covered by native checkcast), a single invokedynamic instruction will cover the operational semantics required and will also feed the right type to the verifier. It will have this signature: (Object) => X It will have a utility bootstrap method which materializes conversions, basically riffing on MethodHandles::identity and asType. (Not MethodHandles::explicitCastArguments, because we are concerned with checked reference conversions.) It will have *no extra arguments* (not even X.class), because the BSM can easily derive X.class from the return type of the method type signature passed to the BSM. ConstantCallSite convertBSM(Lookup ig1, String ig2, MethodType mt) { var mh = MethodHandles.identity(Object.class).asType(mt); return new ConstantCallSite(mh); } As such, it is a candidate for proposed simplifications to bootstrap method configuration (but not the simplest such simplifications, because of the need to feed X.class into the linkage logic). MethodHandle simplifiedConvertBSM() { return MethodHandles.identity(Object.class); } (At some point I should write up those simplifications, shouldn’t I?) — John