public static void renameFieldNode( String originalParentName, String originalFieldName, String originalFieldDesc, String newFieldParent, String newFieldName, String newFieldDesc) { for (ClassNode c : BytecodeViewer.getLoadedClasses()) { for (Object o : c.methods.toArray()) { MethodNode m = (MethodNode) o; for (AbstractInsnNode i : m.instructions.toArray()) { if (i instanceof FieldInsnNode) { FieldInsnNode field = (FieldInsnNode) i; if (field.owner.equals(originalParentName) && field.name.equals(originalFieldName) && field.desc.equals(originalFieldDesc)) { if (newFieldParent != null) field.owner = newFieldParent; if (newFieldName != null) field.name = newFieldName; if (newFieldDesc != null) field.desc = newFieldDesc; } } } } } }
public static void renameClassNode(final String oldName, final String newName) { for (ClassNode c : BytecodeViewer.getLoadedClasses()) { for (Object oo : c.innerClasses) { InnerClassNode innerClassNode = (InnerClassNode) oo; if (innerClassNode.innerName != null && innerClassNode.innerName.equals(oldName)) { innerClassNode.innerName = newName; } if (innerClassNode.name.equals(oldName)) { innerClassNode.name = newName; } if (innerClassNode.outerName != null && innerClassNode.outerName.equals(oldName)) { innerClassNode.outerName = newName; } } if (c.signature != null) c.signature = c.signature.replace(oldName, newName); if (c.superName.equals(oldName)) { c.superName = newName; } for (Object o : c.fields.toArray()) { FieldNode f = (FieldNode) o; f.desc = f.desc.replace(oldName, newName); } for (Object o : c.interfaces.toArray()) { String truxerLipton = (String) o; truxerLipton = truxerLipton.replace(oldName, newName); } for (Object o : c.methods.toArray()) { MethodNode m = (MethodNode) o; if (m.localVariables != null) { for (LocalVariableNode node : (List<LocalVariableNode>) m.localVariables) { node.desc = node.desc.replace(oldName, newName); } } if (m.signature != null) m.signature = m.signature.replace(oldName, newName); for (int i = 0; i < m.exceptions.size(); i++) { if (m.exceptions.get(i).equals(oldName)) m.exceptions.set(i, newName); } for (AbstractInsnNode i : m.instructions.toArray()) { if (i instanceof TypeInsnNode) { TypeInsnNode t = (TypeInsnNode) i; if (t.desc.equals(oldName)) { t.desc = newName; } } if (i instanceof MethodInsnNode) { MethodInsnNode mi = (MethodInsnNode) i; if (mi.owner.equals(oldName)) mi.owner = newName; mi.desc = mi.desc.replace(oldName, newName); } if (i instanceof FieldInsnNode) { FieldInsnNode fi = (FieldInsnNode) i; if (fi.owner.equals(oldName)) fi.owner = newName; fi.desc = fi.desc.replace(oldName, newName); } } } } }
@NotNull public static CapturedParamInfo findCapturedField( FieldInsnNode node, FieldRemapper fieldRemapper) { assert node.name.startsWith("$$$") : "Captured field template should start with $$$ prefix"; FieldInsnNode fin = new FieldInsnNode(node.getOpcode(), node.owner, node.name.substring(3), node.desc); CapturedParamInfo field = fieldRemapper.findField(fin); if (field == null) { throw new IllegalStateException( "Couldn't find captured field " + node.owner + "." + node.name + " in " + fieldRemapper.getLambdaInternalName()); } return field; }
private List<CapturedParamInfo> extractParametersMappingAndPatchConstructor( @NotNull MethodNode constructor, @NotNull ParametersBuilder capturedParamBuilder, @NotNull ParametersBuilder constructorParamBuilder, @NotNull final AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentFieldRemapper) { CapturedParamOwner owner = new CapturedParamOwner() { @Override public Type getType() { return Type.getObjectType(anonymousObjectGen.getOwnerInternalName()); } }; Set<LambdaInfo> capturedLambdas = new LinkedHashSet<LambdaInfo>(); // captured var of inlined parameter List<CapturedParamInfo> constructorAdditionalFakeParams = new ArrayList<CapturedParamInfo>(); Map<Integer, LambdaInfo> indexToLambda = anonymousObjectGen.getLambdasToInline(); Set<Integer> capturedParams = new HashSet<Integer>(); // load captured parameters and patch instruction list (NB: there is also could be object // fields) AbstractInsnNode cur = constructor.instructions.getFirst(); while (cur != null) { if (cur instanceof FieldInsnNode) { FieldInsnNode fieldNode = (FieldInsnNode) cur; String fieldName = fieldNode.name; if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldName)) { boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode; boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode; if (isPrevPrevVarNode) { VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious(); if (node.var == 0) { VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious(); int varIndex = previous.var; LambdaInfo lambdaInfo = indexToLambda.get(varIndex); String newFieldName = isThis0(fieldName) && shouldRenameThis0(parentFieldRemapper, indexToLambda.values()) ? getNewFieldName(fieldName, true) : fieldName; CapturedParamInfo info = capturedParamBuilder.addCapturedParam( owner, fieldName, newFieldName, Type.getType(fieldNode.desc), lambdaInfo != null, null); if (lambdaInfo != null) { info.setLambda(lambdaInfo); capturedLambdas.add(lambdaInfo); } constructorAdditionalFakeParams.add(info); capturedParams.add(varIndex); constructor.instructions.remove(previous.getPrevious()); constructor.instructions.remove(previous); AbstractInsnNode temp = cur; cur = cur.getNext(); constructor.instructions.remove(temp); continue; } } } } cur = cur.getNext(); } constructorParamBuilder.addThis(oldObjectType, false); String constructorDesc = anonymousObjectGen.getConstructorDesc(); if (constructorDesc == null) { // in case of anonymous object with empty closure constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE); } Type[] types = Type.getArgumentTypes(constructorDesc); for (Type type : types) { LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex()); ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null); parameterInfo.setLambda(info); if (capturedParams.contains(parameterInfo.getIndex())) { parameterInfo.setCaptured(true); } else { // otherwise it's super constructor parameter } } // For all inlined lambdas add their captured parameters // TODO: some of such parameters could be skipped - we should perform additional analysis Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); // captured var of inlined parameter List<CapturedParamDesc> allRecapturedParameters = new ArrayList<CapturedParamDesc>(); boolean addCapturedNotAddOuter = parentFieldRemapper.isRoot() || (parentFieldRemapper instanceof InlinedLambdaRemapper && parentFieldRemapper.getParent().isRoot()); Map<String, CapturedParamInfo> alreadyAdded = new HashMap<String, CapturedParamInfo>(); for (LambdaInfo info : capturedLambdas) { if (addCapturedNotAddOuter) { for (CapturedParamDesc desc : info.getCapturedVars()) { String key = desc.getFieldName() + "$$$" + desc.getType().getClassName(); CapturedParamInfo alreadyAddedParam = alreadyAdded.get(key); CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam( desc, alreadyAddedParam != null ? alreadyAddedParam.getNewFieldName() : getNewFieldName(desc.getFieldName(), false)); StackValue composed = StackValue.field( desc.getType(), oldObjectType, /*TODO owner type*/ recapturedParamInfo.getNewFieldName(), false, StackValue.LOCAL_0); recapturedParamInfo.setRemapValue(composed); allRecapturedParameters.add(desc); constructorParamBuilder .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()) .setRemapValue(composed); if (alreadyAddedParam != null) { recapturedParamInfo.setSkipInConstructor(true); } if (isThis0(desc.getFieldName())) { alreadyAdded.put(key, recapturedParamInfo); } } } capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info); } if (parentFieldRemapper instanceof InlinedLambdaRemapper && !capturedLambdas.isEmpty() && !addCapturedNotAddOuter) { // lambda with non InlinedLambdaRemapper already have outer FieldRemapper parent = parentFieldRemapper.getParent(); assert parent instanceof RegeneratedLambdaFieldRemapper; final Type ownerType = Type.getObjectType(parent.getLambdaInternalName()); CapturedParamDesc desc = new CapturedParamDesc( new CapturedParamOwner() { @Override public Type getType() { return ownerType; } }, InlineCodegenUtil.THIS, ownerType); CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam( desc, InlineCodegenUtil.THIS$0 /*outer lambda/object*/); StackValue composed = StackValue.LOCAL_0; recapturedParamInfo.setRemapValue(composed); allRecapturedParameters.add(desc); constructorParamBuilder .addCapturedParam(recapturedParamInfo, recapturedParamInfo.getNewFieldName()) .setRemapValue(composed); } anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters); anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline); return constructorAdditionalFakeParams; }
protected String printFieldInsnNode(FieldInsnNode fin, ListIterator<?> it) { String desc = Type.getType(fin.desc).getClassName(); if (desc == null || desc.equals("null")) desc = fin.desc; return nameOpcode(fin.opcode()) + " " + fin.owner + "." + fin.name + ":" + desc; }