Skip to content

[indylambda] Relieve LambdaMetafactory of boxing duties [ci: last-only]#4497

Merged
retronym merged 2 commits intoscala:2.11.xfrom
retronym:topic/indylambda-diy-boxing
May 16, 2015
Merged

[indylambda] Relieve LambdaMetafactory of boxing duties [ci: last-only]#4497
retronym merged 2 commits intoscala:2.11.xfrom
retronym:topic/indylambda-diy-boxing

Conversation

@retronym
Copy link
Member

LambdaMetafactory generates code to perform a limited number of type
adaptations when delegating from its implementation of the functional
interface method to the lambda target method.

These adaptations are: numeric widening, casting, boxing and unboxing.

However, the semantics of unboxing numerics in Java differs to Scala: they
treat UNBOX(null) as cause to rause a NullPointerException, Scala (in
BoxesRuntime.unboxTo{Byte,Short,...}) reinterprets the null as zero.

Furthermore, Java has no idea how to adapt between a value class and its
wrapped type, nor from a void return to BoxedUnit.

This commit detects when the lambda target method would require such
adaptation. If it does, an extra method, $anonfun$1$adapted is created to
perform the adaptation, and this is used as the target of the lambda.

This obviates the use of JProcedureN for Unit returning lambdas, we
know use JFunctionN as the functional interface and bind this to an
$adapted method that summons the instance of BoxedUnit after calling
the void returning lambda target.

The enclosed test cases fail without boxing changes. They don't execute
with indylambda enabled under regular partest runs yet, you need to add
scala-java8-compat to scala-library and pass the SCALAC_OPTS to partest
manually to try this out, as described in
#4463. Once we enable indylambda by
default, however, this test will exercise the code in this patch all the
time.

It is also possible to run the tests with:

% curl
https://oss.sonatype.org/content/repositories/releases/org/scala-lang/modules/scala-java8-t_2.11/0.4.0/scala-java8-compat_2.11-0.4.0.jar
> scala-java8-compat_2.11-0.4.0.jar
% export INDYLAMBDA="-Ydelambdafy:method -Ybackend:GenBCode -target:jvm-1.8
-classpath .:scala-java8-compat_2.11-0.4.0.jar" qscalac $INDYLAMBDA
test/files/run/indylambda-boxing/*.scala && qscala $INDYLAMBDA Test

@scala-jenkins scala-jenkins added this to the 2.11.7 milestone May 11, 2015
@retronym retronym changed the title [indylambda] Relieve LambdaMetafactory of boxing duties [indylambda] Relieve LambdaMetafactory of boxing duties [ci:last only] May 11, 2015
@retronym retronym changed the title [indylambda] Relieve LambdaMetafactory of boxing duties [ci:last only] [indylambda] Relieve LambdaMetafactory of boxing duties [ci: last-only] May 11, 2015
@lrytz
Copy link
Member

lrytz commented May 11, 2015

typos in the commit message: "rause|rise a NullPointerException", "we know|now use JFunctionN"

@lrytz
Copy link
Member

lrytz commented May 11, 2015

Could you remove the JProcedureN from https://github.com/scala/scala-java8-compat now, or are they still in use elsewhere?

@retronym
Copy link
Member Author

JProcedureN is still used as a target type when writing a Java lambda to conform to FunctionN[A, Unit] without the need to explicitly return a BoxedUnit.INSTANCE.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't easily/lazily convince myself this deals correctly with nested templates. Could you shed some light on that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The train has already been through Flatten Plains, almost at the terminal station.

qscala -Xshow-phases 2>&1| tail -10
    lambdalift  17  move nested functions to top level
  constructors  18  move field definitions into constructors
       flatten  19  eliminate inner classes
         mixin  20  mixin composition
       cleanup  21  platform-specific cleanups, generate reflective calls
  🚅delambdafy  22  remove lambdas
         icode  23  generate portable intermediate code
           jvm  24  generate JVM bytecode
      terminal  25  the last phase during a compilation run

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes. I don't spend nearly enough time in back country.

`LambdaMetafactory` generates code to perform a limited number
of type adaptations when delegating from its implementation of
the functional interface method to the lambda target method.

These adaptations are: numeric widening, casting, boxing and unboxing.

However, the semantics of unboxing numerics in Java differs to Scala:
they treat `UNBOX(null)` as cause to raise a `NullPointerException`,
Scala (in `BoxesRuntime.unboxTo{Byte,Short,...}`) reinterprets the
null as zero.

Furthermore, Java has no idea how to adapt between a value class and
its wrapped type, nor from a void return to `BoxedUnit`.

This commit detects when the lambda target method would require
such adaptation. If it does, an extra method, `$anonfun$1$adapted` is
created to perform the adaptation, and this is used as the target
of the lambda.

This obviates the use of `JProcedureN` for `Unit` returning
lambdas, we know use `JFunctionN` as the functional interface
and bind this to an `$adapted` method that summons the instance
of `BoxedUnit` after calling the `void` returning lambda target.

The enclosed test cases fail without boxing changes. They don't
execute with indylambda enabled under regular partest runs yet,
you need to add scala-java8-compat to scala-library and pass
the SCALAC_OPTS to partest manually to try this out, as described
in scala#4463. Once we enable indylambda
by default, however, this test will exercise the code in this patch
all the time.

It is also possible to run the tests with:

```
% curl https://oss.sonatype.org/content/repositories/releases/org/scala-lang/modules/scala-java8-compat_2.11/0.4.0/scala-java8-compat_2.11-0.4.0.jar > scala-java8-compat_2.11-0.4.0.jar
% export INDYLAMBDA="-Ydelambdafy:method -Ybackend:GenBCode -target:jvm-1.8 -classpath .:scala-java8-compat_2.11-0.4.0.jar"
qscalac $INDYLAMBDA test/files/run/indylambda-boxing/*.scala && qscala $INDYLAMBDA Test
```
@retronym
Copy link
Member Author

@lrytz fxed the typo in the commit message

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nop;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll revert this in the followup PR.

@lrytz
Copy link
Member

lrytz commented May 15, 2015

LGTM!

retronym added a commit that referenced this pull request May 16, 2015
[indylambda] Relieve LambdaMetafactory of boxing duties [ci: last-only]
@retronym retronym merged commit 2f1b525 into scala:2.11.x May 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants