summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2011-11-28 08:03:10 +0000
committerPaul Phillips <paulp@improving.org>2011-11-28 08:03:10 +0000
commit0bea2ab5f6b211a83bbf14ea46fe57b8163c6334 (patch)
tree1eda4c329deee6b43d82f5922fc58f3de878638d /src/compiler/scala/tools
parente4c5e04b06fc434eace07798486a108b6e2d4ae7 (diff)
downloadscala-0bea2ab5f6b211a83bbf14ea46fe57b8163c6334.tar.gz
scala-0bea2ab5f6b211a83bbf14ea46fe57b8163c6334.tar.bz2
scala-0bea2ab5f6b211a83bbf14ea46fe57b8163c6334.zip
Fix for erroneous bytecode generation.
A remedy for an IllegalAccessError where generated bytecode referred to an inaccessible type. Closes SI-1430. Bonus materials: - tore out all the invokedynamic support. The shipped jdk7 implementation shows limited resemblance to the one this was written against; the code mostly serves to distract. (I think I could get invokedynamic working pretty quickly, except that it would mean having a codebase for java7 and one for 5-6, which is not a yak I wish to shave today.) - gave NullClass and NothingClass objects of their own, which allowed a nice polymorphic simplification of isSubClass, plus a couple other streamlinings.
Diffstat (limited to 'src/compiler/scala/tools')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/GenICode.scala15
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Members.scala1
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala4
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala2
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala147
-rw-r--r--src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala2
-rw-r--r--src/compiler/scala/tools/nsc/matching/ParallelMatching.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala2
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala2
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala9
10 files changed, 80 insertions, 106 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
index 90e387d384..e26a0d59e8 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/GenICode.scala
@@ -24,7 +24,7 @@ abstract class GenICode extends SubComponent {
import icodes._
import icodes.opcodes._
import definitions.{
- ArrayClass, ObjectClass, ThrowableClass, StringClass, StringModule, NothingClass, NullClass, AnyRefClass,
+ ArrayClass, ObjectClass, ThrowableClass, StringClass, StringModule, AnyRefClass,
Object_equals, Object_isInstanceOf, Object_asInstanceOf, ScalaRunTimeModule,
BoxedNumberClass, BoxedCharacterClass,
getMember
@@ -923,12 +923,13 @@ abstract class GenICode extends SubComponent {
}
case ApplyDynamic(qual, args) =>
- assert(!forMSIL)
- ctx.clazz.bootstrapClass = Some("scala.runtime.DynamicDispatch")
- val ctx1 = genLoad(qual, ctx, ObjectReference)
- genLoadArguments(args, tree.symbol.info.paramTypes, ctx1)
- ctx1.bb.emit(CALL_METHOD(tree.symbol, InvokeDynamic), tree.pos)
- ctx1
+ assert(!forMSIL, tree)
+ // TODO - this is where we'd catch dynamic applies for invokedynamic.
+ sys.error("No invokedynamic support yet.")
+ // val ctx1 = genLoad(qual, ctx, ObjectReference)
+ // genLoadArguments(args, tree.symbol.info.paramTypes, ctx1)
+ // ctx1.bb.emit(CALL_METHOD(tree.symbol, InvokeDynamic), tree.pos)
+ // ctx1
case This(qual) =>
assert(tree.symbol == ctx.clazz.symbol || tree.symbol.isModuleClass,
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Members.scala b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
index 5aa76fad83..2f43d43bdd 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Members.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Members.scala
@@ -106,7 +106,6 @@ trait Members { self: ICodes =>
var fields: List[IField] = Nil
var methods: List[IMethod] = Nil
var cunit: CompilationUnit = _
- var bootstrapClass: Option[String] = None
def addField(f: IField): this.type = {
fields = f :: fields;
diff --git a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
index ba33c425f2..2bcfb9d4a9 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/Opcodes.scala
@@ -616,7 +616,6 @@ trait Opcodes { self: ICodes =>
/** Returns a string representation of this style. */
override def toString(): String = this match {
case Dynamic => "dynamic"
- case InvokeDynamic => "invoke-dynamic"
case Static(false) => "static-class"
case Static(true) => "static-instance"
case SuperCall(mix) => "super(" + mix + ")"
@@ -626,9 +625,6 @@ trait Opcodes { self: ICodes =>
/** Virtual calls */
case object Dynamic extends InvokeStyle
- /** InvokeDynamic a la JSR 292 (experimental). */
- case object InvokeDynamic extends InvokeStyle
-
/**
* Special invoke. Static(true) is used for calls to private
* members.
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
index 16cba38f9a..5af5b05682 100644
--- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
+++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala
@@ -321,7 +321,7 @@ abstract class CopyPropagation {
out.stack = Unknown :: out.stack.drop(i.consumed)
case CALL_METHOD(method, style) => style match {
- case Dynamic | InvokeDynamic =>
+ case Dynamic =>
out = simulateCall(in, method, false)
case Static(onInstance) =>
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index 9d5cc9e0a6..3fe5b83515 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -31,7 +31,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
import icodes._
import icodes.opcodes._
import definitions.{
- NullClass, RuntimeNullClass, NothingClass, RuntimeNothingClass,
AnyClass, ObjectClass, ThrowsClass, ThrowableClass, ClassfileAnnotationClass,
SerializableClass, StringClass, ClassClass, FunctionClass,
DeprecatedAttr, SerializableAttr, SerialVersionUIDAttr, VolatileAttr,
@@ -332,8 +331,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
ifaces,
c.cunit.source.toString)
- if (isStaticModule(c.symbol) || serialVUID != None || isParcelableClass ||
- clasz.bootstrapClass.isDefined) {
+ if (isStaticModule(c.symbol) || serialVUID != None || isParcelableClass) {
if (isStaticModule(c.symbol))
addModuleInstanceField
addStaticInit(jclass, c.lookupStaticCtor)
@@ -375,9 +373,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
}
}
- if (clasz.bootstrapClass.isDefined)
- jclass setBootstrapClass clasz.bootstrapClass.get
-
clasz.fields foreach genField
clasz.methods foreach genMethod
@@ -913,8 +908,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
mopt match {
case Some(m) =>
- if (clasz.bootstrapClass.isDefined) legacyEmitBootstrapMethodInstall(clinit)
-
val oldLastBlock = m.code.blocks.last
val lastBlock = m.code.newBlock
oldLastBlock.replaceInstruction(oldLastBlock.length - 1, JUMP(lastBlock))
@@ -940,11 +933,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (isParcelableClass)
addCreatorCode(BytecodeGenerator.this, lastBlock)
- if (clasz.bootstrapClass.isDefined) {
- // emit bootstrap method install
- //emitBootstrapMethodInstall(block)
- }
-
lastBlock emit RETURN(UNIT)
lastBlock.close
@@ -975,28 +963,9 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
if (isParcelableClass)
legacyAddCreatorCode(BytecodeGenerator.this, clinit)
- if (clasz.bootstrapClass.isDefined)
- legacyEmitBootstrapMethodInstall(clinit)
-
clinit.emitRETURN()
}
- /** Emit code that installs a boostrap method for invoke dynamic. It
- * installs the default method, found in scala.runtime.DynamicDispatch.
- */
- def legacyEmitBootstrapMethodInstall(jcode: JExtendedCode) {
- jcode emitPUSH jclass.getType.asInstanceOf[JReferenceType]
- jcode emitPUSH new JObjectType("scala.runtime.DynamicDispatch")
- jcode emitPUSH "bootstrapInvokeDynamic"
- jcode.emitGETSTATIC("java.dyn.Linkage", "BOOTSTRAP_METHOD_TYPE", MethodTypeType)
- jcode.emitDUP
- jcode.emitINVOKESTATIC("scala.Console", "println", new JMethodType(JType.VOID, Array(JAVA_LANG_OBJECT)))
- jcode.emitINVOKESTATIC("java.dyn.MethodHandles", "findStatic",
- new JMethodType(MethodHandleType, Array(JavaLangClassType, JAVA_LANG_STRING, MethodTypeType)))
- jcode.emitINVOKESTATIC("java.dyn.Linkage", "registerBootstrapMethod",
- new JMethodType(JType.VOID, Array(JavaLangClassType, MethodHandleType)))
- }
-
/** Add a forwarder for method m */
def addForwarder(jclass: JClass, module: Symbol, m: Symbol) {
val moduleName = javaName(module)
@@ -1197,6 +1166,68 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
}
}
+ def isAccessibleFrom(target: Symbol, site: Symbol): Boolean = {
+ target.isPublic || target.isProtected && {
+ (site.enclClass isSubClass target.enclClass) ||
+ (site.enclosingPackage == target.privateWithin)
+ }
+ }
+
+ def genCallMethod(call: CALL_METHOD) {
+ val CALL_METHOD(method, style) = call
+ val siteSymbol = clasz.symbol
+ val hostSymbol = call.hostClass
+ val methodOwner = method.owner
+ // info calls so that types are up to date; erasure may add lateINTERFACE to traits
+ hostSymbol.info ; methodOwner.info
+
+ def isInterfaceCall(sym: Symbol) = (
+ sym.isInterface
+ || sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass)
+ )
+ // whether to reference the type of the receiver or
+ // the type of the method owner (if not an interface!)
+ val useMethodOwner = (
+ style != Dynamic
+ || !isInterfaceCall(hostSymbol) && isAccessibleFrom(methodOwner, siteSymbol)
+ || hostSymbol.isBottomClass
+ )
+ val receiver = if (useMethodOwner) methodOwner else hostSymbol
+ val jowner = javaName(receiver)
+ val jname = javaName(method)
+ val jtype = javaType(method).asInstanceOf[JMethodType]
+
+ def emit(invoke: String) {
+ log("%s %s %s.%s:%s".format(invoke, receiver.accessString, jowner, jname, jtype))
+ invoke match {
+ case "invokeinterface" => jcode.emitINVOKEINTERFACE(jowner, jname, jtype)
+ case "invokevirtual" => jcode.emitINVOKEVIRTUAL(jowner, jname, jtype)
+ case "invokespecial" => jcode.emitINVOKESPECIAL(jowner, jname, jtype)
+ case "invokestatic" => jcode.emitINVOKESTATIC(jowner, jname, jtype)
+ }
+ }
+ def initModule() {
+ // we initialize the MODULE$ field immediately after the super ctor
+ if (isStaticModule(siteSymbol) && !isModuleInitialized &&
+ jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME &&
+ jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) {
+ isModuleInitialized = true
+ jcode.emitALOAD_0()
+ jcode.emitPUTSTATIC(jclass.getName(),
+ nme.MODULE_INSTANCE_FIELD.toString,
+ jclass.getType())
+ }
+ }
+
+ style match {
+ case Static(true) => emit("invokespecial")
+ case Static(false) => emit("invokestatic")
+ case Dynamic if isInterfaceCall(receiver) => emit("invokeinterface")
+ case Dynamic => emit("invokevirtual")
+ case SuperCall(_) => emit("invokespecial") ; initModule()
+ }
+ }
+
def genBlock(b: BasicBlock) {
labels(b).anchorToNext()
@@ -1276,43 +1307,7 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
jcode.emitINVOKEVIRTUAL(target, "clone", arrayCloneType)
case call @ CALL_METHOD(method, style) =>
- val owner: String = javaName(method.owner)
- // reference the type of the receiver instead of the method owner (if not an interface!)
- val dynamicOwner =
- if (needsInterfaceCall(call.hostClass)) owner
- else javaName(call.hostClass)
- val jname = javaName(method)
- val jtype = javaType(method).asInstanceOf[JMethodType]
-
- style match {
- case InvokeDynamic =>
- jcode.emitINVOKEINTERFACE("java.dyn.Dynamic", jname, jtype)
-
- case Dynamic =>
- if (needsInterfaceCall(method.owner))
- jcode.emitINVOKEINTERFACE(owner, jname, jtype)
- else
- jcode.emitINVOKEVIRTUAL(dynamicOwner, jname, jtype)
-
- case Static(instance) =>
- if (instance)
- jcode.emitINVOKESPECIAL(owner, jname, jtype)
- else
- jcode.emitINVOKESTATIC(owner, jname, jtype)
-
- case SuperCall(_) =>
- jcode.emitINVOKESPECIAL(owner, jname, jtype)
- // we initialize the MODULE$ field immediately after the super ctor
- if (isStaticModule(clasz.symbol) && !isModuleInitialized &&
- jmethod.getName() == JMethod.INSTANCE_CONSTRUCTOR_NAME &&
- jname == JMethod.INSTANCE_CONSTRUCTOR_NAME) {
- isModuleInitialized = true
- jcode.emitALOAD_0()
- jcode.emitPUTSTATIC(jclass.getName(),
- nme.MODULE_INSTANCE_FIELD.toString,
- jclass.getType())
- }
- }
+ genCallMethod(call)
case BOX(kind) =>
val boxedType = definitions.boxedClass(kind.toType.typeSymbol)
@@ -1839,20 +1834,6 @@ abstract class GenJVM extends SubComponent with GenJVMUtil with GenAndroid with
////////////////////// Utilities ////////////////////////
- /** Calls to methods in 'sym' need invokeinterface? */
- def needsInterfaceCall(sym: Symbol): Boolean = {
- debuglog("checking for interface call: " + sym.fullName)
- // the following call to 'info' may cause certain symbols to fail loading
- // because we're too late in the compilation chain (aliases to overloaded
- // symbols will not be properly resolved, see scala.Range, method
- // `super$++` that fails in UnPickler at LazyTypeRefAndAlias.complete
- if (sym.isTrait) sym.info // needed so that the type is up to date
- // (erasure may add lateINTERFACE to traits)
-
- sym.isInterface ||
- (sym.isJavaDefined && sym.isNonBottomSubClass(ClassfileAnnotationClass))
- }
-
/** Merge adjacent ranges. */
private def mergeEntries(ranges: List[(Int, Int)]): List[(Int, Int)] =
(ranges.foldLeft(Nil: List[(Int, Int)]) { (collapsed: List[(Int, Int)], p: (Int, Int)) => (collapsed, p) match {
diff --git a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
index 9c34565928..015dc2a7f1 100644
--- a/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
+++ b/src/compiler/scala/tools/nsc/interpreter/CompletionOutput.scala
@@ -15,7 +15,7 @@ trait CompletionOutput {
val global: Global
import global._
- import definitions.{ NothingClass, AnyClass, isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType }
+ import definitions.{ isTupleTypeOrSubtype, isFunctionType, isRepeatedParamType }
/** Reducing fully qualified noise for some common packages.
*/
diff --git a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
index c97d65c6bc..11d829eadb 100644
--- a/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
+++ b/src/compiler/scala/tools/nsc/matching/ParallelMatching.scala
@@ -25,7 +25,7 @@ trait ParallelMatching extends ast.TreeDSL
import global.{ typer => _, _ }
import definitions.{
- AnyRefClass, NothingClass, IntClass, BooleanClass, SomeClass, OptionClass,
+ AnyRefClass, IntClass, BooleanClass, SomeClass, OptionClass,
getProductArgs, productProj, Object_eq, Any_asInstanceOf
}
import CODE._
diff --git a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala
index 1f32355bf7..e62070a239 100644
--- a/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala
+++ b/src/compiler/scala/tools/nsc/symtab/SymbolTrackers.scala
@@ -131,7 +131,7 @@ trait SymbolTrackers {
else " (" + Flags.flagsToString(masked) + ")"
}
def symString(sym: Symbol) = (
- if (settings.debug.value && sym.hasRawInfo && sym.rawInfo.isComplete) {
+ if (settings.debug.value && sym.hasCompleteInfo) {
val s = sym.defString take 240
if (s.length == 240) s + "..." else s
}
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index ef1bcdd739..e67ce90cfa 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -1257,7 +1257,7 @@ abstract class ClassfileParser {
protected def getScope(flags: Int): Scope =
if (isStatic(flags)) staticDefs else instanceDefs
- private def setPrivateWithin(sym: Symbol, jflags: Int) {
+ private def setPrivateWithin(sym: Symbol, jflags: Int) {
if ((jflags & (JAVA_ACC_PRIVATE | JAVA_ACC_PROTECTED | JAVA_ACC_PUBLIC)) == 0)
// See ticket #1687 for an example of when topLevelClass is NoSymbol: it
// apparently occurs when processing v45.3 bytecode.
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 054fb1c036..62ad78c64d 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -1033,8 +1033,7 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
&& qual.isTerm
&& ((qual.symbol eq null) || !qual.symbol.isTerm || qual.symbol.isValue)
&& !qtpe.isError
- && qtpe.typeSymbol != NullClass
- && qtpe.typeSymbol != NothingClass
+ && !qtpe.typeSymbol.isBottomClass
&& qtpe != WildcardType
&& !qual.isInstanceOf[ApplyImplicitView] // don't chain views
&& context.implicitsEnabled
@@ -2190,10 +2189,8 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser {
* in an argument closure overlaps with an uninstantiated formal?
*/
def needsInstantiation(tparams: List[Symbol], formals: List[Type], args: List[Tree]) = {
- def isLowerBounded(tparam: Symbol) = {
- val losym = tparam.info.bounds.lo.typeSymbol
- losym != NothingClass && losym != NullClass
- }
+ def isLowerBounded(tparam: Symbol) = !tparam.info.bounds.lo.typeSymbol.isBottomClass
+
(formals, args).zipped exists {
case (formal, Function(vparams, _)) =>
(vparams exists (_.tpt.isEmpty)) &&