下面列出了org.objectweb.asm.Opcodes# PUTFIELD 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Redirect(method = "tick",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/block/entity/AbstractFurnaceBlockEntity;burnTime:I",
opcode = Opcodes.PUTFIELD
),
slice = @Slice(
from = @At(
value = "INVOKE",
target = "Lnet/minecraft/block/entity/AbstractFurnaceBlockEntity;isBurning()Z",
opcode = 1
),
to = @At(
value = "FIELD",
target = "Lnet/minecraft/block/entity/AbstractFurnaceBlockEntity;world:Lnet/minecraft/world/World;",
opcode = Opcodes.GETFIELD,
ordinal = 0
)
)
)
private void realTimeImpl$adjustForRealTimeBurnTime(final AbstractFurnaceBlockEntity self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) this.getWorld()).realTimeBridge$getRealTimeTicks();
this.burnTime = Math.max(0, this.burnTime - Math.max(1, ticks - 1));
}
@Override
public MethodNode generate() {
if (this.mutable) {
this.targetField.access &= ~Opcodes.ACC_FINAL;
}
int stackSpace = this.targetIsStatic ? 0 : 1; // Stack space for "this"
int maxLocals = stackSpace + this.targetType.getSize();
int maxStack = stackSpace + this.targetType.getSize();
MethodNode method = this.createMethod(maxLocals, maxStack);
if (!this.targetIsStatic) {
method.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0));
}
method.instructions.add(new VarInsnNode(this.targetType.getOpcode(Opcodes.ILOAD), stackSpace));
int opcode = this.targetIsStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD;
method.instructions.add(new FieldInsnNode(opcode, this.info.getClassNode().name, this.targetField.name, this.targetField.desc));
method.instructions.add(new InsnNode(Opcodes.RETURN));
return method;
}
@Override
public void visitFieldInsn(int opcode,
String owner,
String name,
String desc) {
if (opcode == Opcodes.PUTFIELD && parameterLoadState == ParameterLoadState.LOADED_THIS_AND_PARAMETER
&& owner.equals(slashedClassName) && name.startsWith("this$")) {
// the field that has name starts with "this$" is generated for non-static inner class
// https://sourceforge.net/p/findbugs/bugs/1015/
mBuilder.setVariableIsSynthetic(parameterForLoadState);
}
fieldInstructionCount++;
if (isAccessMethod && this.accessOwner == null) {
this.accessOwner = owner;
this.accessName = name;
this.accessDesc = desc;
this.accessIsStatic = opcode == Opcodes.GETSTATIC || opcode == Opcodes.PUTSTATIC;
this.accessForField = true;
}
visitSomeInsn();
}
/**
* @param opcode
* @param owner
* @param name
* @param desc
* @param s
*/
static void handleFieldInsn ( int opcode, String owner, String name, String desc, JVMStackState s ) {
switch ( opcode ) {
case Opcodes.GETFIELD:
Object tgt = s.pop();
if ( log.isTraceEnabled() ) {
log.trace("From " + tgt); //$NON-NLS-1$
}
case Opcodes.GETSTATIC:
// this can be more specific
if ( log.isTraceEnabled() ) {
log.trace("Load field " + name + " (" + desc + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
s.push(new FieldReference(DotName.createSimple(owner.replace('/', '.')), name, Type.getType(desc), true));
break;
case Opcodes.PUTFIELD:
s.pop();
s.pop();
break;
case Opcodes.PUTSTATIC:
s.pop();
break;
default:
log.warn("Unsupported opcode " + opcode); //$NON-NLS-1$
}
}
@Override
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
switch (opcode) {
case Opcodes.GETSTATIC:
getstatic(owner, name, descriptor);
break;
case Opcodes.PUTSTATIC:
putstatic(owner, name, descriptor);
break;
case Opcodes.GETFIELD:
getfield(owner, name, descriptor);
break;
case Opcodes.PUTFIELD:
putfield(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
}
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
super.visitFieldInsn(opcode, owner, name, desc);
if (!instrumentationActions.trackFieldAssignments) {
return;
}
if (Opcodes.PUTFIELD != opcode && Opcodes.PUTSTATIC != opcode) {
// Only track field state and name at stores (assignments).
return;
}
for (AccessedField accessedField : accessedFields) {
if (accessedField.name.equals(name)) {
instrumentToTrackFieldState(accessedField, lineNumber);
break;
}
}
}
@Override
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
switch (opcode) {
case Opcodes.GETSTATIC:
getstatic(owner, name, descriptor);
break;
case Opcodes.PUTSTATIC:
putstatic(owner, name, descriptor);
break;
case Opcodes.GETFIELD:
getfield(owner, name, descriptor);
break;
case Opcodes.PUTFIELD:
putfield(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
}
}
@Redirect(
method = "tickNetherPortalCooldown",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/server/network/ServerPlayerEntity;netherPortalCooldown:I",
opcode = Opcodes.PUTFIELD
)
)
private void realTimeImpl$adjustForRealTimePortalCooldown(final ServerPlayerEntity self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) this.world).realTimeBridge$getRealTimeTicks();
// The initially apparent function of timeUntilPortal is a cooldown for
// nether portals. However, there is a much more important use:
// preventing players from being immediately sent back to the other end
// of the portal. Since it only checks timeUntilPortal to determine
// whether the player was just in a portal, if timeUntilPortal gets set
// to 0, it assumes the player left and reentered the portal (see
// Entity.setPortal()). To prevent this, "snag" the value of
// timeUntilPortal at 1. If setPortal() does not reset it (the player
// exits the portal), modifier will become 0, indicating that it is
// OK to teleport the player.
this.netherPortalCooldown = Math.max(modifier > 0 ? 1 : 0, this.netherPortalCooldown - ticks);
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
switch (opcode) {
case Opcodes.GETSTATIC:
case Opcodes.GETFIELD:
invokeBeforeSharedVariableRead();
break;
case Opcodes.PUTSTATIC:
case Opcodes.PUTFIELD:
invokeBeforeSharedVariableWrite();
break;
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Redirect(
method = "update",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;tickCounter:I",
opcode = Opcodes.PUTFIELD
)
)
private void realTimeImpl$adjustForRealTimeDiggingTime(final ServerPlayerInteractionManager self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) world.getServer()).realTimeBridge$getRealTimeTicks();
this.tickCounter += ticks;
}
@Redirect(
method = "tick",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;messageCooldown:I",
opcode = Opcodes.PUTFIELD,
ordinal = 0
)
)
private void realTimeImpl$adjustForRealTimeChatSpamCheck(final ServerPlayNetworkHandler self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) this.server).realTimeBridge$getRealTimeTicks();
this.messageCooldown = Math.max(0, this.messageCooldown - ticks);
}
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
if (opcode == Opcodes.PUTFIELD && LineNumberReader.this.name.equals(owner)
&& !lines.containsKey(name) && line != -1) {
lines.put(name, line);
}
}
@Redirect(
method = "tickNewAi",
at = @At(
value = "FIELD",
target = "Lnet/minecraft/entity/mob/MobEntity;despawnCounter:I",
opcode = Opcodes.PUTFIELD
)
)
private void realTimeImpl$adjustForRealTimeEntityDespawnAge(final MobEntity self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) self.getEntityWorld()).realTimeBridge$getRealTimeTicks();
this.despawnCounter += ticks;
}
@Redirect(method = "tick",
at = @At(value = "FIELD", target = "Lnet/minecraft/entity/ItemEntity;pickupDelay:I", opcode = Opcodes.PUTFIELD, ordinal = 0))
private void realTimeImpl$adjustForRealTimePickupDelay(final ItemEntity self, final int modifier) {
final int ticks = (int) ((RealTimeTrackingBridge) self.getEntityWorld()).realTimeBridge$getRealTimeTicks();
this.pickupDelay = Math.max(0, this.pickupDelay - ticks);
}
@Inject(method = "render", at = @At(value = "FIELD", opcode = Opcodes.PUTFIELD, target = "Lnet/minecraft/client/gui/screen/SplashScreen;applyCompleteTime:J"))
private void onResourceReloadComplete(MatrixStack matrixStack, int mouseX, int mouseY, float delta, CallbackInfo ci) {
ConnectionInfo.protocol.setup(true);
ConnectionInfo.stopReloadingResources();
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
if (DEBUG) {
System.out.println(
"Visit field access : " + owner + ":" + name + ":" + desc + ":" + isStatic);
}
AccessRight accessRight;
if (!owner.equals(visitedClassName)) {
if (DEBUG) {
System.out.println(owner + ":" + name + " field access");
}
// we are accessing another object field, and at this point the visitor is not smart
// enough to know if has seen this class before or not so we must assume the field
// is *not* accessible from the $override class which lives in a different
// hierarchy and package.
// However, since we made all package-private and protected fields public, and it
// cannot be private since the visitedClassName is not the "owner", we can safely
// assume it's public.
accessRight = AccessRight.PUBLIC;
} else {
// check the field access bits.
FieldNode fieldNode = getFieldByName(name);
if (fieldNode == null) {
// If this is an inherited field, we might not have had access to the parent
// bytecode. In such a case, treat it as private.
accessRight = AccessRight.PACKAGE_PRIVATE;
} else {
accessRight = AccessRight.fromNodeAccess(fieldNode.access);
}
}
boolean handled = false;
switch (opcode) {
case Opcodes.PUTSTATIC:
case Opcodes.GETSTATIC:
handled = visitStaticFieldAccess(opcode, owner, name, desc, accessRight);
break;
case Opcodes.PUTFIELD:
case Opcodes.GETFIELD:
handled = visitFieldAccess(opcode, owner, name, desc, accessRight);
break;
default:
System.out.println("Unhandled field opcode " + opcode);
}
if (!handled) {
super.visitFieldInsn(opcode, owner, name, desc);
}
}
/**
* Visits an instance field access. The field could be of the visited class or it could be
* an accessible field from the class being visited (unless it's private).
* <p>
* For private instance fields, the access instruction is rewritten to calls to reflection
* to access the fields value:
* <p>
* Pseudo code for Get:
* <code>
* value = $instance.fieldName;
* </code>
* becomes:
* <code>
* value = (unbox)$package/AndroidInstantRuntime.getPrivateField($instance, $fieldName);
* </code>
* <p>
* Pseudo code for Set:
* <code>
* $instance.fieldName = value;
* </code>
* becomes:
* <code>
* $package/AndroidInstantRuntime.setPrivateField($instance, value, $fieldName);
* </code>
*
*
* @param opcode the field access opcode, can only be {@link Opcodes#PUTFIELD} or
* {@link Opcodes#GETFIELD}
* @param owner the field declaring class
* @param name the field name
* @param desc the field type
* @param accessRight the {@link AccessRight} for the field.
* @return true if the field access was handled or false otherwise.
*/
private boolean visitFieldAccess(
int opcode, String owner, String name, String desc, AccessRight accessRight) {
// if the accessed field is anything but public, we must go through reflection.
boolean useReflection = accessRight != AccessRight.PUBLIC;
// if the accessed field is accessed from within a constructor, it might be a public
// final field that cannot be set by anything but the original constructor unless
// we use reflection.
if (!useReflection) {
useReflection = isConstructor && (owner.equals(visitedClassName));
}
if (useReflection) {
// we should make this more efficient, have a per field access type method
// for getting and setting field values.
switch (opcode) {
case Opcodes.GETFIELD:
// if (DEBUG) {
System.out.println("Get field");
// }
// push declaring class
visitLdcInsn(Type.getType("L" + owner + ";"));
// the instance of the owner class we are getting the field value from
// is on top of the stack. It could be "this"
push(name);
// Stack : <receiver>
// <field_declaring_class>
// <field_name>
invokeStatic(RUNTIME_TYPE,
Method.getMethod("Object getPrivateField(Object, Class, String)"));
// Stack : <field_value>
ByteCodeUtils.unbox(this, Type.getType(desc));
break;
case Opcodes.PUTFIELD:
// if (DEBUG) {
System.out.println("Set field");
// }
// the instance of the owner class we are getting the field value from
// is second on the stack. It could be "this"
// top of the stack is the new value we are trying to set, box it.
box(Type.getType(desc));
// push declaring class
visitLdcInsn(Type.getType("L" + owner + ";"));
// push the field name.
push(name);
// Stack : <receiver>
// <boxed_field_value>
// <field_declaring_class>
// <field_name>
invokeStatic(RUNTIME_TYPE,
Method.getMethod(
"void setPrivateField(Object, Object, Class, String)"));
break;
default:
throw new RuntimeException(
"VisitFieldAccess called with wrong opcode " + opcode);
}
return true;
}
// if this is a public field, no need to change anything we can access it from the
// $starkoverride class.
return false;
}
@Override
public void visitFieldInsn(int opcode, String owner, String internalName, String descriptor) {
TypePool.Resolution resolution = typePool.describe(owner.replace('/', '.'));
if (resolution.isResolved()) {
FieldList<FieldDescription.InDefinedShape> candidates = resolution.resolve().getDeclaredFields().filter(strict
? ElementMatchers.<FieldDescription>named(internalName).and(hasDescriptor(descriptor))
: ElementMatchers.<FieldDescription>failSafe(named(internalName).and(hasDescriptor(descriptor))));
if (!candidates.isEmpty()) {
Replacement.Binding binding = replacement.bind(instrumentedType,
instrumentedMethod,
candidates.getOnly(),
opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC);
if (binding.isBound()) {
TypeList.Generic parameters;
TypeDescription.Generic result;
switch (opcode) {
case Opcodes.PUTFIELD:
parameters = new TypeList.Generic.Explicit(candidates.getOnly().getDeclaringType(), candidates.getOnly().getType());
result = TypeDescription.Generic.VOID;
break;
case Opcodes.PUTSTATIC:
parameters = new TypeList.Generic.Explicit(candidates.getOnly().getType());
result = TypeDescription.Generic.VOID;
break;
case Opcodes.GETFIELD:
parameters = new TypeList.Generic.Explicit(candidates.getOnly().getDeclaringType());
result = candidates.getOnly().getType();
break;
case Opcodes.GETSTATIC:
parameters = new TypeList.Generic.Empty();
result = candidates.getOnly().getType();
break;
default:
throw new IllegalStateException("Unexpected opcode: " + opcode);
}
stackSizeBuffer = Math.max(stackSizeBuffer, binding.make(parameters, result, getFreeOffset())
.apply(new LocalVariableTracingMethodVisitor(mv), implementationContext)
.getMaximalSize() - result.getStackSize().getSize());
return;
}
} else if (strict) {
throw new IllegalStateException("Could not resolve " + owner.replace('/', '.')
+ "." + internalName + descriptor + " using " + typePool);
}
} else if (strict) {
throw new IllegalStateException("Could not resolve " + owner.replace('/', '.') + " using " + typePool);
}
super.visitFieldInsn(opcode, owner, internalName, descriptor);
}
public void visitFieldInsn(int opcode, String owner, String fieldName,
String desc) {
if (firstInstruction)
addInc();
if (logPointerChange && opcode == Opcodes.PUTFIELD
&& desc.charAt(0) == 'L') {
if (constructor && !doneSuperConstructor && name.equals(owner)
&& finalFields.contains(fieldName))
delayedFieldPointer.put(fieldName, desc);
else {
// instrument reference changes from
// putfield ...,obj,v' => ...
// to
// dup2 ...,obj,v' => ...,obj,v',obj,v'
// swap ...,obj,v',obj,v' => ...,obj,v',v',obj
// dup ...,obj,v',v',obj => ...,obj,v',v',obj,obj
// getfield ...,obj,v',v',obj,obj => ...,obj,v',v',obj,v
// invokespecial
// pointerchangelog(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
// ...,obj,v',v',obj,v => ...,obj,v'
// putfield ...,obj,v' =>
super.visitInsn(Opcodes.DUP2);
super.visitInsn(Opcodes.SWAP);
super.visitInsn(Opcodes.DUP);
super.visitFieldInsn(Opcodes.GETFIELD, owner, fieldName,
desc);
super.visitMethodInsn(Opcodes.INVOKESTATIC, name,
LOG_INTERNAL_POINTER_CHANGE,
POINTER_CHANGE_SIGNATURE);
}
} else if (logPointerChange && opcode == Opcodes.PUTSTATIC
&& desc.charAt(0) == 'L') {
// if (finalFields.contains(fieldName)) {
// // assume field is initially null
// super.visitInsn(Opcodes.DUP);
// } else {
// instrument reference changes from
// putstatic ...,v' => ...
// to
// dup ...,v' => ...,v',v'
// ldc owner.class ...,v',v' => ...,v',v',k
// getstatic ...,v',v',k => ...,v',v',k,v
// invokespecial
// staticpointerchangelog(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Object;)V
// ...,v',v',k,v => ...,v'
super.visitInsn(Opcodes.DUP);
super.visitLdcInsn(Type.getObjectType(owner));
super.visitFieldInsn(Opcodes.GETSTATIC, owner, fieldName, desc);
super.visitMethodInsn(Opcodes.INVOKESTATIC, name,
LOG_INTERNAL_STATIC_POINTER_CHANGE,
STATIC_POINTER_CHANGE_SIGNATURE);
// }
}
super.visitFieldInsn(opcode, owner, fieldName, desc);
}
public void addField(ByteCodeClass cls, int opcode, String owner, String name, String desc) {
if (cls.getOriginalClassName().equals(owner) && (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC)) {
cls.addWritableField(name);
}
addInstruction(new Field(opcode, owner, name, desc));
}