Skip to content

Instantly share code, notes, and snippets.

@VladUreche
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VladUreche/9609650 to your computer and use it in GitHub Desktop.
Save VladUreche/9609650 to your computer and use it in GitHub Desktop.
Miniboxing Challenge

GSOC 2014 Challenge

####Fix the following bug miniboxing/miniboxing-plugin#63.

Short Explanation

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:

The challenge is to transform the program such that the most specific transformations are generated:

 val y: Int = MiniboxToInt(t) + 1

Step by Step Guide

          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))))
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 for Int:
          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 and IntToMinibox. The first thing is to define the symbols of MiniboxToInt and IntToMinibox 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 and IntToMinibox instead of minibox2box and box2minibox:
          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 and Double)
  • 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.

If you got to here, congratulations, you completed the challenge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment