Skip to content

Enable ClassRule-based JVM transform selection - #8

Open
Creeper-ops wants to merge 2 commits into
Fadouse:mainfrom
Creeper-ops:class-rule-transform-selection
Open

Enable ClassRule-based JVM transform selection#8
Creeper-ops wants to merge 2 commits into
Fadouse:mainfrom
Creeper-ops:class-rule-transform-selection

Conversation

@Creeper-ops

Copy link
Copy Markdown
Contributor

Summary

This PR makes ClassRule effective for JVM transform selection instead of only being parsed and stored.

It adds class-scoped transform resolution, wires the pipeline to schedule transforms enabled by either top-level config or matching rules, and applies the same effective class predicate to scoped global-preparation paths such as renamer and keyDispatch.

Changes

  • Add ordered ClassRule resolution:
    • top-level transforms are the default
    • matching rules are evaluated in file order
    • later matching rules override earlier transform entries by transform ID
    • exclude: true disables JVM transforms for the matched class
  • Preserve original class names in PipelineContext so rule matching remains stable after renaming.
  • Make renamer only rename selected classes while preserving excluded names as occupied names.
  • Fix main-entry verification so excluded/unmatched main owners are not required to be renamed.
  • Make keyDispatch respect scoped rules during descriptor preparation.
  • Prevent keyDispatch descriptor changes for targets reached from excluded callers, including direct calls and invokedynamic/lambda handles.
  • Document ClassRule semantics and matching behavior.
  • Add ClassRuleIntegrationTest coverage for rule-only scheduling, exclude behavior, rule ordering, inner-class matching, renamer reservation, main-entry behavior, and keyDispatch inbound boundaries.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b36c6160e5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.toList();
List<L1Class> renameClasses = remapClasses;
List<L1Class> renameClasses = remapClasses.stream()
.filter(clazz -> pctx.isTransformEnabledForClass(ID, clazz))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve override names when ancestors are out of scope

When a rule enables renamer for a subclass but leaves its application superclass or interface unrenamed, this filter puts only the subclass in renameClasses. buildMemberMap() can still union the subclass method with the excluded ancestor via unionAppAncestors(), but it only emits a member mapping for classes in renameClasses, so the subclass override is renamed while the ancestor method keeps its original name. In that scoped-renamer inheritance case, virtual dispatch through the excluded base/interface no longer reaches the subclass override.

Useful? React with 👍 / 👎.

Map<String, Integer> lambdaIndexes = lambdaKeyIndexes(pctx);
Set<String> unkeyedInboundTargets = unkeyedInboundTargets(pctx);
for (L1Class clazz : pctx.classMap().values()) {
if (!pctx.isTransformEnabledForClass(ID, clazz)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep keyed descriptors aligned across app overrides

With keyDispatch scoped to only part of an application hierarchy, this filter allows an enabled subclass override to receive a hidden long descriptor while an excluded application superclass/interface method with the same slot remains unchanged. Because overridesExternalMethod() only protects external ABI, not excluded in-jar ancestors, a selected Sub.m() can become m(...,J) and stop overriding excluded Base.m(), so virtual calls through the base type dispatch to the wrong implementation.

Useful? React with 👍 / 👎.

for (L1Class clazz : input.classes()) {
ctx.setCurrentL1Class(clazz);
ctx.setCurrentL1Method(null);
if (!ctx.isTransformEnabledForClass(pass.id(), clazz)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid CFF table setup for excluded classes

This per-class gate is not enough for controlFlowFlattening: the first enabled class still calls ControlFlowFlatteningPass.transformClass(), and prepareClassKeyTables() builds metadata from all pctx.classMap().values() with application code before ensureClassKeyTable() adds synthetic fields and <clinit> initialization. As a result, a config that enables CFF only for pkg.Target can still mutate excluded or unmatched application classes during class-key-table preparation.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant