I'm trying to write a custom signature for a java tool called "findbugs." The specific example I'm looking to detect are instances where a static, non-concurrent hashmap is instantiated. In a multi-threaded environment this causes bad things™ to happen.
Here is my java source:
import java.util.HashMap;
import java.util.Map;
public class StaticInitializationOfHashMap {
private static Map<String,String> hashMap;
private static void init() throws Exception {
hashMap = new HashMap<String,String>();
for(int x = 0; x < 1000; x++) {
hashMap.put("Key_" + x, "Value_" + x);
}
}
public static void main(String[] args) throws Exception {
init();
for(int i = 0; i < hashMap.size(); ++i) {
System.out.println(hashMap.get("Key_" + i));
}
}
}
Here is my javap -c -v output:
Classfile /c:/gitRepos/findbugs/findbugsTestCases/build/classes/StaticInitializationOfHashMap.class
Last modified Oct 27, 2015; size 1478 bytes
MD5 checksum d1b1e57f69d1b13f658ee996fc2bbd24
Compiled from "StaticInitializationOfHashMap.java"
public class StaticInitializationOfHashMap
SourceFile: "StaticInitializationOfHashMap.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #20.#45 // java/lang/Object."<init>":()V
#2 = Class #46 // java/util/HashMap
#3 = Methodref #2.#45 // java/util/HashMap."<init>":()V
#4 = Fieldref #19.#47 // StaticInitializationOfHashMap.hashMap:Ljava/util/Map;
#5 = Class #48 // java/lang/StringBuilder
#6 = Methodref #5.#45 // java/lang/StringBuilder."<init>":()V
#7 = String #49 // Key_
#8 = Methodref #5.#50 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#9 = Methodref #5.#51 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#10 = Methodref #5.#52 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#11 = String #53 // Value_
#12 = InterfaceMethodref #54.#55 // java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#13 = Methodref #19.#56 // StaticInitializationOfHashMap.init:()V
#14 = InterfaceMethodref #54.#57 // java/util/Map.size:()I
#15 = Fieldref #58.#59 // java/lang/System.out:Ljava/io/PrintStream;
#16 = InterfaceMethodref #54.#60 // java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
#17 = Class #61 // java/lang/String
#18 = Methodref #62.#63 // java/io/PrintStream.println:(Ljava/lang/String;)V
#19 = Class #64 // StaticInitializationOfHashMap
#20 = Class #65 // java/lang/Object
#21 = Utf8 hashMap
#22 = Utf8 Ljava/util/Map;
#23 = Utf8 Signature
#24 = Utf8 Ljava/util/Map<Ljava/lang/String;Ljava/lang/String;>;
#25 = Utf8 <init>
#26 = Utf8 ()V
#27 = Utf8 Code
#28 = Utf8 LineNumberTable
#29 = Utf8 LocalVariableTable
#30 = Utf8 this
#31 = Utf8 LStaticInitializationOfHashMap;
#32 = Utf8 init
#33 = Utf8 x
#34 = Utf8 I
#35 = Utf8 StackMapTable
#36 = Utf8 Exceptions
#37 = Class #66 // java/lang/Exception
#38 = Utf8 main
#39 = Utf8 ([Ljava/lang/String;)V
#40 = Utf8 i
#41 = Utf8 args
#42 = Utf8 [Ljava/lang/String;
#43 = Utf8 SourceFile
#44 = Utf8 StaticInitializationOfHashMap.java
#45 = NameAndType #25:#26 // "<init>":()V
#46 = Utf8 java/util/HashMap
#47 = NameAndType #21:#22 // hashMap:Ljava/util/Map;
#48 = Utf8 java/lang/StringBuilder
#49 = Utf8 Key_
#50 = NameAndType #67:#68 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#51 = NameAndType #67:#69 // append:(I)Ljava/lang/StringBuilder;
#52 = NameAndType #70:#71 // toString:()Ljava/lang/String;
#53 = Utf8 Value_
#54 = Class #72 // java/util/Map
#55 = NameAndType #73:#74 // put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#56 = NameAndType #32:#26 // init:()V
#57 = NameAndType #75:#76 // size:()I
#58 = Class #77 // java/lang/System
#59 = NameAndType #78:#79 // out:Ljava/io/PrintStream;
#60 = NameAndType #80:#81 // get:(Ljava/lang/Object;)Ljava/lang/Object;
#61 = Utf8 java/lang/String
#62 = Class #82 // java/io/PrintStream
#63 = NameAndType #83:#84 // println:(Ljava/lang/String;)V
#64 = Utf8 StaticInitializationOfHashMap
#65 = Utf8 java/lang/Object
#66 = Utf8 java/lang/Exception
#67 = Utf8 append
#68 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#69 = Utf8 (I)Ljava/lang/StringBuilder;
#70 = Utf8 toString
#71 = Utf8 ()Ljava/lang/String;
#72 = Utf8 java/util/Map
#73 = Utf8 put
#74 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
#75 = Utf8 size
#76 = Utf8 ()I
#77 = Utf8 java/lang/System
#78 = Utf8 out
#79 = Utf8 Ljava/io/PrintStream;
#80 = Utf8 get
#81 = Utf8 (Ljava/lang/Object;)Ljava/lang/Object;
#82 = Utf8 java/io/PrintStream
#83 = Utf8 println
#84 = Utf8 (Ljava/lang/String;)V
{
public StaticInitializationOfHashMap();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this LStaticInitializationOfHashMap;
public static void main(java.lang.String[]) throws java.lang.Exception;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=4, locals=2, args_size=1
0: invokestatic #13 // Method init:()V
3: iconst_0
4: istore_1
5: iload_1
6: getstatic #4 // Field hashMap:Ljava/util/Map;
9: invokeinterface #14, 1 // InterfaceMethod java/util/Map.size:()I
14: if_icmpge 59
17: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
20: getstatic #4 // Field hashMap:Ljava/util/Map;
23: new #5 // class java/lang/StringBuilder
26: dup
27: invokespecial #6 // Method java/lang/StringBuilder."<init>":()V
30: ldc #7 // String Key_
32: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35: iload_1
36: invokevirtual #9 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: invokeinterface #16, 2 // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
47: checkcast #17 // class java/lang/String
50: invokevirtual #18 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
53: iinc 1, 1
56: goto 5
59: return
LineNumberTable:
line 16: 0
line 17: 3
line 18: 17
line 17: 53
line 20: 59
LocalVariableTable:
Start Length Slot Name Signature
5 54 1 i I
0 60 0 args [Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 5
locals = [ int ]
frame_type = 250 /* chop */
offset_delta = 53
Exceptions:
throws java.lang.Exception
}
At 0: invokestatic #13
it appears that we're calling the init()
method, however in my disassembly, I'm not seeing a reference to a decompiled method called init
.
What am I doing wrong? It appears that the init method was optimized directly into my main method, but I thought that when using Oracle products, that all optimizations were deferred to the JIT and not at compile time?