From 0d7abb2bbd697720fc07342b7066c7da96414cd3 Mon Sep 17 00:00:00 2001 From: Chicken-Bones Date: Sun, 10 May 2015 04:09:42 +1000 Subject: [PATCH] Refactoring! --- .../multipart/asm/ASMMixinCompiler.scala | 62 ++-- .../multipart/asm/ScalaSignature.scala | 331 +++++++++--------- 2 files changed, 195 insertions(+), 198 deletions(-) diff --git a/src/codechicken/multipart/asm/ASMMixinCompiler.scala b/src/codechicken/multipart/asm/ASMMixinCompiler.scala index a250b1f..7b4ab1c 100644 --- a/src/codechicken/multipart/asm/ASMMixinCompiler.scala +++ b/src/codechicken/multipart/asm/ASMMixinCompiler.scala @@ -12,7 +12,6 @@ import Type._ import codechicken.lib.asm.ASMHelper._ import codechicken.lib.asm.{InsnListSection, InsnComparator, ASMHelper, ObfMapping} import java.io.File -import ScalaSignature._ import java.lang.reflect.Method import java.lang.reflect.Modifier import net.minecraft.launchwrapper.LaunchClassLoader @@ -198,14 +197,14 @@ object ASMMixinCompiler def methods = cnode.methods.map(MethodNodeInfoSource) } - class ScalaClassInfo(cnode$: ClassNode, val sig:ScalaSignature, val csym:ClassSymbolRef) extends ClassNodeInfo(cnode$) + class ScalaClassInfo(cnode$: ClassNode, val sig:ScalaSignature, val csym:ScalaSignature#ClassSymbolRef) extends ClassNodeInfo(cnode$) { - override def superClass = Some(csym.jParent(sig)) - override def interfaces = csym.jInterfaces(sig).map(getClassInfo) + override def superClass = Some(csym.jParent) + override def interfaces = csym.jInterfaces.map(getClassInfo) override def isScala = true override def isTrait = csym.isTrait - override def isObject = csym.isInstanceOf[ObjectSymbol] + override def isObject = csym.isObject } private[ASMMixinCompiler] def obtainInfo(name: String): ClassInfo = { @@ -542,44 +541,39 @@ object ASMMixinCompiler case None => } + val info = getClassInfo(cnode).asInstanceOf[ClassInfo.ScalaClassInfo] + val sig = info.sig + val parentTraits = getAndRegisterParentTraits(cnode) - val fieldAccessors = MMap[String, MethodSymbol]() + val fieldAccessors = MMap[String, sig.MethodSymbol]() val fields = MList[FieldMixin]() val methods = MList[MethodNode]() val supers = MList[String]() - val info = getClassInfo(cnode).asInstanceOf[ClassInfo.ScalaClassInfo] - val sig = info.sig val csym = info.csym - for (i <- 0 until sig.table.length) { - import ScalaSignature._ - - val e = sig.table(i) - if (e.id == 8) {//method - val sym: MethodSymbol = sig.evalT(i) - if (sym.isParam || sym.owner != csym) {} - else if (sym.isAccessor) { - fieldAccessors.put(sym.name, sym) - } - else if (sym.isMethod) { - val desc = sym.jDesc(sig) - if (sym.name.startsWith("super$")) - supers += sym.name.substring(6) + desc - else if (!sym.isPrivate && !sym.isDeferred && sym.name != "$init$") - methods += (cnode.methods.find(m => m.name == sym.name && m.desc == desc) match { - case Some(m) => m - case None => throw new IllegalArgumentException("Unable to add mixin trait "+cnode.name+": " + - sym.name + desc + " found in scala signature but not in class file. Most likely an obfuscation issue.") - }) - } - else { - fields += FieldMixin(sym.name.trim, getReturnType(sym.jDesc(sig)).getDescriptor, - if (fieldAccessors(sym.name.trim).isPrivate) ACC_PRIVATE else ACC_PUBLIC) - } + for (sym <- sig.collect[sig.MethodSymbol](8)) { + if (sym.isParam || sym.owner != csym) {} + else if (sym.isAccessor) { + fieldAccessors.put(sym.name, sym) + } + else if (sym.isMethod) { + val desc = sym.jDesc + if (sym.name.startsWith("super$")) + supers += sym.name.substring(6) + desc + else if (!sym.isPrivate && !sym.isDeferred && sym.name != "$init$") + methods += (cnode.methods.find(m => m.name == sym.name && m.desc == desc) match { + case Some(m) => m + case None => throw new IllegalArgumentException("Unable to add mixin trait "+cnode.name+": " + + sym.name + desc + " found in scala signature but not in class file. Most likely an obfuscation issue.") + }) + } + else { + fields += FieldMixin(sym.name.trim, getReturnType(sym.jDesc).getDescriptor, + if (fieldAccessors(sym.name.trim).isPrivate) ACC_PRIVATE else ACC_PUBLIC) } } - val mixin = MixinInfo(cnode.name, csym.jParent(sig), parentTraits, fields, methods, supers) + val mixin = MixinInfo(cnode.name, csym.jParent, parentTraits, fields, methods, supers) mixinMap.put(cnode.name, mixin) mixin } diff --git a/src/codechicken/multipart/asm/ScalaSignature.scala b/src/codechicken/multipart/asm/ScalaSignature.scala index fe0df2c..5a2ae9f 100644 --- a/src/codechicken/multipart/asm/ScalaSignature.scala +++ b/src/codechicken/multipart/asm/ScalaSignature.scala @@ -15,104 +15,126 @@ object ScalaSignature { object Bytes { - implicit def reader(bc:Bytes) = new ByteCodeReader(bc) - - def apply(bytes:Array[Byte], pos:Int, len:Int) = new Bytes(bytes, pos, len) - def apply(bytes:Array[Byte]):Bytes = apply(bytes, 0, bytes.length) + def apply(arr: Array[Byte]):Bytes = Bytes(arr, 0, arr.length) } - - class Bytes(val bytes:Array[Byte], val pos:Int, val len:Int) - { - def section() = bytes take pos drop len + + case class Bytes(val arr: Array[Byte], val pos: Int, val len: Int) + { + def reader = new ByteCodeReader(this) + def section = arr.take(pos).drop(len) } - + trait Flags { - def hasFlag(flag:Int):Boolean - + def hasFlag(flag: Int): Boolean + def isPrivate = hasFlag(0x00000004) def isProtected = hasFlag(0x00000008) def isAbstract = hasFlag(0x00000080) - def isDeferred = hasFlag(0x00000100)//abstract for methods + def isDeferred = hasFlag(0x00000100) + //abstract for methods def isMethod = hasFlag(0x00000200) - def isModule = hasFlag(0x00000400)//object module class + def isModule = hasFlag(0x00000400) + //object module class def isInterface = hasFlag(0x00000800) def isParam = hasFlag(0x00002000) def isStatic = hasFlag(0x00800000) def isTrait = hasFlag(0x02000000) def isAccessor = hasFlag(0x08000000) } - +} + +class ScalaSignature(val bytes: Bytes) +{ + val major = bytes.arr(0).toInt + val minor = bytes.arr(1).toInt + val table = { + val bcr = bytes.reader + bcr.pos = 2 + Array.tabulate(bcr.readNat){ i => + val start = bcr.pos + val tpe = bcr.readByte + val len = bcr.readNat + bcr.advance(len)(new SigEntry(i, start, Bytes(bytes.arr, bcr.pos, len))) + } + } + trait SymbolRef extends Flags { - def full:String - def flags:Int - def hasFlag(flag:Int) = (flags&flag) != 0 + def full: String + def flags: Int + def hasFlag(flag: Int) = (flags & flag) != 0 } trait ClassSymbolRef extends SymbolRef { - def name:String - def owner:SymbolRef - def flags:Int - def info:Int + def name: String + def owner: SymbolRef + def flags: Int + def infoId: Int - def full = owner.full+"."+name - override def toString = getClass.getName+"("+name+","+owner+","+flags.toHexString+","+info+")" + def full = owner.full + "." + name + override def toString = getClass.getName.replaceAll(".+\\$", "") + + "(" + name + "," + owner + "," + flags.toHexString + "," + infoId + ")" - def info(sig:ScalaSignature):ClassType = sig.evalT(info) - def jParent(sig:ScalaSignature) = info(sig).parent.jName - def jInterfaces(sig:ScalaSignature) = info(sig).interfaces.map(_.jName) + def isObject = false + def info: ClassType = evalT(infoId) + def jParent = info.parent.jName + def jInterfaces = info.interfaces.map(_.jName) } - - case class ClassSymbol(name:String, owner:SymbolRef, flags:Int, info:Int) extends ClassSymbolRef - case class ObjectSymbol(name:String, owner:SymbolRef, flags:Int, info:Int) extends ClassSymbolRef - case class MethodSymbol(name:String, owner:SymbolRef, flags:Int, info:Int) extends SymbolRef + case class ClassSymbol(name: String, owner: SymbolRef, flags: Int, infoId: Int) extends ClassSymbolRef + + case class ObjectSymbol(name: String, owner: SymbolRef, flags: Int, infoId: Int) extends ClassSymbolRef { - override def toString = "MethodSymbol("+name+","+owner+","+flags.toHexString+","+info+")" - def full = owner.full+"."+name - - def info(sig:ScalaSignature):SMethodType = sig.evalT(info) - def jDesc(sig:ScalaSignature):String = info(sig).jDesc(sig) + override def isObject = true } - - case class ExternalSymbol(name:String) extends SymbolRef + + case class MethodSymbol(name: String, owner: SymbolRef, flags: Int, infoId: Int) extends SymbolRef + { + override def toString = "MethodSymbol(" + name + "," + owner + "," + flags.toHexString + "," + infoId + ")" + def full = owner.full + "." + name + + def info: TMethodType = evalT(infoId) + def jDesc = info.jDesc + } + + case class ExternalSymbol(name: String) extends SymbolRef { override def toString = name def full = name def flags = 0 } - + case object NoSymbol extends SymbolRef { def full = "" def flags = 0 } - - trait SMethodType + + trait TMethodType { - def jDesc(sig:ScalaSignature):String = "("+params.map(m => m.info(sig).returnType.jDesc).mkString+")"+returnType.jDesc - def returnType:TypeRef - def params:List[MethodSymbol] + def jDesc = "(" + params.map(m => m.info.returnType.jDesc).mkString + ")" + returnType.jDesc + def returnType: TypeRef + def params: List[MethodSymbol] } - - case class ClassType(owner:SymbolRef, parents:List[TypeRef]) + + case class ClassType(owner: SymbolRef, parents: List[TypeRef]) { def parent = parents.head def interfaces = parents.drop(1) } - - case class MethodType(returnType:TypeRef, params:List[MethodSymbol]) extends SMethodType - - case class ParameterlessType(returnType:TypeRef) extends SMethodType + + case class MethodType(returnType: TypeRef, params: List[MethodSymbol]) extends TMethodType + + case class ParameterlessType(returnType: TypeRef) extends TMethodType { def params = List() } - + trait TypeRef { - def sym:SymbolRef + def sym: SymbolRef def name = sym.full def jName = name.replace('.', '/') match { @@ -130,27 +152,27 @@ object ScalaSignature case "scala.Float" => "F" case "scala.Boolean" => "Z" case "scala.Unit" => "V" - case _ => "L"+jName+";" + case _ => "L" + jName + ";" } } - - case class TypeRefType(owner:TypeRef, sym:SymbolRef, typArgs:List[TypeRef]) extends TypeRef with SMethodType + + case class TypeRefType(owner: TypeRef, sym: SymbolRef, typArgs: List[TypeRef]) extends TMethodType with TypeRef { def params = List() - + def returnType = this - + override def jDesc = name match { - case "scala.Array" => "["+typArgs(0).jDesc + case "scala.Array" => "[" + typArgs(0).jDesc case _ => super.jDesc } } - - case class ThisType(sym:SymbolRef) extends TypeRef - case class SingleType(owner:TypeRef, sym:SymbolRef) extends TypeRef + case class ThisType(sym: SymbolRef) extends TypeRef + + case class SingleType(owner: TypeRef, sym: SymbolRef) extends TypeRef { - override def jName = super.jName+"$" + override def jName = super.jName + "$" } case object NoType extends TypeRef @@ -158,177 +180,158 @@ object ScalaSignature def sym = null override def name = "" } - - class SigEntry(val start:Int, val bytes:Bytes) + + case class SigEntry(index:Int, start: Int, bytes: Bytes) { - def id = bytes.bytes(start) - - def delete() { - bytes.bytes(start) = 3 - } + def id = bytes.arr(start) + def delete() = bytes.arr(start) = 3 } -} -case class ScalaSignature(major:Int, minor:Int, table:Array[SigEntry], bytes:Bytes) -{ - def evalS(i:Int):String = { + + def evalS(i: Int): String = { val e = table(i) val bc = e.bytes - val bcr = bc:ByteCodeReader + val bcr = bc.reader e.id match { - case 1|2 => bcr.readString(bc.len) + case 1 | 2 => bcr.readString(bc.len) case 3 => NoSymbol.full - case 9|10 => + case 9 | 10 => var s = evalS(bcr.readNat) - if(bc.pos+bc.len > bcr.pos) - s = evalS(bcr.readNat)+"."+s + if (bc.pos + bc.len > bcr.pos) + s = evalS(bcr.readNat) + "." + s s } } - - def evalT[T](i:Int):T = eval(i).asInstanceOf[T] - - def evalList[T](bcr:ByteCodeReader) = { + + def evalT[T](i: Int): T = eval(i).asInstanceOf[T] + + def evalList[T](bcr: ByteCodeReader) = { var l = MList[T]() - while(bcr.more) - l+=evalT(bcr.readNat) + while (bcr.more) + l += evalT(bcr.readNat) l.toList } - - def eval(i:Int):Any = {//only parse the ones that matter for this project + + def eval(i: Int): Any = { + //only parse the ones that matter for this project val e = table(i) - val bc = e.bytes - val bcr = bc:ByteCodeReader + val bcr = e.bytes.reader e.id match { - case 1|2 => evalS(i) + case 1 | 2 => evalS(i) case 6 => ClassSymbol(evalS(bcr.readNat), evalT(bcr.readNat), bcr.readNat, bcr.readNat) case 7 => ObjectSymbol(evalS(bcr.readNat), evalT(bcr.readNat), bcr.readNat, bcr.readNat) case 8 => MethodSymbol(evalS(bcr.readNat), evalT(bcr.readNat), bcr.readNat, bcr.readNat) - case 9|10 => ExternalSymbol(evalS(i)) - case 11|12 => NoType //12 is actually NoPrefixType (no lower bound) + case 9 | 10 => ExternalSymbol(evalS(i)) + case 11 | 12 => NoType //12 is actually NoPrefixType (no lower bound) case 13 => ThisType(evalT(bcr.readNat)) case 14 => SingleType(evalT(bcr.readNat), evalT(bcr.readNat)) case 16 => TypeRefType(evalT(bcr.readNat), evalT(bcr.readNat), evalList(bcr)) case 19 => ClassType(evalT(bcr.readNat), evalList(bcr)) case 20 => MethodType(evalT(bcr.readNat), evalList(bcr)) - case 21|48 => ParameterlessType(evalT(bcr.readNat))//48 is actually a bounded super type, but it should work fine for this project + case 21 | 48 => ParameterlessType(evalT(bcr.readNat)) //48 is actually a bounded super type, but it should work fine for this project case _ => NoSymbol } } - def collect[T](id:Int) = (0 until table.length).collect { - case i if table(i).id == id => evalT(i):T + def collect[T](id: Int) = (0 until table.length).collect { + case i if table(i).id == id => evalT(i): T } - def findObject(name:String) = collect[ObjectSymbol](7).find(_.full == name) - def findClass(name:String) = collect[ClassSymbol](6).find(c => !c.isModule && c.full == name) + def findObject(name: String) = collect[ObjectSymbol](7).find(_.full == name) + def findClass(name: String) = collect[ClassSymbol](6).find(c => !c.isModule && c.full == name) } -class ByteCodeReader(val bc:Bytes) +class ByteCodeReader(val bc: Bytes) { var pos = bc.pos - - def more = pos < bc.pos+bc.len - - def readString(len:Int) = advance(len)(new String(bc.bytes.drop(pos).take(len))) - - def readByte = advance(1)(bc.bytes(pos)) - + + def more = pos < bc.pos + bc.len + + def readString(len: Int) = advance(len)(new String(bc.arr.drop(pos).take(len))) + + def readByte = advance(1)(bc.arr(pos)) + def readNat = { var r = 0 var b = 0 do { b = readByte - r = r<<7|b&0x7F + r = r << 7 | b & 0x7F } - while((b&0x80) != 0) + while ((b & 0x80) != 0) r } - - def advance[A](len:Int)(r:A) = { - if(pos+len > bc.pos+bc.len) + + def advance[A](len: Int)(r: A) = { + if (pos + len > bc.pos + bc.len) throw new IllegalArgumentException("Ran off the end of bytecode") - pos+=len + pos += len r } - - def readEntry = { - val p = pos - val tpe = readByte - val len = readNat - advance(len)(new SigEntry(p, new Bytes(bc.bytes, pos, len))) - } - - def readSig = { - val major = readByte - val minor = readByte - val table = new Array[SigEntry](readNat) - for(i <- 0 until table.size) - table(i) = readEntry - ScalaSignature(major, minor, table, bc) - } } object ScalaSigReader { - def decode(s:String) = { + def decode(s: String) = { val bytes = s.getBytes bytes take ByteCodecs.decode(bytes) } - - def encode(b:Array[Byte]) = { + + def encode(b: Array[Byte]) = { val bytes = ByteCodecs.encode8to7(b) var i = 0 - while(i < bytes.length) { - bytes(i) = ((bytes(i)+1)&0x7F).toByte - i+=1 + while (i < bytes.length) { + bytes(i) = ((bytes(i) + 1) & 0x7F).toByte + i += 1 } - new String(bytes.take(bytes.length-1), "UTF-8") + new String(bytes.take(bytes.length - 1), "UTF-8") } - - def read(ann:AnnotationNode):ScalaSignature = Bytes(decode(ann.values.get(1).asInstanceOf[String])).readSig - - def write(sig:ScalaSignature, ann:AnnotationNode) = ann.values.set(1, encode(sig.bytes.bytes)) - - def ann(cnode:ClassNode):Option[AnnotationNode] = cnode.visibleAnnotations match { + + def read(ann: AnnotationNode): ScalaSignature = new ScalaSignature(Bytes(decode(ann.values.get(1).asInstanceOf[String]))) + + def write(sig: ScalaSignature, ann: AnnotationNode) = ann.values.set(1, encode(sig.bytes.arr)) + + def ann(cnode: ClassNode): Option[AnnotationNode] = cnode.visibleAnnotations match { case null => None case a => a.find(ann => ann.desc.equals("Lscala/reflect/ScalaSignature;")) } } +/** + * Was an idea for a transformer in FML + */ class ScalaSigSideTransformer { - def transform(ann:AnnotationNode, cnode:ClassNode, removedFields:JList[FieldNode], removedMethods:JList[MethodNode]) { - if(removedFields.isEmpty && removedMethods.isEmpty) + def transform(ann: AnnotationNode, cnode: ClassNode, removedFields: JList[FieldNode], removedMethods: JList[MethodNode]) { + if (removedFields.isEmpty && removedMethods.isEmpty) return - + val remFields = removedFields.asScala.map(f => (f.name, f.desc.replace('$', '/'))) val remMethods = removedMethods.asScala.map(f => (f.name, f.desc.replace('$', '/'))) - + val sig = ScalaSigReader.read(ann) - for(i <- 0 until sig.table.length) { - val e = sig.table(i) - if (e.id == 8) {//check and remove - val sym: MethodSymbol = sig.evalT(i) - if (sym.isAccessor) { - val fName = if (sym.name.endsWith("_$eq")) sym.name.substring(0, sym.name.length - 4) else sym.name - if (remFields.find(t => t._1 == sym.name.trim).nonEmpty) { - e.delete() - val it = cnode.methods.iterator - while (it.hasNext) { - val m = it.next - if (m.name == sym.name && m.desc == sym.jDesc(sig)) - it.remove() - } + for (e <- sig.table if e.id == 8) { + //check and remove + val sym: sig.MethodSymbol = sig.evalT(e.index) + if (sym.isAccessor) { + val fName = if (sym.name.endsWith("_$eq")) sym.name.substring(0, sym.name.length - 4) else sym.name + if (remFields.find(t => t._1 == sym.name.trim).nonEmpty) { + e.delete() + val it = cnode.methods.iterator + while (it.hasNext) { + val m = it.next + if (m.name == sym.name && m.desc == sym.jDesc) + it.remove() } } - else if (sym.isMethod) { - if (remMethods.find(t => t._1 == sym.name && t._2 == sym.jDesc(sig)).nonEmpty) - e.delete() - } - else {//field - if (remFields.find(t => t._1 == sym.name.trim).nonEmpty) - e.delete() - } + } + else if (sym.isMethod) { + if (remMethods.find(t => t._1 == sym.name && t._2 == sym.jDesc).nonEmpty) + e.delete() + } + else { + //field + if (remFields.find(t => t._1 == sym.name.trim).nonEmpty) + e.delete() } } ScalaSigReader.write(sig, ann)