From 82174e96fbf9504c6bc14b6db596542f4ae2835e Mon Sep 17 00:00:00 2001 From: Chicken-Bones Date: Sun, 10 May 2015 06:40:43 +1000 Subject: [PATCH] Added SideOnly support to scala mixins --- .../microblock/FaceMicroblock.scala | 2 - .../multipart/asm/ASMMixinCompiler.scala | 11 ++ .../multipart/asm/ScalaSignature.scala | 134 ++++++++++-------- 3 files changed, 85 insertions(+), 62 deletions(-) diff --git a/src/codechicken/microblock/FaceMicroblock.scala b/src/codechicken/microblock/FaceMicroblock.scala index 788ecf7..d8dc32b 100644 --- a/src/codechicken/microblock/FaceMicroblock.scala +++ b/src/codechicken/microblock/FaceMicroblock.scala @@ -4,10 +4,8 @@ import codechicken.lib.vec.Cuboid6 import codechicken.multipart.TFacePart import codechicken.lib.vec.Vector3 import codechicken.lib.vec.Rotation -import codechicken.microblock.MicroMaterialRegistry.IMicroMaterial import Rotation._ import Vector3._ -import codechicken.lib.lighting.LightMatrix object FacePlacement extends PlacementProperties { diff --git a/src/codechicken/multipart/asm/ASMMixinCompiler.scala b/src/codechicken/multipart/asm/ASMMixinCompiler.scala index 7b4ab1c..480181f 100644 --- a/src/codechicken/multipart/asm/ASMMixinCompiler.scala +++ b/src/codechicken/multipart/asm/ASMMixinCompiler.scala @@ -19,6 +19,7 @@ import codechicken.multipart.handler.MultipartProxy import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper import org.apache.logging.log4j.LogManager import ASMImplicits._ +import cpw.mods.fml.relauncher.FMLLaunchHandler object DebugPrinter { @@ -535,6 +536,14 @@ object ASMMixinCompiler fields.values.toSeq, methods, supers)) } + def listSideOnly(sig:ScalaSignature) = { + val side = "cpw.mods.fml.relauncher.Side."+FMLLaunchHandler.side.name + sig.collect[sig.AnnotationInfo](40).filter{ a => + a.annType.name == "cpw.mods.fml.relauncher.SideOnly" && + a.getValue[sig.EnumLiteral]("value").value.full != side + }.map(_.owner.full).toSet + } + def registerScalaTrait(cnode: ClassNode):MixinInfo = { getMixinInfo(cnode.name) match { case Some(info) => return info @@ -543,6 +552,7 @@ object ASMMixinCompiler val info = getClassInfo(cnode).asInstanceOf[ClassInfo.ScalaClassInfo] val sig = info.sig + val sideOnly = listSideOnly(sig) val parentTraits = getAndRegisterParentTraits(cnode) val fieldAccessors = MMap[String, sig.MethodSymbol]() @@ -553,6 +563,7 @@ object ASMMixinCompiler val csym = info.csym for (sym <- sig.collect[sig.MethodSymbol](8)) { if (sym.isParam || sym.owner != csym) {} + else if (sideOnly(sym.full)) {} else if (sym.isAccessor) { fieldAccessors.put(sym.name, sym) } diff --git a/src/codechicken/multipart/asm/ScalaSignature.scala b/src/codechicken/multipart/asm/ScalaSignature.scala index 5a2ae9f..58b8747 100644 --- a/src/codechicken/multipart/asm/ScalaSignature.scala +++ b/src/codechicken/multipart/asm/ScalaSignature.scala @@ -5,7 +5,6 @@ import org.objectweb.asm.tree.AnnotationNode import org.objectweb.asm.tree.FieldNode import org.objectweb.asm.tree.MethodNode import java.util.{List => JList} -import scala.collection.mutable.{ListBuffer => MList} import scala.collection.JavaConverters._ import scala.collection.JavaConversions._ @@ -18,10 +17,10 @@ object ScalaSignature def apply(arr: Array[Byte]):Bytes = Bytes(arr, 0, arr.length) } - case class Bytes(val arr: Array[Byte], val pos: Int, val len: Int) + case class Bytes(arr: Array[Byte], pos: Int, len: Int) { def reader = new ByteCodeReader(this) - def section = arr.take(pos).drop(len) + def section = arr.drop(pos).take(len) } trait Flags @@ -185,6 +184,33 @@ class ScalaSignature(val bytes: Bytes) { def id = bytes.arr(start) def delete() = bytes.arr(start) = 3 + override def toString = "SigEntry("+index+","+id+","+bytes.len+" bytes)" + } + + trait Literal + { + def value:Any + } + case class BooleanLiteral(value:Boolean) extends Literal + case class ByteLiteral(value:Byte) extends Literal + case class ShortLiteral(value:Short) extends Literal + case class CharLiteral(value:Char) extends Literal + case class IntLiteral(value:Int) extends Literal + case class LongLiteral(value:Long) extends Literal + case class FloatLiteral(value:Float) extends Literal + case class DoubleLiteral(value:Double) extends Literal + case object NullLiteral extends Literal + { + override def value = null + } + case class StringLiteral(value:String) extends Literal + case class TypeLiteral(value:TypeRef) extends Literal + case class EnumLiteral(value:ExternalSymbol) extends Literal + case class ArrayLiteral(value:List[_]) extends Literal + + case class AnnotationInfo(owner:SymbolRef, annType:TypeRef, values:Map[String, Literal]) + { + def getValue[T](name:String) = values(name).asInstanceOf[T] } def evalS(i: Int): String = { @@ -202,33 +228,54 @@ class ScalaSignature(val bytes: Bytes) } } - def evalT[T](i: Int): T = eval(i).asInstanceOf[T] + def evalT[T](i: Int) = eval(i).asInstanceOf[T] def evalList[T](bcr: ByteCodeReader) = { - var l = MList[T]() + val l = List.newBuilder while (bcr.more) l += evalT(bcr.readNat) - l.toList + l.result() } def eval(i: Int): Any = { //only parse the ones that matter for this project val e = table(i) val bcr = e.bytes.reader + + def nat = bcr.readNat + def evalS = this.evalS(nat) + def evalT[T] = this.evalT[T](nat) + def evalList[T] = this.evalList[T](bcr) + e.id match { - 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 1 | 2 => this.evalS(i) + case 3 => NoSymbol + case 6 => ClassSymbol(evalS, evalT, nat, nat) + case 7 => ObjectSymbol(evalS, evalT, nat, nat) + case 8 => MethodSymbol(evalS, evalT, nat, nat) + case 9 | 10 => ExternalSymbol(this.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 _ => NoSymbol + case 13 => ThisType(evalT) + case 14 => SingleType(evalT, evalT) + case 16 => TypeRefType(evalT, evalT, evalList) + case 19 => ClassType(evalT, evalList) + case 20 => MethodType(evalT, evalList) + case 21 | 48 => ParameterlessType(evalT) //48 is actually a bounded super type, but it should work fine for this project + case 25 => BooleanLiteral(bcr.readLong != 0) + case 26 => ByteLiteral(bcr.readLong.toByte) + case 27 => ShortLiteral(bcr.readLong.toShort) + case 28 => CharLiteral(bcr.readLong.toChar) + case 29 => IntLiteral(bcr.readLong.toInt) + case 30 => LongLiteral(bcr.readLong) + case 31 => FloatLiteral(java.lang.Float.intBitsToFloat(bcr.readLong.toInt)) + case 32 => DoubleLiteral(java.lang.Double.longBitsToDouble(bcr.readLong)) + case 33 => StringLiteral(evalS) + case 34 => NullLiteral + case 35 => TypeLiteral(evalT) + case 36 => EnumLiteral(evalT) + case 40 => AnnotationInfo(evalT, evalT, evalList.grouped(2).map(g => (g(0), g(1))).toMap) + case 44 => ArrayLiteral(evalList) + case _ => e } } @@ -261,6 +308,15 @@ class ByteCodeReader(val bc: Bytes) r } + def readLong = { + var l = 0L + while(more) { + l <<= 8 + l |= readByte & 0xFF + } + l + } + def advance[A](len: Int)(r: A) = { if (pos + len > bc.pos + bc.len) throw new IllegalArgumentException("Ran off the end of bytecode") @@ -294,46 +350,4 @@ object ScalaSigReader 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) - 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 (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).nonEmpty) - e.delete() - } - else { - //field - if (remFields.find(t => t._1 == sym.name.trim).nonEmpty) - e.delete() - } - } - ScalaSigReader.write(sig, ann) - } } \ No newline at end of file