2

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?

1 Answer 1

1

Turns out that the problem was me:

You need to run the command javap -c -private <className> or else javap defaults to not showing disassembly of private methods.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.