diff options
author | Adriaan Moors <adriaan.moors@epfl.ch> | 2011-11-29 00:03:40 +0100 |
---|---|---|
committer | Adriaan Moors <adriaanm@gmail.com> | 2011-12-24 17:36:52 +0100 |
commit | 08ec6ba4e4aeb94f6505ecb462b94362ff0af096 (patch) | |
tree | a54bad8e6b329e672b64835c5eaa1fae9d25272b /src/compiler/scala/reflect/internal/TreeGen.scala | |
parent | fc0c123e3560da190a3daae35214c2be50fd59e6 (diff) | |
download | scala-08ec6ba4e4aeb94f6505ecb462b94362ff0af096.tar.gz scala-08ec6ba4e4aeb94f6505ecb462b94362ff0af096.tar.bz2 scala-08ec6ba4e4aeb94f6505ecb462b94362ff0af096.zip |
[vpm] optimized codegen avoids option-boxing
introducing two mutable variables per pattern match: matchRes and keepGoing
keepGoing denotes whether the result was Some or None,
and matchRes holds the Some's contents or the right zero for the match's type
Race(() => fastMatch(list), () => virtMatch_no_option(list))(100000).converge() is a virtual tie on my machine after this
see https://gist.github.com/1400910
conveniently also works around SI-5245
don't assign to Unit-typed var's, in fact, make matchRes a val when its only prospect in life is to be unit-valued
propagate eventual type for matchRes thru codegen
so that we can have more robust checks for unit¬hing, when assignment makes no sense
also, added a hack to caseResult to avoid boxed units in
if(keepGoing) { matchRes = ... } else zero
after erasure, we get
if(keepGoing) { matchRes = ...; BoxedUNIT } else zero
genicode broke because i was sharing trees:
[scalacfork] error: java.lang.AssertionError: assertion failed: type error: can't convert from UNIT to REF(class Object) in unit ScalaSig.scala at source-/Users/adriaan/git/scala-dev/src/scalap/scala/tools/scalap/scalax/rules/scalasig/ScalaSig.scala,line-26,offset=868
fixed by duplicating -- so be it (for now -- make this more fine-grained, more efficient)
dodging inliner issues with one/zero (it won't inline, so also directly inline those methods)
Diffstat (limited to 'src/compiler/scala/reflect/internal/TreeGen.scala')
-rw-r--r-- | src/compiler/scala/reflect/internal/TreeGen.scala | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/src/compiler/scala/reflect/internal/TreeGen.scala b/src/compiler/scala/reflect/internal/TreeGen.scala index 1c93a904c0..e537c6b83f 100644 --- a/src/compiler/scala/reflect/internal/TreeGen.scala +++ b/src/compiler/scala/reflect/internal/TreeGen.scala @@ -154,9 +154,13 @@ abstract class TreeGen { debuglog("casting " + tree + ":" + tree.tpe + " to " + pt + " at phase: " + phase) assert(!tree.tpe.isInstanceOf[MethodType], tree) assert(!pt.typeSymbol.isPackageClass && !pt.typeSymbol.isPackageObjectClass, pt) - // @MAT only called during erasure, which already takes care of that - // @PP: "only called during erasure" is not very true these days. - // In addition, at least, are: typer, uncurry, explicitouter, cleanup. + // called during (at least): typer, uncurry, explicitouter, cleanup. + // TODO: figure out the truth table for any/wrapInApply + // - the `any` flag seems to relate to erasure's adaptMember: "x.asInstanceOf[T] becomes x.$asInstanceOf[T]", + // where asInstanceOf is Any_asInstanceOf and $asInstanceOf is Object_asInstanceOf + // erasure will only unbox the value in a tree made by mkCast if `any && wrapInApply` + // - the `wrapInApply` flag need not be true if the tree will be adapted to have the empty argument list added before it gets to erasure + // in fact, I think it should be false for trees that will be type checked during typer assert(pt eq pt.normalize, tree +" : "+ debugString(pt) +" ~>"+ debugString(pt.normalize)) atPos(tree.pos)(mkAsInstanceOf(tree, pt, any = false, wrapInApply = true)) } @@ -262,6 +266,25 @@ abstract class TreeGen { tree setType tp } + def mkZeroContravariantAfterTyper(tp: Type): Tree = { + // contravariant -- for replacing an argument in a method call + // must use subtyping, as otherwise we miss types like `Any with Int` + val tree = + if (NullClass.tpe <:< tp) Literal(Constant(null)) + else if (UnitClass.tpe <:< tp) Literal(Constant()) + else if (BooleanClass.tpe <:< tp) Literal(Constant(false)) + else if (FloatClass.tpe <:< tp) Literal(Constant(0.0f)) + else if (DoubleClass.tpe <:< tp) Literal(Constant(0.0d)) + else if (ByteClass.tpe <:< tp) Literal(Constant(0.toByte)) + else if (ShortClass.tpe <:< tp) Literal(Constant(0.toShort)) + else if (IntClass.tpe <:< tp) Literal(Constant(0)) + else if (LongClass.tpe <:< tp) Literal(Constant(0L)) + else if (CharClass.tpe <:< tp) Literal(Constant(0.toChar)) + else mkCast(Literal(Constant(null)), tp) + + tree + } + /** Builds a tuple */ def mkTuple(elems: List[Tree]): Tree = if (elems.isEmpty) Literal(Constant()) |