@@ -3,14 +3,18 @@ package backend
3
3
package jvm
4
4
5
5
import scala .tools .asm
6
+ import scala .tools .asm .AnnotationVisitor
6
7
import scala .tools .asm .ClassWriter
7
8
import scala .collection .mutable
8
9
import dotty .tools .io .AbstractFile
9
10
10
11
import dotty .tools .dotc .CompilationUnit
12
+ import dotty .tools .dotc .ast .tpd
13
+ import dotty .tools .dotc .ast .Trees
11
14
import dotty .tools .dotc .core .Annotations .Annotation
15
+ import dotty .tools .dotc .core .Constants ._
12
16
import dotty .tools .dotc .core .Symbols ._
13
- import dotty .tools .dotc .core .StdNames .str
17
+ import dotty .tools .dotc .core .StdNames ._
14
18
import dotty .tools .dotc .core .Decorators ._
15
19
import dotty .tools .dotc .core .Flags
16
20
import dotty .tools .dotc .core .Names .Name
@@ -30,6 +34,7 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
30
34
// import bTypes._
31
35
// import coreBTypes._
32
36
import bTypes ._
37
+ import tpd ._
33
38
import coreBTypes ._
34
39
import int ._
35
40
@@ -273,26 +278,138 @@ trait BCodeHelpers extends BCodeIdiomatic with BytecodeWriters {
273
278
/*
274
279
* must-single-thread
275
280
*/
276
- def emitAnnotations (cw : asm.ClassVisitor , annotations : List [Annotation ]) =
277
- int.emitAnnotations(cw, annotations, BCodeHelpers .this )(this )
281
+ def emitAnnotations (cw : asm.ClassVisitor , annotations : List [Annotation ]): Unit =
282
+ for (annot <- annotations; if shouldEmitAnnotation(annot)) {
283
+ val typ = annot.tree.tpe
284
+ val assocs = assocsFromApply(annot.tree)
285
+ val av = cw.visitAnnotation(typeDescriptor(typ.asInstanceOf [Type ]), isRuntimeVisible(annot))
286
+ emitAssocs(av, assocs, BCodeHelpers .this )(this )
287
+ }
278
288
279
289
/*
280
290
* must-single-thread
281
291
*/
282
- def emitAnnotations (mw : asm.MethodVisitor , annotations : List [Annotation ]) =
283
- int.emitAnnotations(mw, annotations, BCodeHelpers .this )(this )
292
+ def emitAnnotations (mw : asm.MethodVisitor , annotations : List [Annotation ]): Unit =
293
+ for (annot <- annotations; if shouldEmitAnnotation(annot)) {
294
+ val typ = annot.tree.tpe
295
+ val assocs = assocsFromApply(annot.tree)
296
+ val av = mw.visitAnnotation(typeDescriptor(typ.asInstanceOf [Type ]), isRuntimeVisible(annot))
297
+ emitAssocs(av, assocs, BCodeHelpers .this )(this )
298
+ }
284
299
285
300
/*
286
301
* must-single-thread
287
302
*/
288
- def emitAnnotations (fw : asm.FieldVisitor , annotations : List [Annotation ]) =
289
- int.emitAnnotations(fw, annotations, BCodeHelpers .this )(this )
303
+ def emitAnnotations (fw : asm.FieldVisitor , annotations : List [Annotation ]): Unit =
304
+ for (annot <- annotations; if shouldEmitAnnotation(annot)) {
305
+ val typ = annot.tree.tpe
306
+ val assocs = assocsFromApply(annot.tree)
307
+ val av = fw.visitAnnotation(typeDescriptor(typ.asInstanceOf [Type ]), isRuntimeVisible(annot))
308
+ emitAssocs(av, assocs, BCodeHelpers .this )(this )
309
+ }
290
310
291
311
/*
292
312
* must-single-thread
293
313
*/
294
- def emitParamAnnotations (jmethod : asm.MethodVisitor , pannotss : List [List [Annotation ]]) =
295
- int.emitParamAnnotations(jmethod, pannotss, BCodeHelpers .this )(this )
314
+ def emitParamAnnotations (jmethod : asm.MethodVisitor , pannotss : List [List [Annotation ]]): Unit =
315
+ val annotationss = pannotss map (_ filter shouldEmitAnnotation)
316
+ if (annotationss forall (_.isEmpty)) return
317
+ for ((annots, idx) <- annotationss.zipWithIndex;
318
+ annot <- annots) {
319
+ val typ = annot.tree.tpe
320
+ val assocs = assocsFromApply(annot.tree)
321
+ val pannVisitor : asm.AnnotationVisitor = jmethod.visitParameterAnnotation(idx, typeDescriptor(typ.asInstanceOf [Type ]), isRuntimeVisible(annot))
322
+ emitAssocs(pannVisitor, assocs, BCodeHelpers .this )(this )
323
+ }
324
+
325
+ private def emitAssocs (av : asm.AnnotationVisitor , assocs : List [(Name , Object )], bcodeStore : BCodeHelpers )
326
+ (innerClasesStore : bcodeStore.BCInnerClassGen ) = {
327
+ for ((name, value) <- assocs)
328
+ emitArgument(av, name.mangledString, value.asInstanceOf [Tree ], bcodeStore)(innerClasesStore)
329
+ av.visitEnd()
330
+ }
331
+
332
+ private def emitArgument (av : AnnotationVisitor ,
333
+ name : String ,
334
+ arg : Tree , bcodeStore : BCodeHelpers )(innerClasesStore : bcodeStore.BCInnerClassGen ): Unit = {
335
+ val narg = normalizeArgument(arg)
336
+ // Transformation phases are not run on annotation trees, so we need to run
337
+ // `constToLiteral` at this point.
338
+ val t = constToLiteral(narg)(ctx.withPhase(ctx.erasurePhase))
339
+ t match {
340
+ case Literal (const @ Constant (_)) =>
341
+ const.tag match {
342
+ case BooleanTag | ByteTag | ShortTag | CharTag | IntTag | LongTag | FloatTag | DoubleTag => av.visit(name, const.value)
343
+ case StringTag =>
344
+ assert(const.value != null , const) // TODO this invariant isn't documented in `case class Constant`
345
+ av.visit(name, const.stringValue) // `stringValue` special-cases null, but that execution path isn't exercised for a const with StringTag
346
+ case ClazzTag => av.visit(name, typeToTypeKind(const.typeValue)(bcodeStore)(innerClasesStore).toASMType)
347
+ case EnumTag =>
348
+ val edesc = innerClasesStore.typeDescriptor(const.tpe.asInstanceOf [bcodeStore.int.Type ]) // the class descriptor of the enumeration class.
349
+ val evalue = const.symbolValue.name.mangledString // value the actual enumeration value.
350
+ av.visitEnum(name, edesc, evalue)
351
+ }
352
+ case t : TypeApply if (t.fun.symbol == defn.Predef_classOf ) =>
353
+ av.visit(name, typeToTypeKind(t.args.head.tpe.classSymbol.denot.info)(bcodeStore)(innerClasesStore).toASMType)
354
+ case Ident (nme.WILDCARD ) =>
355
+ // An underscore argument indicates that we want to use the default value for this parameter, so do not emit anything
356
+ case t : tpd.RefTree if t.symbol.denot.owner.isAllOf(Flags .JavaEnumTrait ) =>
357
+ val edesc = innerClasesStore.typeDescriptor(t.tpe.asInstanceOf [bcodeStore.int.Type ]) // the class descriptor of the enumeration class.
358
+ val evalue = t.symbol.name.mangledString // value the actual enumeration value.
359
+ av.visitEnum(name, edesc, evalue)
360
+ case t : SeqLiteral =>
361
+ val arrAnnotV : AnnotationVisitor = av.visitArray(name)
362
+ for (arg <- t.elems) { emitArgument(arrAnnotV, null , arg, bcodeStore)(innerClasesStore) }
363
+ arrAnnotV.visitEnd()
364
+
365
+ case Apply (fun, args) if fun.symbol == defn.ArrayClass .primaryConstructor ||
366
+ toDenot(fun.symbol).owner == defn.ArrayClass .linkedClass && fun.symbol.name == nme.apply =>
367
+ val arrAnnotV : AnnotationVisitor = av.visitArray(name)
368
+
369
+ var actualArgs = if (fun.tpe.isImplicitMethod) {
370
+ // generic array method, need to get implicit argument out of the way
371
+ fun.asInstanceOf [Apply ].args
372
+ } else args
373
+
374
+ val flatArgs = actualArgs.flatMap { arg =>
375
+ normalizeArgument(arg) match {
376
+ case t : tpd.SeqLiteral => t.elems
377
+ case e => List (e)
378
+ }
379
+ }
380
+ for (arg <- flatArgs) {
381
+ emitArgument(arrAnnotV, null , arg, bcodeStore)(innerClasesStore)
382
+ }
383
+ arrAnnotV.visitEnd()
384
+ /*
385
+ case sb @ ScalaSigBytes(bytes) =>
386
+ // see http://www.scala-lang.org/sid/10 (Storage of pickled Scala signatures in class files)
387
+ // also JVMS Sec. 4.7.16.1 The element_value structure and JVMS Sec. 4.4.7 The CONSTANT_Utf8_info Structure.
388
+ if (sb.fitsInOneString) {
389
+ av.visit(name, BCodeAsmCommon.strEncode(sb))
390
+ } else {
391
+ val arrAnnotV: asm.AnnotationVisitor = av.visitArray(name)
392
+ for(arg <- BCodeAsmCommon.arrEncode(sb)) { arrAnnotV.visit(name, arg) }
393
+ arrAnnotV.visitEnd()
394
+ } // for the lazy val in ScalaSigBytes to be GC'ed, the invoker of emitAnnotations() should hold the ScalaSigBytes in a method-local var that doesn't escape.
395
+ */
396
+ case t @ Apply (constr, args) if t.tpe.derivesFrom(JavaAnnotationClass ) =>
397
+ val typ = t.tpe.classSymbol.denot.info
398
+ val assocs = assocsFromApply(t)
399
+ val desc = innerClasesStore.typeDescriptor(typ.asInstanceOf [bcodeStore.int.Type ]) // the class descriptor of the nested annotation class
400
+ val nestedVisitor = av.visitAnnotation(name, desc)
401
+ emitAssocs(nestedVisitor, assocs, bcodeStore)(innerClasesStore)
402
+
403
+ case t =>
404
+ ctx.error(ex " Annotation argument is not a constant " , t.sourcePos)
405
+ }
406
+ }
407
+
408
+ private def normalizeArgument (arg : Tree ): Tree = arg match {
409
+ case Trees .NamedArg (_, arg1) => normalizeArgument(arg1)
410
+ case Trees .Typed (arg1, _) => normalizeArgument(arg1)
411
+ case _ => arg
412
+ }
296
413
297
414
} // end of trait BCAnnotGen
298
415
0 commit comments