Skip to content

Commit

Permalink
Add inline processor for better mod mixin compatibility
Browse files Browse the repository at this point in the history
Cleanup unused code in gradle source.
  • Loading branch information
IzzelAliz committed Feb 4, 2024
1 parent db09e93 commit 19def4b
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 171 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.izzel.arclight.common.mixin.core.world.level.block;

import io.izzel.arclight.common.bridge.core.world.level.block.FireBlockBridge;
import io.izzel.arclight.common.mod.mixins.annotation.Inline;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -39,6 +40,7 @@ public abstract class FireBlockMixin extends BaseFireBlockMixin implements FireB
@Shadow @Final private Object2IntMap<net.minecraft.world.level.block.Block> burnOdds;
// @formatter:on

@Inline
@Redirect(method = "tick", at = @At(value = "INVOKE", ordinal = 1, target = "Lnet/minecraft/server/level/ServerLevel;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z"))
public boolean arclight$fireSpread(ServerLevel world, BlockPos mutablePos, BlockState newState, int flags,
BlockState state, ServerLevel worldIn, BlockPos pos) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import io.izzel.arclight.api.ArclightPlatform;
import io.izzel.arclight.common.mod.mixins.CreateConstructorProcessor;
import io.izzel.arclight.common.mod.mixins.InlineProcessor;
import io.izzel.arclight.common.mod.mixins.MixinProcessor;
import io.izzel.arclight.common.mod.mixins.RenameIntoProcessor;
import io.izzel.arclight.common.mod.mixins.TransformAccessProcessor;
Expand All @@ -22,7 +23,8 @@ public class ArclightMixinPlugin implements IMixinConfigPlugin, IEnvironmentToke
private final List<MixinProcessor> postProcessors = List.of(
new RenameIntoProcessor(),
new TransformAccessProcessor(),
new CreateConstructorProcessor()
new CreateConstructorProcessor(),
new InlineProcessor()
);

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package io.izzel.arclight.common.mod.mixins;

import io.izzel.arclight.common.mod.mixins.annotation.Inline;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
import org.spongepowered.asm.util.Locals;

import java.lang.reflect.Modifier;

public class InlineProcessor implements MixinProcessor {

private static final String TYPE = Type.getDescriptor(Inline.class);
private static final String MERGED = Type.getDescriptor(Inline.Merged.class);

@Override
public void accept(String className, ClassNode classNode, IMixinInfo mixinInfo) {
for (var methodNode : classNode.methods) {
if (methodNode.invisibleAnnotations != null) {
for (var ann : methodNode.invisibleAnnotations) {
if (ann.desc.equals(TYPE)) {
new MethodInliner(methodNode, classNode).accept();
ann.desc = MERGED;
}
}
}
}
}

private record MethodInliner(MethodNode target, ClassNode callerClass) {

public void accept() {
for (var node : callerClass.methods) {
this.accept(node);
}
}

public void accept(MethodNode node) {
for (var iterator = node.instructions.iterator(); iterator.hasNext(); ) {
var insn = iterator.next();
if (insn instanceof MethodInsnNode method) {
if (method.owner.equals(callerClass.name) && method.name.equals(target.name) && method.desc.equals(target.desc)) {
var buf = new MethodNode(Opcodes.ASM9, node.access, node.name, node.desc, node.signature, node.exceptions.toArray(String[]::new));
target.accept(new RemappingVisitor(Opcodes.ASM9, buf, Locals.getLocalsAt(callerClass, node, insn, Locals.Settings.DEFAULT)));
node.instructions.insertBefore(insn, buf.instructions);
node.tryCatchBlocks.addAll(buf.tryCatchBlocks);
node.localVariables.addAll(buf.localVariables);
node.maxLocals = Math.max(node.maxLocals, buf.maxLocals);
node.maxStack = Math.max(node.maxStack, buf.maxStack);
iterator.remove();
}
}
}
}

protected class RemappingVisitor extends MethodVisitor {

private final Label end = new Label();
private final Type returnType = Type.getReturnType(target.desc);

private final LocalVariableNode[] locals;
private final int localOffset, localCount;

protected RemappingVisitor(int api, MethodVisitor mv, LocalVariableNode[] locals) {
super(api, mv);
this.locals = locals;
var offset = 0;
var count = 0;
for (int i = 0; i < locals.length; i++) {
var local = locals[i];
if (local != null) {
offset = Math.max(offset, local.index + Type.getType(local.desc).getSize());
count = i + 1;
}
}
this.localOffset = offset;
this.localCount = count;
this.visitStart();
}

protected void visitStart() {
var offset = Modifier.isStatic(target.access) ? 0 : 1;
var args = Type.getArgumentTypes(target.desc);
for (var i = args.length - 1; i >= 0; i--) {
super.visitVarInsn(args[i].getOpcode(Opcodes.ISTORE), localOffset + i + offset);
}
if (offset > 0) {
super.visitVarInsn(Opcodes.ASTORE, localOffset);
}
}

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
if (owner.equals(callerClass.name) && name.equals(target.name) && descriptor.equals(target.desc)) {
throw new IllegalStateException("Inlining recursive method");
}
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

@Override
public void visitVarInsn(int opcode, int varIndex) {
super.visitVarInsn(opcode, localOffset + varIndex);
}

@Override
public void visitIincInsn(int varIndex, int increment) {
super.visitIincInsn(localOffset + varIndex, increment);
}

@Override
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
super.visitLocalVariable(name, descriptor, signature, start, end, localOffset + index);
}

@Override
public void visitMaxs(int maxStack, int maxLocals) {
super.visitMaxs(maxStack, localOffset + maxLocals);
}

@Override
public void visitInsn(int opcode) {
if (opcode == returnType.getOpcode(Opcodes.IRETURN)) {
super.visitJumpInsn(Opcodes.GOTO, this.end);
} else {
super.visitInsn(opcode);
}
}

@Override
public void visitEnd() {
super.visitLabel(this.end);
Object[] locals = new Object[localCount];
for (int i = 0; i < localCount; i++) {
var local = this.locals[i];
if (local == null) {
locals[i] = null;
} else {
var type = Type.getType(local.desc);
Object v = switch (type.getSort()) {
case Type.BOOLEAN, Type.CHAR, Type.BYTE, Type.SHORT, Type.INT -> Opcodes.INTEGER;
case Type.FLOAT -> Opcodes.FLOAT;
case Type.LONG -> Opcodes.LONG;
case Type.DOUBLE -> Opcodes.DOUBLE;
case Type.ARRAY, Type.OBJECT -> type.getInternalName();
default -> Opcodes.TOP;
};
locals[i] = v;
}
}
super.visitFrame(Opcodes.F_FULL, localCount, locals, 0, null);
super.visitEnd();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package io.izzel.arclight.common.mod.mixins.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface Inline {

@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
@interface Merged {
}
}
2 changes: 1 addition & 1 deletion arclight-forge-bootstrap/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ dependencies {
implementation 'org.apache.logging.log4j:log4j-api:2.17.2'
implementation 'org.apache.logging.log4j:log4j-core:2.17.2'
implementation 'org.jetbrains:annotations:23.0.0'
implementation 'org.spongepowered:mixin:0.8.3'
implementation 'org.spongepowered:mixin:0.8.5'
implementation 'org.apache.logging.log4j:log4j-jul:2.17.2'
implementation "net.minecraftforge:fmlloader:${minecraftVersion}-${forgeVersion}"
for (def lib : embedLibs) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class ArclightExtension {
private String forgeVersion
private File accessTransformer
private File extraMapping
private List<String> installerInfo = new ArrayList<>()
private final MappingsConfiguration mappingsConfiguration = new MappingsConfiguration()

ArclightExtension(Project project) {
Expand Down Expand Up @@ -41,14 +40,6 @@ class ArclightExtension {
this.accessTransformer = accessTransformer
}

List<String> getInstallerInfo() {
return installerInfo
}

void setInstallerInfo(List<String> installerInfo) {
this.installerInfo = installerInfo
}

String getForgeVersion() {
return forgeVersion
}
Expand Down
Loading

0 comments on commit 19def4b

Please sign in to comment.