summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGilles Dubochet <gilles.dubochet@epfl.ch>2010-04-29 17:01:22 +0000
committerGilles Dubochet <gilles.dubochet@epfl.ch>2010-04-29 17:01:22 +0000
commit5b937bacd38c34718e16989f3752e1f582ae2698 (patch)
tree6b14bd7647a353d9f39f3973a6e0e3444b738066 /src
parent8eb1d0c6ac940438b5f81d832dd3d0ab26de1ff5 (diff)
downloadscala-5b937bacd38c34718e16989f3752e1f582ae2698.tar.gz
scala-5b937bacd38c34718e16989f3752e1f582ae2698.tar.bz2
scala-5b937bacd38c34718e16989f3752e1f582ae2698.zip
Closes #3310 (very large Scala class is compile...
Closes #3310 (very large Scala class is compiled to invalid classfile because Scala signature can't fit into constant pool). Review by dragos.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala23
-rw-r--r--src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala11
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Definitions.scala1
-rw-r--r--src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala45
-rw-r--r--src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java3
-rw-r--r--src/library/scala/reflect/ScalaLongSignature.java13
6 files changed, 88 insertions, 8 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
index dc193b03db..2b4878a93b 100644
--- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
+++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala
@@ -163,10 +163,10 @@ abstract class GenJVM extends SubComponent {
fjbgContext.JOtherAttribute(jclass, jclass, nme.ScalaSignatureATTR.toString,
versionPickle.bytes, versionPickle.writeIndex)
jclass.addAttribute(scalaAttr)
- val scalaAnnot =
- AnnotationInfo(definitions.ScalaSignatureAnnotation.tpe, Nil, List(
- (nme.bytes, ScalaSigBytes(pickle.bytes.take(pickle.writeIndex)))
- ))
+ val scalaAnnot = {
+ val sigBytes = ScalaSigBytes(pickle.bytes.take(pickle.writeIndex))
+ AnnotationInfo(sigBytes.sigAnnot, Nil, List((nme.bytes, sigBytes)))
+ }
pickledBytes = pickledBytes + pickle.writeIndex
currentRun.symData -= sym
currentRun.symData -= sym.companionSymbol
@@ -416,9 +416,20 @@ abstract class GenJVM extends SubComponent {
buf.putShort(cpool.addUtf8(const.symbolValue.name.toString).toShort)
}
- case ScalaSigBytes(bytes) =>
+ case sb@ScalaSigBytes(bytes) if (!sb.isLong) =>
buf.put('s'.toByte)
- buf.putShort(cpool.addUtf8(reflect.generic.ByteCodecs.encode(bytes)).toShort)
+ buf.putShort(cpool.addUtf8(sb.encodedBytes).toShort)
+
+ case sb@ScalaSigBytes(bytes) if (sb.isLong) =>
+ buf.put('['.toByte)
+ val stringCount = (sb.encodedBytes.length / 65534) + 1
+ buf.putShort(stringCount.toShort)
+ for (i <- 0 until stringCount) {
+ buf.put('s'.toByte)
+ val j = i * 65535
+ val string = sb.encodedBytes.slice(j, j + 65535)
+ buf.putShort(cpool.addUtf8(string).toShort)
+ }
case ArrayAnnotArg(args) =>
buf.put('['.toByte)
diff --git a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
index efb68c4873..edc87108b4 100644
--- a/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
+++ b/src/compiler/scala/tools/nsc/symtab/AnnotationInfos.scala
@@ -45,9 +45,16 @@ trait AnnotationInfos extends reflect.generic.AnnotationInfos { self: SymbolTabl
/** A specific annotation argument that encodes an array of bytes as an array of `Long`. The type of the argument
* declared in the annotation must be `String`. This specialised class is used to encode scala signatures for
* reasons of efficiency, both in term of class-file size and in term of compiler performance. */
- case class ScalaSigBytes(bytes: Array[Byte])
- extends ClassfileAnnotArg {
+ case class ScalaSigBytes(bytes: Array[Byte]) extends ClassfileAnnotArg {
override def toString = (bytes map { byte => (byte & 0xff).toHexString }).mkString("[ ", " ", " ]")
+ lazy val encodedBytes =
+ reflect.generic.ByteCodecs.encode(bytes)
+ def isLong: Boolean = (encodedBytes.length > 65535)
+ def sigAnnot: Type =
+ if (this.isLong)
+ definitions.ScalaLongSignatureAnnotation.tpe
+ else
+ definitions.ScalaSignatureAnnotation.tpe
}
object ScalaSigBytes extends ScalaSigBytesExtractor
diff --git a/src/compiler/scala/tools/nsc/symtab/Definitions.scala b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
index db48189b6b..ed26ebac03 100644
--- a/src/compiler/scala/tools/nsc/symtab/Definitions.scala
+++ b/src/compiler/scala/tools/nsc/symtab/Definitions.scala
@@ -243,6 +243,7 @@ trait Definitions extends reflect.generic.StandardDefinitions {
def Code_lift = getMember(CodeModule, nme.lift_)
lazy val ScalaSignatureAnnotation = getClass("scala.reflect.ScalaSignature")
+ lazy val ScalaLongSignatureAnnotation = getClass("scala.reflect.ScalaLongSignature")
// invoke dynamic support
lazy val LinkageModule = getModule("java.dyn.Linkage")
diff --git a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
index fc635874a6..7cd32ff81e 100644
--- a/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
+++ b/src/compiler/scala/tools/nsc/symtab/classfile/ClassfileParser.scala
@@ -377,6 +377,26 @@ abstract class ClassfileParser {
value
}
+ def getBytes(indices: List[Int]): Array[Byte] = {
+ assert(!indices.isEmpty)
+ var value = values(indices.head).asInstanceOf[Array[Byte]]
+ if (value eq null) {
+ val bytesBuffer = ArrayBuffer.empty[Byte]
+ for (index <- indices) {
+ if (index <= 0 || ConstantPool.this.len <= index) errorBadIndex(index)
+ val start = starts(index)
+ if (in.buf(start).toInt != CONSTANT_UTF8) errorBadTag(start)
+ val len = in.getChar(start + 1)
+ bytesBuffer ++= (in.buf, start + 3, len)
+ }
+ val bytes = bytesBuffer.toArray
+ val decodedLength = reflect.generic.ByteCodecs.decode(bytes)
+ value = bytes.take(decodedLength)
+ values(indices.head) = value
+ }
+ value
+ }
+
/** Throws an exception signaling a bad constant index. */
private def errorBadIndex(index: Int) =
throw new RuntimeException("bad constant pool index: " + index + " at pos: " + in.bp)
@@ -923,6 +943,24 @@ abstract class ClassfileParser {
Some(ScalaSigBytes(pool.getBytes(in.nextChar)))
}
+ def parseScalaLongSigBytes: Option[ScalaSigBytes] = try {
+ val tag = in.nextByte.toChar
+ assert(tag == ARRAY_TAG)
+ val stringCount = in.nextChar
+ val entries =
+ for (i <- 0 until stringCount) yield {
+ val stag = in.nextByte.toChar
+ assert(stag == STRING_TAG)
+ in.nextChar.toInt
+ }
+ Some(ScalaSigBytes(pool.getBytes(entries.toList)))
+ }
+ catch {
+ case e: Throwable =>
+ e.printStackTrace
+ throw e
+ }
+
/** Parse and return a single annotation. If it is malformed,
* return None.
*/
@@ -941,6 +979,11 @@ abstract class ClassfileParser {
case Some(c) => nvpairs += ((name, c))
case None => hasError = true
}
+ else if ((attrType == definitions.ScalaLongSignatureAnnotation.tpe) && (name == nme.bytes))
+ parseScalaLongSigBytes match {
+ case Some(c) => nvpairs += ((name, c))
+ case None => hasError = true
+ }
else
parseAnnotArg match {
case Some(c) => nvpairs += ((name, c))
@@ -981,6 +1024,8 @@ abstract class ClassfileParser {
parseAnnotation(in.nextChar) match {
case Some(scalaSig) if (scalaSig.atp == definitions.ScalaSignatureAnnotation.tpe) =>
scalaSigAnnot = Some(scalaSig)
+ case Some(scalaSig) if (scalaSig.atp == definitions.ScalaLongSignatureAnnotation.tpe) =>
+ scalaSigAnnot = Some(scalaSig)
case Some(annot) =>
sym.addAnnotation(annot)
case None =>
diff --git a/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java b/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java
index 4fa048177c..0e6b43f1e2 100644
--- a/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java
+++ b/src/fjbg/ch/epfl/lamp/fjbg/JConstantPool.java
@@ -383,6 +383,9 @@ public class JConstantPool {
public int getSize() { return 1; }
public void writeContentsTo(DataOutputStream stream) throws IOException {
if (bytes != null) {
+ if (bytes.length > 65535) {
+ throw new IOException("String literal of length " + bytes.length + " does not fit in Classfile");
+ }
stream.writeShort(bytes.length);
stream.write(bytes);
}
diff --git a/src/library/scala/reflect/ScalaLongSignature.java b/src/library/scala/reflect/ScalaLongSignature.java
new file mode 100644
index 0000000000..1ffd6d2520
--- /dev/null
+++ b/src/library/scala/reflect/ScalaLongSignature.java
@@ -0,0 +1,13 @@
+package scala.reflect;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/** */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ScalaLongSignature {
+ public String[] bytes();
+}