mirror of
https://github.com/GTNewHorizons/ForgeMultipart.git
synced 2026-11-12 16:37:38 +00:00
Use FML logging system.
Made some of the ASM code more concise
This commit is contained in:
1 parent
5c4b9e0a5b
commit
bd1a72e958
13 files changed
+388
-451
No files matched your search
@@ -109,8 +109,8 @@ object ConfigContent
|
||||
catch
|
||||
{
|
||||
case e:Exception =>
|
||||
System.err.println("Invalid line in microblocks.cfg: "+s)
|
||||
System.err.println(e.getMessage)
|
||||
logger.error("Invalid line in microblocks.cfg: "+s)
|
||||
logger.error(e.getMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -126,7 +126,7 @@ object ConfigContent
|
||||
if(idMap(i) != null)
|
||||
{
|
||||
if(block == Blocks.air)
|
||||
System.err.println("Warning: Unable to add micro material for block with ID "+i+" as it doesn't exist")
|
||||
logger.warn("Unable to add micro material for block with ID "+i+" as it doesn't exist")
|
||||
else
|
||||
createAndRegister(block, idMap(i))
|
||||
}
|
||||
@@ -142,10 +142,10 @@ object ConfigContent
|
||||
createAndRegister(block, m)
|
||||
}
|
||||
catch {
|
||||
case e:IllegalStateException => System.err.println("Unable to register micro material: "+
|
||||
case e:IllegalStateException => logger.error("Unable to register micro material: "+
|
||||
materialKey(block, m)+"\n\t"+e.getMessage)
|
||||
case e:Exception =>
|
||||
System.err.println("Unable to register micro material: "+materialKey(block, m))
|
||||
logger.error("Unable to register micro material: "+materialKey(block, m))
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
@@ -153,14 +153,14 @@ object ConfigContent
|
||||
}
|
||||
}
|
||||
|
||||
nameMap.foreach(e => System.err.println("Warning: Unable to add micro material for block with unlocalised name "+e._1+" as it doesn't exist"))
|
||||
nameMap.foreach(e => logger.warn("Unable to add micro material for block with unlocalised name "+e._1+" as it doesn't exist"))
|
||||
}
|
||||
|
||||
def handleIMC(messages:Seq[IMCMessage]) {
|
||||
messages.filter(_.key == "microMaterial").foreach{msg =>
|
||||
|
||||
def error(s:String) {
|
||||
System.err.println("Invalid microblock IMC message from "+msg.getSender+": "+s)
|
||||
logger.error("Invalid microblock IMC message from "+msg.getSender+": "+s)
|
||||
}
|
||||
|
||||
if(msg.getMessageType != classOf[ItemStack])
|
||||
@@ -168,15 +168,15 @@ object ConfigContent
|
||||
else {
|
||||
val stack = msg.getItemStackValue
|
||||
if(Block.blockRegistry.containsId(Item.getIdFromItem(stack.getItem)))
|
||||
System.err.println("Invalid Block: "+stack.getItem)
|
||||
error("Invalid Block: "+stack.getItem)
|
||||
else if(stack.getItemDamage < 0 || stack.getItemDamage >= 16)
|
||||
System.err.println("Invalid metadata: "+stack.getItemDamage)
|
||||
error("Invalid metadata: "+stack.getItemDamage)
|
||||
else {
|
||||
try {
|
||||
createAndRegister(Block.getBlockFromItem(stack.getItem), stack.getItemDamage)
|
||||
}
|
||||
catch {
|
||||
case e:IllegalStateException => System.err.println("Unable to register micro material: "+
|
||||
case e:IllegalStateException => error("Unable to register micro material: "+
|
||||
materialKey(Block.getBlockFromItem(stack.getItem), stack.getItemDamage)+"\n\t"+e.getMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import net.minecraft.block.Block.SoundType
|
||||
|
||||
object MicroMaterialRegistry
|
||||
{
|
||||
|
||||
/**
|
||||
* Interface for defining a micro material
|
||||
*/
|
||||
@@ -127,11 +126,11 @@ object MicroMaterialRegistry
|
||||
throw new IllegalStateException("You must register your materials in the init methods.")
|
||||
|
||||
if (typeMap.contains(name)) {
|
||||
System.err.println("Material with id " + name + " is already registered.")
|
||||
logger.error("Material with id " + name + " is already registered.")
|
||||
return
|
||||
}
|
||||
|
||||
System.out.println("Registered micro material: " + name)
|
||||
logger.info("Registered micro material: " + name)
|
||||
|
||||
typeMap.put(name, material)
|
||||
}
|
||||
@@ -144,9 +143,9 @@ object MicroMaterialRegistry
|
||||
throw new IllegalStateException("You must register your materials in the init methods.")
|
||||
|
||||
if (typeMap.remove(name).isEmpty)
|
||||
System.err.println("Material with id " + name + " is was not registered.")
|
||||
logger.error("Material with id " + name + " is was not registered.")
|
||||
|
||||
System.out.println("Replaced micro material: " + name)
|
||||
logger.info("Replaced micro material: " + name)
|
||||
|
||||
typeMap.put(name, material)
|
||||
}
|
||||
@@ -215,7 +214,7 @@ object MicroMaterialRegistry
|
||||
def materialID(name: String) = nameMap.get(name) match {
|
||||
case Some(v) => v
|
||||
case None =>
|
||||
System.err.println("Missing mapping for part with ID: " + name)
|
||||
logger.error("Missing mapping for part with ID: " + name)
|
||||
0
|
||||
}
|
||||
|
||||
|
||||
@@ -12,41 +12,35 @@ import codechicken.microblock.ConfigContent
|
||||
import cpw.mods.fml.common.event.FMLInterModComms.IMCEvent
|
||||
import scala.collection.JavaConversions._
|
||||
|
||||
@Mod(modid = "ForgeMicroblock", acceptedMinecraftVersions = "[1.7.2]",
|
||||
dependencies="required-after:ForgeMultipart;after:*", modLanguage="scala")
|
||||
@Mod(modid = "ForgeMicroblock", acceptedMinecraftVersions = "[1.7.2]", dependencies = "required-after:ForgeMultipart;after:*", modLanguage = "scala")
|
||||
object MicroblockMod
|
||||
{
|
||||
@EventHandler
|
||||
def preInit(event:FMLPreInitializationEvent)
|
||||
{
|
||||
MicroblockProxy.preInit()
|
||||
def preInit(event: FMLPreInitializationEvent) {
|
||||
MicroblockProxy.preInit(event.getModLog)
|
||||
DefaultContent.load()
|
||||
ConfigContent.parse(event.getModConfigurationDirectory)
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def init(event:FMLInitializationEvent)
|
||||
{
|
||||
def init(event: FMLInitializationEvent) {
|
||||
MicroblockProxy.init()
|
||||
ConfigContent.load()
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def postInit(event:FMLPostInitializationEvent)
|
||||
{
|
||||
def postInit(event: FMLPostInitializationEvent) {
|
||||
MicroMaterialRegistry.setupIDMap()
|
||||
MicroblockProxy.postInit()
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def beforeServerStart(event:FMLServerAboutToStartEvent)
|
||||
{
|
||||
def beforeServerStart(event: FMLServerAboutToStartEvent) {
|
||||
MicroMaterialRegistry.setupIDMap()
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def handleIMC(event:IMCEvent)
|
||||
{
|
||||
def handleIMC(event: IMCEvent) {
|
||||
ConfigContent.handleIMC(event.getMessages)
|
||||
}
|
||||
}
|
||||
@@ -20,9 +20,12 @@ import cpw.mods.fml.common.registry.GameRegistry
|
||||
import cpw.mods.fml.common.network.NetworkRegistry
|
||||
import net.minecraft.client.renderer.RenderBlocks
|
||||
import net.minecraft.init.{Blocks, Items}
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
class MicroblockProxy_serverImpl
|
||||
{
|
||||
var logger:Logger = _
|
||||
|
||||
private var baseID = 24875-1
|
||||
|
||||
def nextItemID = {baseID+=1; baseID}
|
||||
@@ -33,8 +36,9 @@ class MicroblockProxy_serverImpl
|
||||
var sawDiamond:Item = _
|
||||
var stoneRod:Item = _
|
||||
|
||||
def preInit()
|
||||
def preInit(logger:Logger)
|
||||
{
|
||||
this.logger = logger
|
||||
itemMicro = new ItemMicroPart
|
||||
GameRegistry.registerItem(itemMicro, "microblock")
|
||||
sawStone = createSaw(config, "sawStone", 1)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package codechicken
|
||||
|
||||
import codechicken.microblock.handler.MicroblockProxy
|
||||
|
||||
package object microblock
|
||||
{
|
||||
def logger = MicroblockProxy.logger
|
||||
}
|
||||
@@ -162,7 +162,7 @@ object MultiPartRegistry
|
||||
if (part.isDefined)
|
||||
return part.get(client)
|
||||
else {
|
||||
System.err.println("Missing mapping for part with ID: " + name)
|
||||
logger.error("Missing mapping for part with ID: " + name)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ object MultipartGenerator
|
||||
if(c_trait != null)
|
||||
{
|
||||
if(interfaceTraitMap_c.contains(s_interface))
|
||||
System.err.println("Trait already registered for "+s_interface)
|
||||
logger.error("Trait already registered for "+s_interface)
|
||||
else
|
||||
{
|
||||
interfaceTraitMap_c = interfaceTraitMap_c+(s_interface->c_trait)
|
||||
@@ -169,7 +169,7 @@ object MultipartGenerator
|
||||
if(s_trait != null)
|
||||
{
|
||||
if(interfaceTraitMap_s.contains(s_interface))
|
||||
System.err.println("Trait already registered for "+s_interface)
|
||||
logger.error("Trait already registered for "+s_interface)
|
||||
else
|
||||
{
|
||||
interfaceTraitMap_s = interfaceTraitMap_s+(s_interface->s_trait)
|
||||
@@ -198,14 +198,14 @@ object MultipartGenerator
|
||||
if(client)
|
||||
{
|
||||
if(interfaceTraitMap_c.contains(s_interface))
|
||||
System.err.println("Trait already registered for "+s_interface)
|
||||
logger.error("Trait already registered for "+s_interface)
|
||||
else
|
||||
interfaceTraitMap_c = interfaceTraitMap_c+(s_interface->tType)
|
||||
}
|
||||
if(server)
|
||||
{
|
||||
if(interfaceTraitMap_s.contains(s_interface))
|
||||
System.err.println("Trait already registered for "+s_interface)
|
||||
logger.error("Trait already registered for "+s_interface)
|
||||
else
|
||||
interfaceTraitMap_s = interfaceTraitMap_s+(s_interface->tType)
|
||||
}
|
||||
|
||||
@@ -6,62 +6,53 @@ import scala.collection.JavaConversions._
|
||||
import org.objectweb.asm.tree._
|
||||
import org.objectweb.asm.Opcodes._
|
||||
import org.objectweb.asm.ClassReader
|
||||
import org.objectweb.asm.util.TraceClassVisitor
|
||||
import org.objectweb.asm.util.Textifier
|
||||
import org.objectweb.asm.Type
|
||||
import org.objectweb.asm.MethodVisitor
|
||||
import Type._
|
||||
import codechicken.lib.asm.ASMHelper._
|
||||
import codechicken.lib.asm.ObfMapping
|
||||
import codechicken.lib.asm.{InsnListSection, InsnComparator, ASMHelper, ObfMapping}
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import ScalaSignature._
|
||||
import java.lang.reflect.Method
|
||||
import java.lang.reflect.Modifier
|
||||
import net.minecraft.launchwrapper.LaunchClassLoader
|
||||
import codechicken.multipart.handler.MultipartProxy
|
||||
import cpw.mods.fml.common.asm.transformers.deobf.FMLDeobfuscatingRemapper
|
||||
import org.apache.logging.log4j.LogManager
|
||||
|
||||
object DebugPrinter
|
||||
{
|
||||
val debug = MultipartProxy.config.getTag("debug_asm").getBooleanValue(!ObfMapping.obfuscated)
|
||||
|
||||
val logger = LogManager.getLogger("Multipart ASM")
|
||||
|
||||
private var permGenUsed = 0
|
||||
val dir = new File("asm/multipart")
|
||||
if(debug)
|
||||
{
|
||||
if(!dir.exists)
|
||||
if (debug) {
|
||||
if (!dir.exists)
|
||||
dir.mkdirs()
|
||||
for(file <- dir.listFiles)
|
||||
for (file <- dir.listFiles)
|
||||
file.delete
|
||||
}
|
||||
|
||||
def dump(name:String, bytes:Array[Byte])
|
||||
{
|
||||
if(!debug) return
|
||||
|
||||
val fileout = new File(dir, name.replace('/', '#')+".txt")
|
||||
val pout = new PrintWriter(fileout)
|
||||
|
||||
new ClassReader(bytes).accept(new TraceClassVisitor(null, new Textifier(), pout), 0)
|
||||
pout.close()
|
||||
|
||||
def dump(name: String, bytes: Array[Byte]) {
|
||||
if (debug) ASMHelper.dump(bytes, new File(dir, name.replace('/', '#') + ".txt"), false, false)
|
||||
}
|
||||
|
||||
def defined(name:String, bytes:Array[Byte])
|
||||
{
|
||||
if((permGenUsed+bytes.length)/16000 != permGenUsed/16000)
|
||||
log((permGenUsed+bytes.length)+" bytes of permGen has been used by ASMMixinCompiler")
|
||||
|
||||
|
||||
def defined(name: String, bytes: Array[Byte]) {
|
||||
if ((permGenUsed + bytes.length) / 16000 != permGenUsed / 16000)
|
||||
log((permGenUsed + bytes.length) + " bytes of permGen has been used by ASMMixinCompiler")
|
||||
|
||||
permGenUsed += bytes.length
|
||||
}
|
||||
|
||||
def log(msg:String) = if(debug) println(msg)
|
||||
|
||||
def log(msg: String) = if (debug) println(msg)
|
||||
}
|
||||
|
||||
object ASMMixinCompiler
|
||||
{
|
||||
|
||||
import StackAnalyser.width
|
||||
|
||||
|
||||
val cl = getClass.getClassLoader.asInstanceOf[LaunchClassLoader]
|
||||
val m_defineClass = classOf[ClassLoader].getDeclaredMethod("defineClass", classOf[Array[Byte]], Integer.TYPE, Integer.TYPE)
|
||||
val m_runTransformers = classOf[LaunchClassLoader].getDeclaredMethod("runTransformers", classOf[String], classOf[String], classOf[Array[Byte]])
|
||||
@@ -69,141 +60,141 @@ object ASMMixinCompiler
|
||||
m_defineClass.setAccessible(true)
|
||||
m_runTransformers.setAccessible(true)
|
||||
f_transformerExceptions.setAccessible(true)
|
||||
|
||||
|
||||
private val traitByteMap = MMap[String, Array[Byte]]()
|
||||
private val mixinMap = MMap[String, MixinInfo]()
|
||||
|
||||
def define(name:String, bytes:Array[Byte]) =
|
||||
{
|
||||
|
||||
def define(name: String, bytes: Array[Byte]) = {
|
||||
internalDefine(name, bytes)
|
||||
DebugPrinter.defined(name, bytes)
|
||||
|
||||
try {
|
||||
m_defineClass.invoke(cl, bytes, 0:Integer, bytes.length:Integer).asInstanceOf[Class[_]]
|
||||
m_defineClass.invoke(cl, bytes, 0: Integer, bytes.length: Integer).asInstanceOf[Class[_]]
|
||||
} catch {
|
||||
case link:LinkageError if link.getMessage.contains("duplicate") =>
|
||||
throw new IllegalStateException("class with name: "+name+" already loaded. Do not reference your mixin classes before registering them with MultipartGenerator", link)
|
||||
case link: LinkageError if link.getMessage.contains("duplicate") =>
|
||||
throw new IllegalStateException("class with name: " + name + " already loaded. Do not reference your mixin classes before registering them with MultipartGenerator", link)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getBytes("cpw/mods/fml/common/asm/FMLSanityChecker")
|
||||
|
||||
def getBytes(name:String):Array[Byte] =
|
||||
{
|
||||
|
||||
def getBytes(name: String): Array[Byte] = {
|
||||
val jName = name.replace('/', '.')
|
||||
if(jName.equals("java.lang.Object"))
|
||||
if (jName.equals("java.lang.Object"))
|
||||
return null
|
||||
|
||||
|
||||
def useTransformers = f_transformerExceptions.get(cl).asInstanceOf[JSet[String]]
|
||||
.find(jName.startsWith).isEmpty
|
||||
|
||||
val obfName = if(ObfMapping.obfuscated) FMLDeobfuscatingRemapper.INSTANCE.unmap(name).replace('/', '.') else jName
|
||||
.find(jName.startsWith).isEmpty
|
||||
|
||||
val obfName = if (ObfMapping.obfuscated) FMLDeobfuscatingRemapper.INSTANCE.unmap(name).replace('/', '.') else jName
|
||||
val bytes = cl.getClassBytes(obfName)
|
||||
if(bytes != null && useTransformers)
|
||||
if (bytes != null && useTransformers)
|
||||
return m_runTransformers.invoke(cl, jName, obfName, bytes).asInstanceOf[Array[Byte]]
|
||||
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
def internalDefine(name:String, bytes:Array[Byte])
|
||||
{
|
||||
|
||||
def internalDefine(name: String, bytes: Array[Byte]) {
|
||||
traitByteMap.put(name.replace('.', '/'), bytes)
|
||||
BaseNodeInfo.clear(name)
|
||||
DebugPrinter.dump(name, bytes)
|
||||
}
|
||||
|
||||
def classNode(name:String) = traitByteMap.getOrElseUpdate(name.replace('.', '/'), getBytes(name.replace('.', '/'))) match {
|
||||
|
||||
def classNode(name: String) = traitByteMap.getOrElseUpdate(name.replace('.', '/'), getBytes(name.replace('.', '/'))) match {
|
||||
case null => null
|
||||
case v => createClassNode(v, ClassReader.EXPAND_FRAMES)
|
||||
}
|
||||
|
||||
def isScala(cnode:ClassNode) = ScalaSigReader.ann(cnode).isDefined
|
||||
|
||||
def isTrait(cnode:ClassNode) =
|
||||
{
|
||||
val csym:ClassSymbol = ScalaSigReader.read(ScalaSigReader.ann(cnode).get).evalT(0)
|
||||
|
||||
def isScala(cnode: ClassNode) = ScalaSigReader.ann(cnode).isDefined
|
||||
|
||||
def isTrait(cnode: ClassNode) = {
|
||||
val csym: ClassSymbol = ScalaSigReader.read(ScalaSigReader.ann(cnode).get).evalT(0)
|
||||
csym.isTrait && !csym.isInterface
|
||||
}
|
||||
|
||||
def getMixinInfo(name:String) = mixinMap.get(name)
|
||||
|
||||
case class FieldMixin(name:String, desc:String, access:Int)
|
||||
|
||||
def getMixinInfo(name: String) = mixinMap.get(name)
|
||||
|
||||
case class FieldMixin(name: String, desc: String, access: Int)
|
||||
{
|
||||
def accessName(owner:String) = if((access & ACC_PRIVATE) != 0)
|
||||
owner.replace('/', '$')+"$$"+name
|
||||
else
|
||||
name
|
||||
def accessName(owner: String) = if ((access & ACC_PRIVATE) != 0)
|
||||
owner.replace('/', '$') + "$$" + name
|
||||
else
|
||||
name
|
||||
}
|
||||
|
||||
case class MixinInfo(name:String, parent:String, fields:Seq[FieldMixin],
|
||||
methods:Seq[MethodNode], supers:Map[String, String])
|
||||
|
||||
case class MixinInfo(name: String, parent: String, fields: Seq[FieldMixin],
|
||||
methods: Seq[MethodNode], supers: Map[String, String])
|
||||
{
|
||||
def tname = name+"$class"
|
||||
def tname = name + "$class"
|
||||
}
|
||||
|
||||
|
||||
object BaseNodeInfo
|
||||
{
|
||||
private val baseNodeMap = MMap[String, BaseNodeInfo]()
|
||||
|
||||
def clear(name:String) = baseNodeMap.remove(name)
|
||||
|
||||
def getNodeInfo(name:String) = baseNodeMap.getOrElseUpdate(name, new BaseNodeInfo(name))
|
||||
|
||||
private def getNodeInfo(clazz:ClassInfoSource) = clazz match {
|
||||
|
||||
def clear(name: String) = baseNodeMap.remove(name)
|
||||
|
||||
def getNodeInfo(name: String) = baseNodeMap.getOrElseUpdate(name, new BaseNodeInfo(name))
|
||||
|
||||
private def getNodeInfo(clazz: ClassInfoSource) = clazz match {
|
||||
case null => null
|
||||
case v => baseNodeMap.getOrElseUpdate(v.name, new BaseNodeInfo(v))
|
||||
}
|
||||
|
||||
case class MethodNodeInfo(owner:String, m:MethodInfoSource)
|
||||
|
||||
case class MethodNodeInfo(owner: String, m: MethodInfoSource)
|
||||
{
|
||||
def name = m.name
|
||||
def desc = m.desc
|
||||
}
|
||||
|
||||
|
||||
trait MethodInfoSource
|
||||
{
|
||||
def name:String
|
||||
def desc:String
|
||||
def isPrivate:Boolean
|
||||
def isAbstract:Boolean
|
||||
def name: String
|
||||
def desc: String
|
||||
def isPrivate: Boolean
|
||||
def isAbstract: Boolean
|
||||
}
|
||||
|
||||
|
||||
trait ClassInfoSource
|
||||
{
|
||||
def name:String
|
||||
def superClass:Option[BaseNodeInfo]
|
||||
def interfaces:Seq[BaseNodeInfo]
|
||||
def methods:Seq[MethodInfoSource]
|
||||
def name: String
|
||||
def superClass: Option[BaseNodeInfo]
|
||||
def interfaces: Seq[BaseNodeInfo]
|
||||
def methods: Seq[MethodInfoSource]
|
||||
}
|
||||
|
||||
implicit def JClassInfoSource(clazz:Class[_]) = if(clazz == null) null else new JClassInfoSource(clazz)
|
||||
class JClassInfoSource(clazz:Class[_]) extends ClassInfoSource
|
||||
|
||||
implicit def JClassInfoSource(clazz: Class[_]) = if (clazz == null) null else new JClassInfoSource(clazz)
|
||||
|
||||
class JClassInfoSource(clazz: Class[_]) extends ClassInfoSource
|
||||
{
|
||||
case class JMethodInfoSource(method:Method) extends MethodInfoSource
|
||||
|
||||
case class JMethodInfoSource(method: Method) extends MethodInfoSource
|
||||
{
|
||||
def name = method.getName
|
||||
def desc = getType(method).getDescriptor
|
||||
def isPrivate = Modifier.isPrivate(method.getModifiers)
|
||||
def isAbstract = Modifier.isAbstract(method.getModifiers)
|
||||
}
|
||||
|
||||
|
||||
def name = clazz.getName.replace('.', '/')
|
||||
def superClass = Option(getNodeInfo(clazz.getSuperclass))
|
||||
def interfaces = clazz.getInterfaces.map(getNodeInfo(_))
|
||||
def methods = clazz.getMethods.map(JMethodInfoSource(_))
|
||||
}
|
||||
|
||||
implicit def ClassNodeInfoSource(cnode:ClassNode) = if(cnode == null) null else new ClassNodeInfoSource(cnode)
|
||||
class ClassNodeInfoSource(cnode:ClassNode) extends ClassInfoSource
|
||||
|
||||
implicit def ClassNodeInfoSource(cnode: ClassNode) = if (cnode == null) null else new ClassNodeInfoSource(cnode)
|
||||
|
||||
class ClassNodeInfoSource(cnode: ClassNode) extends ClassInfoSource
|
||||
{
|
||||
case class MethodNodeInfoSource(mnode:MethodNode) extends MethodInfoSource
|
||||
|
||||
case class MethodNodeInfoSource(mnode: MethodNode) extends MethodInfoSource
|
||||
{
|
||||
def name = mnode.name
|
||||
def desc = mnode.desc
|
||||
def isPrivate = (mnode.access & ACC_PRIVATE) != 0
|
||||
def isAbstract = (mnode.access & ACC_ABSTRACT) != 0
|
||||
}
|
||||
|
||||
|
||||
def name = cnode.name
|
||||
def superClass = Option(getNodeInfo(cnode.superName))
|
||||
def interfaces = cnode.interfaces match {
|
||||
@@ -212,17 +203,17 @@ object ASMMixinCompiler
|
||||
}
|
||||
def methods = cnode.methods.map(MethodNodeInfoSource(_))
|
||||
}
|
||||
|
||||
class ScalaNodeInfoSource(cnode:ClassNode) extends ClassNodeInfoSource(cnode)
|
||||
|
||||
class ScalaNodeInfoSource(cnode: ClassNode) extends ClassNodeInfoSource(cnode)
|
||||
{
|
||||
val sig = ScalaSigReader.read(ScalaSigReader.ann(cnode).get)
|
||||
val csym = sig.evalT(0):ClassSymbol
|
||||
|
||||
val csym = sig.evalT(0): ClassSymbol
|
||||
|
||||
override def superClass = Option(getNodeInfo(csym.jParent(sig)))
|
||||
override def interfaces = csym.jInterfaces(sig).map(getNodeInfo)
|
||||
}
|
||||
|
||||
def classInfo(name:String):ClassInfoSource = name match {
|
||||
|
||||
def classInfo(name: String): ClassInfoSource = name match {
|
||||
case null => null
|
||||
case s => classNode(s) match {
|
||||
case null => cl.findClass(s.replace('/', '.'))
|
||||
@@ -231,239 +222,229 @@ object ASMMixinCompiler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
import BaseNodeInfo._
|
||||
class BaseNodeInfo(val clazz:ClassInfoSource)
|
||||
|
||||
class BaseNodeInfo(val clazz: ClassInfoSource)
|
||||
{
|
||||
def this(name:String) = this(classInfo(name))
|
||||
|
||||
val publicmethods = exportedMethods(clazz)//map of nameDesc to owner+method
|
||||
|
||||
def exportedMethods(o:ClassInfoSource):Map[String, MethodNodeInfo] =
|
||||
{
|
||||
val eMethods = o.methods.filter(!_.isPrivate)//defined accessible methods
|
||||
.map(m => (m.name+m.desc, MethodNodeInfo(o.name, m))).toMap
|
||||
|
||||
eMethods ++ (o.superClass++o.interfaces).flatMap(_.publicmethods)
|
||||
def this(name: String) = this(classInfo(name))
|
||||
|
||||
val publicmethods = exportedMethods(clazz) //map of nameDesc to owner+method
|
||||
|
||||
def exportedMethods(o: ClassInfoSource): Map[String, MethodNodeInfo] = {
|
||||
val eMethods = o.methods.filter(!_.isPrivate) //defined accessible methods
|
||||
.map(m => (m.name + m.desc, MethodNodeInfo(o.name, m))).toMap
|
||||
|
||||
eMethods ++ (o.superClass ++ o.interfaces).flatMap(_.publicmethods)
|
||||
}
|
||||
}
|
||||
|
||||
def finishBridgeCall(mv:MethodVisitor, mvdesc:String, opcode:Int, owner:String, name:String, desc:String)
|
||||
{
|
||||
|
||||
def finishBridgeCall(mv: MethodVisitor, mvdesc: String, opcode: Int, owner: String, name: String, desc: String) {
|
||||
val args = getArgumentTypes(mvdesc)
|
||||
val ret = getReturnType(mvdesc)
|
||||
var localIndex = 1
|
||||
args.foreach{arg =>
|
||||
mv.visitVarInsn(arg.getOpcode(ILOAD), localIndex)
|
||||
localIndex+=width(arg)
|
||||
args.foreach {
|
||||
arg =>
|
||||
mv.visitVarInsn(arg.getOpcode(ILOAD), localIndex)
|
||||
localIndex += width(arg)
|
||||
}
|
||||
mv.visitMethodInsn(opcode, owner, name, desc)
|
||||
mv.visitInsn(ret.getOpcode(IRETURN))
|
||||
mv.visitMaxs(Math.max(width(args)+1, width(ret)), width(args)+1)
|
||||
mv.visitMaxs(Math.max(width(args) + 1, width(ret)), width(args) + 1)
|
||||
}
|
||||
|
||||
def writeBridge(mv:MethodVisitor, mvdesc:String, opcode:Int, owner:String, name:String, desc:String)
|
||||
{
|
||||
|
||||
def writeBridge(mv: MethodVisitor, mvdesc: String, opcode: Int, owner: String, name: String, desc: String) {
|
||||
mv.visitVarInsn(ALOAD, 0)
|
||||
finishBridgeCall(mv, mvdesc, opcode, owner, name, desc)
|
||||
}
|
||||
|
||||
def writeStaticBridge(mv:MethodNode, mname:String, t:MixinInfo) =
|
||||
|
||||
def writeStaticBridge(mv: MethodNode, mname: String, t: MixinInfo) =
|
||||
writeBridge(mv, mv.desc, INVOKESTATIC, t.tname, mname, staticDesc(t.name, mv.desc))
|
||||
|
||||
def mixinClasses(name:String, superClass:String, traits:Seq[String]) =
|
||||
{
|
||||
|
||||
def mixinClasses(name: String, superClass: String, traits: Seq[String]) = {
|
||||
val traitInfos = traits.map(t => mixinMap(t.replace('.', '/')))
|
||||
|
||||
|
||||
val cnode = new ClassNode()
|
||||
cnode.visit(V1_6, ACC_PUBLIC, name, null, superClass.replace('.', '/'), traitInfos.map(_.name).toArray[String])
|
||||
|
||||
|
||||
val minit = cnode.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null)
|
||||
minit.visitVarInsn(ALOAD, 0)
|
||||
minit.visitMethodInsn(INVOKESPECIAL, cnode.superName, "<init>", "()V")
|
||||
|
||||
|
||||
val prevInfos = MList[MixinInfo]()
|
||||
|
||||
traitInfos.foreach{ t =>
|
||||
minit.visitVarInsn(ALOAD, 0)
|
||||
minit.visitMethodInsn(INVOKESTATIC, t.tname, "$init$", "(L"+t.name+";)V")
|
||||
|
||||
t.fields.foreach{ f =>
|
||||
val fv = cnode.visitField(ACC_PRIVATE, f.accessName(t.name), f.desc, null, null).asInstanceOf[FieldNode]
|
||||
|
||||
val ftype = getType(fv.desc)
|
||||
var mv = cnode.visitMethod(ACC_PUBLIC, fv.name, "()"+f.desc, null, null)
|
||||
mv.visitVarInsn(ALOAD, 0)
|
||||
mv.visitFieldInsn(GETFIELD, name, fv.name, fv.desc)
|
||||
mv.visitInsn(ftype.getOpcode(IRETURN))
|
||||
mv.visitMaxs(1, 1)
|
||||
|
||||
mv = cnode.visitMethod(ACC_PUBLIC, fv.name+"_$eq", "("+f.desc+")V", null, null)
|
||||
mv.visitVarInsn(ALOAD, 0)
|
||||
mv.visitVarInsn(ftype.getOpcode(ILOAD), 1)
|
||||
mv.visitFieldInsn(PUTFIELD, name, fv.name, fv.desc)
|
||||
mv.visitInsn(RETURN)
|
||||
mv.visitMaxs(width(ftype)+1, width(ftype)+1)
|
||||
}
|
||||
|
||||
t.supers.foreach{ s =>
|
||||
val (name, desc) = seperateDesc(s._1)
|
||||
val mv = cnode.visitMethod(ACC_PUBLIC, t.name.replace('/', '$')+"$$super$"+name, desc, null, null).asInstanceOf[MethodNode]
|
||||
|
||||
prevInfos.reverse.find(t => t.supers.contains(s._1)) match {//each super goes to the one before
|
||||
case Some(st) => writeStaticBridge(mv, name, st)
|
||||
case None => writeBridge(mv, desc, INVOKESPECIAL, s._2, name, desc)
|
||||
|
||||
traitInfos.foreach {
|
||||
t =>
|
||||
minit.visitVarInsn(ALOAD, 0)
|
||||
minit.visitMethodInsn(INVOKESTATIC, t.tname, "$init$", "(L" + t.name + ";)V")
|
||||
|
||||
t.fields.foreach {
|
||||
f =>
|
||||
val fv = cnode.visitField(ACC_PRIVATE, f.accessName(t.name), f.desc, null, null).asInstanceOf[FieldNode]
|
||||
|
||||
val ftype = getType(fv.desc)
|
||||
var mv = cnode.visitMethod(ACC_PUBLIC, fv.name, "()" + f.desc, null, null)
|
||||
mv.visitVarInsn(ALOAD, 0)
|
||||
mv.visitFieldInsn(GETFIELD, name, fv.name, fv.desc)
|
||||
mv.visitInsn(ftype.getOpcode(IRETURN))
|
||||
mv.visitMaxs(1, 1)
|
||||
|
||||
mv = cnode.visitMethod(ACC_PUBLIC, fv.name + "_$eq", "(" + f.desc + ")V", null, null)
|
||||
mv.visitVarInsn(ALOAD, 0)
|
||||
mv.visitVarInsn(ftype.getOpcode(ILOAD), 1)
|
||||
mv.visitFieldInsn(PUTFIELD, name, fv.name, fv.desc)
|
||||
mv.visitInsn(RETURN)
|
||||
mv.visitMaxs(width(ftype) + 1, width(ftype) + 1)
|
||||
}
|
||||
}
|
||||
|
||||
prevInfos+=t
|
||||
|
||||
t.supers.foreach {
|
||||
s =>
|
||||
val (name, desc) = seperateDesc(s._1)
|
||||
val mv = cnode.visitMethod(ACC_PUBLIC, t.name.replace('/', '$') + "$$super$" + name, desc, null, null).asInstanceOf[MethodNode]
|
||||
|
||||
prevInfos.reverse.find(t => t.supers.contains(s._1)) match {
|
||||
//each super goes to the one before
|
||||
case Some(st) => writeStaticBridge(mv, name, st)
|
||||
case None => writeBridge(mv, desc, INVOKESPECIAL, s._2, name, desc)
|
||||
}
|
||||
}
|
||||
|
||||
prevInfos += t
|
||||
}
|
||||
|
||||
|
||||
val methodSigs = MSet[String]()
|
||||
traitInfos.reverse.foreach{ t => //last trait gets first pick on methods
|
||||
t.methods.foreach{ m =>
|
||||
if(!methodSigs(m.name+m.desc))
|
||||
{
|
||||
val mv = cnode.visitMethod(ACC_PUBLIC, m.name, m.desc, null, Array(m.exceptions:_*)).asInstanceOf[MethodNode]
|
||||
copy(m, mv)
|
||||
mv.instructions = new InsnList()
|
||||
mv.tryCatchBlocks.clear()
|
||||
|
||||
writeStaticBridge(mv, m.name, t)
|
||||
methodSigs+=m.name+m.desc
|
||||
traitInfos.reverse.foreach {
|
||||
t => //last trait gets first pick on methods
|
||||
t.methods.foreach {
|
||||
m =>
|
||||
if (!methodSigs(m.name + m.desc)) {
|
||||
val mv = cnode.visitMethod(ACC_PUBLIC, m.name, m.desc, null, Array(m.exceptions: _*)).asInstanceOf[MethodNode]
|
||||
writeStaticBridge(mv, m.name, t)
|
||||
methodSigs += m.name + m.desc
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
minit.visitInsn(RETURN)
|
||||
minit.visitMaxs(1, 1)
|
||||
|
||||
|
||||
define(cnode.name, createBytes(cnode, 0))
|
||||
}
|
||||
|
||||
def seperateDesc(nameDesc:String) = {
|
||||
|
||||
def seperateDesc(nameDesc: String) = {
|
||||
val n = nameDesc.indexOf('(')
|
||||
(nameDesc.substring(0, n), nameDesc.substring(n))
|
||||
}
|
||||
|
||||
def staticDesc(owner:String, desc:String) =
|
||||
{
|
||||
|
||||
def staticDesc(owner: String, desc: String) = {
|
||||
val descT = getMethodType(desc)
|
||||
getMethodDescriptor(descT.getReturnType, getType("L"+owner+";")+:descT.getArgumentTypes : _*)
|
||||
getMethodDescriptor(descT.getReturnType, getType("L" + owner + ";") +: descT.getArgumentTypes: _*)
|
||||
}
|
||||
|
||||
def getSuper(minsn:MethodInsnNode, stack:StackAnalyser):Option[String] =
|
||||
{
|
||||
|
||||
def getSuper(minsn: MethodInsnNode, stack: StackAnalyser): Option[String] = {
|
||||
import StackAnalyser._
|
||||
|
||||
if(minsn.getOpcode != INVOKESPECIAL) return None
|
||||
|
||||
if (minsn.getOpcode != INVOKESPECIAL) return None
|
||||
val oname = stack.owner.getInternalName
|
||||
|
||||
if(minsn.owner.equals(oname)) return None//private this
|
||||
|
||||
|
||||
if (minsn.owner.equals(oname)) return None //private this
|
||||
|
||||
stack.peek(Type.getType(minsn.desc).getArgumentTypes.length) match {
|
||||
case Load(This(o)) =>
|
||||
case _ => return None//have to be invoked on this
|
||||
case _ => return None //have to be invoked on this
|
||||
}
|
||||
|
||||
getSuper(minsn.name+minsn.desc, oname)
|
||||
|
||||
getSuper(minsn.name + minsn.desc, oname)
|
||||
}
|
||||
|
||||
def getSuper(nameDesc:String, cname:String) =
|
||||
|
||||
def getSuper(nameDesc: String, cname: String) =
|
||||
getNodeInfo(cname).clazz.superClass match {
|
||||
case None => None//no super class
|
||||
case None => None //no super class
|
||||
case Some(o) => o.publicmethods.get(nameDesc) match {
|
||||
case None => None//no method with sig in super
|
||||
case Some(m) => if(m.m.isAbstract)
|
||||
None //abstract can't be called for supers
|
||||
else
|
||||
Some(m.owner)//congrats, that's a super
|
||||
case None => None //no method with sig in super
|
||||
case Some(m) => if (m.m.isAbstract)
|
||||
None //abstract can't be called for supers
|
||||
else
|
||||
Some(m.owner) //congrats, that's a super
|
||||
}
|
||||
}
|
||||
|
||||
def registerJavaTrait(cnode:ClassNode)
|
||||
{
|
||||
if((cnode.access & ACC_INTERFACE) != 0)
|
||||
throw new IllegalArgumentException("Cannot register java interface "+cnode.name+" as a multipart trait. Try register passThroughInterface")
|
||||
if((cnode.access & ACC_ABSTRACT) != 0)
|
||||
throw new IllegalArgumentException("Cannot register abstract class "+cnode.name+" as a multipart trait")
|
||||
if(!cnode.innerClasses.isEmpty)
|
||||
throw new IllegalArgumentException("Inner classes are not permitted for "+cnode.name+" as a multipart trait. Use scala")
|
||||
|
||||
val inode = new ClassNode()//impl node
|
||||
inode.visit(V1_6, ACC_ABSTRACT|ACC_PUBLIC, cnode.name+"$class", null, "java/lang/Object", null)
|
||||
|
||||
def registerJavaTrait(cnode: ClassNode) {
|
||||
if ((cnode.access & ACC_INTERFACE) != 0)
|
||||
throw new IllegalArgumentException("Cannot register java interface " + cnode.name + " as a multipart trait. Try register passThroughInterface")
|
||||
if ((cnode.access & ACC_ABSTRACT) != 0)
|
||||
throw new IllegalArgumentException("Cannot register abstract class " + cnode.name + " as a multipart trait")
|
||||
if (!cnode.innerClasses.isEmpty)
|
||||
throw new IllegalArgumentException("Inner classes are not permitted for " + cnode.name + " as a multipart trait. Use scala")
|
||||
|
||||
val inode = new ClassNode() //impl node
|
||||
inode.visit(V1_6, ACC_ABSTRACT | ACC_PUBLIC, cnode.name + "$class", null, "java/lang/Object", null)
|
||||
inode.sourceFile = cnode.sourceFile
|
||||
|
||||
|
||||
val fields = cnode.fields.map(f => (f.name, FieldMixin(f.name, f.desc, f.access))).toMap
|
||||
val supers = MMap[String, String]()//nameDesc to super owner
|
||||
val supers = MMap[String, String]() //nameDesc to super owner
|
||||
val methods = MList[MethodNode]()
|
||||
val methodSigs = cnode.methods.map(m => m.name+m.desc).toSet
|
||||
|
||||
val tnode = new ClassNode()//trait node (interface)
|
||||
tnode.visit(V1_6, ACC_INTERFACE|ACC_ABSTRACT|ACC_PUBLIC, cnode.name, null, "java/lang/Object", Array(cnode.interfaces:_*))
|
||||
|
||||
def fname(name:String) = fields(name).accessName(cnode.name)
|
||||
|
||||
fields.values.foreach{ fnode =>
|
||||
tnode.visitMethod(ACC_PUBLIC|ACC_ABSTRACT, fname(fnode.name), "()"+fnode.desc, null, null)
|
||||
tnode.visitMethod(ACC_PUBLIC|ACC_ABSTRACT, fname(fnode.name)+"_$eq", "("+fnode.desc+")V", null, null)
|
||||
val methodSigs = cnode.methods.map(m => m.name + m.desc).toSet
|
||||
|
||||
val tnode = new ClassNode() //trait node (interface)
|
||||
tnode.visit(V1_6, ACC_INTERFACE | ACC_ABSTRACT | ACC_PUBLIC, cnode.name, null, "java/lang/Object", Array(cnode.interfaces: _*))
|
||||
|
||||
def fname(name: String) = fields(name).accessName(cnode.name)
|
||||
|
||||
fields.values.foreach {
|
||||
fnode =>
|
||||
tnode.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fname(fnode.name), "()" + fnode.desc, null, null)
|
||||
tnode.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, fname(fnode.name) + "_$eq", "(" + fnode.desc + ")V", null, null)
|
||||
}
|
||||
|
||||
def superInsn(minsn:MethodInsnNode) =
|
||||
{
|
||||
val bridgeName = cnode.name.replace('/', '$')+"$$super$"+minsn.name
|
||||
if(!supers.contains(minsn.name+minsn.desc))
|
||||
{
|
||||
tnode.visitMethod(ACC_PUBLIC|ACC_ABSTRACT, bridgeName, minsn.desc, null, null)
|
||||
supers.put(minsn.name+minsn.desc, minsn.owner)
|
||||
|
||||
def superInsn(minsn: MethodInsnNode) = {
|
||||
val bridgeName = cnode.name.replace('/', '$') + "$$super$" + minsn.name
|
||||
if (!supers.contains(minsn.name + minsn.desc)) {
|
||||
tnode.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, bridgeName, minsn.desc, null, null)
|
||||
supers.put(minsn.name + minsn.desc, minsn.owner)
|
||||
}
|
||||
new MethodInsnNode(INVOKEINTERFACE, cnode.name, bridgeName, minsn.desc)
|
||||
}
|
||||
|
||||
def staticClone(mnode:MethodNode, name:String, access:Int) =
|
||||
{
|
||||
val mv = inode.visitMethod(access|ACC_STATIC, name,
|
||||
staticDesc(cnode.name, mnode.desc),
|
||||
null, Array(mnode.exceptions:_*)).asInstanceOf[MethodNode]
|
||||
|
||||
def staticClone(mnode: MethodNode, name: String, access: Int) = {
|
||||
val mv = inode.visitMethod(access | ACC_STATIC, name,
|
||||
staticDesc(cnode.name, mnode.desc),
|
||||
null, Array(mnode.exceptions: _*)).asInstanceOf[MethodNode]
|
||||
copy(mnode, mv)
|
||||
mv
|
||||
}
|
||||
|
||||
def staticTransform(mnode:MethodNode, base:MethodNode)
|
||||
{
|
||||
|
||||
def staticTransform(mnode: MethodNode, base: MethodNode) {
|
||||
val stack = new StackAnalyser(getType(cnode.name), base)
|
||||
val insnList = mnode.instructions
|
||||
var insn = insnList.getFirst
|
||||
|
||||
def replace(newinsn:AbstractInsnNode)
|
||||
{
|
||||
|
||||
def replace(newinsn: AbstractInsnNode) {
|
||||
insnList.insert(insn, newinsn)
|
||||
insnList.remove(insn)
|
||||
insn = newinsn
|
||||
}
|
||||
|
||||
//transform
|
||||
while(insn != null)
|
||||
{
|
||||
while (insn != null) {
|
||||
insn match {
|
||||
case finsn:FieldInsnNode => insn.getOpcode match
|
||||
{
|
||||
case GETFIELD => replace(new MethodInsnNode(INVOKEINTERFACE, cnode.name,
|
||||
fname(finsn.name), "()"+finsn.desc))
|
||||
case PUTFIELD => replace(new MethodInsnNode(INVOKEINTERFACE, cnode.name,
|
||||
fname(finsn.name)+"_$eq", "("+finsn.desc+")V"))
|
||||
case finsn: FieldInsnNode => insn.getOpcode match {
|
||||
case GETFIELD => replace(new MethodInsnNode(INVOKEINTERFACE, cnode.name,
|
||||
fname(finsn.name), "()" + finsn.desc))
|
||||
case PUTFIELD => replace(new MethodInsnNode(INVOKEINTERFACE, cnode.name,
|
||||
fname(finsn.name) + "_$eq", "(" + finsn.desc + ")V"))
|
||||
case _ =>
|
||||
}
|
||||
case minsn:MethodInsnNode => insn.getOpcode match
|
||||
{
|
||||
case INVOKESPECIAL =>
|
||||
if(getSuper(minsn, stack).isDefined)
|
||||
case minsn: MethodInsnNode => insn.getOpcode match {
|
||||
case INVOKESPECIAL =>
|
||||
if (getSuper(minsn, stack).isDefined)
|
||||
replace(superInsn(minsn))
|
||||
case INVOKEVIRTUAL =>
|
||||
if(minsn.owner.equals(cnode.name)) {
|
||||
if(methodSigs.contains(minsn.name+minsn.desc))//call the interface method
|
||||
if (minsn.owner.equals(cnode.name)) {
|
||||
if (methodSigs.contains(minsn.name + minsn.desc)) //call the interface method
|
||||
minsn.setOpcode(INVOKEINTERFACE)
|
||||
else {//cast to parent class and call
|
||||
else {
|
||||
//cast to parent class and call
|
||||
val mType = Type.getMethodType(minsn.desc)
|
||||
val instanceEntry = stack.peek(width(mType.getArgumentTypes))
|
||||
insnList.insert(instanceEntry.insn, new TypeInsnNode(CHECKCAST, cnode.superName))
|
||||
@@ -478,150 +459,102 @@ object ASMMixinCompiler
|
||||
insn = insn.getNext
|
||||
}
|
||||
}
|
||||
|
||||
def convertMethod(mnode:MethodNode)
|
||||
{
|
||||
if(mnode.name.equals("<clinit>"))
|
||||
throw new IllegalArgumentException("Static initialisers are not permitted "+cnode.name+" as a multipart trait")
|
||||
|
||||
if(mnode.name.equals("<init>"))
|
||||
{
|
||||
if(!mnode.desc.equals("()V"))
|
||||
throw new IllegalArgumentException("Constructor arguments are not permitted "+cnode.name+" as a multipart trait")
|
||||
|
||||
|
||||
def convertMethod(mnode: MethodNode) {
|
||||
if (mnode.name.equals("<clinit>"))
|
||||
throw new IllegalArgumentException("Static initialisers are not permitted " + cnode.name + " as a multipart trait")
|
||||
|
||||
if (mnode.name.equals("<init>")) {
|
||||
if (!mnode.desc.equals("()V"))
|
||||
throw new IllegalArgumentException("Constructor arguments are not permitted " + cnode.name + " as a multipart trait")
|
||||
|
||||
val mv = staticClone(mnode, "$init$", ACC_PUBLIC)
|
||||
def removeSuperConstructor()
|
||||
{
|
||||
def throwI = throw new IllegalArgumentException("Invalid constructor insn sequence "+cnode.name)
|
||||
|
||||
val insnList = mv.instructions
|
||||
var insn = insnList.getFirst
|
||||
var state = 0
|
||||
while(insn != null && state < 2)
|
||||
{
|
||||
val next = insn.getNext
|
||||
insn match {
|
||||
case linsn:LabelNode =>
|
||||
case linsn:LineNumberNode =>
|
||||
case vinsn:VarInsnNode =>
|
||||
if(state == 0)
|
||||
{
|
||||
if(vinsn.getOpcode == ALOAD && vinsn.`var` == 0)
|
||||
{
|
||||
state = 1
|
||||
insnList.remove(insn)
|
||||
}
|
||||
else
|
||||
throwI
|
||||
}
|
||||
else
|
||||
throwI
|
||||
case minsn:MethodInsnNode =>
|
||||
if(state == 1)
|
||||
{
|
||||
if(minsn.getOpcode == INVOKESPECIAL && minsn.name.equals("<init>") &&
|
||||
minsn.owner.equals(cnode.superName))
|
||||
{
|
||||
insnList.remove(insn)
|
||||
state = 2
|
||||
}
|
||||
else
|
||||
throwI
|
||||
}
|
||||
else
|
||||
throwI
|
||||
case _ => throwI
|
||||
}
|
||||
insn = next
|
||||
}
|
||||
if(state != 2)
|
||||
throwI
|
||||
def removeSuperConstructor() {
|
||||
val insns = new InsnListSection
|
||||
insns.add(new VarInsnNode(ALOAD, 0))
|
||||
insns.add(new MethodInsnNode(INVOKESPECIAL, cnode.superName, "<init>", "()V"))
|
||||
|
||||
val minsns = new InsnListSection(mv.instructions)
|
||||
val found = InsnComparator.matches(minsns, insns, Set[LabelNode]())
|
||||
if(found == null)
|
||||
throw new IllegalArgumentException("Invalid constructor insn sequence " + cnode.name + "\n" + minsns)
|
||||
found.trim(Set[LabelNode]()).remove()
|
||||
}
|
||||
removeSuperConstructor()
|
||||
staticTransform(mv, mnode)
|
||||
return
|
||||
}
|
||||
|
||||
if((mnode.access & ACC_PRIVATE) == 0)
|
||||
{
|
||||
val mv = tnode.visitMethod(ACC_PUBLIC|ACC_ABSTRACT, mnode.name, mnode.desc, null, Array(mnode.exceptions:_*))
|
||||
methods+=mv.asInstanceOf[MethodNode]
|
||||
|
||||
if ((mnode.access & ACC_PRIVATE) == 0) {
|
||||
val mv = tnode.visitMethod(ACC_PUBLIC | ACC_ABSTRACT, mnode.name, mnode.desc, null, Array(mnode.exceptions: _*))
|
||||
methods += mv.asInstanceOf[MethodNode]
|
||||
}
|
||||
|
||||
|
||||
//convert that method!
|
||||
val access = if((mnode.access & ACC_PRIVATE) == 0) ACC_PUBLIC else ACC_PRIVATE
|
||||
val access = if ((mnode.access & ACC_PRIVATE) == 0) ACC_PUBLIC else ACC_PRIVATE
|
||||
val mv = staticClone(mnode, mnode.name, access)
|
||||
staticTransform(mv, mnode)
|
||||
}
|
||||
|
||||
|
||||
cnode.methods.foreach(convertMethod)
|
||||
|
||||
define(inode.name, createBytes(inode, 0))
|
||||
define(tnode.name, createBytes(tnode, 0))
|
||||
|
||||
mixinMap.put(tnode.name, MixinInfo(tnode.name, cnode.superName,
|
||||
fields.values.toSeq,
|
||||
methods.toSeq, supers.toMap))
|
||||
|
||||
mixinMap.put(tnode.name, MixinInfo(tnode.name, cnode.superName,
|
||||
fields.values.toSeq,
|
||||
methods.toSeq, supers.toMap))
|
||||
}
|
||||
|
||||
def registerScalaTrait(cnode:ClassNode)
|
||||
{
|
||||
for(i <- cnode.interfaces)
|
||||
{
|
||||
|
||||
def registerScalaTrait(cnode: ClassNode) {
|
||||
for (i <- cnode.interfaces) {
|
||||
val inode = classNode(i)
|
||||
if(isScala(inode) && isTrait(inode))
|
||||
throw new IllegalArgumentException("Multipart trait "+cnode.name+" cannot extend other traits")
|
||||
if (isScala(inode) && isTrait(inode))
|
||||
throw new IllegalArgumentException("Multipart trait " + cnode.name + " cannot extend other traits")
|
||||
}
|
||||
|
||||
|
||||
val fieldAccessors = MMap[String, MethodSymbol]()
|
||||
val fields = MList[MethodSymbol]()
|
||||
val methods = MList[MethodNode]()
|
||||
val supers = MMap[String, String]()
|
||||
|
||||
|
||||
val sig = ScalaSigReader.read(ScalaSigReader.ann(cnode).get)
|
||||
val csym:ClassSymbol = sig.evalT(0)
|
||||
for(i <- 0 until sig.table.length)
|
||||
{
|
||||
val csym: ClassSymbol = sig.evalT(0)
|
||||
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.equals(csym)){}
|
||||
else if(sym.isAccessor)
|
||||
{
|
||||
if (e.id == 8) {//method
|
||||
val sym: MethodSymbol = sig.evalT(i)
|
||||
if (sym.isParam || !sym.owner.equals(csym)) {}
|
||||
else if (sym.isAccessor) {
|
||||
fieldAccessors.put(sym.name, sym)
|
||||
}
|
||||
else if(sym.isMethod)
|
||||
{
|
||||
else if (sym.isMethod) {
|
||||
val desc = sym.jDesc(sig)
|
||||
if(sym.name.contains("super$"))
|
||||
{
|
||||
if (sym.name.contains("super$")) {
|
||||
val name = sym.name.substring(6)
|
||||
supers.put(name+desc, getSuper(name+desc, cnode.name).get)
|
||||
supers.put(name + desc, getSuper(name + desc, cnode.name).get)
|
||||
}
|
||||
else if(!sym.name.equals("$init$") && !sym.isPrivate)
|
||||
{
|
||||
else if (!sym.name.equals("$init$") && !sym.isPrivate) {
|
||||
val map = new ObfMapping(cnode.name, sym.name, desc)
|
||||
val method = findMethod(map, cnode)
|
||||
if(method == null)
|
||||
throw new RuntimeException("Unable to add multipart trait: "+map+" found in scala signature but not in class file. Most likely an obfuscation issue.")
|
||||
methods+=method
|
||||
if (method == null)
|
||||
throw new RuntimeException("Unable to add multipart trait: " + map + " found in scala signature but not in class file. Most likely an obfuscation issue.")
|
||||
methods += method
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fields+=sym
|
||||
else {
|
||||
fields += sym
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixinMap.put(cnode.name, MixinInfo(cnode.name, csym.jParent(sig),
|
||||
fields.map(sym => FieldMixin(sym.name.trim, getReturnType(sym.jDesc(sig)).getDescriptor,
|
||||
if(fieldAccessors(sym.name.trim).isPrivate) ACC_PRIVATE else ACC_PUBLIC)),
|
||||
methods, supers.toMap))
|
||||
mixinMap.put(cnode.name, MixinInfo(cnode.name, csym.jParent(sig),
|
||||
fields.map(sym => FieldMixin(sym.name.trim, getReturnType(sym.jDesc(sig)).getDescriptor,
|
||||
if (fieldAccessors(sym.name.trim).isPrivate) ACC_PRIVATE else ACC_PUBLIC)),
|
||||
methods, supers.toMap))
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -189,7 +189,7 @@ object ASMMixinFactory extends IMultipartFactory
|
||||
|
||||
val inode = classNode(s_interface)
|
||||
if(inode == null) {
|
||||
System.out.println("Unable to generate pass through trait for: "+s_interface+" class not found.")
|
||||
logger.error("Unable to generate pass through trait for: "+s_interface+" class not found.")
|
||||
return null
|
||||
}
|
||||
if((inode.access&ACC_INTERFACE) == 0) throw new IllegalArgumentException(s_interface+" is not an interface.")
|
||||
|
||||
@@ -24,7 +24,7 @@ object MCPCCompatModule
|
||||
}
|
||||
} catch {
|
||||
case e:Exception =>
|
||||
System.err.println("Failed to integrate MCPC placement hooks")
|
||||
MultipartProxy.logger.error("Failed to integrate MCPC placement hooks")
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,35 +8,29 @@ import cpw.mods.fml.common.Mod.EventHandler
|
||||
import cpw.mods.fml.common.event.FMLServerAboutToStartEvent
|
||||
import codechicken.multipart.MultiPartRegistry
|
||||
|
||||
@Mod(modid = "ForgeMultipart", acceptedMinecraftVersions = "[1.7.2]",
|
||||
modLanguage="scala")
|
||||
@Mod(modid = "ForgeMultipart", acceptedMinecraftVersions = "[1.7.2]", modLanguage = "scala")
|
||||
object MultipartMod
|
||||
{
|
||||
@EventHandler
|
||||
def preInit(event:FMLPreInitializationEvent)
|
||||
{
|
||||
MultipartProxy.preInit(event.getModConfigurationDirectory)
|
||||
def preInit(event: FMLPreInitializationEvent) {
|
||||
MultipartProxy.preInit(event.getModConfigurationDirectory, event.getModLog)
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def init(event:FMLInitializationEvent)
|
||||
{
|
||||
def init(event: FMLInitializationEvent) {
|
||||
MultipartProxy.init()
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def postInit(event:FMLPostInitializationEvent)
|
||||
{
|
||||
if(MultiPartRegistry.required)
|
||||
{
|
||||
def postInit(event: FMLPostInitializationEvent) {
|
||||
if (MultiPartRegistry.required) {
|
||||
MultiPartRegistry.postInit()
|
||||
MultipartProxy.postInit()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@EventHandler
|
||||
def beforeServerStart(event:FMLServerAboutToStartEvent)
|
||||
{
|
||||
def beforeServerStart(event: FMLServerAboutToStartEvent) {
|
||||
MultiPartRegistry.beforeServerStart()
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import cpw.mods.fml.client.registry.ClientRegistry
|
||||
import net.minecraft.tileentity.TileEntity
|
||||
import codechicken.lib.config.ConfigFile
|
||||
import java.io.File
|
||||
import codechicken.multipart.handler.MultipartProxy._
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
import cpw.mods.fml.relauncher.SideOnly
|
||||
import cpw.mods.fml.relauncher.Side
|
||||
@@ -17,11 +16,16 @@ import codechicken.lib.world.WorldExtensionManager
|
||||
import cpw.mods.fml.common.FMLCommonHandler
|
||||
import cpw.mods.fml.common.registry.GameRegistry
|
||||
import net.minecraft.block.Block
|
||||
import org.apache.logging.log4j.Logger
|
||||
|
||||
class MultipartProxy_serverImpl
|
||||
{
|
||||
def preInit(cfgdir:File)
|
||||
{
|
||||
var block:BlockMultipart = _
|
||||
var config:ConfigFile = _
|
||||
var logger:Logger = _
|
||||
|
||||
def preInit(cfgdir: File, logger:Logger) {
|
||||
this.logger = logger
|
||||
config = new ConfigFile(new File(cfgdir, "multipart.cfg"))
|
||||
.setComment("Multipart API config file")
|
||||
|
||||
@@ -36,14 +40,13 @@ class MultipartProxy_serverImpl
|
||||
MultipartGenerator.registerTrait("codechicken.multipart.IRedstonePart", "codechicken.multipart.scalatraits.TRedstoneTile")
|
||||
MultipartGenerator.registerTrait("codechicken.multipart.IRandomDisplayTick", "codechicken.multipart.scalatraits.TRandomDisplayTickTile", null)
|
||||
MultipartGenerator.registerTrait("codechicken.multipart.INeighborTileChange", null, "codechicken.multipart.scalatraits.TTileChangeTile")
|
||||
|
||||
|
||||
MultipartSaveLoad.hookLoader()
|
||||
}
|
||||
|
||||
def init(){}
|
||||
def init() {}
|
||||
|
||||
def postInit()
|
||||
{
|
||||
def postInit() {
|
||||
FMLCommonHandler.instance().bus().register(MultipartEventHandler)
|
||||
MinecraftForge.EVENT_BUS.register(MultipartEventHandler)
|
||||
PacketCustom.assignHandler(MultipartSPH.channel, MultipartSPH)
|
||||
@@ -53,18 +56,16 @@ class MultipartProxy_serverImpl
|
||||
|
||||
MultipartCompatiblity.load()
|
||||
}
|
||||
|
||||
def onTileClassBuilt(t:Class[_ <: TileEntity])
|
||||
{
|
||||
MultipartSaveLoad.registerTileClass(t)
|
||||
|
||||
def onTileClassBuilt(t: Class[_ <: TileEntity]) {
|
||||
MultipartSaveLoad.registerTileClass(t)
|
||||
}
|
||||
}
|
||||
|
||||
class MultipartProxy_clientImpl extends MultipartProxy_serverImpl
|
||||
{
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def postInit()
|
||||
{
|
||||
override def postInit() {
|
||||
super.postInit()
|
||||
RenderingRegistry.registerBlockHandler(MultipartRenderer)
|
||||
PacketCustom.assignHandler(MultipartCPH.channel, MultipartCPH)
|
||||
@@ -73,10 +74,9 @@ class MultipartProxy_clientImpl extends MultipartProxy_serverImpl
|
||||
FMLCommonHandler.instance().bus().register(ControlKeyHandler)
|
||||
ClientRegistry.registerKeyBinding(ControlKeyHandler)
|
||||
}
|
||||
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
override def onTileClassBuilt(t:Class[_ <: TileEntity])
|
||||
{
|
||||
override def onTileClassBuilt(t: Class[_ <: TileEntity]) {
|
||||
super.onTileClassBuilt(t)
|
||||
ClientRegistry.bindTileEntitySpecialRenderer(t, MultipartRenderer)
|
||||
}
|
||||
@@ -84,9 +84,6 @@ class MultipartProxy_clientImpl extends MultipartProxy_serverImpl
|
||||
|
||||
object MultipartProxy extends MultipartProxy_clientImpl
|
||||
{
|
||||
var block:BlockMultipart = _
|
||||
var config:ConfigFile = _
|
||||
|
||||
def indexInChunk(cc:ChunkCoordIntPair, i:Int) = new BlockCoord(cc.chunkXPos<<4|i&0xF, (i>>8)&0xFF, cc.chunkZPos<<4|(i&0xF0)>>4)
|
||||
def indexInChunk(pos:BlockCoord) = pos.x&0xF|pos.y<<8|(pos.z&0xF)<<4
|
||||
def indexInChunk(cc: ChunkCoordIntPair, i: Int) = new BlockCoord(cc.chunkXPos << 4 | i & 0xF, (i >> 8) & 0xFF, cc.chunkZPos << 4 | (i & 0xF0) >> 4)
|
||||
def indexInChunk(pos: BlockCoord) = pos.x & 0xF | pos.y << 8 | (pos.z & 0xF) << 4
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package codechicken
|
||||
|
||||
import codechicken.multipart.handler.MultipartProxy
|
||||
|
||||
package object multipart
|
||||
{
|
||||
def logger = MultipartProxy.logger
|
||||
}
|
||||
Reference in new issue
Block a user