From c98f8ec7425435ab10af3b3ff6031924ba51b171 Mon Sep 17 00:00:00 2001 From: mihaylov Date: Wed, 17 May 2006 08:43:54 +0000 Subject: Added support for emitting Java annotations int... Added support for emitting Java annotations into classfiles --- lib/fjbg.jar.desired.sha1 | 2 +- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 86 ++++++++++++++++++++-- src/compiler/scala/tools/nsc/symtab/StdNames.scala | 1 + .../nsc/symtab/classfile/ClassfileParser.scala | 33 ++++++--- 4 files changed, 107 insertions(+), 15 deletions(-) diff --git a/lib/fjbg.jar.desired.sha1 b/lib/fjbg.jar.desired.sha1 index 992da0b168..872a94f9b0 100644 --- a/lib/fjbg.jar.desired.sha1 +++ b/lib/fjbg.jar.desired.sha1 @@ -1 +1 @@ -020a429f8adc3e7230fb8dab88c38619123eeafa ?fjbg.jar +6c45acb11cf51afe1d734eea4ccd9d55cf41d271 ?fjbg.jar diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index c49854e277..4d73965840 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -8,6 +8,7 @@ package scala.tools.nsc.backend.jvm; import java.io.File; +import java.nio.ByteBuffer; import scala.collection.mutable.{Map, HashMap}; import scala.tools.nsc.symtab._; @@ -169,9 +170,79 @@ abstract class GenJVM extends SubComponent { clasz.fields foreach genField; clasz.methods foreach genMethod; + addAttributes(jclass, c.symbol.attributes); + emitClass(jclass, c.symbol) } + + def addAttributes(jmember: JMember, attributes: List[AttrInfo]): Unit = { + if (attributes.isEmpty) return; + + val cpool = jmember.getConstantPool(); + val buf: ByteBuffer = ByteBuffer.allocate(2048); + var nattr = 0; + + // put some radom value; the actual number is determined at the end + buf.putShort(0xbaba.toShort) + + for (val Pair(typ, consts) <- attributes; typ.symbol.hasFlag(Flags.JAVA)) { + nattr = nattr + 1; + val jtype = javaType(toTypeKind(typ)); + buf.putShort(cpool.addUtf8(jtype.getSignature()).toShort); + assert(consts.length == 1, consts.toString()) + buf.putShort(1.toShort); // for now only 1 constructor parameter + buf.putShort(cpool.addUtf8("value").toShort); + for (val const <- consts) { + const.tag match { + case BooleanTag => + buf.put('Z'.toByte) + buf.putShort(cpool.addInteger(if(const.booleanValue) 1 else 0).toShort) + case ByteTag => + buf.put('B'.toByte) + buf.putShort(cpool.addInteger(const.byteValue).toShort) + case ShortTag => + buf.put('S'.toByte) + buf.putShort(cpool.addInteger(const.shortValue).toShort) + case CharTag => + buf.put('C'.toByte) + buf.putShort(cpool.addInteger(const.charValue).toShort) + case IntTag => + buf.put('I'.toByte) + buf.putShort(cpool.addInteger(const.intValue).toShort) + case LongTag => + buf.put('J'.toByte) + buf.putShort(cpool.addLong(const.longValue).toShort) + case FloatTag => + buf.put('F'.toByte) + buf.putShort(cpool.addFloat(const.floatValue).toShort) + case DoubleTag => + buf.put('D'.toByte) + buf.putShort(cpool.addDouble(const.doubleValue).toShort) + case StringTag => + buf.put('s'.toByte); + buf.putShort(cpool.addUtf8(const.stringValue).toShort) + case ClassTag => + buf.put('c'.toByte); + buf.putShort(cpool.addUtf8(javaType(toTypeKind(const.typeValue)).getSignature()).toShort) + //case NullTag => AllRefClass.tpe + } + } + } + if (nattr > 0) { + val length = buf.position(); + buf.putShort(0, nattr.toShort) + val arr = buf.array().subArray(0, length); + + val attr = jmember.getContext().JOtherAttribute(jmember.getJClass(), + jmember, + nme.RuntimeAnnotationATTR.toString(), + arr, + length) + jmember.addAttribute(attr) + } + } + def isTopLevelModule(sym: Symbol): Boolean = atPhase (currentRun.refchecksPhase) { sym.isModuleClass && !sym.isImplClass && !sym.isNestedClass @@ -191,9 +262,12 @@ abstract class GenJVM extends SubComponent { case Pair(VolatileAttr, _) => attributes = attributes | JAccessFlags.ACC_VOLATILE; case _ => (); }} - jclass.addNewField(javaFlags(f.symbol) | attributes, - javaName(f.symbol), - javaType(toTypeKind(f.symbol.tpe))); + val jfield = + jclass.addNewField(javaFlags(f.symbol) | attributes, + javaName(f.symbol), + javaType(toTypeKind(f.symbol.tpe))); + + addAttributes(jfield, f.symbol.attributes) } def genMethod(m: IMethod): Unit = { @@ -231,7 +305,7 @@ abstract class GenJVM extends SubComponent { // } val cp = jclass.getConstantPool(); val reInx = cp.addClass(JAVA_RMI_REMOTEEXCEPTION); - val contents = java.nio.ByteBuffer.allocate(4); // u2 + u2[1] + val contents = ByteBuffer.allocate(4); // u2 + u2[1] contents.putShort(1.asInstanceOf[Short]); contents.putShort(reInx.asInstanceOf[Short]); if (settings.debug.value) @@ -251,6 +325,8 @@ abstract class GenJVM extends SubComponent { genCode(m); genLocalVariableTable; } + + addAttributes(jmethod, m.symbol.attributes) } def addModuleInstanceField: Unit = { @@ -1075,7 +1151,7 @@ abstract class GenJVM extends SubComponent { val pc = jcode.getPC(); var anonCounter = 0; - val lvTab = java.nio.ByteBuffer.allocate(2 + 10 * vars.length); + val lvTab = ByteBuffer.allocate(2 + 10 * vars.length); lvTab.putShort(vars.length.asInstanceOf[Short]); for (val lv <- vars) { val name = if (lv.getName() == null) { diff --git a/src/compiler/scala/tools/nsc/symtab/StdNames.scala b/src/compiler/scala/tools/nsc/symtab/StdNames.scala index 549d2dac23..deecaeb63c 100644 --- a/src/compiler/scala/tools/nsc/symtab/StdNames.scala +++ b/src/compiler/scala/tools/nsc/symtab/StdNames.scala @@ -284,6 +284,7 @@ trait StdNames requires SymbolTable { val tag = newTermName("$tag"); val wait_ = newTermName("wait"); val lift_ = newTermName("lift") + val value = newTermName("value"); val ZNOT = encode("!"); val ZAND = encode("&&"); diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index 489502910c..0bd20198a4 100644 --- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -242,12 +242,14 @@ abstract class ClassfileParser { def parseClass(): unit = { val jflags = in.nextChar; + val isAttribute = (jflags & JAVA_ACC_ANNOTATION) != 0; var sflags = transFlags(jflags); if ((sflags & DEFERRED) != 0) sflags = sflags & ~DEFERRED | ABSTRACT; val c = pool.getClassSymbol(in.nextChar); if (c != clazz) throw new IOException("class file '" + in.file + "' contains wrong " + clazz); - val superType = pool.getSuperClass(in.nextChar).tpe; + val superType = if (isAttribute) { in.nextChar; definitions.AttributeClass.tpe } + else pool.getSuperClass(in.nextChar).tpe; val ifaceCount = in.nextChar; val parents = (superType :: (for (val i <- List.range(0, ifaceCount)) @@ -276,12 +278,24 @@ abstract class ClassfileParser { for (val i <- Iterator.range(0, fieldCount)) parseField(); val methodCount = in.nextChar; for (val i <- Iterator.range(0, methodCount)) parseMethod(); - if (instanceDefs.lookup(nme.CONSTRUCTOR) == NoSymbol && (sflags & INTERFACE) == 0) { - //System.out.println("adding constructor to " + clazz);//DEBUG - instanceDefs.enter( - clazz.newConstructor(Position.NOPOS) - .setFlag(clazz.flags & ConstrFlags).setInfo(MethodType(List(), clazz.tpe))); - } + if ((instanceDefs.lookup(nme.CONSTRUCTOR) == NoSymbol + && (sflags & INTERFACE) == 0) || + isAttribute) + { + //System.out.println("adding constructor to " + clazz);//DEBUG + val constrParamTypes = + if (isAttribute) { + val value = instanceDefs.lookup(nme.value) + if (value == NoSymbol) List () + else List(value.tpe.resultType) + //System.out.println("" + value + " : " + value.tpe) + } + else List() + instanceDefs.enter( + clazz.newConstructor(Position.NOPOS) + .setFlag(clazz.flags & ConstrFlags) + .setInfo(MethodType(constrParamTypes, clazz.tpe))); + } } } @@ -600,11 +614,12 @@ abstract class ClassfileParser { res = res | PRIVATE else if ((flags & JAVA_ACC_PROTECTED) != 0) res = res | PROTECTED - if ((flags & JAVA_ACC_ABSTRACT) != 0) + if ((flags & JAVA_ACC_ABSTRACT) != 0 && (flags & JAVA_ACC_ANNOTATION) == 0) res = res | DEFERRED; if ((flags & JAVA_ACC_FINAL) != 0) res = res | FINAL; - if ((flags & JAVA_ACC_INTERFACE) != 0) + if (((flags & JAVA_ACC_INTERFACE) != 0) && + ((flags & JAVA_ACC_ANNOTATION) == 0)) res = res | TRAIT | INTERFACE | ABSTRACT; if ((flags & JAVA_ACC_SYNTHETIC) != 0) res = res | SYNTHETIC; -- cgit v1.2.3