Refactoring!

This commit is contained in:
Chicken-Bones committed 2015-05-10 04:09:42 +10:00
1 parent e1b50199bb
commit 0d7abb2bbd
2 files changed
+195 -198

No files matched your search

@@ -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
}
+167 -164
View File
@@ -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 = "<no symbol>"
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 = "<no type>"
}
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)