Interoperability with @specialized

40 views
Skip to first unread message

Alexandru Nedelcu

unread,
Jun 27, 2014, 10:00:13 AM6/27/14
to scala-mi...@googlegroups.com

I may have encountered a limitation, not sure.
In Scala Function1 at least is specialized.

So given this sample:

class Sample[@miniboxed +T](val value: T) {
  def map[U](f: T => U) =
    new Sample[U](f(value))
}

The bytecode generated for that map function uses Function.apply(Object) instead of Function1.apply$mcJJ$sp(Long), which would be the specialized apply version for Long on Function1.

Is there something that can be done about it?

I don’t care much about interoperability with other @specialized classes, but using specialized functions is important for my use-case.

--
Alexandru Nedelcu
www.bionicspirit.com

PGP Public Key:
https://bionicspirit.com/key.aexpk

Alexandru Nedelcu

unread,
Jun 27, 2014, 10:10:40 AM6/27/14
to scala-mi...@googlegroups.com

Here’s the full listing of that method as extracted with javap on the generated Sample_J:

  public <U extends java/lang/Object> Sample<U> map(scala.Function1<Tsp, U>); 
    Code:
       0: new           #16                 // class Sample_L
       3: dup           
       4: aload_1       
       5: aload_0       
       6: aload_0        
       7: getfield      #18                 // Field "CancelSample_J|T_TypeTag":B
      10: invokevirtual #22                 // Method value_J:(B)J
      13: aload_0       
      14: getfield      #18                 // Field "CancelSample_J|T_TypeTag":B 
      17: invokestatic  #28                 // Method miniboxing/runtime/MiniboxConversions.minibox2box:(JB)Ljava/lang/Object;
      20: invokeinterface #34,  2           // InterfaceMethod scala/Function1.apply:(Ljava/lang/Object;)Ljava/lang/Object; 
      25: invokespecial #38                 // Method Sample_L."<init>":(Ljava/lang/Object;)V
      28: areturn

Vlad Ureche

unread,
Jun 27, 2014, 11:00:30 AM6/27/14
to Alexandru Nedelcu, scala-mi...@googlegroups.com
Thanks for the report Alexandru!

Indeed, this is a current limitation that the miniboxing plugin can't interoperate with specialization and can't retroactively transform Function1.

When Aymeric benchmarked the mock-up of the Scala linked list, he actually created a new Function1 trait with miniboxing and performed the desugaring by hand: scala-miniboxing.org/example_linkedlist.html
Here's how he did it:
 - Function1 definition: https://github.com/miniboxing/miniboxing-plugin/blob/wip/tests/lib-bench/src/miniboxing/benchmarks/simple/miniboxed/LinkedList.scala#L3-L6 for the Function1
Would this work for you as an intermediate workaround?

I will try to design a proper solution and will ping you back once I have a draft, probably in a few days.

Cheers,
Vlad



--
You received this message because you are subscribed to the Google Groups "Scala Miniboxing Mailing List" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-miniboxi...@googlegroups.com.
To post to this group, send email to scala-mi...@googlegroups.com.
Visit this group at http://groups.google.com/group/scala-miniboxing.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-miniboxing/CAN9KCosLBcOwWdpZgTE8RL4pwAaHvABBvOod9atjGs7vwmVxmw%40mail.gmail.com.

For more options, visit https://groups.google.com/d/optout.

Alexandru Nedelcu

unread,
Jun 27, 2014, 11:31:41 AM6/27/14
to Vlad Ureche, scala-mi...@googlegroups.com
Not sure if I can use that as a workaround - being a public interface, I want it to be usable - though if I think about it, I can probably use an implicit conversion based on macros :-)

Not a problem as long as a solution is eventually implemented. At least for functions, since collection types are heavy on operators taking functions as parameters.

Thanks,

Vlad Ureche

unread,
Jun 27, 2014, 4:58:04 PM6/27/14
to Alexandru Nedelcu, scala-mi...@googlegroups.com
Alexandru, I sketched a proposed solution here: https://github.com/miniboxing/miniboxing-plugin/issues/108

I'm not sure how it would affect performance -- it may be the case that the overhead of the "specialization bridge method" outweighs the benefits of avoiding boxing -- we need to check this using benchmarks. I will be implementing the two proposed solutions over the next days, so we can let benchmarks decide what is the best solution.

Thanks,
Vlad


Alexandru Nedelcu

unread,
Jun 30, 2014, 3:11:48 AM6/30/14
to Vlad Ureche, scala-mi...@googlegroups.com
On Fri, Jun 27, 2014 at 11:57 PM, Vlad Ureche <vlad....@gmail.com> wrote:
Alexandru, I sketched a proposed solution here: https://github.com/miniboxing/miniboxing-plugin/issues/108

I'm not sure how it would affect performance -- it may be the case that the overhead of the "specialization bridge method" outweighs the benefits of avoiding boxing -- we need to check this using benchmarks. I will be implementing the two proposed solutions over the next days, so we can let benchmarks decide what is the best solution.

Thanks Vlad,

I'm also flirting with the idea of having my own Function interface and do implicit conversions to it by means of macros. This would also work OK for purposes of Java 8 interoperability, since Scala's function types are not `@FunctionalInterface` precisely because of specialization. Haven't tried it out yet, but I don't see a reason for why this shouldn't work.

Of course, it would be nice if miniboxing would just work with FunctionX, so it all depends on the results of those benchmarks you're planning.

BTW, speaking of benchmarking and boxing, I'm sure you know really well what you're doing - just want to point out that for me the biggest benefit of avoiding boxing is to relieve pressure from the GC, as to avoid stop-the-world sweeps as much as possible - which becomes incredibly important for my use-case - optimizing my library to be able to move millions of messages per second over asynchronous boundaries. Boxing is one reason for why the GC can end up acting like a GIL that chokes the process and you end up acquainted with Amdahl's law :-)

Vlad Ureche

unread,
Jul 14, 2014, 3:17:29 PM7/14/14
to Alexandru Nedelcu, scala-mi...@googlegroups.com
2014-06-30 10:11 GMT+03:00 Alexandru Nedelcu <al...@bionicspirit.com>:

Thanks Vlad,

I'm also flirting with the idea of having my own Function interface and do implicit conversions to it by means of macros. This would also work OK for purposes of Java 8 interoperability, since Scala's function types are not `@FunctionalInterface` precisely because of specialization. Haven't tried it out yet, but I don't see a reason for why this shouldn't work.

[sorry for taking so long to pick this up, I implemented the solution I had in version 0.4-SNAPSHOT]

This is a very interesting avenue to pursue. I think the only reason this is done in the plugin right now is because with macros you can change local scopes, whereas right now the plugin is changing all occurrences of FunctionX to MiniboxedFunctionX and patching up the inconsistencies where necessary (FunctionX and MiniboxedFunctionX do not extend eachother).
 

Of course, it would be nice if miniboxing would just work with FunctionX, so it all depends on the results of those benchmarks you're planning.

The benchmarks look okay, with 15% overhead but still a good 30% below generics: http://localhost:4000/example_functions.html#benchmarks
There are further optimization opportunities: https://github.com/miniboxing/miniboxing-plugin/issues/114, but I'll have to focus on something else now (academic paper)
 

BTW, speaking of benchmarking and boxing, I'm sure you know really well what you're doing - just want to point out that for me the biggest benefit of avoiding boxing is to relieve pressure from the GC, as to avoid stop-the-world sweeps as much as possible - which becomes incredibly important for my use-case - optimizing my library to be able to move millions of messages per second over asynchronous boundaries.

It would be really good to have a version of the library where we show where boxing occurs -- I've been doing this by hand, but in principle it could be automated. The Racket guys have very advanced tools for this.
 

Boxing is one reason for why the GC can end up acting like a GIL that chokes the process and you end up acquainted with Amdahl's law :-)

Good point :))

Cheers,
Vlad

Alexandru Nedelcu

unread,
Jul 14, 2014, 4:21:10 PM7/14/14
to Vlad Ureche, scala-mi...@googlegroups.com
Thanks Vlad, I've seen your commit. I've also been away on vacation and haven't tried it out yet. Will play with it.
Reply all
Reply to author
Forward
0 new messages