This phase converts classes with parameters into Java-like classes with fields, which are assigned to from constructors.
This transformer is responsible for preparing lambdas for runtime, by either translating to anonymous classes or to a tree that will be convereted to invokedynamic by the JVM 1.8+ backend.
This transformer is responsible for preparing lambdas for runtime, by either translating to anonymous classes or to a tree that will be convereted to invokedynamic by the JVM 1.8+ backend.
The main assumption it makes is that a lambda {args => body} has been turned into {args => liftedBody()} where lifted body is a top level method that implements the body of the lambda. Currently Uncurry is responsible for that transformation.
From a lambda, Delambdafy will create:
Under -target:jvm-1.7 and below:
1) a new top level class that a) has fields and a constructor taking the captured environment (including possibly the "this" reference) b) an apply method that calls the target method c) if needed a bridge method for the apply method 2) an instantiation of the newly created class which replaces the lambda
Under -target:jvm-1.8 with GenBCode:
1) An application of the captured arguments to a fictional symbol representing the lambda factory.
This will be translated by the backed into an invokedynamic using a bootstrap method in JDK8's LambdaMetaFactory
.
The captured arguments include this
if liftedBody
is unable to be made STATIC.
This class ...
This class ...
1.0
Perform Step 1 in the inline classes SIP: Creates extension methods for all methods in a value class, except parameter or super accessors, or constructors.
Perform Step 1 in the inline classes SIP: Creates extension methods for all methods in a value class, except parameter or super accessors, or constructors.
2.10
An InfoTransform contains a compiler phase that transforms trees and symbol infos -- making sure they stay consistent.
An InfoTransform contains a compiler phase that transforms trees and symbol infos -- making sure they stay consistent. The symbol info is transformed assuming it is consistent right before this phase. The info transformation is triggered by Symbol::rawInfo, which caches the results in the symbol's type history. This way sym.info (during an enteringPhase(p)) can look up what the symbol's info should look like at the beginning of phase p. (If the transformed info had not been stored yet, rawInfo will compute the info by composing the info-transformers of the most recent phase before p, up to the transformer of the phase right before p.)
Concretely, enteringPhase(p) { sym.info } yields the info *before* phase p has transformed it. Imagine you're a phase and it all makes sense.
A class that yields a kind of iterator (Cursor
),
which yields pairs of corresponding symbols visible in some base class,
unless there's a parent class that already contains the same pairs.
A class that yields a kind of iterator (Cursor
),
which yields pairs of corresponding symbols visible in some base class,
unless there's a parent class that already contains the same pairs.
Most of the logic is in SymbolPairs, which contains generic
pair-oriented traversal logic.
This phase maps ErasedValueTypes to the underlying unboxed representation and performs peephole optimizations.
A sample transform.
Specialize code on types.
Specialize code on types.
Make sure you've read the thesis:
Iulian Dragos: Compiling Scala for Performance (chapter 4)
There are some things worth noting, (possibly) not mentioned there:
0) Make sure you understand the meaning of various SpecializedInfo
descriptors
defined below.
1) Specializing traits by introducing bridges in specialized methods
of the specialized trait may introduce problems during mixin composition.
Concretely, it may cause cyclic calls and result in a stack overflow.
See ticket #4351.
This was solved by introducing an Abstract
specialized info descriptor.
Instead of generating a bridge in the trait, an abstract method is generated.
2) Specialized private members sometimes have to be switched to protected. In some cases, even this is not enough. Example:
class A[@specialized T](protected val d: T) { def foo(that: A[T]) = that.d }
Specialization will generate a specialized class and a specialized method:
class A$mcI$sp(protected val d: Int) extends A[Int] { def foo(that: A[Int]) = foo$mcI$sp(that) def foo(that: A[Int]) = that.d }
Above, A$mcI$sp
cannot access d
, so the method cannot be typechecked.
Perform tail recursive call elimination.
Perform tail recursive call elimination.
1.0
A base class for transforms.
A base class for transforms.
A transform contains a compiler phase which applies a tree transformer.
1.0
A trait usable by transforms that need to adapt trees of one type to another type
A base class for transforms.
A base class for transforms. A transform contains a compiler phase which applies a tree transformer.
- uncurry all symbol and tree types (@see UnCurryPhase) -- this includes normalizing all proper types.
- uncurry all symbol and tree types (@see UnCurryPhase) -- this includes normalizing all proper types.
x: => T':
if argument is not a reference to a def parameter:
convert argument
e to (expansion of)
() => e'x: T*' --> x: Seq[T].
x: T...' --> x: Array[T], except:
if T is an unbounded abstract type, replace --> x: Array[Object]
meth(x_1,..., try { x_i } catch { ..}, .. x_b0) ==> { def liftedTry$1 = try { x_i } catch { .. } meth(x_1, .., liftedTry$1(), .. ) }