From a274f949c3aa9db16bd5addd0eed4f85388e74ed Mon Sep 17 00:00:00 2001 From: schinz Date: Sat, 26 Mar 2005 17:50:46 +0000 Subject: - introduced isInstanceOf$erased and asInstance... - introduced isInstanceOf$erased and asInstanceOf$erased methods, which work on the erased types; things to note: * before TypesAsValues phase, either variant can be used, although the erased ones need to be used with caution, when speed matters; * after TypesAsValues phase, only the erased variants should be used (done automatically by TreeGen); * when run time types are disabled, the TypesAsValues phase is not skipped anymore: it is turned into a trivial phase which rewrites all non-erased instanceof/casts into erased ones. --- .../scala/tools/scalac/typechecker/RefCheck.scala | 2 +- sources/scala/tools/scalai/ExpressionCompiler.java | 5 +- sources/scalac/Global.java | 1 - sources/scalac/ast/TreeGen.java | 12 ++-- sources/scalac/atree/ATreeFromSTree.java | 4 +- sources/scalac/backend/Primitives.java | 4 +- sources/scalac/backend/jvm/GenJVM.java | 4 +- sources/scalac/symtab/Definitions.java | 12 ++++ sources/scalac/transformer/Erasure.java | 4 +- sources/scalac/transformer/TypesAsValuesPhase.java | 72 ++++++++++++++++++---- sources/scalac/util/Names.java | 2 + 11 files changed, 93 insertions(+), 29 deletions(-) diff --git a/sources/scala/tools/scalac/typechecker/RefCheck.scala b/sources/scala/tools/scalac/typechecker/RefCheck.scala index 25eab9e202..48390d2777 100755 --- a/sources/scala/tools/scalac/typechecker/RefCheck.scala +++ b/sources/scala/tools/scalac/typechecker/RefCheck.scala @@ -776,7 +776,7 @@ class RefCheck(globl: scalac.Global) extends Transformer(globl) { gen.TypeApply( gen.Select( gen.mkLocalRef(clazz.pos, equalsParam), - defs.ANY_AS), + defs.ANY_AS_ERASED), NewArray.Tree(gen.mkType(clazz.pos, testtp))); val that1sym = equalsSym.newVariable(clazz.pos, 0, Names.that1) .setType(testtp); diff --git a/sources/scala/tools/scalai/ExpressionCompiler.java b/sources/scala/tools/scalai/ExpressionCompiler.java index f2442df655..80dd874a3b 100644 --- a/sources/scala/tools/scalai/ExpressionCompiler.java +++ b/sources/scala/tools/scalai/ExpressionCompiler.java @@ -223,10 +223,11 @@ public class ExpressionCompiler { private Code tapply(Tree target, Symbol symbol, Tree[] targs, Tree[]vargs){ Code object = object(target); - if (symbol == definitions.ANY_IS || symbol == definitions.ANY_AS) { + if (symbol == definitions.ANY_IS_ERASED + || symbol == definitions.ANY_AS_ERASED) { assert targs.length == 1: Debug.show(targs); assert vargs.length == 0 : Debug.show(vargs); - boolean cast = symbol == definitions.ANY_AS; + boolean cast = symbol == definitions.ANY_AS_ERASED; Type type = targs[0].type(); return Code.IsAs(object, type, context.getClass(type), cast); } diff --git a/sources/scalac/Global.java b/sources/scalac/Global.java index ead3469865..6c2b9ac200 100644 --- a/sources/scalac/Global.java +++ b/sources/scalac/Global.java @@ -276,7 +276,6 @@ public abstract class Global { args.phases.WHOLEPROG.addSkipFlag(); // !!! // if (!optimize) PHASE.remove(args.phases.OPTIMIZE); // TODO: Enable TailCall for other backends when they handle LabelDefs - if (!runTimeTypes) args.phases.TYPESASVALUES.addSkipFlag(); if (target != TARGET_JVMFROMICODE) args.phases.ICODE.addSkipFlag(); PHASE.freeze(); PhaseDescriptor[] descriptors = PHASE.phases(); diff --git a/sources/scalac/ast/TreeGen.java b/sources/scalac/ast/TreeGen.java index 31389a3227..43d1fc1ed5 100644 --- a/sources/scalac/ast/TreeGen.java +++ b/sources/scalac/ast/TreeGen.java @@ -641,8 +641,10 @@ public class TreeGen implements Kinds, Modifiers, TypeTags { /** Builds an instance test with given value and type. */ public Tree mkIsInstanceOf(int pos, Tree value, Type type) { - Type[] targs = new Type[]{type}; - return mkApplyT_(pos, Select(value, definitions.ANY_IS), targs); + Symbol sym = global.currentPhase.id >= global.PHASE.TYPESASVALUES.id() + ? definitions.ANY_IS_ERASED + : definitions.ANY_IS; + return mkApplyT_(pos, Select(value, sym), new Type[]{type}); } public Tree mkIsInstanceOf(Tree value, Type type) { return mkIsInstanceOf(value.pos, value, type); @@ -650,8 +652,10 @@ public class TreeGen implements Kinds, Modifiers, TypeTags { /** Builds a cast with given value and type. */ public Tree mkAsInstanceOf(int pos, Tree value, Type type) { - Type[] targs = new Type[]{type}; - return mkApplyT_(pos, Select(value, definitions.ANY_AS), targs); + Symbol sym = global.currentPhase.id >= global.PHASE.TYPESASVALUES.id() + ? definitions.ANY_AS_ERASED + : definitions.ANY_AS; + return mkApplyT_(pos, Select(value, sym), new Type[]{type}); } public Tree mkAsInstanceOf(Tree value, Type type) { return mkAsInstanceOf(value.pos, value, type); diff --git a/sources/scalac/atree/ATreeFromSTree.java b/sources/scalac/atree/ATreeFromSTree.java index ba5cb03155..43944c47c2 100644 --- a/sources/scalac/atree/ATreeFromSTree.java +++ b/sources/scalac/atree/ATreeFromSTree.java @@ -476,8 +476,8 @@ public class ATreeFromSTree { if (clasz == definitions.ANY_CLASS) { addGenerator(definitions.ANY_EQEQ, Generator.ANYEQ); addGenerator(definitions.ANY_BANGEQ, Generator.ANYNE); - addGenerator(definitions.ANY_IS, Generator.ISAS(false)); - addGenerator(definitions.ANY_AS, Generator.ISAS(true)); + addGenerator(definitions.ANY_IS_ERASED, Generator.ISAS(false)); + addGenerator(definitions.ANY_AS_ERASED, Generator.ISAS(true)); } if (clasz == definitions.OBJECT_CLASS) { addGenerator(definitions.OBJECT_EQ, Generator.ANYID); diff --git a/sources/scalac/backend/Primitives.java b/sources/scalac/backend/Primitives.java index 3334b35748..76869c2f78 100644 --- a/sources/scalac/backend/Primitives.java +++ b/sources/scalac/backend/Primitives.java @@ -467,8 +467,8 @@ public class Primitives { Definitions defs = definitions; // scala.Any - addPrimitive(defs.ANY_IS, Primitive.IS); - addPrimitive(defs.ANY_AS, Primitive.AS); + addPrimitive(defs.ANY_IS_ERASED, Primitive.IS); + addPrimitive(defs.ANY_AS_ERASED, Primitive.AS); addPrimitive(defs.ANY_EQEQ, Primitive.EQ); addPrimitive(defs.ANY_BANGEQ, Primitive.NE); // !!! addPrimitive(defs.ANY_EQUALS, Primitive.EQUALS); diff --git a/sources/scalac/backend/jvm/GenJVM.java b/sources/scalac/backend/jvm/GenJVM.java index 84108ed57c..9ba9b67939 100644 --- a/sources/scalac/backend/jvm/GenJVM.java +++ b/sources/scalac/backend/jvm/GenJVM.java @@ -299,10 +299,10 @@ public class GenJVM { genLoadQualifier(ctx, fun); JType type = typeStoJ(args[0].type); - if (fun.symbol() == defs.ANY_IS) { + if (fun.symbol() == defs.ANY_IS_ERASED) { ctx.code.emitINSTANCEOF((JReferenceType)type); generatedType = JType.BOOLEAN; - } else if (fun.symbol() == defs.ANY_AS) { + } else if (fun.symbol() == defs.ANY_AS_ERASED) { ctx.code.emitCHECKCAST((JReferenceType)type); generatedType = type; } else diff --git a/sources/scalac/symtab/Definitions.java b/sources/scalac/symtab/Definitions.java index a5b3951ac8..6dda72353e 100644 --- a/sources/scalac/symtab/Definitions.java +++ b/sources/scalac/symtab/Definitions.java @@ -320,7 +320,9 @@ public class Definitions { public final Symbol ANY_TOSTRING; //public final Symbol ANY_PLUS; public final Symbol ANY_IS; + public final Symbol ANY_IS_ERASED; public final Symbol ANY_AS; + public final Symbol ANY_AS_ERASED; public final Symbol ANY_MATCH; //######################################################################## @@ -815,7 +817,9 @@ public class Definitions { ANY_TOSTRING = newMethod(ANY_CLASS,Names.toString ,0); // ANY_PLUS = newMethod(ANY_CLASS,Names.PLUS ,Modifiers.FINAL); ANY_IS = newMethod(ANY_CLASS,Names.isInstanceOf,Modifiers.FINAL); + ANY_IS_ERASED= newMethod(ANY_CLASS,Names.isInstanceOfE,Modifiers.FINAL); ANY_AS = newMethod(ANY_CLASS,Names.asInstanceOf,Modifiers.FINAL); + ANY_AS_ERASED= newMethod(ANY_CLASS,Names.asInstanceOfE,Modifiers.FINAL); ANY_MATCH = newMethod(ANY_CLASS,Names._match ,Modifiers.FINAL); initMethod(ANY_EQEQ , new Type[]{ANY_TYPE()} , boolean_TYPE()); @@ -827,9 +831,17 @@ public class Definitions { Symbol[] ANY_IS_TPARAMS = {newTParam(ANY_IS, 0, ANY_TYPE())}; ANY_IS.setInfo(Type.PolyType(ANY_IS_TPARAMS, boolean_TYPE())); + Symbol[] ANY_IS_ERASED_TPARAMS = + {newTParam(ANY_IS_ERASED, 0, ANY_TYPE())}; + ANY_IS_ERASED.setInfo(Type.PolyType(ANY_IS_ERASED_TPARAMS, + boolean_TYPE())); Symbol[] ANY_AS_TPARAMS = {newTParam(ANY_AS, 0, ANY_TYPE())}; ANY_AS.setInfo(Type.PolyType(ANY_AS_TPARAMS,ANY_AS_TPARAMS[0].type())); + Symbol[] ANY_AS_ERASED_TPARAMS = + {newTParam(ANY_AS_ERASED, 0, ANY_TYPE())}; + ANY_AS_ERASED.setInfo(Type.PolyType(ANY_AS_ERASED_TPARAMS, + ANY_AS_ERASED_TPARAMS[0].type())); Symbol[] ANY_MATCH_TPARAMS = { newTParam(ANY_MATCH, 0, ANY_TYPE()), diff --git a/sources/scalac/transformer/Erasure.java b/sources/scalac/transformer/Erasure.java index ea77bdf926..67a462b1f4 100644 --- a/sources/scalac/transformer/Erasure.java +++ b/sources/scalac/transformer/Erasure.java @@ -163,11 +163,11 @@ public class Erasure extends GenTransformer implements Modifiers { fun = transform(fun); vargs = transform(vargs); Symbol symbol = fun.symbol(); - if (symbol == definitions.ANY_AS) { + if (symbol == definitions.ANY_AS_ERASED) { assert targs.length == 1 && vargs.length == 0: tree; return coerce(getQualifier(fun), targs[0].getType().erasure()); } - if (symbol == definitions.ANY_IS) { + if (symbol == definitions.ANY_IS_ERASED) { assert targs.length == 1 && vargs.length == 0: tree; Type type = targs[0].type.erasure(); if (isUnboxedSimpleType(type)) type = targs[0].type; diff --git a/sources/scalac/transformer/TypesAsValuesPhase.java b/sources/scalac/transformer/TypesAsValuesPhase.java index 11dcaa2487..b5dc28a0c0 100644 --- a/sources/scalac/transformer/TypesAsValuesPhase.java +++ b/sources/scalac/transformer/TypesAsValuesPhase.java @@ -21,6 +21,7 @@ import scalac.atree.AConstant; import scalac.ast.Transformer; import scalac.ast.GenTransformer; import scalac.ast.Tree; +import scalac.ast.TreeGen; import scalac.ast.TreeList; import scalac.backend.Primitives; @@ -63,7 +64,7 @@ import java.util.Collections; // time. public class TypesAsValuesPhase extends Phase { - private final TV_Transformer transformer; + private final GenTransformer transformer; /** * The list of members to add to a given class (either type @@ -108,7 +109,12 @@ public class TypesAsValuesPhase extends Phase { public TypesAsValuesPhase(Global global, PhaseDescriptor descriptor) { super(global, descriptor); - transformer = new TV_Transformer(global); + // If RTT are disabled, use a minimal transformer which simply + // replaces [ia]sInstanceOf with their erased counterpart. + if (global.runTimeTypes) + transformer = new TV_Transformer(global); + else + transformer = new TV_MiniTransformer(global); predefTypes = new HashMap(); predefTypes.put(defs.DOUBLE_CLASS, defs.RTT_DOUBLE()); @@ -271,10 +277,14 @@ public class TypesAsValuesPhase extends Phase { || sym == ARRAY_CONSTRUCTOR || sym == defs.OBJECT_SYNCHRONIZED || sym == defs.ANY_IS - || sym == defs.ANY_AS; + || sym == defs.ANY_IS_ERASED + || sym == defs.ANY_AS + || sym == defs.ANY_AS_ERASED; } public Type transformInfo(Symbol symbol, Type type) { + if (!global.runTimeTypes) return type; + if (symbol.isClass()) { Symbol[] toAdd = membersToAdd(symbol); @@ -925,16 +935,6 @@ public class TypesAsValuesPhase extends Phase { return tparamsPerm; } - /** - * Extract qualifier from a tree, which must be a Select node. - */ - private Tree qualifierOf(Tree tree) { - switch (tree) { - case Select(Tree qualifier, _): return qualifier; - default: throw Debug.abort("cannot extract qualifier from ", tree); - } - } - private boolean isValuePrefix(Type pre) { switch (pre) { case ThisType(Symbol clazz): @@ -1056,6 +1056,52 @@ public class TypesAsValuesPhase extends Phase { } } + /** + * Minimalistic transformer, which simply transforms calls to + * isInstanceOf/asInstanceOf by calls to their erased + * counterparts. Used when full run time types are disabled. + */ + private class TV_MiniTransformer extends GenTransformer { + private final Definitions defs; + + public TV_MiniTransformer(Global global) { + super(global); + defs = global.definitions; + } + + public Tree transform(Tree tree) { + switch (tree) { + case Apply(TypeApply(Tree fun, Tree[] targs), Tree[] vargs): + Symbol funSym = fun.symbol(); + if (funSym == defs.ANY_IS || funSym == defs.ANY_AS) { + Symbol erasedSym = (funSym == defs.ANY_AS) + ? defs.ANY_AS_ERASED + : defs.ANY_IS_ERASED; + return gen.mkApplyTV(tree.pos, + gen.Select(fun.pos, + qualifierOf(fun), + erasedSym), + targs, + vargs); + } else + return super.transform(tree); + + default: + return super.transform(tree); + } + } + } + + /** + * Extract qualifier from a tree, which must be a Select node. + */ + private Tree qualifierOf(Tree tree) { + switch (tree) { + case Select(Tree qualifier, _): return qualifier; + default: throw Debug.abort("cannot extract qualifier from ", tree); + } + } + // Debugging function private void debugPrintAncestor(Symbol sym, Ancestor[][] ancestor) { System.out.println("ancestor for " + Debug.show(sym)); diff --git a/sources/scalac/util/Names.java b/sources/scalac/util/Names.java index c2e759920c..18013be172 100644 --- a/sources/scalac/util/Names.java +++ b/sources/scalac/util/Names.java @@ -157,6 +157,7 @@ public class Names { public static final Name apply = Name.fromString("apply"); public static final Name array = Name.fromString("array"); public static final Name asInstanceOf = Name.fromString("asInstanceOf"); + public static final Name asInstanceOfE = Name.fromString("asInstanceOf$erased"); public static final Name box = Name.fromString("box"); public static final Name caseArity = Name.fromString("caseArity"); public static final Name caseElement = Name.fromString("caseElement"); @@ -185,6 +186,7 @@ public class Names { public static final Name hasNext = Name.fromString("hasNext"); public static final Name head = Name.fromString("head"); public static final Name isInstanceOf = Name.fromString("isInstanceOf"); + public static final Name isInstanceOfE = Name.fromString("isInstanceOf$erased"); public static final Name isDefinedAt = Name.fromString("isDefinedAt"); public static final Name isEmpty = Name.fromString("isEmpty"); public static final Name instantiate = Name.fromString("instantiate"); -- cgit v1.2.3