On Wed, Jan 30, 2019 at 11:07 PM Brian Craft <craft.br...@gmail.com> 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