View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.IOException;
23  import java.util.concurrent.TimeUnit;
24  import java.util.jar.JarEntry;
25  import java.util.jar.JarFile;
26  
27  import org.apache.bcel.classfile.ClassParser;
28  import org.apache.bcel.classfile.JavaClass;
29  import org.apache.bcel.classfile.Method;
30  import org.apache.bcel.generic.ClassGen;
31  import org.apache.bcel.generic.InstructionList;
32  import org.apache.bcel.generic.MethodGen;
33  import org.apache.commons.collections4.Predicate;
34  import org.apache.commons.collections4.iterators.EnumerationIterator;
35  import org.apache.commons.collections4.iterators.FilterIterator;
36  import org.apache.commons.collections4.iterators.IteratorIterable;
37  import org.apache.commons.io.IOUtils;
38  import org.openjdk.jmh.annotations.Benchmark;
39  import org.openjdk.jmh.annotations.BenchmarkMode;
40  import org.openjdk.jmh.annotations.Fork;
41  import org.openjdk.jmh.annotations.Measurement;
42  import org.openjdk.jmh.annotations.Mode;
43  import org.openjdk.jmh.annotations.OutputTimeUnit;
44  import org.openjdk.jmh.annotations.Threads;
45  import org.openjdk.jmh.annotations.Warmup;
46  import org.openjdk.jmh.infra.Blackhole;
47  
48  @BenchmarkMode(Mode.AverageTime)
49  @Fork(value = 1, jvmArgs = "-server")
50  @Threads(1)
51  @Warmup(iterations = 10)
52  @Measurement(iterations = 20)
53  @OutputTimeUnit(TimeUnit.MILLISECONDS)
54  public class BCELBenchmark {
55  
56      /**
57       * Baseline benchmark. Read the classes but don't parse them.
58       */
59      @Benchmark
60      public void baseline(Blackhole bh) throws IOException {
61          final JarFile jar = getJarFile();
62          for (JarEntry entry : getClasses(jar)) {
63              final byte[] bytes = IOUtils.toByteArray(jar.getInputStream(entry));
64              bh.consume(bytes);
65          }
66          jar.close();
67      }
68  
69      @Benchmark
70      public void generator(Blackhole bh) throws IOException {
71          final JarFile jar = getJarFile();
72          for (JarEntry entry : getClasses(jar)) {
73              final byte[] bytes = IOUtils.toByteArray(jar.getInputStream(entry));
74              final JavaClass clazz = new ClassParser(new ByteArrayInputStream(bytes), entry.getName()).parse();
75              final ClassGen cg = new ClassGen(clazz);
76              for (Method m : cg.getMethods()) {
77                  final MethodGen mg = new MethodGen(m, cg.getClassName(), cg.getConstantPool());
78                  final InstructionList il = mg.getInstructionList();
79                  if (il != null) {
80                      mg.getInstructionList().setPositions();
81                      mg.setMaxLocals();
82                      mg.setMaxStack();
83                  }
84                  cg.replaceMethod(m, mg.getMethod());
85              }
86              bh.consume(cg.getJavaClass().getBytes());
87          }
88          jar.close();
89      }
90  
91      private Iterable<JarEntry> getClasses(JarFile jar) {
92          return new IteratorIterable<>(new FilterIterator<>(new EnumerationIterator<>(jar.entries()), new Predicate<JarEntry>() {
93              @Override
94              public boolean evaluate(JarEntry entry) {
95                  return entry.getName().endsWith(JavaClass.EXTENSION);
96              }
97          }));
98      }
99  
100     private JarFile getJarFile() throws IOException {
101         final String javaHome = System.getProperty("java.home");
102         return new JarFile(javaHome + "/lib/rt.jar");
103     }
104 
105     @Benchmark
106     public void parser(final Blackhole bh) throws IOException {
107         final JarFile jar = getJarFile();
108         for (JarEntry entry : getClasses(jar)) {
109             final byte[] bytes = IOUtils.toByteArray(jar.getInputStream(entry));
110             final JavaClass clazz = new ClassParser(new ByteArrayInputStream(bytes), entry.getName()).parse();
111             bh.consume(clazz);
112         }
113         jar.close();
114     }
115 }