Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8198749

[lworld] Translation of value constructors in classic constructor notation

XMLWordPrintable

    • generic
    • generic

      0. Background:

      http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003709.html
      http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003712.html
      http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-February/003883.html
      http://mail.openjdk.java.net/pipermail/valhalla-spec-experts/2018-February/000581.html

      1. At the moment value instances cannot be created using new but are instantiated using __MakeDefault.
      Alternatively new value instances can be carved out of existing ones using the __WithField operator.

      The present ticket is to follow up on Brian's observation that we should "offer a syntax for declaring constructors that
      looks more like a regular constructor or factory." This is motivated by "missed the point" comments from several people
      who were distracted by __MakeDefault and __WithField."

      2. Here are some notes from John Rose on a syntax for declaring value constructors that
      looks more like a regular constructor or factory.

      This is what I call "classic constructor notation" (CCN). Given that it works OK
      out of the box for VBCs, it will also work OK for values. We will want to give it
      a refresh (along the Project Amber lines) to work *better* for values (including
      withers and other "reconstructors"!). And *better* for objects too, again along
      Amber lines (notation improvement across the board, not just for new types).

      So, for CCN, I am convinced the most direct translation strategy is the one
      which translates 'this.x = y' to 'push L0; push y; withfield VT.x'. Brian would
      like to suppress other uses of 'this', which I am fine with pending further discussion.
      I think the less-buggy way to translate classic constructors is to set up a hidden
      'this' in L0 with 'vdefault' and then piecemeal translate the field assignments (with
      or without explicit 'this.' qualifier), adding 'areturn L0' at the end (and every 'return').
      The existing DU/DA tracking for fields should be unchanged.

      The other translation strategy which Brian suggested publicly, of creating a bunch
      of temps for the fields and then assembling the value at the end, may be trickier
      to implement in javac (as well as requiring a backtrack if I'm right about user model).

      But my main point at this time is to please use the piecemeal withfield translation *if*
      it is (as I think it may be) significantly simpler to program in javac.

      3. Here is the sketch Brian and John converged on for how we could implement “codes like a class” constructors.

      We accept the same compiler productions for constructors as for classes. We impose the following semantic restrictions:
       - super() calls are illegal, as there is no superclass
       - Forbid all uses of `this` in the constructor body, implicit and explicit, except for
         - reads of fields (this.x)
         - assignments to fields (this.x = …)
         - delegation to this() constructors
       This means no instance method calls, no this-bound method refs, etc.
       - We use the usual DA/DU analysis on fields, since they’re final

      What we change is the translation. We introduce a synthetic local variable, $this, that is initialized to vdefault. Every time we see an assignment to a field, we transform that into a withheld. When we write out the method, instead of writing out a ctor, we write out a synthetic static factory method instead.

      So if the user writes:

      <acc> Foo(ARGS) {
          BODY
      }

      we translate into

      <acc> synthetic static $make$(ARGS) {
          $this = vdefault Foo
          { tranform(BODY) }
          }
          return $this;
      }

      where transform(BODY) incorporates the following transformations:

          this.x = e —> $this = $this.withfield(x, e)
          this.x —> getfield $this.x
          this(args) —> $this = invokestatic $make$(args)
          return —> return $this
       
      any other use of `this`, implicit or not, is an error.

      4. Here is some additional notes from John:
      I was thinking about value type constructors, and it seems to me that a first
      cut is fairly simple.

      The first set of actions basically removes value-type specific checks:

      * Allow trees of the form x=this.f and this.f=x (get and set value field).
      * Allow trees of the form x=f and f=x, converting to this.f as needed.
      * Do the DU/DA analysis for final fields, as usual.

      Carry those trees through various phases of the compiler, until it's
      time to emit code.

      The tricky part is modifying code generation of constructors for
      value types.

      For a constructor, reserve a local (say Local[0]) and use it as a temp
      to hold the value type instance under constructor. In a preamble,
      initialize it to VT.default.

      When generating x=this.f, use a getfield bytecode on the temp.
      (This is the same as for object classes, so it's a no-op.)

      When generating this.f=x, push the temp, execute withfield
      (after a swap, I guess), and store the new value back to the temp.

      Finally, emit an epilogue for the constructor which returns the temp.

      The constructor must not be named <init>; pick a name (we'll
      change it over time) that's conventional. I suggest "$make",
      with ACC_STATIC and ACC_SYNTHETIC, and a signature
      that returns the VT as its result. It's really an unnamed factory
      method, hence the odd spelling and ACC_SYNTHETIC.

      Other uses of 'this' should turn into errors, but a first cut can ignore
      throwing diagnostics. Finding 'this', apart from a field reference,
      in code generation can just throw an assert. But the best design
      of all, IMO, would be to allow arbitrary use of 'this' when all fields
      are DA. After all, that's the point at which the full instance is live.

      I'm probably missing a couple of points but I think the above is
      the substance of a solution for adapting object constructors to
      values. Note that there doesn't have to be much tree transformation.
      No lowering, for example. The raw field references this.f can flow
      all the way to code generation. Or so I think…


            sadayapalam Srikanth Adayapalam (Inactive)
            sadayapalam Srikanth Adayapalam (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            6 Start watching this issue

              Created:
              Updated:
              Resolved: