Reputation: 27385
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?
Upvotes: 3
Views: 399
Reputation: 18847
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
Upvotes: 2
Reputation: 3491
Well, you're dabbling in disassembly, so you probably will have to reconstruct the functions represented by those jumps. Might be a good idea to use a JVM whose source code is available and for which you have the debugging symbols.
Just based on the semantics of instanceof
, I'd wage that what these jumps do is execute the same test recursively for superclasses (since basically instanceof
can be written in functional pseudocode as instanceof(object, class) = class != null and (object.class == class or instanceof(object.class.superclass, class) or instanceof(any object.class.interface, class))
Upvotes: 2