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