/** Construct a new compiler from a shared context. */ public AptJavaCompiler(Context context) { super(preRegister(context)); context.put(compilerKey, this); apt = Apt.instance(context); ClassReader classReader = ClassReader.instance(context); classReader.preferSource = true; // TEMPORARY NOTE: bark==log, but while refactoring, we maintain their // original identities, to remember the original intent. log = Log.instance(context); bark = Bark.instance(context); Options options = Options.instance(context); classOutput = options.get("-retrofit") == null; nocompile = options.get("-nocompile") != null; print = options.get("-print") != null; classesAsDecls = options.get("-XclassesAsDecls") != null; genSourceFileNames = new java.util.LinkedHashSet<String>(); genClassFileNames = new java.util.LinkedHashSet<String>(); // this forces a copy of the line map to be kept in the tree, // for use by com.sun.mirror.util.SourcePosition. lineDebugInfo = true; }
@Override public void visitInnerClass( final String name, final String outerName, final String innerName, final int access) { if ((access & Opcodes.ACC_SYNTHETIC) != 0) return; if (!isCorrectName(innerName) || outerName == null) return; if ((getClassName(outerName) + "." + innerName).equals(myResult.getQualifiedName())) { // our result is inner class if (myParent instanceof PsiFileStub) { throw new OutOfOrderInnerClassException(); } } if (!getClassName(outerName).equals(myResult.getQualifiedName())) return; final T innerSource = myInnersStrategy.findInnerClass(innerName, mySource); if (innerSource == null) return; final ClassReader reader = myInnersStrategy.readerForInnerClass(innerSource); if (reader == null) return; final StubBuildingVisitor<T> classVisitor = new StubBuildingVisitor<T>(innerSource, myInnersStrategy, myResult, access, innerName); reader.accept(classVisitor, ClassReader.SKIP_FRAMES); }
@Override public void handle(StringBuilder line, TemplateReader tpl, Environment env, Appendable out) throws IOException { // get the class name String klass = getArgs(line); // read in the class ClassReader rdr = new ClassReader(); while (true) { line = tpl.next(); if (line == null || (isCodeLine(line) && getCmd(line).equals("endclass"))) break; rdr.add(line.toString()); } // format and print objects! Environment oenv; int i = 0; for (TemplateObject o : env.getObjectsFor(klass)) { rdr.rewind(); oenv = env.getEnvironmentFor(o); oenv.setValue("FIRST", (i == 0) ? "1" : null); oenv.setValue("NOTFIRST", (i != 0) ? "1" : null); oenv.setValue("INDEX", String.valueOf(i++)); Template.doTemplateLoop(rdr, oenv, out); } }
private byte[] transformThreadPool(ThreadPoolCfg md, byte[] classfileBuffer) { ClassWriter w = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); ClassVisitor a = new PoolClassAdapter(w, md); ClassReader r = new ClassReader(classfileBuffer); r.accept(a, ClassReader.EXPAND_FRAMES); return w.toByteArray(); }
@Override public void generate(GeneratorContext context, SourceWriter writer, MethodReference methodRef) throws IOException { ClassReader cls = context.getClassSource().get(methodRef.getClassName()); MethodReader method = cls.getMethod(methodRef.getDescriptor()); AnnotationReader providerAnnot = method.getAnnotations().get(MetadataProvider.class.getName()); AnnotationReader refAnnot = method.getAnnotations().get(MetadataProviderRef.class.getName()); methodRef = MethodReference.parse(refAnnot.getValue("value").getString()); // Find and instantiate metadata generator ValueType generatorType = providerAnnot.getValue("value").getJavaClass(); String generatorClassName = ((ValueType.Object) generatorType).getClassName(); Class<?> generatorClass; try { generatorClass = Class.forName(generatorClassName, true, context.getClassLoader()); } catch (ClassNotFoundException e) { context .getDiagnostics() .error( new CallLocation(methodRef), "Can't find metadata provider class {{c0}}", generatorClassName); return; } Constructor<?> cons; try { cons = generatorClass.getConstructor(); } catch (NoSuchMethodException e) { context .getDiagnostics() .error( new CallLocation(methodRef), "Metadata generator {{c0}} does not have " + "a public no-arg constructor", generatorClassName); return; } MetadataGenerator generator; try { generator = (MetadataGenerator) cons.newInstance(); } catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { context .getDiagnostics() .error( new CallLocation(methodRef), "Error instantiating metadata " + "generator {{c0}}", generatorClassName); return; } DefaultMetadataGeneratorContext metadataContext = new DefaultMetadataGeneratorContext( context.getClassSource(), context.getClassLoader(), context.getProperties(), context); // Generate resource loader Resource resource = generator.generateMetadata(metadataContext, methodRef); writer.append("return "); ResourceWriterHelper.write(writer, resource); writer.append(';').softNewLine(); }
@Override public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); if (tree.pid != null) { tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid)); if (tree.packageAnnotations.nonEmpty() || pkginfoOpt == PkgInfo.ALWAYS) { if (isPkgInfo) { addEnv = true; } else { log.error(tree.packageAnnotations.head.pos(), "pkg.annotations.sb.in.package-info.java"); } } } else { tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. Env<AttrContext> topEnv = topLevelEnv(tree); // Save environment of package-info.java file. if (isPkgInfo) { Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { typeEnvs.put(tree.packge, topEnv); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { log.warning( tree.pid != null ? tree.pid.pos() : null, "pkg-info.already.seen", tree.packge); if (addEnv || (tree0.packageAnnotations.isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { typeEnvs.put(tree.packge, topEnv); } } } for (Symbol q = tree.packge; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; Name name = names.package_info; ClassSymbol c = reader.enterClass(name, tree.packge); c.flatname = names.fromString(tree.packge + "." + name); c.sourcefile = tree.sourcefile; c.completer = null; c.members_field = new Scope(c); tree.packge.package_info = c; } classEnter(tree.defs, topEnv); if (addEnv) { todo.append(topEnv); } log.useSource(prev); result = null; }
protected void doTest(String path) throws Exception { File ktFile = new File(path); assertTrue("Cannot find a file " + ktFile.getAbsolutePath(), ktFile.exists()); String fileText = FileUtil.loadFile(ktFile, true); KtFile psiFile = KotlinTestUtils.createFile(ktFile.getName(), fileText, jetCoreEnvironment.getProject()); OutputFileCollection outputFiles = GenerationUtils.compileFileGetClassFileFactoryForTest(psiFile, jetCoreEnvironment); List<TestedObject> testedObjects = parseExpectedTestedObject(fileText); for (TestedObject testedObject : testedObjects) { String className = null; for (OutputFile outputFile : outputFiles.asList()) { String filePath = outputFile.getRelativePath(); if (testedObject.isFullContainingClassName && filePath.equals(testedObject.containingClass + ".class")) { className = filePath; } else if (!testedObject.isFullContainingClassName && filePath.startsWith(testedObject.containingClass)) { className = filePath; } } assertNotNull( "Couldn't find a class file with name " + testedObject.containingClass, className); OutputFile outputFile = outputFiles.get(className); assertNotNull(outputFile); ClassReader cr = new ClassReader(outputFile.asByteArray()); TestClassVisitor classVisitor = getClassVisitor(testedObject.kind, testedObject.name, false); cr.accept(classVisitor, ClassReader.SKIP_CODE); if (!classVisitor.isExists()) { classVisitor = getClassVisitor(testedObject.kind, testedObject.name, true); cr.accept(classVisitor, ClassReader.SKIP_CODE); } boolean isObjectExists = !Boolean.valueOf(findStringWithPrefixes(testedObject.textData, "// ABSENT: ")); assertEquals( "Wrong object existence state: " + testedObject, isObjectExists, classVisitor.isExists()); if (isObjectExists) { assertEquals( "Wrong access flag for " + testedObject + " \n" + outputFile.asText(), getExpectedFlags(testedObject.textData), classVisitor.getAccess()); } } }
@Override public byte[] transform(String name, String transformedName, byte[] basicClass) { if (basicClass == null) return null; ClassReader reader = new ClassReader(basicClass); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); ClassVisitor visitor = writer; visitor = new ExitVisitor(visitor); reader.accept(visitor, 0); return writer.toByteArray(); }
RuntimeParameterAnnotations_attribute(ClassReader cr, int name_index, int length) throws IOException, Annotation.InvalidAnnotation { super(name_index, length); int num_parameters = cr.readUnsignedByte(); parameter_annotations = new Annotation[num_parameters][]; for (int p = 0; p < parameter_annotations.length; p++) { int num_annotations = cr.readUnsignedShort(); Annotation[] annotations = new Annotation[num_annotations]; for (int i = 0; i < num_annotations; i++) annotations[i] = new Annotation(cr); parameter_annotations[p] = annotations; } }
Code_attribute(ClassReader cr, int name_index, int length) throws IOException, ConstantPoolException { super(name_index, length); max_stack = cr.readUnsignedShort(); max_locals = cr.readUnsignedShort(); code_length = cr.readInt(); code = new byte[code_length]; cr.readFully(code); exception_table_langth = cr.readUnsignedShort(); exception_table = new Exception_data[exception_table_langth]; for (int i = 0; i < exception_table_langth; i++) exception_table[i] = new Exception_data(cr); attributes = new Attributes(cr); }
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()); }
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; }
private static void checkLeakingParameters(Class<?> jClass) throws IOException { final HashMap<Method, boolean[]> map = new HashMap<Method, boolean[]>(); // collecting leakedParameters final ClassReader classReader = new ClassReader( new FileInputStream( jClass.getResource("/" + jClass.getName().replace('.', '/') + ".class").getFile())); classReader.accept( new ClassVisitor(Opcodes.ASM5) { @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { final MethodNode node = new MethodNode(Opcodes.ASM5, access, name, desc, signature, exceptions); final Method method = new Method(classReader.getClassName(), name, desc); return new MethodVisitor(Opcodes.ASM5, node) { @Override public void visitEnd() { super.visitEnd(); try { map.put( method, LeakingParameters.build(classReader.getClassName(), node, false).parameters); } catch (AnalyzerException ignore) { } } }; } }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); for (java.lang.reflect.Method jMethod : jClass.getDeclaredMethods()) { Method method = new Method( Type.getType(jClass).getInternalName(), jMethod.getName(), Type.getMethodDescriptor(jMethod)); Annotation[][] annotations = jMethod.getParameterAnnotations(); for (int i = 0; i < annotations.length; i++) { boolean isLeaking = false; Annotation[] parameterAnnotations = annotations[i]; for (Annotation parameterAnnotation : parameterAnnotations) { if (parameterAnnotation.annotationType() == ExpectLeaking.class) { isLeaking = true; } } assertEquals(method.toString() + " #" + i, isLeaking, map.get(method)[i]); } } }
@Nullable public static SMAPAndMethodNode getMethodNode( byte[] classData, final String methodName, final String methodDescriptor, ClassId classId) throws ClassNotFoundException, IOException { ClassReader cr = new ClassReader(classData); final MethodNode[] node = new MethodNode[1]; final String[] debugInfo = new String[2]; final int[] lines = new int[2]; lines[0] = Integer.MAX_VALUE; lines[1] = Integer.MIN_VALUE; cr.accept( new ClassVisitor(API) { @Override public void visitSource(String source, String debug) { super.visitSource(source, debug); debugInfo[0] = source; debugInfo[1] = debug; } @Override public MethodVisitor visitMethod( int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions) { if (methodName.equals(name) && methodDescriptor.equals(desc)) { node[0] = new MethodNode(API, access, name, desc, signature, exceptions) { @Override public void visitLineNumber(int line, @NotNull Label start) { super.visitLineNumber(line, start); lines[0] = Math.min(lines[0], line); lines[1] = Math.max(lines[1], line); } }; return node[0]; } return null; } }, ClassReader.SKIP_FRAMES | (GENERATE_SMAP ? 0 : ClassReader.SKIP_DEBUG)); SMAP smap = SMAPParser.parseOrCreateDefault( debugInfo[1], debugInfo[0], classId.toString(), lines[0], lines[1]); return new SMAPAndMethodNode(node[0], smap); }
Module_attribute(ClassReader cr, int name_index, int length) throws IOException { super(name_index, length); requires_count = cr.readUnsignedShort(); requires = new RequiresEntry[requires_count]; for (int i = 0; i < requires_count; i++) requires[i] = new RequiresEntry(cr); exports_count = cr.readUnsignedShort(); exports = new ExportsEntry[exports_count]; for (int i = 0; i < exports_count; i++) exports[i] = new ExportsEntry(cr); uses_count = cr.readUnsignedShort(); uses_index = new int[uses_count]; for (int i = 0; i < uses_count; i++) uses_index[i] = cr.readUnsignedShort(); provides_count = cr.readUnsignedShort(); provides = new ProvidesEntry[provides_count]; for (int i = 0; i < provides_count; i++) provides[i] = new ProvidesEntry(cr); }
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(); }
protected Enter(Context context) { DEBUG.P(this,"Enter(1)"); context.put(enterKey, this); log = Log.instance(context); reader = ClassReader.instance(context); make = TreeMaker.instance(context); syms = Symtab.instance(context); chk = Check.instance(context); memberEnter = MemberEnter.instance(context); annotate = Annotate.instance(context); lint = Lint.instance(context); predefClassDef = make.ClassDef( make.Modifiers(PUBLIC), syms.predefClass.name, null, null, null, null); //predefClass是一个ClassSymbol(PUBLIC|ACYCLIC, names.empty, rootPackage) //且它的Scope members_field已有成员(几个基本类型符号(symbols for basic types)及其他操作符) //请参考Systab类的predefClass字段说明 predefClassDef.sym = syms.predefClass; todo = Todo.instance(context); fileManager = context.get(JavaFileManager.class); names = Name.Table.instance(context); //我加上的 DEBUG.P(0,this,"Enter(1)"); }
private List<Instruction> transformInvoke(InvokeInstruction insn) { if (insn.getType() != InvocationType.VIRTUAL) { return null; } MethodReference method = insn.getMethod(); if (method.getClassName().equals(ResourceArray.class.getName()) || method.getClassName().equals(ResourceMap.class.getName())) { if (method.getName().equals("keys")) { return transformKeys(insn); } InvokeInstruction accessInsn = new InvokeInstruction(); accessInsn.setType(InvocationType.SPECIAL); ValueType[] types = new ValueType[method.getDescriptor().parameterCount() + 2]; types[0] = ValueType.object("java.lang.Object"); System.arraycopy( method.getDescriptor().getSignature(), 0, types, 1, method.getDescriptor().parameterCount() + 1); accessInsn.setMethod( new MethodReference(ResourceAccessor.class.getName(), method.getName(), types)); accessInsn.getArguments().add(insn.getInstance()); accessInsn.getArguments().addAll(insn.getArguments()); accessInsn.setReceiver(insn.getReceiver()); return Arrays.asList(accessInsn); } ClassReader iface = innerSource.get(method.getClassName()); if (iface == null || !innerSource.isSuperType(Resource.class.getName(), iface.getName()).orElse(false)) { return null; } if (method.getName().startsWith("get")) { if (method.getName().length() > 3) { return transformGetterInvocation(insn, getPropertyName(method.getName().substring(3))); } } else if (method.getName().startsWith("is")) { if (method.getName().length() > 2) { return transformGetterInvocation(insn, getPropertyName(method.getName().substring(2))); } } else if (method.getName().startsWith("set")) { if (method.getName().length() > 3) { return transformSetterInvocation(insn, getPropertyName(method.getName().substring(3))); } } return null; }
public String[] lookupParameterNames( AccessibleObject methodOrCtor, boolean throwExceptionIfMissing) { Class<?>[] types = null; Class<?> declaringClass = null; String name = null; if (methodOrCtor instanceof Method) { Method method = (Method) methodOrCtor; types = method.getParameterTypes(); name = method.getName(); declaringClass = method.getDeclaringClass(); } else { Constructor<?> constructor = (Constructor<?>) methodOrCtor; types = constructor.getParameterTypes(); declaringClass = constructor.getDeclaringClass(); name = "<init>"; } if (types.length == 0) { return EMPTY_NAMES; } InputStream byteCodeStream = getClassAsStream(declaringClass); if (byteCodeStream == null) { if (throwExceptionIfMissing) { throw new ParameterNamesNotFoundException("Unable to get class bytes"); } else { return Paranamer.EMPTY_NAMES; } } try { ClassReader reader = new ClassReader(byteCodeStream); TypeCollector visitor = new TypeCollector(name, types, throwExceptionIfMissing); reader.accept(visitor); String[] parameterNamesForMethod = visitor.getParameterNamesForMethod(); try { byteCodeStream.close(); } catch (IOException e) { } return parameterNamesForMethod; } catch (IOException e) { if (throwExceptionIfMissing) { throw new ParameterNamesNotFoundException("IoException while reading class bytes", e); } else { return Paranamer.EMPTY_NAMES; } } }
public static void main(String[] args) { String fileName = null; ClassReader classReader = null; try { /* Filename should be the first command line argument */ fileName = args[0]; } catch (ArrayIndexOutOfBoundsException ex) { errorMessage("Usage: java Decompile <class file>"); } try { try { /* Create ClassReader instance and fill it */ classReader = new ClassReader(fileName); classReader.readAll(); } catch (ClassFileMagicMismatch ex) { errorMessage("This does not appear to be a class file!"); } catch (FileNotFoundException ex) { errorMessage("File not found!"); } catch (EOFException ex) { errorMessage("Class file format seems to be invalid!"); } catch (UnknownConstantPoolTag ex) { errorMessage("Class file format seems to be invalid" + " (unknown tag in constant pool)!"); } catch (NullPointerException ex) { bug(); } finally { /* we no longer need the file object in classReader */ if (classReader != null) classReader.close(); } } catch (IOException ex) { errorMessage("I/O error!"); } /* Here goes the printing */ System.out.format("\n/* File %s */%n", fileName); try { classReader.printNice(); } catch (NullPointerException ex) { bug(); } }
/** Enter a set of generated class files. */ private List<ClassSymbol> enterClassFiles(Map<String, JavaFileObject> classFiles) { ClassReader reader = ClassReader.instance(context); Names names = Names.instance(context); List<ClassSymbol> list = List.nil(); for (Map.Entry<String, JavaFileObject> entry : classFiles.entrySet()) { Name name = names.fromString(entry.getKey()); JavaFileObject file = entry.getValue(); if (file.getKind() != JavaFileObject.Kind.CLASS) throw new AssertionError(file); ClassSymbol cs; if (isPkgInfo(file, JavaFileObject.Kind.CLASS)) { Name packageName = Convert.packagePart(name); PackageSymbol p = reader.enterPackage(packageName); if (p.package_info == null) p.package_info = reader.enterClass(Convert.shortName(name), p); cs = p.package_info; if (cs.classfile == null) cs.classfile = file; } else cs = reader.enterClass(name, file); list = list.prepend(cs); } return list.reverse(); }
public byte[] process(byte[] input) { ClassWriter classWriter = new ClassWriter(false); ClassAdapter classAdapter = new ClassAdapter(classWriter) { @Override public MethodVisitor visitMethod( final int access, final String name, final String desc, final String signature, final String[] exceptions) { final MethodVisitor methodVisitor = super.visitMethod(access, name, desc, signature, exceptions); if ("<clinit>".equals(name)) { return new StaticInitRemovingAdapter(methodVisitor); } else { return methodVisitor; } } }; ClassReader classReader = new ClassReader(input); classReader.accept(classAdapter, false); return classWriter.toByteArray(); }
public void visitTopLevel(JCCompilationUnit tree) { JavaFileObject prev = log.useSource(tree.sourcefile); boolean addEnv = false; boolean isPkgInfo = tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); if (tree.pid != null) { tree.packge = reader.enterPackage(TreeInfo.fullName(tree.pid)); if (tree.packageAnnotations.nonEmpty()) { if (isPkgInfo) { addEnv = true; } else { log.error(tree.packageAnnotations.head.pos(), "pkg.annotations.sb.in.package-info.java"); } } } else { tree.packge = syms.unnamedPackage; } tree.packge.complete(); // Find all classes in package. Env<AttrContext> env = topLevelEnv(tree); // Save environment of package-info.java file. if (isPkgInfo) { Env<AttrContext> env0 = typeEnvs.get(tree.packge); if (env0 == null) { typeEnvs.put(tree.packge, env); } else { JCCompilationUnit tree0 = env0.toplevel; if (!fileManager.isSameFile(tree.sourcefile, tree0.sourcefile)) { log.warning( tree.pid != null ? tree.pid.pos() : null, "pkg-info.already.seen", tree.packge); if (addEnv || (tree0.packageAnnotations.isEmpty() && tree.docComments != null && tree.docComments.get(tree) != null)) { typeEnvs.put(tree.packge, env); } } } } classEnter(tree.defs, env); if (addEnv) { todo.append(env); } log.useSource(prev); result = null; }
protected Enter(Context context) { context.put(enterKey, this); log = Log.instance(context); reader = ClassReader.instance(context); make = TreeMaker.instance(context); syms = Symtab.instance(context); chk = Check.instance(context); memberEnter = MemberEnter.instance(context); types = Types.instance(context); annotate = Annotate.instance(context); lint = Lint.instance(context); predefClassDef = make.ClassDef(make.Modifiers(PUBLIC), syms.predefClass.name, null, null, null, null); predefClassDef.sym = syms.predefClass; todo = Todo.instance(context); fileManager = context.get(JavaFileManager.class); }
/** * Constructs a new {@link ClassWriter} object and enables optimizations for "mostly add" bytecode * transformations. These optimizations are the following: * * <ul> * <li>The constant pool from the original class is copied as is in the new class, which saves * time. New constant pool entries will be added at the end if necessary, but unused * constant pool entries <i>won't be removed</i>. * <li>Methods that are not transformed are copied as is in the new class, directly from the * original class bytecode (i.e. without emitting visit events for all the method * instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come * from a {@link ClassWriter} (and not from a custom {@link ClassAdapter} or any other * {@link ClassVisitor} instance). * </ul> * * @param classReader the {@link ClassReader} used to read the original class. It will be used to * copy the entire constant pool from the original class and also to copy other fragments of * original bytecode where applicable. * @param flags option flags that can be used to modify the default behavior of this class. See * {@link #COMPUTE_MAXS}, {@link #COMPUTE_FRAMES}. */ public ClassWriter(final ClassReader classReader, final int flags) { this(flags); classReader.copyPool(this); this.cr = classReader; }
/** * 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; }
SourceID_attribute(ClassReader cr, int name_index, int length) throws IOException { super(name_index, length); sourceID_index = cr.readUnsignedShort(); }
/** * Constructs a new ClassWriter object and enables optimizations for "mostly add" bytecode * transformations. These optimizations are the following: * * <ul> * <li>The constant pool from the original class is copied as is in the new class, which saves * time. New constant pool entries will be added at the end if necessary, but unused * constant pool entries <i>won't be removed</i>. * <li>Methods that are not transformed are copied as is in the new class, directly from the * original class bytecode (i.e. without emitting visit events for all the method * instructions), which saves a <i>lot</i> of time. Untransformed methods are detected by * the fact that the {@link ClassReader} receives {@link MethodVisitor} objects that come * from a ClassWriter (and not from any other {@link ClassVisitor} instance). * </ul> * * @param classReader the {@link ClassReader} used to read the original class. It will be used to * copy the entire constant pool from the original class and also to copy other fragments of * original bytecode where applicable. * @param computeMaxs <tt>true</tt> if the maximum stack size and the maximum number of local * variables must be automatically computed. If this flag is <tt>true</tt>, then the arguments * of the {@link MethodVisitor#visitMaxs visitMaxs} method of the {@link MethodVisitor} * returned by the {@link #visitMethod visitMethod} method will be ignored, and computed * automatically from the signature and the bytecode of each method. */ public ClassWriter(ClassReader classReader, boolean computeMaxs) { this(computeMaxs); classReader.copyPool(this); cr = classReader; }
public void visitClassDef(JCClassDecl tree) { Symbol owner = env.info.scope.owner; Scope enclScope = enterScope(env); ClassSymbol c; if (owner.kind == PCK) { // We are seeing a toplevel class. PackageSymbol packge = (PackageSymbol) owner; for (Symbol q = packge; q != null && q.kind == PCK; q = q.owner) q.flags_field |= EXISTS; c = reader.enterClass(tree.name, packge); packge.members().enterIfAbsent(c); if ((tree.mods.flags & PUBLIC) != 0 && !classNameMatchesFileName(c, env)) { log.error(tree.pos(), "class.public.should.be.in.file", tree.name); } } else { if (!tree.name.isEmpty() && !chk.checkUniqueClassName(tree.pos(), tree.name, enclScope)) { result = null; return; } if (owner.kind == TYP) { // We are seeing a member class. c = reader.enterClass(tree.name, (TypeSymbol) owner); if ((owner.flags_field & INTERFACE) != 0) { tree.mods.flags |= PUBLIC | STATIC; } } else { // We are seeing a local class. c = reader.defineClass(tree.name, owner); c.flatname = chk.localClassName(c); if (!c.name.isEmpty()) chk.checkTransparentClass(tree.pos(), c, env.info.scope); } } tree.sym = c; // Enter class into `compiled' table and enclosing scope. if (chk.compiled.get(c.flatname) != null) { duplicateClass(tree.pos(), c); result = types.createErrorType(tree.name, (TypeSymbol) owner, Type.noType); tree.sym = (ClassSymbol) result.tsym; return; } chk.compiled.put(c.flatname, c); enclScope.enter(c); // Set up an environment for class block and store in `typeEnvs' // table, to be retrieved later in memberEnter and attribution. Env<AttrContext> localEnv = classEnv(tree, env); typeEnvs.put(c, localEnv); // Fill out class fields. c.completer = memberEnter; c.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, c, tree); c.sourcefile = env.toplevel.sourcefile; c.members_field = new Scope(c); ClassType ct = (ClassType) c.type; if (owner.kind != PCK && (c.flags_field & STATIC) == 0) { // We are seeing a local or inner class. // Set outer_field of this class to closest enclosing class // which contains this class in a non-static context // (its "enclosing instance class"), provided such a class exists. Symbol owner1 = owner; while ((owner1.kind & (VAR | MTH)) != 0 && (owner1.flags_field & STATIC) == 0) { owner1 = owner1.owner; } if (owner1.kind == TYP) { ct.setEnclosingType(owner1.type); } } // Enter type parameters. ct.typarams_field = classEnter(tree.typarams, localEnv); // Add non-local class to uncompleted, to make sure it will be // completed later. if (!c.isLocal() && uncompleted != null) uncompleted.append(c); // System.err.println("entering " + c.fullname + " in " + c.owner);//DEBUG // Recursively enter all member classes. classEnter(tree.defs, localEnv); result = c.type; }
@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; }