Permalink
Browse files

Updated proguard script + added experimental trimmer subproject

  • Loading branch information...
1 parent 031a6a5 commit dc3709528671440db83b256545c3e839702089c8 @ochafik committed May 12, 2012
@@ -52,6 +52,12 @@ find src/library -name '*.scala' -exec sed -i.bak -E 's/@specialized(\([^)]+\))?
echo "Recompiling 'quick'"
ant quick.clean build || exit 1
+echo "Converting line endings of scripts"
+for B in scala scalac scalap scaladoc ; do
+ dos2unix build/pack/bin/$B || exit 1
+done
+
+echo "Copying scala-patched-library.jar"
cp -f build/pack/lib/scala-library.jar ../scala-patched-library.jar || exit 1
cd ..
@@ -1,5 +1,8 @@
#!/bin/bash
+# Revert @specialized removal
+#find . -name '*.scala' -exec mv -f '{}.bak' '{}' ';'
+
cd scala-scalight || exit 1
git diff src/compiler > ../scalight-compiler.diff
git diff src/library > ../scalight-library.diff
@@ -6,18 +6,28 @@
** MODULE$;
}
--keep class scala.Product*
--keep class scala.Tuple*
--keep class scala.Function*
--keep class scala.PartialFunction*
--keep class scala.Option*
--keep class scala.Some*
--keep class scala.None*
--keep class scala.Either*
--keep class scala.Predef*
--keep class scala.runtime.BoxesRunTime
+-keep class scala.Serializable { *; }
+-keep class scala.Product* { *; }
+-keep class scala.Tuple* { *; }
+-keep class scala.Function* { *; }
+-keep class scala.PartialFunction* { *; }
+-keep class scala.runtime.AbstractFunction* { *; }
+-keep class scala.Option* { *; }
+-keep class scala.Some* { *; }
+-keep class scala.None* { *; }
+-keep class scala.Either* { *; }
+-keep class scala.Predef* {
+ public <methods>;
+}
+-keep class scala.runtime.BoxesRunTime* {
+ public <methods>;
+}
+-keep class scala.runtime.ScalaRunTime* {
+ public <methods>;
+}
+-keep class scala.runtime.VolatileObjectRef* { *; }
-optimizationpasses 3
-overloadaggressively
--repackageclasses ''
+-repackageclasses 'scala.private'
-allowaccessmodification
@@ -0,0 +1,81 @@
+import org.objectweb.asm._
+
+/**
+ * MUST COMPILE SCALA WITH -no-specialization first !
+ * http://asm.ow2.org/asm40/javadoc/user/
+ */
+object ASMUtils {
+
+ def removeAnnotations(b: Array[Byte]) = //if (true) b else
+ {
+ val w = new ClassWriter(0)
+ val f = new ClassVisitor(0, w) {
+ override def visitMethod(access: Int, name: String, desc: String, signature: String, exceptions: Array[String]) = {
+ new MethodVisitor(Opcodes.ASM4, super.visitMethod(access, name, desc, signature, exceptions)) {
+ override def visitAnnotation(desc: String, visible: Boolean) =
+ null
+ override def visitAnnotationDefault() =
+ null
+ override def visitParameterAnnotation(parameter: Int, desc: String, visible: Boolean) =
+ null
+ override def visitAttribute(a: Attribute) = {}
+ }
+ }
+ override def visitAnnotation(desc: String, visible: Boolean) =
+ null
+
+ override def visitAttribute(a: Attribute) = {}
+ }
+ new ClassReader(b).accept(f, 0)
+ w.toByteArray
+ }
+
+ def getReferencedClasses(b: Array[Byte]) = {
+ val s = collection.mutable.HashSet[String]()
+
+ val r = new ClassReader(b)
+ val n = r.getClassName
+ r.accept(
+ new ClassVisitor(0) {
+ def add(t: Type) = {
+ if (t.getSort == Type.OBJECT)
+ s += t.getInternalName
+ }
+ override def visitOuterClass(owner: String, name: String, desc: String) = {
+ s += owner
+ super.visitOuterClass(owner, name, desc)
+ }
+ override def visitMethod(access: Int, name: String, desc: String, signature: String, exceptions: Array[String]) = {
+ val t = Type.getMethodType(desc)
+ t.getArgumentTypes().map(add(_))
+ add(t.getReturnType())
+
+ new MethodVisitor(Opcodes.ASM4, super.visitMethod(access, name, desc, signature, exceptions)) {
+ override def visitFieldInsn(opcode: Int, owner: String, name: String, desc: String) = {
+ s += owner
+ super.visitFieldInsn(opcode, owner, name, desc)
+ }
+ override def visitMethodInsn(opcode: Int, owner: String, name: String, desc: String) = {
+ s += owner
+ super.visitMethodInsn(opcode, owner, name, desc)
+ }
+ override def visitTypeInsn(opcode: Int, `type`: String) = {
+ s += `type`
+ super.visitTypeInsn(opcode, `type`)
+ }
+ override def visitMultiANewArrayInsn(desc: String, dims: Int) = {
+ add(Type.getType(desc).getElementType)
+ super.visitMultiANewArrayInsn(desc, dims)
+ }
+ }
+ }
+ override def visitField(access: Int, name: String, desc: String, signature: String, value: AnyRef) = {
+ add(Type.getType(desc))
+ super.visitField(access, name, desc, signature, value)
+ }
+ },
+ 0
+ )
+ (n, s.toSet)
+ }
+}
View
@@ -0,0 +1,12 @@
+object IOUtils {
+ import java.io._
+
+ def readBytes(in: InputStream) = {
+ val o = new ByteArrayOutputStream
+ val b = new Array[Byte](1024)
+ var l = 0
+ while ({ l = in.read(b) ; l > 0 })
+ o.write(b, 0, l)
+ o.toByteArray
+ }
+}
View
@@ -0,0 +1,3 @@
+Program that just reads a scala-library.jar, chooses a few root classes to keep, follows the dependencies and writes the result into a scalight-library.jar.
+
+This is like a very simple version of Proguard, which helps when trying to analyze the dependencies and/or explicitly breaking them.
View
@@ -0,0 +1,127 @@
+import System._
+import java.io._
+import sys._
+import process._
+import java.util.zip._
+
+import collection.JavaConversions._
+import org.objectweb.asm._
+import ASMUtils._
+import IOUtils._
+
+/**
+ * MUST COMPILE SCALA WITH -no-specialization first !
+ * http://asm.ow2.org/asm40/javadoc/user/
+ */
+object Trimmer extends App {
+ val (jar, dest) = args match {
+ case Array(j, d) => (j, d)
+ case _ =>
+ (
+ getProperty("user.home") +
+ "RuntimeLibrary/scala-patched-library.jar",
+ "scalight-trimmed-library.jar"
+ )
+ }
+
+ def analyzeJarDependencies(in: ZipInputStream): Map[String, Set[String]] = {
+ val deps = new collection.mutable.HashMap[String, Set[String]]()
+ var e: ZipEntry = null
+
+ while ({ e = in.getNextEntry ; e != null }) {
+ val f = e.getName
+ if (f.endsWith(".class")) {
+ val b = readBytes(in)
+ deps += getReferencedClasses(b)
+ }
+ }
+ deps.toMap
+ }
+ def analyzeJarDependencies(file: File): Map[String, Set[String]] = {
+ val in = new ZipInputStream(new FileInputStream(file))
+ val deps = analyzeJarDependencies(in)
+ in.close
+ deps
+ }
+
+ def rewriteJarWithoutAnnotations(in: ZipInputStream, out: ZipOutputStream, entries: Set[String]): Unit = {
+ val classNamePat = "(.*?)\\.class".r
+ var e: ZipEntry = null
+
+ while ({ e = in.getNextEntry ; e != null }) {
+ e.getName match {
+ case f @ classNamePat(n) if entries.contains(n) =>
+ out.putNextEntry(new ZipEntry(f))
+ out.write(removeAnnotations(readBytes(in)))
+ out.closeEntry
+ case f =>
+ //println("\tSkipped '" + f + "'")
+ }
+ }
+ }
+
+ def rewriteJarWithoutAnnotations(source: File, dest: File, entries: Set[String]): Unit = {
+ val in = new ZipInputStream(new FileInputStream(source))
+ val out = new ZipOutputStream(new FileOutputStream(dest))
+
+ rewriteJarWithoutAnnotations(in, out, entries)
+
+ in.close
+ out.close
+ }
+
+ object Roots {
+ val rootClasses = Set[String](
+ "scala/Option",
+ "scala/Either",
+ "scala/PartialFunction"
+ )
+ val rootPatterns = Set[String](
+ "scala/Tuple\\d*",
+ "scala/Function\\d*"
+ )//.map(_.r)
+
+ def isRoot(n: String) =
+ rootClasses.contains(n) ||
+ rootPatterns.exists(n.matches(_))
+ }
+
+ val depsFile = new PrintWriter("deps.out")
+
+ def resolveDeps(n: String, out: java.util.Set[String]): Unit = {
+ if (out.add(n)) {
+ depsFile.println("DEPENDENCIES FOR " + n + ": ")
+ for (od <- deps.get(n); d <- od) {
+ depsFile.println("\t" + d)
+ resolveDeps(d, out)
+ }
+ }
+ }
+ def resolveDeps(nn: Set[String]): Set[String] = {
+ val out = new java.util.HashSet[String]()
+ for (n <- nn)
+ resolveDeps(n, out)
+ out.toSet
+ }
+
+ println("Processing " + jar)
+ val deps = analyzeJarDependencies(new File(jar))
+ val roots = deps.keys.filter(Roots.isRoot(_)).toSet
+ val resolved: Set[String] = resolveDeps(roots)
+
+ depsFile.close
+
+ val retained = resolved.filter(d => deps.keys.contains(d))
+
+ //println(retained.toSeq.map("\t" + _).sorted.mkString("\n"))
+ println("Got " + roots.size + " roots, resolved to " + retained.size + " dependencies")
+
+ rewriteJarWithoutAnnotations(new File(jar), new File(dest), retained)
+
+ Seq("unzip", "-l", dest) #| Seq("wc", "-l") !
+
+ Seq("ls", "-l", jar, dest) !
+
+ //println(roots.toSeq.map("\t" + _).sorted.mkString("\n"))
+ //Seq("unzip", jar, "-d", tmp.toString) !
+}
@@ -59,8 +59,8 @@ object ScalightBuild extends Build
Project(id = "scalight", base = file("."), settings = standardSettings ++ Seq(
scalacOptions in console in Compile <+= (packageBin in compilerPlugin in Compile) map("-Xplugin:" + _)
)).
- dependsOn(staticLibrary, compilets, compilerPlugin).
- aggregate(staticLibrary, compilets, compilerPlugin)
+ dependsOn(staticLibrary, compilets, compilerPlugin, trimmer).
+ aggregate(staticLibrary, compilets, compilerPlugin, trimmer)
lazy val compilerPlugin =
Project(id = "scalight-compiler-plugin", base = file("CompilerPlugin"), settings = standardSettings ++ Seq(
@@ -83,12 +83,10 @@ object ScalightBuild extends Build
)).
dependsOn(staticLibrary)
- /*
lazy val trimmer =
Project(id = "scalight-trimmer", base = file("Trimmer"), settings = standardSettings ++ Seq(
libraryDependencies += "org.ow2.asm" % "asm" % "4.0"
))
- */
/*
import ProguardPlugin._

0 comments on commit dc37095

Please sign in to comment.