From brian.goetz at oracle.com Thu Sep 1 17:32:18 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 1 Sep 2022 13:32:18 -0400 Subject: Try/catch/finally builder In-Reply-To: <9B963A4E-A779-46C7-94F2-A237238C863A@oracle.com> References: <6D1023A6-1B0D-4E88-88FD-60B913ACC134@oracle.com> <76FD98D4-EEF5-44E1-95E9-25441B4BEA19@oracle.com> <09f2222e-8b9e-527a-ac73-b8e1948f959a@oracle.com> <3BC824FC-F922-4D9D-8B3B-EA368E0271B4@oracle.com> <9B963A4E-A779-46C7-94F2-A237238C863A@oracle.com> Message-ID: >> The first one uses a label defined in the outer try scope, so we only inline finally A here. The second uses a label defined outside the outer try scope, so we have to inline A and B (in the right order) here. >> > Indeed it's complex. I think the test membership of block labels can work, since X is a member of the outer try?s label set, where as Y is not. But, we have to be careful how we propagate the branch instruction up the chain of builders. I think its fair to assume that users will either use TCB, or will build exception tables and inline finallys themselves, but not expect the interaction of the two to work automagically.? So let's confine ourselves to nested use of TCB for the time being. It is quite likely that we may have indirect nesting: a try block inside an an if/else block inside a try block.? So in order to make the automagic finally-expansion work, we have to be prepared to walk the chain of parents back to the terminal builder, to find TCBs, even if the immediately enclosing block builder is not a TCB. There are basically three paths here: ?- the automagic path, which we're exploring now -- retain enough information at run time to determine which "block" owns the branch target, and inline the finally blocks for the TCBs between the outermost block and the branch target block. ?- the totally manual path, where the user has to figure out which finally blocks to emit for any given branch, and maybe we give them a "BlockBuilder::emitFinally" to emit each one individually. ?- an intermediate path, where we don't try to guess at what block owns the target label, but instead let the user tell us what block owns the target label, with some sort of emitFinally(CodeBuilder thoughThisBuilder) method. It feels like the automagic approach is almost there, so I suggest we continue pulling on this string for a bit. > At the moment it's a little messy (do we use parent or terminal etc?) and I need clear this up. We have three kinds of builder: > > - the root builder, not an instance of BlockCodeBuilder. > - the terminal builder , an instance of TerminalCodeBuilder. > - the parent block builder, an instance of BlockCodeBuilder. I'm a little unsure of these terms.? How does the root builder differ from the terminal builder? From paul.sandoz at oracle.com Thu Sep 1 18:20:08 2022 From: paul.sandoz at oracle.com (Paul Sandoz) Date: Thu, 1 Sep 2022 18:20:08 +0000 Subject: Try/catch/finally builder In-Reply-To: References: <6D1023A6-1B0D-4E88-88FD-60B913ACC134@oracle.com> <76FD98D4-EEF5-44E1-95E9-25441B4BEA19@oracle.com> <09f2222e-8b9e-527a-ac73-b8e1948f959a@oracle.com> <3BC824FC-F922-4D9D-8B3B-EA368E0271B4@oracle.com> <9B963A4E-A779-46C7-94F2-A237238C863A@oracle.com> Message-ID: <41AF1FB0-721B-41CA-B170-DE07D799D9BA@oracle.com> > On Sep 1, 2022, at 10:32 AM, Brian Goetz wrote: > > > >>> The first one uses a label defined in the outer try scope, so we only inline finally A here. The second uses a label defined outside the outer try scope, so we have to inline A and B (in the right order) here. >>> >> Indeed it's complex. I think the test membership of block labels can work, since X is a member of the outer try?s label set, where as Y is not. But, we have to be careful how we propagate the branch instruction up the chain of builders. > > I think its fair to assume that users will either use TCB, or will build exception tables and inline finallys themselves, but not expect the interaction of the two to work automagically. So let's confine ourselves to nested use of TCB for the time being. > Yes. > It is quite likely that we may have indirect nesting: a try block inside an an if/else block inside a try block. So in order to make the automagic finally-expansion work, we have to be prepared to walk the chain of parents back to the terminal builder, to find TCBs, even if the immediately enclosing block builder is not a TCB. > > There are basically three paths here: > > - the automagic path, which we're exploring now -- retain enough information at run time to determine which "block" owns the branch target, and inline the finally blocks for the TCBs between the outermost block and the branch target block. > > - the totally manual path, where the user has to figure out which finally blocks to emit for any given branch, and maybe we give them a "BlockBuilder::emitFinally" to emit each one individually. > > - an intermediate path, where we don't try to guess at what block owns the target label, but instead let the user tell us what block owns the target label, with some sort of emitFinally(CodeBuilder thoughThisBuilder) method. > > It feels like the automagic approach is almost there, so I suggest we continue pulling on this string for a bit. > Agreed, it looks possible. (Separately we need to add some loop support, plus perhaps a way to model lambda expressions, which interestingly will build synthetic methods.) >> At the moment it's a little messy (do we use parent or terminal etc?) and I need clear this up. We have three kinds of builder: >> >> - the root builder, not an instance of BlockCodeBuilder. >> - the terminal builder , an instance of TerminalCodeBuilder. >> - the parent block builder, an instance of BlockCodeBuilder. > > I'm a little unsure of these terms. How does the root builder differ from the terminal builder? > The root builder is that passed by the MethodBuilder::withCode method to its consumer argument. I am still uncertain how code transformers layer in. I think they interject a form of builder in the builder chain but I am currently unsure of any impact related to TCB. Paul. From brian.goetz at oracle.com Thu Sep 1 18:45:00 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 1 Sep 2022 14:45:00 -0400 Subject: Try/catch/finally builder In-Reply-To: <41AF1FB0-721B-41CA-B170-DE07D799D9BA@oracle.com> References: <6D1023A6-1B0D-4E88-88FD-60B913ACC134@oracle.com> <76FD98D4-EEF5-44E1-95E9-25441B4BEA19@oracle.com> <09f2222e-8b9e-527a-ac73-b8e1948f959a@oracle.com> <3BC824FC-F922-4D9D-8B3B-EA368E0271B4@oracle.com> <9B963A4E-A779-46C7-94F2-A237238C863A@oracle.com> <41AF1FB0-721B-41CA-B170-DE07D799D9BA@oracle.com> Message-ID: <0afc9bdc-6fe9-70a3-3147-db1f0a748b76@oracle.com> On 9/1/2022 2:20 PM, Paul Sandoz wrote: >> I'm a little unsure of these terms. How does the root builder differ from the terminal builder? >> > The root builder is that passed by the MethodBuilder::withCode method to its consumer argument. > > I am still uncertain how code transformers layer in. I think they interject a form of builder in the builder chain but I am currently unsure of any impact related to TCB. In the absence of transforms, the root builder == terminal builder == direct builder.? Transforms introduce two kinds of additional builders, chained and buffered. Chained builders are the obvious thing you'd expect from a transform.? The chained builder embodies the transform, it applies the transform and sends any emitted elements to a downstream builder (which will bottom out at a direct builder.)? If our transform is composed with other transforms (CodeTransform::andThen), we'll have multiple steps of chained builders, one for each step in the transform chain. Buffered builders arise from a more complicated situation, where we have lifted a CodeTransform to be a MethodTransform, and then want to chain that method transform with another.? In this case, we allocate not a direct builder at the terminal end of the chain, but a buffered builder, one that just accumulates the elements into an ArrayList, so we can lift it into a MethodModel.? When we are lifting and chaining, we need to do this because we don't know if the next transform in the method transform chain will want to explode the Code attribute, so we have to be able to wrap a MethodModel around it.? But buffered builders are more expensive, so we only employ them when absolutely necessary.? From the perspective of a builder chain, a buffered builder is also a terminal builder; you can't see through the lifting. Block builders are technically not chained builders, but that's mostly an accident of naming.? Both block and chained builders are "nonterminal" builders, which is where we maintain the reference to the terminal builder.? Block builders remember their parent, but chained builders do not (only because they have not needed to, to date, this is easy to add back in, and maybe you'll want this for being able to find all the finally blocks.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Sep 5 17:21:09 2022 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 5 Sep 2022 18:21:09 +0100 Subject: Try/catch/finally builder In-Reply-To: References: <6D1023A6-1B0D-4E88-88FD-60B913ACC134@oracle.com> <76FD98D4-EEF5-44E1-95E9-25441B4BEA19@oracle.com> <09f2222e-8b9e-527a-ac73-b8e1948f959a@oracle.com> <3BC824FC-F922-4D9D-8B3B-EA368E0271B4@oracle.com> <9B963A4E-A779-46C7-94F2-A237238C863A@oracle.com> Message-ID: On 01/09/2022 18:32, Brian Goetz wrote: > ?- the automagic path, which we're exploring now -- retain enough > information at run time to determine which "block" owns the branch > target, and inline the finally blocks for the TCBs between the > outermost block and the branch target block. I think it *should* be possible. Javac does something like this by keeping track of a generation context (GenContext) class. When there's a jump (break/continue/return), we call a routine which "traverses" the context, and adds finalizer calls for all pending finalizers: https://github.com/openjdk/jdk/blob/master/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java#L365 Javac can do this because code is generated in a structured fashion - so javac knows the "boundaries" of each block of code involved. But, doing this with builders and lambdas should more or less land us in the same place. Of course, mixing and matching (e.g. using both manual generation and auto generation) will not work, as some of the structured-ness assumptions would go out of the window. Maurizio From heidinga at redhat.com Mon Sep 12 13:16:46 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Mon, 12 Sep 2022 09:16:46 -0400 Subject: Experience report In-Reply-To: <71bfabc1-29fd-ad90-518c-45298d62c5ca@oracle.com> References: <8ebb41d5-c598-e825-1062-14d1fe3b150d@oracle.com> <6da06023-3d91-d0bd-55c2-b6f868eddf9a@oracle.com> <71bfabc1-29fd-ad90-518c-45298d62c5ca@oracle.com> Message-ID: I've updated the PR to include the following: * CE.adding/addingSymbols methods * a List deduplicate(List) method that removes duplicate entries from the List * equals() methods to the ConcreteEntry subclasses Let me know if this fits with the intended approach for the jdk.classfile library. https://github.com/openjdk/jdk-sandbox/pull/35 --Dan On Wed, Aug 24, 2022 at 2:55 PM Brian Goetz wrote: > I'd say let's give this a try and see what we think of the resulting > transformation code. It feels like right-sizing the overhead at first look. > > On 8/24/2022 9:22 AM, Dan Heidinga wrote: > > >> > I took another pass through the Attributes that deal with Lists of things > and most cases are well handled by existing List helpers. It's only the > CE/CD cases that need data conversion and would therefore benefit from > additional methods to create their lists. > > If we expect to be content with these 4 methods, then adding them as > static methods on ClassEntry seems reasonable. It makes them easy to find > and avoids a garbage "Helpers/Utils" class. If we expect more of these > methods (and I currently don't but that may be lack of imagination), then a > garbage class might be better. > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Sep 12 15:35:54 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 12 Sep 2022 11:35:54 -0400 Subject: Experience report In-Reply-To: References: <8ebb41d5-c598-e825-1062-14d1fe3b150d@oracle.com> <6da06023-3d91-d0bd-55c2-b6f868eddf9a@oracle.com> <71bfabc1-29fd-ad90-518c-45298d62c5ca@oracle.com> Message-ID: These look good to from an API perspective.? What was the user experience like for things like injecting interfaces?? Did the new methods feel clumsy or natural? I'll make a stylistic nit not because I want you to change your code, but to remind the world that the language has changed. The way you write this equals() method follows all the Effective Java recommendations: ??????? public boolean equals(Object o) { ??????????? if (this == o) return true; ??????????? if (o instanceof ConcreteMethodHandleEntry m) { ??????????????? return kind() == m.kind() ??????????????? && reference.equals(m.reference()); ??????????? } ??????????? return false; ??????? } but I might write it this way with the language we have now: ??????? public boolean equals(Object o) { ??? ??? ??? return (this == o) ??? ??? ??? || (o instanceof ConcreteMethodHandleEntry m ??????????????? && kind() == m.kind() ??????????????? && reference.equals(m.reference()); ??????? } To be clear, the code you wrote is OK, but I've gotten used to writing it the second way and I find it more straightforward to read. +1 from me. On 9/12/2022 9:16 AM, Dan Heidinga wrote: > I've updated the PR to include the following: > * CE.adding/addingSymbols methods > * a List deduplicate(List) method that removes duplicate > entries from the List > * equals() methods to the ConcreteEntry subclasses > > Let me know if this fits with the intended approach for the > jdk.classfile library. > > https://github.com/openjdk/jdk-sandbox/pull/35 > > > --Dan > > On Wed, Aug 24, 2022 at 2:55 PM Brian Goetz > wrote: > > I'd say let's give this a try and see what we think of the > resulting transformation code.? It feels like right-sizing the > overhead at first look. > > On 8/24/2022 9:22 AM, Dan Heidinga wrote: >> >> >> >> I took another pass through the?Attributes that deal with Lists >> of things and most cases are well handled by existing List >> helpers.? It's only the CE/CD cases that need data conversion and >> would therefore benefit from additional methods to create their >> lists. >> >> If we expect to be content with these 4 methods, then adding them >> as static methods on ClassEntry seems reasonable. It makes them >> easy to find and avoids a garbage "Helpers/Utils" class.? If we >> expect more of these methods (and I currently don't but that may >> be lack of imagination), then a garbage class might be better. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Mon Sep 12 17:06:22 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Mon, 12 Sep 2022 17:06:22 +0000 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc Message-ID: Hi, I?ve performed some cleanup, renaming and API unification in jdk.classfile.transforms package. Plus added Javadoc with code snippets. Please let me know your comments: https://github.com/openjdk/jdk-sandbox/pull/36 Thanks, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Sep 12 18:17:27 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 12 Sep 2022 14:17:27 -0400 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc In-Reply-To: References: Message-ID: This is a good improvement.? I have a few additional suggestions and questions: ?- The ClassRemapper spec talks about what it _doesn't_ map, rather than what it does.? We should characterize what it does do (e.g., for every ClassEntry referenced by an instruction, attribute, or metadata, map it to a new ClassEntry as per the contents of the map...)? It should also give a plain explanation of when you would use it (e.g., package renaming.) ?- You might want to give some example code for how to remap _all_ classes in package com.foo to com.bar -- this involves writing a Function that looks at prefixes. ?- Does CodeLocalsShifter::addLocal work in concert with the local-allocation feature of BlockBuilder? ?- Should explain why fork() exists There is some question about what package these should go in.? I think the current package "transforms" is probably not optimal. ?- We could put these in the jdk.classfile package.? There's only a handful of them, I think this would be OK. ?- We could put these in some package that suggests these are reusable components that are not part of the classfile API.? But if so, "transform" is probably a little too specific, since one can imagine reusable components for other things (e.g., a pedantic verifying builder wrapper, an AttributeBuilder for foreign but common attributes, if such a thing existed, etc.) "Util" is a little general (plus it has the feeling of a "dumping ground") but might be OK.? ASM also has "commons", which has the suggestion of "stuff contributed from the community", but that's also not a great name. The ASM "util" package contains: Trace/CheckClassAdapter and friends, ClassPrinter, etc.? This feels in roughly the same category -- stuff you may want to use, but which are "components" rather than framework. On 9/12/2022 1:06 PM, Adam Sotona wrote: > > Hi, > > I?ve performed some cleanup, renaming and API unification in > jdk.classfile.transforms package. > > Plus added Javadoc with code snippets. > > Please let me know your comments: > > https://github.com/openjdk/jdk-sandbox/pull/36 > > Thanks, > > Adam > -------------- next part -------------- An HTML attachment was scrubbed... URL: From heidinga at redhat.com Mon Sep 12 20:33:44 2022 From: heidinga at redhat.com (Dan Heidinga) Date: Mon, 12 Sep 2022 16:33:44 -0400 Subject: Experience report In-Reply-To: References: <8ebb41d5-c598-e825-1062-14d1fe3b150d@oracle.com> <6da06023-3d91-d0bd-55c2-b6f868eddf9a@oracle.com> <71bfabc1-29fd-ad90-518c-45298d62c5ca@oracle.com> Message-ID: On Mon, Sep 12, 2022 at 11:36 AM Brian Goetz wrote: > These look good to from an API perspective. What was the user experience > like for things like injecting interfaces? Did the new methods feel clumsy > or natural? > I modified some of the ExampleGallery.java classes to use the new methods and wrote a similar test case. The new methods feel pretty natural for those use cases with the "addingSymbols" method taking the place of Stream.concat and "deduplicate" replacing Stream.distinct: public void accept(ClassBuilder builder, ClassElement element) { switch (element) { case Interfaces i: // List interfaces = Stream.concat(i.interfaces().stream(), // Stream.of(builder.constantPool().classEntry(newIntf))) // .distinct() // .toList(); List interfaces = ClassEntry.deduplicate(ClassEntry.addingSymbols(i.interfaces(), newIntf)); builder.withInterfaces(interfaces); > > > I'll make a stylistic nit not because I want you to change your code, but > to remind the world that the language has changed. The way you write this > equals() method follows all the Effective Java recommendations: > > public boolean equals(Object o) { > if (this == o) return true; > if (o instanceof ConcreteMethodHandleEntry m) { > return kind() == m.kind() > && reference.equals(m.reference()); > } > return false; > } > > but I might write it this way with the language we have now: > > public boolean equals(Object o) { > return (this == o) > || (o instanceof ConcreteMethodHandleEntry m > && kind() == m.kind() > && reference.equals(m.reference()); > } > > To be clear, the code you wrote is OK, but I've gotten used to writing it > the second way and I find it more straightforward to read. > > I'll keep the second way in mind for future changes. It'll probably take a while for the new pattern to replace the muscle-memory of the old =) What's the next step for getting these changes merged? --Dan > > +1 from me. > > On 9/12/2022 9:16 AM, Dan Heidinga wrote: > > I've updated the PR to include the following: > * CE.adding/addingSymbols methods > * a List deduplicate(List) method that removes duplicate entries > from the List > * equals() methods to the ConcreteEntry subclasses > > Let me know if this fits with the intended approach for the jdk.classfile > library. > > https://github.com/openjdk/jdk-sandbox/pull/35 > > > --Dan > > On Wed, Aug 24, 2022 at 2:55 PM Brian Goetz > wrote: > >> I'd say let's give this a try and see what we think of the resulting >> transformation code. It feels like right-sizing the overhead at first look. >> >> On 8/24/2022 9:22 AM, Dan Heidinga wrote: >> >> >>> >> I took another pass through the Attributes that deal with Lists of things >> and most cases are well handled by existing List helpers. It's only the >> CE/CD cases that need data conversion and would therefore benefit from >> additional methods to create their lists. >> >> If we expect to be content with these 4 methods, then adding them as >> static methods on ClassEntry seems reasonable. It makes them easy to find >> and avoids a garbage "Helpers/Utils" class. If we expect more of these >> methods (and I currently don't but that may be lack of imagination), then a >> garbage class might be better. >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Tue Sep 13 08:22:24 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 13 Sep 2022 08:22:24 +0000 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc In-Reply-To: References: Message-ID: From: Brian Goetz Date: Monday, 12 September 2022 20:17 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: RFR: jdk.classfile.transforms package cleanup + javadoc This is a good improvement. I have a few additional suggestions and questions: - The ClassRemapper spec talks about what it _doesn't_ map, rather than what it does. We should characterize what it does do (e.g., for every ClassEntry referenced by an instruction, attribute, or metadata, map it to a new ClassEntry as per the contents of the map...) It should also give a plain explanation of when you would use it (e.g., package renaming.) Right, thanks, I?ll fix it. - You might want to give some example code for how to remap _all_ classes in package com.foo to com.bar -- this involves writing a Function that looks at prefixes. There is such example ?Sample use with map function?, however not enough described and highlighted. I?ll fix it. - Does CodeLocalsShifter::addLocal work in concert with the local-allocation feature of BlockBuilder? Good point :) It does not yet, however I?ll try to reimplement it to do so. We may get rid of counting the method arguments, local counting of ?next?, use BlockBuilders instead of the ?fork?, etc... - Should explain why fork() exists Maybe it doesn?t need to exist :) There is some question about what package these should go in. I think the current package "transforms" is probably not optimal. - We could put these in the jdk.classfile package. There's only a handful of them, I think this would be OK. - We could put these in some package that suggests these are reusable components that are not part of the classfile API. But if so, "transform" is probably a little too specific, since one can imagine reusable components for other things (e.g., a pedantic verifying builder wrapper, an AttributeBuilder for foreign but common attributes, if such a thing existed, etc.) "Util" is a little general (plus it has the feeling of a "dumping ground") but might be OK. ASM also has "commons", which has the suggestion of "stuff contributed from the community", but that's also not a great name. The ASM "util" package contains: Trace/CheckClassAdapter and friends, ClassPrinter, etc. This feels in roughly the same category -- stuff you may want to use, but which are "components" rather than framework. I think ?commons? was not the best choice for ASM, as it represent common (the bottom) parts of complex APIs in many external Java libraries. And I agree ?transform? is too specific and ?util? is probably too general. My personal preference would be ?components?. Thanks, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Tue Sep 13 13:06:43 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 13 Sep 2022 13:06:43 +0000 Subject: Question on locals allocation in BlockCodeBuilder Message-ID: Hi, I have a question related to an older fragment of code in BlockCodeBuilderImpl, that actively prohibits allocation of locals in BlockCodeBuilder: public void end() { terminal.with((LabelTarget) endLabel); if (terminalMaxLocals != topLocal(terminal)) { throw new IllegalStateException("Interference in local variable slot management"); } } Do we really want to prevent locals allocated and valid in the context of BlockCodeBuilder only? Thanks, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Sep 13 14:17:46 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Sep 2022 10:17:46 -0400 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc In-Reply-To: References: Message-ID: <9c5f5281-5633-8e03-425a-cd4a02d57e4c@oracle.com> > ?- Does CodeLocalsShifter::addLocal work in concert with the > local-allocation feature of BlockBuilder? > > Good point :) > > It does not yet, however I?ll try to reimplement it to do so. We may > get rid of counting the method arguments, local counting of ?next?, > use BlockBuilders instead of the ?fork?, etc... > The local-allocation feature of BlockBuilder and friends is very "green" right now.? So I would not be surprised if you found potholes.? It also needs more tests.? As you point out in your other mail, there is nothing to stop the user from just "making up" local slot allocations, and then of course there would be conflicts between the automatic allocation and the user choices.? We try to detect this with this check: ??????? if (terminalMaxLocals != topLocal(terminal)) ??????????? throw new IllegalStateException("Interference in local variable slot management"); in BlockBuilder::end.? (One case we do not have a test for is where a stateful transform allocates a local in its atStart() method with builder::allocateLocal, and then the transform uses BlockBuilder::allocateLocal inside that.) The package Javadoc probably needs a section for local variable management too, to explain how allocateLocal works, and what not to do when using it.? With some examples. > > The ASM "util" package contains: Trace/CheckClassAdapter and friends, > ClassPrinter, etc.? This feels in roughly the same category -- stuff > you may want to use, but which are "components" rather than framework. > > I think ?commons? was not the best choice for ASM, as it represent > common (the bottom) parts of complex APIs in many external Java libraries. > > And I agree ?transform? is too specific and ?util? is probably too > general. > > My personal preference would be ?components?. > > I think that's a fair choice.? Just to validate that, here's some other things I can imagine going in that bucket: ?- ClassPrinter ?- Utilities for parsing descriptor strings.? To start with we might cleanup the most useful ones that are currently internal.? (Its possible that these could eventually be used by java.lang.constant too; there are too many ad-hoc copies of descriptor string parsers in java.base.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Sep 13 14:28:31 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Sep 2022 10:28:31 -0400 Subject: Question on locals allocation in BlockCodeBuilder In-Reply-To: References: Message-ID: <0290ac77-8646-ef18-a5e6-49d926c8f458@oracle.com> This isn't intended to prohibit allocation of locals in blocks; it is to detect when two different mechanisms are used to allocate locals together. Are you getting this error? We define allocateLocal in CodeBuilder.? In the base (Direct) code builder, when you call allocateLocal, it bumps up a high water mark (topLocal).? There is no way to "deallocate" a local; this is an allocation that is global to the Code attribute being built. In the various BlockBuilder implementations, they implement their own allocateLocal to: ?- start counting initially at the high water mark of their parent; ?- let the user allocate locals starting at that high water mark; ?- when the block is finished, we reclaim all of the locals allocate in the block, by dropping back down to the starting high water mark. The problem is that these two mechanisms -- the "global" allocation of DirectCodeBuilder and the "local" allocation of BlockCodeBuilder don't know about each other's work.? Here's an example of what could go wrong: .withCode(db -> { ??? int x = db.allocateLocal(TypeKind.INT); // OK, global allocation ??? db.aconst_1(); ??? db.ifThen(bb -> { ??????? // both the DirectCodeBuilder and BlockCodeBuilder (db and bb) are in scope here ??????? int y = bb.allocateLocal(TypeKind.INT);? // OK, local allocation ??????? int z = db.allocateLocal(TypeKind.INT);? // conflict! ??? }); }); The problem is that I used both mechanisms inside the block.? It would be ok to exclusively use db, or exclusively use bb, to allocate locals, but not both at once.? The error you've found detects this conflict and throws, albeit with a not so helpful error message. Overall I think using both mechanisms at once will be rare, because its rare to mix using both the "tip" and "root" builders at the same time -- that's usually a bug. If a transform needs locals for its work, it should allocate a local from the root builder in the (stateful) transform atStart() method. On 9/13/2022 9:06 AM, Adam Sotona wrote: > > Hi, > > I have a question related to an older fragment of code in > BlockCodeBuilderImpl, that actively prohibits allocation of locals in > BlockCodeBuilder: > > publicvoid*end*() { > > terminal.with((LabelTarget) endLabel); > > if(terminalMaxLocals!= topLocal(terminal)) { > > thrownewIllegalStateException("Interference in local variable slot > management"); > > ??????? } > > ??? } > > Do we really want to prevent locals allocated and valid in the context > of BlockCodeBuilder only? > > Thanks, > > Adam > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Sep 13 14:30:59 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Sep 2022 10:30:59 -0400 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc In-Reply-To: References: Message-ID: <95b686b4-9bf9-e404-9b3c-0dfc09f23ba0@oracle.com> > My personal preference would be ?components?. > The components package should have a package javadoc that offers a brief tour of its components, and the section on transforms in the main javadoc should point to the components package javadoc as examples of pre-baked transforms. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Tue Sep 13 14:41:25 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Tue, 13 Sep 2022 14:41:25 +0000 Subject: Question on locals allocation in BlockCodeBuilder In-Reply-To: <0290ac77-8646-ef18-a5e6-49d926c8f458@oracle.com> References: <0290ac77-8646-ef18-a5e6-49d926c8f458@oracle.com> Message-ID: OK, understood. Problem is probably in ChainedCodeBuilder, which skips BlockCodeBuilder downstream and allocates locals in the terminal DirectCodeBuilder directly. From: Brian Goetz Date: Tuesday, 13 September 2022 16:28 To: Adam Sotona , classfile-api-dev at openjdk.org Subject: Re: Question on locals allocation in BlockCodeBuilder This isn't intended to prohibit allocation of locals in blocks; it is to detect when two different mechanisms are used to allocate locals together. Are you getting this error? We define allocateLocal in CodeBuilder. In the base (Direct) code builder, when you call allocateLocal, it bumps up a high water mark (topLocal). There is no way to "deallocate" a local; this is an allocation that is global to the Code attribute being built. In the various BlockBuilder implementations, they implement their own allocateLocal to: - start counting initially at the high water mark of their parent; - let the user allocate locals starting at that high water mark; - when the block is finished, we reclaim all of the locals allocate in the block, by dropping back down to the starting high water mark. The problem is that these two mechanisms -- the "global" allocation of DirectCodeBuilder and the "local" allocation of BlockCodeBuilder don't know about each other's work. Here's an example of what could go wrong: .withCode(db -> { int x = db.allocateLocal(TypeKind.INT); // OK, global allocation db.aconst_1(); db.ifThen(bb -> { // both the DirectCodeBuilder and BlockCodeBuilder (db and bb) are in scope here int y = bb.allocateLocal(TypeKind.INT); // OK, local allocation int z = db.allocateLocal(TypeKind.INT); // conflict! }); }); The problem is that I used both mechanisms inside the block. It would be ok to exclusively use db, or exclusively use bb, to allocate locals, but not both at once. The error you've found detects this conflict and throws, albeit with a not so helpful error message. Overall I think using both mechanisms at once will be rare, because its rare to mix using both the "tip" and "root" builders at the same time -- that's usually a bug. If a transform needs locals for its work, it should allocate a local from the root builder in the (stateful) transform atStart() method. On 9/13/2022 9:06 AM, Adam Sotona wrote: Hi, I have a question related to an older fragment of code in BlockCodeBuilderImpl, that actively prohibits allocation of locals in BlockCodeBuilder: public void end() { terminal.with((LabelTarget) endLabel); if (terminalMaxLocals != topLocal(terminal)) { throw new IllegalStateException("Interference in local variable slot management"); } } Do we really want to prevent locals allocated and valid in the context of BlockCodeBuilder only? Thanks, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Sep 13 15:12:04 2022 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 13 Sep 2022 11:12:04 -0400 Subject: Question on locals allocation in BlockCodeBuilder In-Reply-To: References: <0290ac77-8646-ef18-a5e6-49d926c8f458@oracle.com> Message-ID: Right, that's probably a mistake.? (This is what I meant by the locals stuff is under-tested.) Yes, CCB should probably delegate to parent.? If the parent is a block, any locals used by transforming that block should be local to that block. On 9/13/2022 10:41 AM, Adam Sotona wrote: > > OK, understood. > > Problem is probably in ChainedCodeBuilder, which skips > BlockCodeBuilder downstream and allocates locals in the terminal > DirectCodeBuilder directly. > > *From: *Brian Goetz > *Date: *Tuesday, 13 September 2022 16:28 > *To: *Adam Sotona , > classfile-api-dev at openjdk.org > *Subject: *Re: Question on locals allocation in BlockCodeBuilder > > This isn't intended to prohibit allocation of locals in blocks; it is > to detect when two different mechanisms are used to allocate locals > together.? Are you getting this error? > > We define allocateLocal in CodeBuilder.? In the base (Direct) code > builder, when you call allocateLocal, it bumps up a high water mark > (topLocal).? There is no way to "deallocate" a local; this is an > allocation that is global to the Code attribute being built. > > In the various BlockBuilder implementations, they implement their own > allocateLocal to: > > ?- start counting initially at the high water mark of their parent; > ?- let the user allocate locals starting at that high water mark; > ?- when the block is finished, we reclaim all of the locals allocate > in the block, by dropping back down to the starting high water mark. > > The problem is that these two mechanisms -- the "global" allocation of > DirectCodeBuilder and the "local" allocation of BlockCodeBuilder don't > know about each other's work. Here's an example of what could go wrong: > > .withCode(db -> { > ??? int x = db.allocateLocal(TypeKind.INT); // OK, global allocation > ??? db.aconst_1(); > ??? db.ifThen(bb -> { > ??????? // both the DirectCodeBuilder and BlockCodeBuilder (db and bb) > are in scope here > ??????? int y = bb.allocateLocal(TypeKind.INT);? // OK, local allocation > ??????? int z = db.allocateLocal(TypeKind.INT);? // conflict! > ??? }); > }); > > The problem is that I used both mechanisms inside the block.? It would > be ok to exclusively use db, or exclusively use bb, to allocate > locals, but not both at once.? The error you've found detects this > conflict and throws, albeit with a not so helpful error message. > > Overall I think using both mechanisms at once will be rare, because > its rare to mix using both the "tip" and "root" builders at the same > time -- that's usually a bug. > > If a transform needs locals for its work, it should allocate a local > from the root builder in the (stateful) transform atStart() method. > > On 9/13/2022 9:06 AM, Adam Sotona wrote: > > Hi, > > I have a question related to an older fragment of code in > BlockCodeBuilderImpl, that actively prohibits allocation of locals > in BlockCodeBuilder: > > ??? public void *end*() { > > terminal.with((LabelTarget) endLabel); > > ??????? if (terminalMaxLocals != topLocal(terminal)) { > > ??????????? throw new IllegalStateException("Interference in local > variable slot management"); > > ??????? } > > ??? } > > Do we really want to prevent locals allocated and valid in the > context of BlockCodeBuilder only? > > Thanks, > > Adam > -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Wed Sep 14 09:20:47 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Wed, 14 Sep 2022 09:20:47 +0000 Subject: RFR: jdk.classfile.transforms package cleanup + javadoc In-Reply-To: <95b686b4-9bf9-e404-9b3c-0dfc09f23ba0@oracle.com> References: <95b686b4-9bf9-e404-9b3c-0dfc09f23ba0@oracle.com> Message-ID: OK, I?ll do the refactoring in this round, fix classfile-api-dev-branch and then another round of javadoc updates. On 13.09.2022 16:31, "Brian Goetz" wrote: My personal preference would be ?components?. The components package should have a package javadoc that offers a brief tour of its components, and the section on transforms in the main javadoc should point to the components package javadoc as examples of pre-baked transforms. -------------- next part -------------- An HTML attachment was scrubbed... URL: From adam.sotona at oracle.com Fri Sep 23 12:45:05 2022 From: adam.sotona at oracle.com (Adam Sotona) Date: Fri, 23 Sep 2022 12:45:05 +0000 Subject: RFR: Classfile API Proposal to add CodeBuilder.CatchBuilder::catchingMulti Message-ID: Hi, In https://github.com/openjdk/jdk-sandbox/pull/37 I?m proposing to add method: catchingMulti(List exceptionTypes, Consumer catchHandler); to CodeBuilder.CatchBuilder The method creates multiple records into the exception table for the same handler. Thanks, Adam -------------- next part -------------- An HTML attachment was scrubbed... URL: