protected byte[] transformClass(byte[] bytes, String clssname) { InputStream is = getClass().getResourceAsStream("/" + clssname.replace('.', '/') + ".class"); ClassReader orig = null; try { ClassReader crRepl = new ClassReader(is); ClassNode cnRepl = new ClassNode(Opcodes.ASM4); crRepl.accept(cnRepl, ClassReader.SKIP_FRAMES); ClassReader crOrig = new ClassReader(bytes); ClassNode cnOrig = new ClassNode(Opcodes.ASM4); crOrig.accept(cnOrig, ClassReader.SKIP_FRAMES); for (Object ofnRepl : cnRepl.fields) { FieldNode fnRepl = (FieldNode) ofnRepl; if (hasReplaceAnnotation(fnRepl.visibleAnnotations)) { FieldNode fnOrig = findField(cnOrig.fields, fnRepl); if (fnOrig != null) { cnOrig.fields.remove(fnOrig); cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } else if (hasAddAnnotation(fnRepl.visibleAnnotations)) { cnOrig.fields.add(cnOrig.fields.size(), scrubField(cnOrig, cnRepl, fnRepl)); } } for (Object omnRepl : cnRepl.methods) { MethodNode mnRepl = (MethodNode) omnRepl; if (hasReplaceAnnotation(mnRepl.visibleAnnotations)) { MethodNode mnOrig = findMethod(cnOrig.methods, mnRepl); if (mnOrig != null) { cnOrig.methods.remove(mnOrig); cnOrig.methods.add(cnOrig.methods.size(), scrubMethod(cnOrig, cnRepl, mnRepl)); } } else if (hasAddAnnotation(mnRepl.visibleAnnotations)) { cnOrig.methods.add(cnOrig.methods.size() + 1, scrubMethod(cnOrig, cnRepl, mnRepl)); } } ClassWriter cwNew = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); cnOrig.accept(cwNew); return cwNew.toByteArray(); } catch (IOException e) { e.printStackTrace(); // To change body of catch statement use File | Settings | File // Templates. } return bytes; }
public Pair<ClassRepr, Set<UsageRepr.Usage>> analyze(final int fileName, final ClassReader cr) { final ClassCrawler visitor = new ClassCrawler(fileName); cr.accept(visitor, 0); return visitor.getResult(); }
public static Class<?> malform(Class<?> type) throws Exception { ClassReader classReader = new ClassReader(type.getName()); ClassWriter classWriter = new ClassWriter(classReader, 0); classReader.accept(new SignatureMalformer(classWriter), 0); ClassLoader classLoader = new ByteArrayClassLoader( null, Collections.singletonMap(type.getName(), classWriter.toByteArray()), null, ByteArrayClassLoader.PersistenceHandler.MANIFEST, PackageDefinitionStrategy.NoOp.INSTANCE); return classLoader.loadClass(type.getName()); }
/** * Construct a proxy generator. This generator is used when we need to create a proxy object for a * class or an interface given a map of closures. * * @param closureMap the delegates implementations * @param superClass corresponding to the superclass class visitor * @param interfaces extra interfaces the proxy should implement * @param proxyLoader the class loader which should be used to load the generated proxy * @param delegateClass if not null, generate a delegate field with the corresponding class * @param emptyBody if set to true, the unimplemented abstract methods will receive an empty body * instead of throwing an {@link UnsupportedOperationException}. */ public ProxyGeneratorAdapter( final Map<Object, Object> closureMap, final Class superClass, final Class[] interfaces, final ClassLoader proxyLoader, final boolean emptyBody, final Class delegateClass) { super(new ClassWriter(0)); this.visitedMethods = new LinkedHashSet<Object>(); this.delegatedClosures = closureMap.isEmpty() ? EMPTY_DELEGATECLOSURE_MAP : new HashMap<String, Boolean>(); boolean wildcard = false; for (Map.Entry<Object, Object> entry : closureMap.entrySet()) { String name = entry.getKey().toString(); if ("*".equals(name)) { wildcard = true; } this.delegatedClosures.put(name, Boolean.FALSE); } this.hasWildcard = wildcard; // if we have to delegate to another object, generate the appropriate delegate field // and collect the name of the methods for which delegation is active this.generateDelegateField = delegateClass != null; this.objectDelegateMethods = generateDelegateField ? createDelegateMethodList(delegateClass, interfaces) : EMPTY_STRING_SET; this.delegateClass = delegateClass; // a proxy is supposed to be a concrete class, so it cannot extend an interface. // If the provided superclass is an interface, then we replace the superclass with Object // and add this interface to the list of implemented interfaces boolean isSuperClassAnInterface = superClass.isInterface(); this.superClass = isSuperClassAnInterface ? Object.class : superClass; // create the base list of classes which have possible methods to be overloaded this.classList = new LinkedList<Class>(); this.classList.add(superClass); if (generateDelegateField) { classList.add(delegateClass); } if (interfaces != null) { Collections.addAll(this.classList, interfaces); } this.proxyName = proxyName(); this.loader = proxyLoader != null ? new InnerLoader(proxyLoader) : findClassLoader(superClass); this.emptyBody = emptyBody; // generate bytecode ClassWriter writer = (ClassWriter) cv; ClassReader cr = createClassVisitor(Object.class); cr.accept(this, 0); byte[] b = writer.toByteArray(); // CheckClassAdapter.verify(new ClassReader(b), true, new PrintWriter(System.err)); cachedClass = loader.defineClass(proxyName.replace('/', '.'), b); // cache no-arg constructor Class[] args = generateDelegateField ? new Class[] {Map.class, delegateClass} : new Class[] {Map.class}; Constructor constructor; try { constructor = cachedClass.getConstructor(args); } catch (NoSuchMethodException e) { constructor = null; } cachedNoArgConstructor = constructor; }
@NotNull public InlineResult doTransform( @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) { final List<InnerClassNode> innerClassNodes = new ArrayList<InnerClassNode>(); ClassBuilder classBuilder = createClassBuilder(); final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>(); reader.accept( new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { @Override public void visit( int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { InlineCodegenUtil.assertVersionNotGreaterThanJava6(version, name); super.visit(version, access, name, signature, superName, interfaces); } @Override public void visitInnerClass( @NotNull String name, String outerName, String innerName, int access) { innerClassNodes.add(new InnerClassNode(name, outerName, innerName, access)); } @Override public MethodVisitor visitMethod( int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { MethodNode node = new MethodNode(access, name, desc, signature, exceptions); if (name.equals("<init>")) { if (constructor != null) throw new RuntimeException( "Lambda, SAM or anonymous object should have only one constructor"); constructor = node; } else { methodsToTransform.add(node); } return node; } @Override public FieldVisitor visitField( int access, @NotNull String name, @NotNull String desc, String signature, Object value) { addUniqueField(name); if (InlineCodegenUtil.isCapturedFieldName(name)) { return null; } else { return super.visitField(access, name, desc, signature, value); } } @Override public void visitSource(String source, String debug) { sourceInfo = source; debugInfo = debug; } @Override public void visitEnd() {} }, ClassReader.SKIP_FRAMES); if (!inliningContext.isInliningLambda) { if (debugInfo != null && !debugInfo.isEmpty()) { sourceMapper = SourceMapper.Companion.createFromSmap(SMAPParser.parse(debugInfo)); } else { // seems we can't do any clever mapping cause we don't know any about original class name sourceMapper = IdenticalSourceMapper.INSTANCE; } if (sourceInfo != null && !InlineCodegenUtil.GENERATE_SMAP) { classBuilder.visitSource(sourceInfo, debugInfo); } } else { if (sourceInfo != null) { classBuilder.visitSource(sourceInfo, debugInfo); } sourceMapper = IdenticalSourceMapper.INSTANCE; } ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); List<CapturedParamInfo> additionalFakeParams = extractParametersMappingAndPatchConstructor( constructor, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper); List<MethodVisitor> deferringMethods = new ArrayList<MethodVisitor>(); for (MethodNode next : methodsToTransform) { MethodVisitor deferringVisitor = newMethod(classBuilder, next); InlineResult funResult = inlineMethodAndUpdateGlobalResult( anonymousObjectGen, parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false); Type returnType = Type.getReturnType(next.desc); if (!AsmUtil.isPrimitive(returnType)) { String oldFunReturnType = returnType.getInternalName(); String newFunReturnType = funResult.getChangedTypes().get(oldFunReturnType); if (newFunReturnType != null) { inliningContext.typeRemapper.addAdditionalMappings(oldFunReturnType, newFunReturnType); } } deferringMethods.add(deferringVisitor); } for (MethodVisitor method : deferringMethods) { method.visitEnd(); } generateConstructorAndFields( classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams); SourceMapper.Companion.flushToClassBuilder(sourceMapper, classBuilder); ClassVisitor visitor = classBuilder.getVisitor(); for (InnerClassNode node : innerClassNodes) { visitor.visitInnerClass(node.name, node.outerName, node.innerName, node.access); } writeOuterInfo(visitor); classBuilder.done(); anonymousObjectGen.setNewLambdaType(newLambdaType); return transformationResult; }
/** Index format : @see jd.gui.spi.Indexer */ @SuppressWarnings("unchecked") public void index(API api, Container.Entry entry, Indexes indexes) { // Cleaning sets... typeDeclarationSet.clear(); constructorDeclarationSet.clear(); methodDeclarationSet.clear(); fieldDeclarationSet.clear(); typeReferenceSet.clear(); constructorReferenceSet.clear(); methodReferenceSet.clear(); fieldReferenceSet.clear(); stringSet.clear(); superTypeNameSet.clear(); descriptorSet.clear(); try (InputStream inputStream = entry.getInputStream()) { // Index field, method, interfaces & super type ClassReader classReader = new ClassReader(inputStream); classReader.accept( classIndexer, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); // Index descriptors for (String descriptor : descriptorSet) { new SignatureReader(descriptor).accept(signatureIndexer); } // Index references char[] buffer = new char[classReader.getMaxStringLength()]; for (int i = classReader.getItemCount() - 1; i > 0; i--) { int startIndex = classReader.getItem(i); if (startIndex != 0) { int tag = classReader.readByte(startIndex - 1); switch (tag) { case 7: // CONSTANT_Class String className = classReader.readUTF8(startIndex, buffer); if (className.startsWith("[")) { new SignatureReader(className).acceptType(signatureIndexer); } else { typeReferenceSet.add(className); } break; case 8: // CONSTANT_String String str = classReader.readUTF8(startIndex, buffer); stringSet.add(str); break; case 9: // CONSTANT_Fieldref int nameAndTypeItem = classReader.readUnsignedShort(startIndex + 2); int nameAndTypeIndex = classReader.getItem(nameAndTypeItem); tag = classReader.readByte(nameAndTypeIndex - 1); if (tag == 12) { // CONSTANT_NameAndType String fieldName = classReader.readUTF8(nameAndTypeIndex, buffer); fieldReferenceSet.add(fieldName); } break; case 10: // CONSTANT_Methodref: case 11: // CONSTANT_InterfaceMethodref: nameAndTypeItem = classReader.readUnsignedShort(startIndex + 2); nameAndTypeIndex = classReader.getItem(nameAndTypeItem); tag = classReader.readByte(nameAndTypeIndex - 1); if (tag == 12) { // CONSTANT_NameAndType String methodName = classReader.readUTF8(nameAndTypeIndex, buffer); if ("<init>".equals(methodName)) { int classItem = classReader.readUnsignedShort(startIndex); int classIndex = classReader.getItem(classItem); className = classReader.readUTF8(classIndex, buffer); constructorReferenceSet.add(className); } else { methodReferenceSet.add(methodName); } } break; } } } String typeName = classIndexer.name; // Append sets to indexes addToIndex(indexes, "typeDeclarations", typeDeclarationSet, entry); addToIndex(indexes, "constructorDeclarations", constructorDeclarationSet, entry); addToIndex(indexes, "methodDeclarations", methodDeclarationSet, entry); addToIndex(indexes, "fieldDeclarations", fieldDeclarationSet, entry); addToIndex(indexes, "typeReferences", typeReferenceSet, entry); addToIndex(indexes, "constructorReferences", constructorReferenceSet, entry); addToIndex(indexes, "methodReferences", methodReferenceSet, entry); addToIndex(indexes, "fieldReferences", fieldReferenceSet, entry); addToIndex(indexes, "strings", stringSet, entry); // Populate map [super type name : [sub type name]] if (superTypeNameSet.size() > 0) { Map<String, Collection> index = indexes.getIndex("subTypeNames"); for (String superTypeName : superTypeNameSet) { index.get(superTypeName).add(typeName); } } } catch (Exception ignore) { } }