Skip to content

Commit b301881

Browse files
committed
Virtualize attribute read
1 parent e63dbd6 commit b301881

File tree

1 file changed

+60
-31
lines changed

1 file changed

+60
-31
lines changed

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ class ClassfileParser(
191191

192192
setClassInfo(moduleRoot, staticInfo, fromScala2 = false)
193193

194-
classInfo = parseAttributes(classRoot.symbol, classInfo)
194+
classInfo = parseAttributes(classInfo).complete(classRoot.symbol)
195195
if (isAnnotation)
196196
// classInfo must be a TempClassInfoType and not a TempPolyType,
197197
// because Java annotations cannot have type parameters.
@@ -227,26 +227,28 @@ class ClassfileParser(
227227
val sflags =
228228
if (method) Flags.Method | methodTranslation.flags(jflags)
229229
else fieldTranslation.flags(jflags)
230-
val name = pool.getName(in.nextChar)
231-
if (!sflags.isOneOf(Flags.PrivateOrArtifact) || name.name == nme.CONSTRUCTOR) {
230+
val preName = pool.getName(in.nextChar)
231+
if (!sflags.isOneOf(Flags.PrivateOrArtifact) || preName.name == nme.CONSTRUCTOR) {
232+
val isVarargs = sflags.is(Flags.Method) && (jflags & JAVA_ACC_VARARGS) != 0
233+
val info = pool.getType(in.nextChar, isVarargs) // info
234+
val attrCompleter = parseAttributes(info, isVarargs)
235+
val completer = memberCompleter(attrCompleter, preName.name, jflags, info)
232236
val member = newSymbol(
233-
getOwner(jflags), name.name, sflags, memberCompleter,
237+
getOwner(jflags), preName.name, sflags, completer,
234238
getPrivateWithin(jflags), coord = start)
235239
getScope(jflags).enter(member)
236240
}
237-
// skip rest of member for now
238-
in.nextChar // info
239-
skipAttributes()
241+
else {
242+
in.nextChar // info
243+
skipAttributes()
244+
}
240245
}
241246

242-
val memberCompleter: LazyType = new LazyType {
247+
def memberCompleter(attrCompleter: AttributeCompleter, name: SimpleName, jflags: Int, info: Type): LazyType = new LazyType {
243248

244-
def complete(denot: SymDenotation)(using Context): Unit = withReader(classfile) { (using in) =>
245-
in.bp = denot.symbol.coord.toIndex
249+
def complete(denot: SymDenotation)(using Context): Unit = {
246250
val sym = denot.symbol
247-
val jflags = in.nextChar
248251
val isEnum = (jflags & JAVA_ACC_ENUM) != 0
249-
val name = pool.getName(in.nextChar).name
250252
val isConstructor = name eq nme.CONSTRUCTOR
251253

252254
/** Strip leading outer param from constructor and trailing access tag for
@@ -282,10 +284,9 @@ class ClassfileParser(
282284
addConstructorTypeParams(denot)
283285
}
284286

285-
val isVarargs = denot.is(Flags.Method) && (jflags & JAVA_ACC_VARARGS) != 0
286-
denot.info = pool.getType(in.nextChar, isVarargs)
287+
denot.info = info
287288
if (isConstructor) normalizeConstructorParams()
288-
denot.info = translateTempPoly(parseAttributes(sym, denot.info, isVarargs))
289+
denot.info = translateTempPoly(attrCompleter.complete(sym))
289290
if (isConstructor) normalizeConstructorInfo()
290291

291292
if (ctx.explicitNulls) denot.info = JavaNullInterop.nullifyMember(denot.symbol, denot.info, isEnum)
@@ -604,38 +605,63 @@ class ClassfileParser(
604605
None // ignore malformed annotations
605606
}
606607

607-
def parseAttributes(sym: Symbol, symtype: Type, isVarargs: Boolean = false)(using ctx: Context, in: DataReader): Type = {
608+
abstract class AttributeCompleter {
609+
private val effectList = new ArrayBuffer[Context => Unit]()
610+
inline def later(inline op: Context ?=> Unit): Unit =
611+
effectList.append((ctx: Context) => op(using ctx)) // TODO: avoid closure creation
612+
613+
protected def force()(using ctx: Context): Unit =
614+
effectList.foreach(_.apply(ctx))
615+
616+
def complete(sym: Symbol)(using Context): Type
617+
}
618+
619+
// invariant: `in` should not be captured inside the result function
620+
def parseAttributes(symtype: Type, isVarargs: Boolean = false)(using ctx: Context, in: DataReader): AttributeCompleter = {
621+
var sym: Symbol = null // placeholder
608622
var newType = symtype
609623

624+
val res = new AttributeCompleter {
625+
def complete(symIn: Symbol)(using Context): Type = {
626+
sym = symIn
627+
force()
628+
cook.apply(newType)
629+
}
630+
}
631+
632+
import res.later
633+
610634
def parseAttribute(): Unit = {
611635
val attrName = pool.getName(in.nextChar).name.toTypeName
612636
val attrLen = in.nextInt
613637
val end = in.bp + attrLen
614638
attrName match {
615639
case tpnme.SignatureATTR =>
616640
val sig = pool.getExternalName(in.nextChar)
617-
newType = sigToType(sig.value, sym, isVarargs)
618-
if (ctx.debug && ctx.verbose)
619-
println("" + sym + "; signature = " + sig + " type = " + newType)
641+
later {
642+
newType = sigToType(sig.value, sym, isVarargs)
643+
if (ctx.debug && ctx.verbose)
644+
println("" + sym + "; signature = " + sig + " type = " + newType)
645+
}
620646

621647
case tpnme.SyntheticATTR =>
622-
sym.setFlag(Flags.SyntheticArtifact)
648+
later { sym.setFlag(Flags.SyntheticArtifact) }
623649

624650
case tpnme.BridgeATTR =>
625-
sym.setFlag(Flags.Bridge)
651+
later { sym.setFlag(Flags.Bridge) }
626652

627653
case tpnme.DeprecatedATTR =>
628654
val msg = Literal(Constant("see corresponding Javadoc for more information."))
629655
val since = Literal(Constant(""))
630-
sym.addAnnotation(Annotation(defn.DeprecatedAnnot, msg, since))
656+
later { sym.addAnnotation(Annotation(defn.DeprecatedAnnot, msg, since)) }
631657

632658
case tpnme.ConstantValueATTR =>
633659
val c = pool.getConstant(in.nextChar, symtype)
634660
if (c ne null) newType = ConstantType(c)
635661
else report.warning(s"Invalid constant in attribute of ${sym.showLocated} while parsing ${classfile}")
636662

637663
case tpnme.AnnotationDefaultATTR =>
638-
sym.addAnnotation(Annotation(defn.AnnotationDefaultAnnot, Nil))
664+
later { sym.addAnnotation(Annotation(defn.AnnotationDefaultAnnot, Nil)) }
639665

640666
// Java annotations on classes / methods / fields with RetentionPolicy.RUNTIME
641667
case tpnme.RuntimeVisibleAnnotationATTR
@@ -652,12 +678,14 @@ class ClassfileParser(
652678
parseExceptions(attrLen)
653679

654680
case tpnme.CodeATTR =>
655-
if (sym.owner.isAllOf(Flags.JavaInterface)) {
656-
sym.resetFlag(Flags.Deferred)
657-
sym.owner.resetFlag(Flags.PureInterface)
658-
report.log(s"$sym in ${sym.owner} is a java8+ default method.")
659-
}
660681
in.skip(attrLen)
682+
later {
683+
if (sym.owner.isAllOf(Flags.JavaInterface)) {
684+
sym.resetFlag(Flags.Deferred)
685+
sym.owner.resetFlag(Flags.PureInterface)
686+
report.log(s"$sym in ${sym.owner} is a java8+ default method.")
687+
}
688+
}
661689

662690
case _ =>
663691
}
@@ -673,18 +701,19 @@ class ClassfileParser(
673701
for (n <- 0 until nClasses) {
674702
// FIXME: this performs an equivalent of getExceptionTypes instead of getGenericExceptionTypes (SI-7065)
675703
val cls = pool.getClassSymbol(in.nextChar.toInt)
676-
sym.addAnnotation(ThrowsAnnotation(cls.asClass))
704+
later { sym.addAnnotation(ThrowsAnnotation(cls.asClass)) }
677705
}
678706
}
679707

708+
680709
/** Parse a sequence of annotations and attaches them to the
681710
* current symbol sym, except for the ScalaSignature annotation that it returns, if it is available. */
682711
def parseAnnotations(len: Int): Unit = {
683712
val nAttr = in.nextChar
684713
for (n <- 0 until nAttr)
685714
parseAnnotation(in.nextChar) match {
686715
case Some(annot) =>
687-
sym.addAnnotation(annot)
716+
later { sym.addAnnotation(annot) }
688717
case None =>
689718
}
690719
}
@@ -693,7 +722,7 @@ class ClassfileParser(
693722
for (i <- 0 until in.nextChar)
694723
parseAttribute()
695724

696-
cook.apply(newType)
725+
res
697726
}
698727

699728
/** Annotations in Scala are assumed to get all their arguments as constructor

0 commit comments

Comments
 (0)