####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
minibox2boxandbox2miniboxcalls 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
MiniboxToIntandIntToMinibox. The first thing is to define the symbols ofMiniboxToIntandIntToMiniboxin 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
MiniboxToIntandIntToMiniboxinstead ofminibox2boxandbox2minibox:
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,FloatandDouble) - Prepare a test for the primitives and place it in the proper directory. Don't forget the
.flagsand.checkfiles. - 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.