Skip to content

Add field write stripping with @Environment #1047

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Player3324
Copy link
Contributor

This extends field stripping with stripping the field write from initializers. Usually the initializer itself is benign and only broke on the assignment with NoSuchFieldError like

@Environment(EnvType.CLIENT)
private SomeType myField = null;

This PR should resolve most incompatibilities introduced by #860 - which made field stripping work in the first place. If an initializer ran successfully before that PR, it'd work again with this PR unless there is a read to a stripped field involved. Initializers that accessed missing types or other elements were and remain unsupported.

Mods still shouldn't use @Environment over proper environment specific code separation, ideally with split client/common/server source sets.

@cputnam-a11y
Copy link

cputnam-a11y commented May 3, 2025

Does this mean that method calls and other related references may come also in the future?

}

@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
if (stripMethods.contains(name + descriptor)) return null;
return super.visitMethod(access, name, descriptor, signature, exceptions);
if (stripMethods.contains(name + descriptor)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

More of a problem with the existing code than your changes but using fresh strings as hashtable keys is very slow because each one needs a fresh hashcode computation. Should be a record instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we don't have records in this world :D

I'll probably overhaul the whole thing after the extension merge

Copy link
Contributor

Choose a reason for hiding this comment

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

It can equally be a small regular class with a proper equals and hashCode.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Of course, but it also touches at least 3 classes. For best performance it'd ideally be a specialized dual key set that can be queried without allocating anything.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds overkill, allocations are more or less free and this is especially elidable by the JIT. Point is allocating a class which holds both strings is far far cheaper than concatenation and a subsequent uncached hashCode computation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They are almost always latin 1 strings of short length, I don't see how that'd dominate the allocation and associated cleanup.

Copy link
Contributor

Choose a reason for hiding this comment

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

Method descriptors can be very long. Regardless I'm not saying it's necessarily a real performance issue, just a code smell IMO

MethodVisitor ret = super.visitMethod(access, name, descriptor, signature, exceptions);

// strip field writes from static init and constructor
if (!stripFields.isEmpty() && (name.equals("<clinit>") || name.equals("<init>"))) {
Copy link
Contributor

@LlamaLad7 LlamaLad7 May 3, 2025

Choose a reason for hiding this comment

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

This will strip writes to other instances, will strip non-ctor writes to instance fields, but only if they're in <clinit>, and vice versa. Seems confusing and is mostly avoidable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure that's a problem? It essentially pretends the field isn't there at all and there can't be both a static and non-static version of the same name+desc pair

Copy link
Contributor

Choose a reason for hiding this comment

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

It seems odd for a non-static write to be stripped from <clinit> but not from any other non-ctor methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not too concerned about other methods since they aren't being populated by the inline field initializer syntax and scanning everything might be a bit too expensive. Restricting <clinit> to PUTSTATIC and <init> to PUTFIELD would be more effort while potentially leaving more "fixable" references that'd throw.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think stripping PUTSTATIC from clinit and PUTFIELD from init would be very little effort and make far more sense.

@Player3324
Copy link
Contributor Author

Does this mean that method calls and other related references may come also in the future?

Unlikely, this would be too much effort to implement and potentially too costly at runtime. The latter however might not matter much after implementing caching the final bytecode.

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.

3 participants