Skip to content

Instantly share code, notes, and snippets.

@Daomephsta
Created June 11, 2023 09:45
Show Gist options
  • Save Daomephsta/df5f331f915a089c7d5cf527af6ac894 to your computer and use it in GitHub Desktop.
Save Daomephsta/df5f331f915a089c7d5cf527af6ac894 to your computer and use it in GitHub Desktop.
Transaction debugging
package io.github.daomephsta;
import java.lang.StackWalker.StackFrame;
import java.util.List;
public interface OriginAware
{
public List<StackFrame> silverfish_getOrigin();
}
package io.github.daomephsta.mixin;
import java.lang.StackWalker.StackFrame;
import java.util.Iterator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import io.github.daomephsta.OriginAware;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
import net.fabricmc.fabric.api.transfer.v1.transaction.TransactionContext;
import net.fabricmc.fabric.impl.transfer.transaction.TransactionManagerImpl;
@Mixin(TransactionManagerImpl.class)
public abstract class TransactionManagerImplMixin
{
@Shadow
public abstract TransactionContext getCurrentUnsafe();
@Inject(method = "openOuter",
at = @At(value = "NEW", target = "java.lang.IllegalStateException"))
private void silverfish_improveOuterTransactionError(CallbackInfoReturnable<Transaction> info)
{
var originAware = (OriginAware) getCurrentUnsafe();
var origin = new StringBuilder().append("Origin of current outer transaction\n");
for (Iterator<StackFrame> iter = originAware.silverfish_getOrigin().iterator(); iter.hasNext();)
{
StackFrame frame = iter.next();
origin.append("\tat ").append(frame);
if (iter.hasNext()) origin.append('\n');
}
System.err.println(origin);
}
}
package io.github.daomephsta.mixin;
import java.lang.StackWalker.Option;
import java.lang.StackWalker.StackFrame;
import java.util.List;
import java.util.stream.Stream;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import io.github.daomephsta.OriginAware;
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
@Mixin(targets = "net/fabricmc/fabric/impl/transfer/transaction/TransactionManagerImpl$TransactionImpl")
public abstract class TransactionOriginTracer implements Transaction, OriginAware
{
@Unique
private @Final List<StackFrame> silverfish_origin;
@Inject(method = "<init>", at = @At("TAIL"))
private void silverfish_traceOrigin(CallbackInfo info)
{
silverfish_origin = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
.walk(this::silverfish_originWalker);
}
private List<StackFrame> silverfish_originWalker(Stream<StackFrame> trace)
{
return trace
// Trim the head until it's the frame calling the constructor
.dropWhile(this::silverfish_trimHead)
.toList();
}
private boolean silverfish_trimHead(StackFrame frame)
{
return frame.getMethodName().contains("silverfish_traceOrigin") ||
frame.getMethodName().equals("<init>") &&
// Check the constructor is declared by the target or a supertype
frame.getDeclaringClass().isAssignableFrom(getClass());
}
@Override
public List<StackFrame> silverfish_getOrigin()
{
return silverfish_origin;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment