Is there any way to inspect what the jit does to it?

On Wednesday, January 30, 2019 at 10:07:38 PM UTC-8, Alex Miller wrote:
>
>
>
> On Wed, Jan 30, 2019 at 11:07 PM Brian Craft <craft...@gmail.com 
> <javascript:>> wrote:
>
>> With much experimentation, I ended up with this:
>>
>>   (let [a 1
>>         b (.longValue ^Long (:foo {:foo 3}))
>>         c (if (< a b) a b)])
>>
>> which seems to avoid the longCast call:
>>
>>         Object o;
>>         if (_thunk__0__ == (o = _thunk__0__.get(const__3))) {
>>             o = (__thunk__0__ = 
>> __site__0__.fault(const__3)).get(const__3);
>>         }
>>         final long b = (long)o;
>>         final long c = (a < b) ? a : b;
>>
>> I don't know if this is advisable. Does anyone do this?
>>
>
> No, I wouldn't do this. `long` can inline so it's going to be better (it's 
> also more likely to jit well as it's used other places and is likely hotter 
> in the jit).
>
> Going back to the original...
>
>   (let [a 1
>         b (:foo {:foo 3})
>         c (if (< a b) a b)])
>
> let will track primitives if possible.
> - a is going to be a primitive long. 
> - (:foo {:foo 3}) is going to (always) return an Object and it's best to 
> recognize that and make an explicit cast to a primitive long.
> - if a and b are both primitives, then < is able to inline a 
> long-primitive comparison (via Numbers.lt())
> - the if is going to return an Object though, so again you'll probably 
> want to type hint or cast c, but it's hard to know for sure without seeing 
> more code
>
> Without other info, I would probably start with 
>
>   (let [a 1
>         b (long (:foo {:foo 3}))
>         c (if (< a b) a b)])
>
> Or alternately, it might be better to just type hint b in the comparison 
> to avoid reboxing b, but hard to know without more context:
>
>   (let [a 1
>         b (:foo {:foo 3})
>         c (if (< a ^long b) a b)])
>
> Comparing the bytecode for these (skipping everything up through the 
> keyword lookup, which is same for all):
>
> Original:                                  Option 1:                      
>        Option 2:
> 45: astore_2                           45: invokestatic  #41           45: 
> astore_2  
> 46: lload_0                             48: lstore_2                      
>    46: lload_0
> 47: aload_2                            49: lload_0                        
>   47: aload_2
> 48: invokestatic  #41              50: lload_2                          
> 48: checkcast     #37
> 51: ifeq          62                     51: lcmp                          
>     51: invokestatic  #43
> 54: lload_0                             52: ifge          60              
>     54: lcmp
> 55: invokestatic  #45              55: lload_0                          
> 55: ifge          66
> 58: goto          65                    56: goto          61              
>   58: lload_0
> 61: pop                                   59: pop                          
>      59: invokestatic  #49
> 62: aload_2                            60: lload_2                        
>   62: goto          69
> 63: aconst_null                       61: lstore        4                  
>  65: pop
> 64: astore_2                           63: lload         4                
>    66: aload_2
> 65: astore_3                           65: invokestatic  #47           67: 
> aconst_null
> 66: aload_3                                                                
>         68: astore_2
> 67: aconst_null                                                            
>        69: astore_3
> 68: astore_3                                                              
>          70: aload_3
>                                                                           
>                  71: aconst_null
>                                                                           
>                  72: astore_3
>
> Option 1 does an lstore/lload (long) instead of an astore/lstore (object). 
> Both options use lcmp which is likely the fastest path to compare longs. 
> I've omitted some info here to make these fit, but Original line 48 will 
> invoke Numbers.lt:(JLjava/lang/Object;)Z which is the Numbers.lt(long, 
> Object) - lcmp is definitely going to be preferable to this. Also of 
> importance is that in Option 1, both a and b are stored as longs and loaded 
> as longs so if there is subsequent stuff to do on them, they can avoid 
> boxing (this is also betrayed by the shorter length from fewer casts).
>
> Your longValue one is like Option 1, but starts:
>
>       45: checkcast     #37                 // class java/lang/Long
>       48: invokevirtual #41                 // Method 
> java/lang/Long.longValue:()J
>
> I guess I don't know whether that's faster than an invokestatic call to 
> clojure/lang/RT.longCast:(Ljava/lang/Object;)J, hard to tell without 
> testing in a real context. I'd certainly use the (long ...) one though 
> unless I proved it mattered.
>  
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to