1
+ import java .lang .reflect .{Method , Modifier }
2
+
3
+ import Implicits ._
4
+ import org .objectweb .asm .Opcodes ._
5
+ import org .objectweb .asm .Type ._
6
+ import org .objectweb .asm ._
7
+
8
+ import scala .collection .mutable .ArrayBuffer
9
+
10
+ case class MethodContainer (methodName : String , methodDesc : String , interface : String , signature : String )
11
+ class ClassModifier (visitor : ClassVisitor , byteCodeVersion : Int = V1_6 ) extends ClassVisitor (ASM5 , visitor) {
12
+
13
+ var methodsToOverride : List [MethodContainer ] = Nil
14
+ var className : String = _
15
+ type MethodDesc = (String , String )
16
+ var implementedMethods = ArrayBuffer [MethodDesc ]()
17
+
18
+ override def visit (version : Int , access : Int , name : String , signature : String , superName : String , interfaces : Array [String ]) = {
19
+ val isClass = (access & ACC_INTERFACE ) == 0
20
+ if (isClass) {
21
+ val defaultMethods = for {
22
+ interface <- interfaces
23
+ cl = interface.getInternalClass
24
+ m @ DefaultMethod () <- cl.getMethods
25
+ } yield MethodContainer (m.getName, Type .getMethodDescriptor(m), interface, signature)
26
+ println(s " Default methods: ${defaultMethods.mkString(" ," )}" )
27
+ methodsToOverride = defaultMethods.toList
28
+ className = name
29
+ }
30
+ super .visit(byteCodeVersion, access, name, signature, superName, interfaces)
31
+ }
32
+
33
+ // gotta keep track of overriden default methods
34
+ override def visitMethod (access : Int , name : String , desc : String , signature : String , exceptions : Array [String ]): MethodVisitor = {
35
+ implementedMethods += name -> desc
36
+ new InterfaceToHelperRewriter (super .visitMethod(access, name, desc, signature, exceptions))
37
+ }
38
+
39
+ override def visitEnd () = {
40
+ def createProxy (l : MethodContainer ) = l match {
41
+ case MethodContainer (name, desc, interface, signature) if ! implementedMethods.contains(name -> desc) =>
42
+ val tmp = super .visitMethod(ACC_PUBLIC , name, desc, signature, null )
43
+ tmp.visitVarInsn(ALOAD , 0 )
44
+ Type .getArgumentTypes(desc).zipWithIndex.foreach{
45
+ case (PrimitiveLoad (instruction), i) => tmp.visitVarInsn(instruction, i + 1 )
46
+ case (_, i) => tmp.visitVarInsn(ALOAD , i + 1 )
47
+ }
48
+ tmp.visitMethodInsn(INVOKESTATIC , interface + " helper" , name, desc.addParam(interface), false )
49
+ Type .getReturnType(desc) match {
50
+ case ReturnIns (ins) => tmp.visitInsn(ins)
51
+ case otherwise : Type => tmp.visitInsn(ARETURN )
52
+ }
53
+ tmp.visitMaxs(0 , 0 )
54
+ tmp.visitEnd()
55
+ case _ => // noop
56
+ }
57
+ methodsToOverride.foreach{ createProxy }
58
+ super .visitEnd()
59
+ }
60
+ }
61
+
62
+ class InterfaceToHelperRewriter (mv : MethodVisitor ) extends MethodVisitor (Opcodes .ASM5 , mv) {
63
+ override def visitMethodInsn (opcode : Int , owner : String , name : String , desc : String , isInterface : Boolean ) = opcode match {
64
+ case INVOKESPECIAL if isInterface =>
65
+ super .visitMethodInsn(INVOKESTATIC , owner + " helper" , name, desc.addParam(owner), false )
66
+ case INVOKESTATIC if isInterface =>
67
+ super .visitMethodInsn(INVOKESTATIC , owner + " helper" , name + " $static" , desc, false )
68
+ case _ =>
69
+ super .visitMethodInsn(opcode, owner, name, desc, isInterface)
70
+ }
71
+ }
72
+
73
+ object DefaultMethod {
74
+ def unapply (m : Method ) = ! Modifier .isAbstract(m.getModifiers)
75
+ }
76
+
77
+ object InstructorExtractor {
78
+ val (loadMap, returnMap) = {
79
+ val types = List (INT_TYPE , LONG_TYPE , FLOAT_TYPE , DOUBLE_TYPE , VOID_TYPE )
80
+ val loads = List (ILOAD , LLOAD , FLOAD , DLOAD , - 1 ) // omg a null
81
+ val rets = List (IRETURN , LRETURN , FRETURN , DRETURN , RETURN )
82
+ val mkMap = types.zip(_ : List [Int ]).toMap
83
+ mkMap(loads) -> mkMap(rets)
84
+ }
85
+ }
86
+
87
+ class InstructorExtractor (m : Map [Type , Int ]) {
88
+ def unapply (f : Type ) = m.get(f)
89
+ }
90
+ object PrimitiveLoad extends InstructorExtractor (InstructorExtractor .loadMap)
91
+ object ReturnIns extends InstructorExtractor (InstructorExtractor .returnMap)
0 commit comments