####Fix the following bug miniboxing/miniboxing-plugin#63.
In miniboxing, the optimized data representation stores values encoded on a long integer. Still, whenever the program needs to perform operations on the actual data, it is transformed to its original type.
For example, when doing the following operation:
val y: Int = x + 1
with x
encoded as long, the program actually does:
val y: Int = minibox2box[Int](t, ...) + 1
Both minibox2box
and box2minibox
can handle any primitive data type. Yet, whenever the data type is known statically to be Int
, you can use the more optimized MiniboxToInt
or IntToMinibox
instead:
minibox2box
: https://github.com/miniboxing/miniboxing-plugin/blob/wip/components/runtime/src/miniboxing/runtime/MiniboxConversions.scala#L60-L75 (please ignore the outdated comments)box2minibox_tt
: https://github.com/miniboxing/miniboxing-plugin/blob/wip/components/runtime/src/miniboxing/runtime/MiniboxConversions.scala#L97-L108 (please ignore the outdated comments)- optimized variants: https://github.com/miniboxing/miniboxing-plugin/blob/wip/components/runtime/src/miniboxing/runtime/MiniboxConversions.scala#L18-L45 (please ignore the outdated comments)
The challenge is to transform the program such that the most specific transformations are generated:
val y: Int = MiniboxToInt(t) + 1
- Fork the miniboxing github repository, clone it on your machine and set up sbt and the Eclipse project: https://github.com/miniboxing/miniboxing-plugin/wiki/Try-|-Local-installation
- In Eclipse, navigate to the MiniboxSpecTreeTransformer.scala and add logging whenever
minibox2box
andbox2minibox
calls are inserted in the AST: https://github.com/miniboxing/miniboxing-plugin/blob/wip/components/plugin/src/miniboxing/plugin/transform/spec/MiniboxSpecTreeTransformer.scala#L169-L175. Log both tree and targ:
case BoxToMinibox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
println(s"[log] inserting BoxToMinibox for type: $targ with argument: $tree")
localTyper.typed(gen.mkMethodCall(box2minibox, List(targ), List(transform(tree), tags(targ.typeSymbol))))
case MiniboxToBox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
println(s"[log] inserting MiniboxToBox for type: $targ with argument: $tree")
localTyper.typed(gen.mkMethodCall(minibox2box, List(targ), List(transform(tree), tags(targ.typeSymbol))))
- Now, looking at the test case from the bug description, you will notice that some calls to minibox2box are made for integers while other are made for Tsp:
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ (cd .. && sbt package)
...
[info] Done packaging.
[success] Total time: ...
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ ../mb-scalac -Xprint:minibox-spec test.scala
[log] inserting MiniboxToBox for type: Int with argument: D.this.foo_J(5, marker_box2minibox[Int](t))
[log] inserting BoxToMinibox for type: Int with argument: t
[log] inserting BoxToMinibox for type: Int with argument: marker_minibox2box[Int](t).+(1)
[log] inserting MiniboxToBox for type: Int with argument: t
[log] inserting MiniboxToBox for type: Tsp with argument: C_J.this.foo_J(C_J.this.C_J|T_TypeTag, marker_box2minibox[Tsp](t))
[log] inserting BoxToMinibox for type: Tsp with argument: t
[log] inserting BoxToMinibox for type: Tsp with argument: C_L.this.foo(marker_minibox2box[Tsp](t))
[log] inserting MiniboxToBox for type: Tsp with argument: t
[[syntax trees at end of minibox-spec]] // test.scala
package <empty> {
...
}
- You only need to change those calls made for
Int
. Add a test to log only the calls made forInt
:
case BoxToMinibox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
if (targ == IntClass.tpe)
println(s"[log] inserting BoxToMinibox for type: $targ with argument: $tree")
localTyper.typed(gen.mkMethodCall(box2minibox, List(targ), List(transform(tree), tags(targ.typeSymbol))))
case MiniboxToBox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
if (targ == IntClass.tpe)
println(s"[log] inserting MiniboxToBox for type: $targ with argument: $tree")
localTyper.typed(gen.mkMethodCall(minibox2box, List(targ), List(transform(tree), tags(targ.typeSymbol))))
The result should be:
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ (cd .. && sbt package)
...
[info] Done packaging.
[success] Total time: ...
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ ../mb-scalac -Xprint:minibox-spec test.scala
[log] inserting MiniboxToBox for type: Int with argument: D.this.foo_J(5, marker_box2minibox[Int](t))
[log] inserting BoxToMinibox for type: Int with argument: t
[log] inserting BoxToMinibox for type: Int with argument: marker_minibox2box[Int](t).+(1)
[log] inserting MiniboxToBox for type: Int with argument: t
[[syntax trees at end of minibox-spec]] // test.scala
package <empty> {
...
}
- Now, you should replace those calls to
MiniboxToInt
andIntToMinibox
. The first thing is to define the symbols ofMiniboxToInt
andIntToMinibox
in MiniboxDefinitions.scala:
lazy val minibox2int = definitions.getMember(ConversionsObjectSymbol, newTermName("MiniboxToInt"))
lazy val int2minibox = definitions.getMember(ConversionsObjectSymbol, newTermName("IntToMinibox"))
- The next step if to create new calls to
MiniboxToInt
andIntToMinibox
instead ofminibox2box
andbox2minibox
:
case BoxToMinibox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
val tree1 =
if (targ == IntClass.tpe)
gen.mkMethodCall(int2minibox, List(transform(tree))) // notice the fewer arguments
else
gen.mkMethodCall(box2minibox, List(targ), List(transform(tree), tags(targ.typeSymbol)))
localTyper.typed(tree1)
case MiniboxToBox(tree, targ) =>
val tags = minibox.typeTagTrees(currentOwner)
val tree1 =
if (targ == IntClass.tpe)
gen.mkMethodCall(minibox2int, List(transform(tree))) // notice the fewer arguments
else
gen.mkMethodCall(minibox2box, List(targ), List(transform(tree), tags(targ.typeSymbol)))
localTyper.typed(tree1)
Now the test case should look like this:
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ (cd .. && sbt package)
...
[info] Done packaging.
[success] Total time: ...
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ ../mb-scalac -Xprint:minibox-spec test.scala
[[syntax trees at end of minibox-spec]] // test.scala
package <empty> {
abstract trait C[@miniboxed T >: Nothing <: Any] extends Object {
def foo(t: T): T;
def foo_J(T_TypeTag: Byte, t: Long): Long
};
class D extends C_J[Int] {
def <init>(): D = {
D.super.<init>(5);
()
};
override def foo(t: Int): Int = MiniboxConversions.this.MiniboxToInt(D.this.foo_J(5, MiniboxConversions.this.IntToMinibox(t)));
override def foo_J(T_TypeTag: Byte, t: Long): Long = MiniboxConversions.this.IntToMinibox(MiniboxConversions.this.MiniboxToInt(t).+(1))
};
class C_J[Tsp >: Nothing <: Any] extends Object with C[Tsp] {
def <init>(C_J|T_TypeTag: Byte): C_J[Tsp] = {
C_J.super.<init>();
()
};
def foo(t: Tsp): Tsp = MiniboxConversions.this.minibox2box[Tsp](C_J.this.foo_J(C_J.this.C_J|T_TypeTag, MiniboxConversions.this.box2minibox_tt[Tsp](t, C_J.this.C_J|T_TypeTag)), C_J.this.C_J|T_TypeTag);
def foo_J(T_TypeTag: Byte, t: Long): Long = t;
<paramaccessor> private[this] val C_J|T_TypeTag: Byte = _
};
class C_L[Tsp >: Nothing <: Any] extends Object with C[Tsp] {
def <init>(): C_L[Tsp] = {
C_L.super.<init>();
()
};
def foo(t: Tsp): Tsp = t;
def foo_J(T_TypeTag: Byte, t: Long): Long = MiniboxConversions.this.box2minibox_tt[Tsp](C_L.this.foo(MiniboxConversions.this.minibox2box[Tsp](t, T_TypeTag)), T_TypeTag)
}
}
Notice the calls to MiniboxConversions.this.IntToMinibox
instead of MiniboxConversions.this.box2minibox_tt[Int]
- Now, make this work for all primitive types (9 of them:
Unit
,Boolean
,Byte
,Char
,Short
,Int
,Long
,Float
andDouble
) - Prepare a test for the primitives and place it in the proper directory. Don't forget the
.flags
and.check
files. - Try the tests again:
sun@sun-laptop:~/workspace/dev/miniboxing-plugin/sandbox(wip)$ cd ..
sun@sun-laptop:~/workspace/dev/miniboxing-plugin(wip)$ sbt miniboxing-tests/test
Detected sbt version 0.13.1
[info] Loading project definition from /mnt/data-local/Work/Workspace/dev/miniboxing-plugin/project
[info] Set current project to miniboxing (in build file:/mnt/data-local/Work/Workspace/dev/miniboxing-plugin/)
[info] Test run started
[info] Test miniboxing.infrastructure.TestSuite.testCompileOutput started
Picking tests from: /mnt/data-local/Work/Workspace/dev/miniboxing-plugin/tests/correctness/../../components/plugin/target/scala-2.10
Picking tests from: /mnt/data-local/Work/Workspace/dev/miniboxing-plugin/tests/correctness/src/miniboxing/tests/compile
Compiling gh-bug-1.scala ... [ OK ]
...
- If any test needs to be updated, review the diff and update the checkfiles.
- Once you're done, commit all the files and make a pull request.