Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Java instance of really so fast?

I'm trying to measure if instance of really fast. Here is very simple benchmark:

public Object a = 2;

@Benchmark
@Warmup(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@Measurement(iterations = 5, timeUnit = TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public boolean test() {
    return a instanceof Double;
}

I ran this bench

Benchmark              Mode  Cnt  Score   Error  Units
MyBenchmark.test       avgt    5  3.105 ± 0.086  ns/op

The assembly output of the benchmark is too long, omitted.

I also wrote a simple java program

private static Object i = 123;

public static boolean insOf(){
    return i instanceof Double;
}

public static void main(String[] args) throws IOException {
    for (int i = 0; i < 100000000; i++)
        if(insOf())
            System.out.print("");
}

The assembly output of the compiled insOf method is this:

0x00007fd761114b60: mov     %eax,0xfffffffffffec000(%rsp)
  0x00007fd761114b67: push    %rbp
  0x00007fd761114b68: sub     $0x10,%rsp        ;*synchronization entry
                                                ; - com.get.intent.App::insOf@-1 (line 24)

  0x00007fd761114b6c: movabs  $0xd6f788e0,%r10  ;   {oop(a 'java/lang/Class' = 'com/get/intent/App')}
  0x00007fd761114b76: mov     0x68(%r10),%r11d  ;*getstatic i
                                                ; - com.get.intent.App::insOf@0 (line 24)

  0x00007fd761114b7a: mov     0x8(%r11),%r10d   ; implicit exception: dispatches to 0x00007fd761114b9c
  0x00007fd761114b7e: cmp     $0x20002192,%r10d  ;   {metadata('java/lang/Double')}
  0x00007fd761114b85: jne     0x7fd761114b98          <-------- HERE!!!
  0x00007fd761114b87: mov     $0x1,%eax
  0x00007fd761114b8c: add     $0x10,%rsp
  0x00007fd761114b90: pop     %rbp
  0x00007fd761114b91: test    %eax,0x16774469(%rip)  ;   {poll_return}
  0x00007fd761114b97: retq
  0x00007fd761114b98: xor     %eax,%eax
  0x00007fd761114b9a: jmp     0x7fd761114b8c          <------- HERE!!!
  0x00007fd761114b9c: mov     $0xfffffff4,%esi
  0x00007fd761114ba1: nop
  0x00007fd761114ba3: callq   0x7fd7610051a0    ; OopMap{off=72}
                                                ;*instanceof
                                                ; - com.get.intent.App::insOf@3 (line 24)
                                                ;   {runtime_call}
  0x00007fd761114ba8: callq   0x7fd776591a20    ;*instanceof
                                                ; - com.get.intent.App::insOf@3 (line 24)
                                                ;   {runtime_call}

Tons of hlt instructions omitted.

From what I can see, instance of is about ten of assembly instructions with two jumps (jne, jmp). The jumps are a little bit confusing. Why do we need them?

QUESTION: Is Java instance of really so fast?

like image 610
St.Antario Avatar asked Mar 12 '26 06:03

St.Antario


1 Answers

Yes, it is that fast for most cases, including the trivial case like yours. It first optimistically checks for the exact hit on the type (Double in your case), and then falls back to slow branch which would pessimistically call the runtime, because class hierarchy might need to be walked. But, in Double case, the compiler knows that no subclasses of Double exist in the system, and therefore slow branch is trivially "false".

   mov     0x8(%r11),%r10d    ; read the klass ptr
   cmp     $0x20002192,%r10d  ;   klass for 'java/lang/Double'
   jne     NOT_EQUAL          ; not equal? slow branch
   mov     $0x1,%eax          ; return value = "true"
RETURN:
   add     $0x10,%rsp         ; epilog
   pop     %rbp
   test    %eax,0x16774469(%rip) 
   retq
NOT_EQUAL:
   xor     %eax,%eax          ; return value = "false"
   jmp     RETURN             
like image 83
Aleksey Shipilev Avatar answered Mar 14 '26 19:03

Aleksey Shipilev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!