Level 2, new optimizer: method inlining, closure elimination

The ICode-based inliner has a few problems:

  (a) closure elimination is implemented as repeated method inlinings.
      Upon being forced to stop doing that (e.g., recursive method) none of the previous inlinings is undone, leaving both the closure class and a trail of duplicate code.

  (b) code may be inlined from third-party libraries or the JDK. In general methods not marked @inline may be inlined as discussed in thread the perils of inlining

  (c) invocation cycles (ie M1() calling M2() calling M1() etc) are "broken" only after hitting the maximum method size threshold, leaving a trail of duplicate code behind.

Instead, the experimental optimizer just follows a simple principle:

    only inline @inline-marked methods, and always inline them, including under separate-compilation

Thus the new inliner is deterministic, not dependent on heuristics about method sizes or similar.
The only additional requirement (if you will) is for the method to be dispatched (the one marked @inline) to be determined via the static type of the receiver,
e.g. in a Range.foreach() callsite the type of the receiver must be Range or subtype (in general, not a super type of another which overrides the @inline method).
After all, inlining is a conscious decision: making that explicit via the type of the receiver is straightforward.
As a result, the @noinline annotation doesn't play a role anymore.

Under -log:jvm , the new optimizer provides detailed logging about performed inlinings, as well as diagnostics when inlining proves unfeasible (down to the culprit bytecode instructions).