summaryrefslogtreecommitdiff
path: root/ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala
diff options
context:
space:
mode:
Diffstat (limited to 'ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala')
-rw-r--r--ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala180
1 files changed, 180 insertions, 0 deletions
diff --git a/ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala b/ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala
new file mode 100644
index 0000000..dfb520f
--- /dev/null
+++ b/ir/src/main/scala/scala/scalajs/ir/InfoSerializers.scala
@@ -0,0 +1,180 @@
+/* __ *\
+** ________ ___ / / ___ __ ____ Scala.js IR **
+** / __/ __// _ | / / / _ | __ / // __/ (c) 2014, LAMP/EPFL **
+** __\ \/ /__/ __ |/ /__/ __ |/_// /_\ \ http://scala-js.org/ **
+** /____/\___/_/ |_/____/_/ | |__/ /____/ **
+** |/____/ **
+\* */
+
+
+package scala.scalajs.ir
+
+import java.io._
+
+import Infos._
+
+object InfoSerializers {
+
+ /** Scala.js IR File Magic Number
+ *
+ * CA FE : first part of magic number of Java class files
+ * 4A 53 : "JS" in ASCII
+ *
+ */
+ final val IRMagicNumber = 0xCAFE4A53
+
+ def serialize(stream: OutputStream, classInfo: ClassInfo): Unit = {
+ new Serializer().serialize(stream, classInfo)
+ }
+
+ def deserializeRoughInfo(stream: InputStream): RoughClassInfo = {
+ deserializeVersionRoughInfo(stream)._2
+ }
+
+ def deserializeFullInfo(stream: InputStream): ClassInfo = {
+ deserializeVersionFullInfo(stream)._2
+ }
+
+ def deserializeVersionRoughInfo(stream: InputStream): (String, RoughClassInfo) = {
+ new Deserializer(stream).deserializeRough()
+ }
+
+ def deserializeVersionFullInfo(stream: InputStream): (String, ClassInfo) = {
+ new Deserializer(stream).deserializeFull()
+ }
+
+ private final class Serializer {
+ def serialize(stream: OutputStream, classInfo: ClassInfo): Unit = {
+ val s = new DataOutputStream(stream)
+
+ def writeSeq[A](seq: Seq[A])(writeElem: A => Unit): Unit = {
+ s.writeInt(seq.size)
+ seq.foreach(writeElem)
+ }
+
+ def writeStrings(seq: Seq[String]): Unit =
+ writeSeq(seq)(s.writeUTF(_))
+
+ // Write the Scala.js IR magic number
+ s.writeInt(IRMagicNumber)
+
+ // Write the Scala.js Version
+ s.writeUTF(ScalaJSVersions.binaryEmitted)
+
+ import classInfo._
+ s.writeUTF(name)
+ s.writeUTF(encodedName)
+ s.writeBoolean(isExported)
+ s.writeInt(ancestorCount)
+ s.writeByte(ClassKind.toByte(kind))
+ s.writeUTF(superClass)
+ writeStrings(ancestors)
+ s.writeInt(optimizerHints.bits)
+
+ def writeMethodInfo(methodInfo: MethodInfo): Unit = {
+ import methodInfo._
+ s.writeUTF(encodedName)
+ s.writeBoolean(isAbstract)
+ s.writeBoolean(isExported)
+ writeSeq(calledMethods.toSeq) {
+ case (caller, callees) => s.writeUTF(caller); writeStrings(callees)
+ }
+ writeSeq(calledMethodsStatic.toSeq) {
+ case (caller, callees) => s.writeUTF(caller); writeStrings(callees)
+ }
+ writeStrings(instantiatedClasses)
+ writeStrings(accessedModules)
+ writeStrings(accessedClassData)
+ s.writeInt(optimizerHints.bits)
+ }
+
+ writeSeq(methods)(writeMethodInfo(_))
+
+ s.flush()
+ }
+ }
+
+ private final class Deserializer(stream: InputStream) {
+ private[this] val input = new DataInputStream(stream)
+
+ def readList[A](readElem: => A): List[A] =
+ List.fill(input.readInt())(readElem)
+
+ def readStrings(): List[String] =
+ readList(input.readUTF())
+
+ def deserializeRough(): (String, RoughClassInfo) = {
+ val version = readHeader()
+
+ import input._
+ val name = readUTF()
+ val encodedName = readUTF()
+ val isExported = readBoolean()
+ val ancestorCount = readInt()
+ val info = RoughClassInfo(name, encodedName, isExported, ancestorCount)
+
+ (version, info)
+ }
+
+ def deserializeFull(): (String, ClassInfo) = {
+ val version = readHeader()
+
+ import input._
+
+ val name = readUTF()
+ val encodedName = readUTF()
+ val isExported = readBoolean()
+ val ancestorCount = readInt()
+ val kind = ClassKind.fromByte(readByte())
+ val superClass = readUTF()
+ val ancestors = readList(readUTF())
+
+ val optimizerHints =
+ if (version == "0.5.0" || version == "0.5.2") OptimizerHints.empty
+ else new OptimizerHints(readInt())
+
+ def readMethod(): MethodInfo = {
+ val encodedName = readUTF()
+ val isAbstract = readBoolean()
+ val isExported = readBoolean()
+ val calledMethods = readList(readUTF() -> readStrings()).toMap
+ val calledMethodsStatic = readList(readUTF() -> readStrings()).toMap
+ val instantiatedClasses = readStrings()
+ val accessedModules = readStrings()
+ val accessedClassData = readStrings()
+ val optimizerHints = new OptimizerHints(readInt())
+ MethodInfo(encodedName, isAbstract, isExported,
+ calledMethods, calledMethodsStatic,
+ instantiatedClasses, accessedModules, accessedClassData,
+ optimizerHints)
+ }
+
+ val methods = readList(readMethod())
+
+ val info = ClassInfo(name, encodedName, isExported, ancestorCount, kind,
+ superClass, ancestors, optimizerHints, methods)
+
+ (version, info)
+ }
+
+ /** Reads the Scala.js IR header and verifies the version compatibility.
+ * Returns the emitted binary version.
+ */
+ def readHeader(): String = {
+ // Check magic number
+ if (input.readInt() != IRMagicNumber)
+ throw new IOException("Not a Scala.js IR file")
+
+ // Check that we support this version of the IR
+ val version = input.readUTF()
+ val supported = ScalaJSVersions.binarySupported
+ if (!supported.contains(version)) {
+ throw new IOException(
+ s"This version ($version) of Scala.js IR is not supported. " +
+ s"Supported versions are: ${supported.mkString(", ")}")
+ }
+
+ version
+ }
+ }
+}