ref : stack) {
+ if (ref.get() != null) return ref.get();
+ }
+
+ return null;
+ }
+
+ @Override
+ public final void visitClassDef(JCTree.JCClassDecl tree) {
+ isStatic = false;
+ contextMakerStack.push(new AtomicReference<>());
+ staticMakerStack.push(new AtomicReference<>());
+ visitClassDefSub(tree);
+ contextMakerStack.pop();
+ staticMakerStack.pop();
+ }
+
+ public void visitClassDefSub(JCTree.JCClassDecl tree){
+ super.visitClassDef(tree);
+ }
+
+ @Override
+ public final void visitBlock(JCTree.JCBlock tree) {
+ boolean tmp = isStatic;
+ isStatic = isStatic || ((tree.flags & Flags.STATIC) != 0);
+ staticMakerStack.push(new AtomicReference<>());
+ contextMakerStack.push(new AtomicReference<>());
+ visitBlockSub(tree);
+ staticMakerStack.pop();
+ contextMakerStack.pop();
+ isStatic = tmp;
+ }
+
+ public void visitBlockSub(JCTree.JCBlock tree) {
+ super.visitBlock(tree);
+ }
+
+ @Override
+ public final void visitMethodDef(JCTree.JCMethodDecl tree) {
+ boolean tmp = isStatic;
+ isStatic = tree.sym.isStatic();
+ contextMakerStack.push(new AtomicReference<>());
+ staticMakerStack.push(new AtomicReference<>());
+ visitMethodDefSub(tree);
+ contextMakerStack.pop();
+ staticMakerStack.pop();
+ isStatic = tmp;
+ }
+
+ public void visitMethodDefSub(JCTree.JCMethodDecl tree) {
+ super.visitMethodDef(tree);
+ }
+
+ @Override
+ public final void visitVarDef(JCTree.JCVariableDecl tree) {
+ boolean tmp = isStatic;
+ isStatic = (tree.sym != null && tree.sym.isStatic()) || tmp;
+ if (getAnnotationParams(tree.mods.annotations, ContextMaker.class, unit) != null) {
+ if (tree.vartype.type.getKind() != TypeKind.DECLARED || !isAssignable(DynamicMakerType, tree.vartype.type))
+ throw new RuntimeException("illegal annotation using! @ContextMaker can only annotate on var and field that type was DynamicMaker or it subclass");
+
+ setTopSym(tree.sym);
+ }
+ visitVarDefSub(tree);
+ isStatic = tmp;
+ }
+
+ public void visitVarDefSub(JCTree.JCVariableDecl tree){
+ super.visitVarDef(tree);
+ }
+ }
+}
diff --git a/baseimpl/.gitignore b/baseimpl/.gitignore
new file mode 100644
index 0000000..b63da45
--- /dev/null
+++ b/baseimpl/.gitignore
@@ -0,0 +1,42 @@
+.gradle
+build/
+!gradle/wrapper/gradle-wrapper.jar
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+out/
+!**/src/main/**/out/
+!**/src/test/**/out/
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+bin/
+!**/src/main/**/bin/
+!**/src/test/**/bin/
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store
\ No newline at end of file
diff --git a/baseimpl/build.gradle b/baseimpl/build.gradle
new file mode 100644
index 0000000..2b6f728
--- /dev/null
+++ b/baseimpl/build.gradle
@@ -0,0 +1,44 @@
+plugins {
+ id 'java'
+}
+apply plugin: 'maven-publish'
+
+sourceSets.main.java.srcDirs = ["src/main/java"]
+sourceSets.test.java.srcDirs = ["src/test/java"]
+
+group = 'com.github.EB-wilson'
+
+sourceCompatibility = 16
+targetCompatibility = 16
+
+repositories {
+ mavenCentral()
+ maven{ url 'https://www.jitpack.io' }
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ groupId = 'com.github.EB-wilson.JavaDynamilizer'
+ artifactId = 'baseimpl'
+ version = "$JDERVersion"
+ from components.java
+ }
+ }
+}
+
+dependencies {
+ compileOnly project(":core")
+
+ annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2'
+ compileOnly 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2'
+}
+
+tasks.withType(JavaCompile).configureEach {
+ sourceCompatibility = 9
+ targetCompatibility = 9
+
+ options.compilerArgs.addAll([
+ "--add-exports", "java.base/jdk.internal.misc=ALL-UNNAMED"
+ ])
+}
diff --git a/baseimpl/src/main/java/dynamilize/Demodulator.java b/baseimpl/src/main/java/dynamilize/Demodulator.java
new file mode 100644
index 0000000..8c5358e
--- /dev/null
+++ b/baseimpl/src/main/java/dynamilize/Demodulator.java
@@ -0,0 +1,120 @@
+package dynamilize;
+
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**反模块化工具, 仅提供了一个主要方法{@link Demodulator#makeModuleOpen(Module, Package, Module)}用于强制对需要的模块开放模块的软件包。
+ * 此类行为可能完全打破模块化的访问保护,本身是不安全的,若不是必要情况,请尽量避免使用该类
+ *
此类仅在JDK9之后可用,避免在更早的版本引用此类的方法,且此类仅在desktop平台可用,安卓平台不可使用此类的任何行为
+ *
+ * @author EBwilson */
+@SuppressWarnings({"unchecked"})
+public class Demodulator{
+ private static final long fieldFilterOffset = 112L;
+
+ private static final Unsafe unsafe;
+
+ private static final Field opensField;
+ private static final Field exportField;
+
+ private static final Method exportNative;
+
+ static{
+ try{
+ Constructor cstr = Unsafe.class.getDeclaredConstructor();
+ cstr.setAccessible(true);
+ unsafe = cstr.newInstance();
+
+ ensureFieldOpen();
+
+ opensField = Module.class.getDeclaredField("openPackages");
+ exportField = Module.class.getDeclaredField("exportedPackages");
+
+ makeModuleOpen(Module.class.getModule(), "java.lang", Demodulator.class.getModule());
+
+ exportNative = Module.class.getDeclaredMethod("addExports0", Module.class, String.class, Module.class);
+ exportNative.setAccessible(true);
+ exportNative.invoke(null, Module.class.getModule(), "java.lang", Demodulator.class.getModule());
+ }catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException |
+ NoSuchFieldException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ public static void makeModuleOpen(Module from, Class> clazz, Module to){
+ if (clazz.isArray()){
+ makeModuleOpen(from, clazz.getComponentType(), to);
+ }
+ else makeModuleOpen(from, clazz.getPackage(), to);
+ }
+
+ public static void makeModuleOpen(Module from, Package pac, Module to){
+ if(checkModuleOpen(from, pac, to)) return;
+
+ makeModuleOpen(from, pac.getName(), to);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static void makeModuleOpen(Module from, String pac, Module to){
+ try {
+ if (exportNative != null) exportNative.invoke(null, from, pac, to);
+ } catch (IllegalAccessException | InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+
+ Map> opensMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(opensField));
+ if(opensMap == null){
+ opensMap = new HashMap<>();
+ unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(opensField), opensMap);
+ }
+
+ Map> exportsMap = (Map>) unsafe.getObjectVolatile(from, unsafe.objectFieldOffset(exportField));
+ if(exportsMap == null){
+ exportsMap = new HashMap<>();
+ unsafe.putObjectVolatile(from, unsafe.objectFieldOffset(exportField), exportsMap);
+ }
+
+ Set opens = opensMap.computeIfAbsent(pac, e -> new HashSet<>());
+ Set exports = exportsMap.computeIfAbsent(pac, e -> new HashSet<>());
+
+ try{
+ opens.add(to);
+ }catch(UnsupportedOperationException e){
+ ArrayList lis = new ArrayList<>(opens);
+ lis.add(to);
+ opensMap.put(pac, new HashSet<>(lis));
+ }
+
+ try{
+ exports.add(to);
+ }catch(UnsupportedOperationException e){
+ ArrayList lis = new ArrayList<>(exports);
+ lis.add(to);
+ exportsMap.put(pac, new HashSet<>(lis));
+ }
+ }
+
+ public static boolean checkModuleOpen(Module from, Package pac, Module to){
+ Objects.requireNonNull(from);
+ Objects.requireNonNull(to);
+
+ if(pac == null) return true;
+
+ return from.isOpen(pac.getName(), to);
+ }
+
+ public static void ensureFieldOpen(){
+ try{
+ Class> clazz = Class.forName("jdk.internal.reflect.Reflection");
+ Map, Set> map = (Map, Set>) unsafe.getObject(clazz, fieldFilterOffset);
+ map.clear();
+ }catch(ClassNotFoundException e){
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/baseimpl/src/main/java/dynamilize/DynamicFactory.java b/baseimpl/src/main/java/dynamilize/DynamicFactory.java
new file mode 100644
index 0000000..90b3ddc
--- /dev/null
+++ b/baseimpl/src/main/java/dynamilize/DynamicFactory.java
@@ -0,0 +1,161 @@
+package dynamilize;
+
+import dynamilize.classmaker.ASMGenerator;
+import dynamilize.classmaker.AbstractClassGenerator;
+import dynamilize.classmaker.BaseClassLoader;
+import dynamilize.classmaker.ByteClassLoader;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+/**用于创建{@linkplain DynamicMaker 动态生成器}的工厂类,内部提供了默认生成器的声明
+ *
+ * @author EBwilson
+ * @since 1.6*/
+public class DynamicFactory {
+ protected PackageAccHandler handler;
+ protected AbstractClassGenerator generator;
+ protected JavaHandleHelper helper;
+
+ private static final DynamicFactory DEFAULT = new DynamicFactory(){{
+ setDefaultGenerator();
+ setDefaultHelper();
+ setPackageAccHandler(new UnsafePackageAccHandler(generator));
+ }};
+
+ /**直接获取默认的通用实现实例,该方法获取的动态生成器等价于:
+ * {@code
+ * new DynamicFactory().setDefaultGenerator().setDefaultHelper().getMaker();
+ * }
+ *
+ * @see DynamicFactory#setDefaultGenerator()
+ * @see DynamicFactory#setDefaultHelper()
+ * @return 一个由默认声明生产的动态生成器*/
+ public static DynamicMaker getDefault(){
+ return DEFAULT.getMaker();
+ }
+
+ /**获取{@linkplain DynamicMaker 动态生成器}实例
+ *
+ * @throws NullPointerException 若有必要的属性尚未设置*/
+ public DynamicMaker getMaker(){
+ PackageAccHandler handler = this.handler;
+
+ AbstractClassGenerator generator = this.generator;
+
+ Objects.requireNonNull(helper);
+ Objects.requireNonNull(generator);
+
+ return handler == null? new DynamicMaker(helper) {
+ @Override
+ protected Class extends T> generateClass(Class baseClass, Class>[] interfaces, Class>[] aspects) {
+ return makeClassInfo(baseClass, interfaces, aspects).generate(generator);
+ }
+ }: new DynamicMaker(helper) {
+ @Override
+ protected Class extends T> generateClass(Class baseClass, Class>[] interfaces, Class>[] aspects) {
+ return makeClassInfo(baseClass, interfaces, aspects).generate(generator);
+ }
+
+ @Override
+ protected Class extends T> handleBaseClass(Class baseClass) {
+ return handler.handle(baseClass);
+ }
+ };
+ }
+
+ /**设置{@linkplain PackageAccHandler 包私有访问处理器},若不设置则动态生成器不对超类的包私有方法进行委托
+ *
+ * @see PackageAccHandler*/
+ public DynamicFactory setPackageAccHandler(PackageAccHandler handler){
+ this.handler = handler;
+ return this;
+ }
+
+ /**设置将{@linkplain dynamilize.classmaker.ClassInfo 类型描述}生成为Java类对象的{@linkplain AbstractClassGenerator 类型生成器},必要!
+ *
+ * @see AbstractClassGenerator*/
+ public DynamicFactory setGenerator(AbstractClassGenerator generator){
+ this.generator = generator;
+ return this;
+ }
+
+ /**设置对Java层行为进行处理的{@linkplain JavaHandleHelper Java行为支持器},必要!
+ *
+ * @see JavaHandleHelper*/
+ public DynamicFactory setJavaHandleHelper(JavaHandleHelper helper){
+ this.helper = helper;
+ return this;
+ }
+
+ /**使用{@linkplain DynamicFactory#setDefaultGenerator(ByteClassLoader, int) 默认配置}设置类型生成器,字节码加载器使用默认实现{@link BaseClassLoader},目标字节码版本为152(Java1.8)
+ *
+ * @see DynamicFactory#setDefaultGenerator(ByteClassLoader, int)
+ * @see BaseClassLoader*/
+ public DynamicFactory setDefaultGenerator(){
+ return setDefaultGenerator(new BaseClassLoader(DynamicFactory.class.getClassLoader()), 52);
+ }
+
+ /**将类型生成器设置为{@link ASMGenerator}的实现,该实现适用于绝大多数情况的JVM
+ *
+ * @param loader 加载字节码为类对象的类加载器
+ * @param byteLevel 目标字节码级别,最低支持50(Java1.8)
+ *
+ * @see ASMGenerator*/
+ public DynamicFactory setDefaultGenerator(ByteClassLoader loader, int byteLevel){
+ if (byteLevel < 52 || byteLevel > 255)
+ throw new IllegalArgumentException("illegal byte code level: " + byteLevel);
+
+ generator = new ASMGenerator(loader, byteLevel);
+
+ return this;
+ }
+
+ /**设置{@link JavaHandleHelper}的默认内部实现,该实现直接引用{@link JavaVariable}和{@link JavaMethodEntry}以及默认的反模块化访问
+ *
+ * @see JavaVariable
+ * @see JavaMethodEntry*/
+ public DynamicFactory setDefaultHelper(){
+ helper = new JavaHandleHelper() {
+ @Override
+ public void makeAccess(Object object) {
+ if (object instanceof Executable ext){
+ if (ext instanceof Method method) Demodulator.makeModuleOpen(method.getReturnType().getModule(), method.getReturnType(), DynamicMaker.class.getModule());
+
+ if (ext instanceof Constructor> cstr) Demodulator.makeModuleOpen(cstr.getDeclaringClass().getModule(), cstr.getDeclaringClass(), DynamicMaker.class.getModule());
+
+ for (Class> type : ext.getParameterTypes()) {
+ Demodulator.makeModuleOpen(type.getModule(), type, DynamicMaker.class.getModule());
+ }
+
+ ext.setAccessible(true);
+ }
+ else if (object instanceof Field field){
+ Demodulator.makeModuleOpen(field.getType().getModule(), field.getType(), DynamicMaker.class.getModule());
+
+ field.setAccessible(true);
+ }
+ else if (object instanceof Class> clazz){
+ Demodulator.makeModuleOpen(clazz.getModule(), clazz.getPackage(), DynamicMaker.class.getModule());
+ }
+ }
+
+ @Override
+ public IVariable genJavaVariableRef(Field field) {
+ makeAccess(field);
+ return new JavaVariable(field);
+ }
+
+ @Override
+ public IFunctionEntry genJavaMethodRef(Method method) {
+ makeAccess(method);
+ return new JavaMethodEntry(method);
+ }
+ };
+
+ return this;
+ }
+}
diff --git a/baseimpl/src/main/java/dynamilize/JavaMethodEntry.java b/baseimpl/src/main/java/dynamilize/JavaMethodEntry.java
new file mode 100644
index 0000000..63a588e
--- /dev/null
+++ b/baseimpl/src/main/java/dynamilize/JavaMethodEntry.java
@@ -0,0 +1,46 @@
+package dynamilize;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**对{@linkplain DynamicClass#visitClass(Class, JavaHandleHelper) 行为样版}中方法描述的入口,在动态类中描述子实例的某一函数行为。
+ * 方法入口的运行实际上是对样版方法的引用,因此需要确保样版方法所在的类始终有效,方法入口会生成这个方法的入口函数提供给动态对象使用
+ *
+ * @author EBwilson */
+@SuppressWarnings("unchecked")
+public class JavaMethodEntry implements IFunctionEntry{
+ private final String name;
+ private final FunctionType type;
+ private final Function, ?> defFunc;
+
+ /**直接通过目标方法创建方法入口,并生成对方法引用的句柄提供给匿名函数以描述此函数行为
+ *
+ * @param invokeMethod 样版方法*/
+ public JavaMethodEntry(Method invokeMethod){
+ this.name = invokeMethod.getName();
+ this.type = FunctionType.inst(invokeMethod);
+
+ defFunc = (self, args) -> {
+ try {
+ return invokeMethod.invoke(self.objSelf(), args.args());
+ } catch (InvocationTargetException|IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ };
+ }
+
+ @Override
+ public String getName(){
+ return name;
+ }
+
+ @Override
+ public Function getFunction(){
+ return (Function) defFunc;
+ }
+
+ @Override
+ public FunctionType getType(){
+ return type;
+ }
+}
diff --git a/baseimpl/src/main/java/dynamilize/JavaVariable.java b/baseimpl/src/main/java/dynamilize/JavaVariable.java
new file mode 100644
index 0000000..fad6f1c
--- /dev/null
+++ b/baseimpl/src/main/java/dynamilize/JavaVariable.java
@@ -0,0 +1,183 @@
+package dynamilize;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
+
+/**对java字段的引用对象,基于{@linkplain MethodHandle 方法句柄}的默认内部实现
+ *
+ * @author EBwilson */
+public class JavaVariable implements IVariable{
+ private final Field field;
+
+ private final MethodHandle getter;
+ private final MethodHandle setter;
+
+ private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
+
+ public JavaVariable(Field field){
+ this.field = field;
+
+ try {
+ getter = LOOKUP.unreflectGetter(field);
+ setter = LOOKUP.unreflectSetter(field);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String name(){
+ return field.getName();
+ }
+
+ @Override
+ public void init(DynamicObject> object) { /*no action*/ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public T get(DynamicObject> obj){
+ try{
+ return (T) getter.invoke(obj);
+ }catch(ClassCastException e){
+ throw e;
+ }catch(Throwable e){
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, Object value){
+ try{
+ setter.invoke(obj, value);
+ }catch(Throwable e){
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public boolean get(DynamicObject> obj, boolean def) {
+ try {
+ return field.getBoolean(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public byte get(DynamicObject> obj, byte def) {
+ try {
+ return field.getByte(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public short get(DynamicObject> obj, short def) {
+ try {
+ return field.getShort(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public int get(DynamicObject> obj, int def) {
+ try {
+ return field.getInt(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public long get(DynamicObject> obj, long def) {
+ try {
+ return field.getLong(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public float get(DynamicObject> obj, float def) {
+ try {
+ return field.getFloat(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public double get(DynamicObject> obj, double def) {
+ try {
+ return field.getDouble(obj);
+ } catch (IllegalAccessException e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, boolean value) {
+ try {
+ field.setBoolean(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, byte value) {
+ try {
+ field.setByte(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, short value) {
+ try {
+ field.setShort(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, int value) {
+ try {
+ field.setInt(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, long value) {
+ try {
+ field.setLong(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, float value) {
+ try {
+ field.setFloat(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void set(DynamicObject> obj, double value) {
+ try {
+ field.setDouble(obj, value);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/baseimpl/src/main/java/dynamilize/UnsafePackageAccHandler.java b/baseimpl/src/main/java/dynamilize/UnsafePackageAccHandler.java
new file mode 100644
index 0000000..37a63e4
--- /dev/null
+++ b/baseimpl/src/main/java/dynamilize/UnsafePackageAccHandler.java
@@ -0,0 +1,44 @@
+package dynamilize;
+
+import dynamilize.classmaker.AbstractClassGenerator;
+import dynamilize.classmaker.ClassInfo;
+import jdk.internal.misc.Unsafe;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**基于{@link jdk.internal.misc.Unsafe}实现的强制保护域类加载处理程序
+ *
+ * @author EBwilson
+ * @since 1.6*/
+public class UnsafePackageAccHandler extends PackageAccHandler{
+ private static final Object unsafe;
+
+ static{
+ try{
+ Demodulator.makeModuleOpen(Object.class.getModule(), "jdk.internal.misc", UnsafePackageAccHandler.class.getModule());
+
+ Constructor> cstr = Unsafe.class.getDeclaredConstructor();
+ cstr.setAccessible(true);
+ unsafe = cstr.newInstance();
+ }catch(NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e){
+ throw new RuntimeException(e);
+ }
+ }
+
+ private final AbstractClassGenerator generator;
+
+ public UnsafePackageAccHandler(AbstractClassGenerator generator){
+ this.generator = generator;
+ }
+
+ @Override
+ protected Class extends T> loadClass(ClassInfo> clazz, Class baseClass) {
+ return defineClass(clazz.name(), generator.genByteCode(clazz), baseClass.getClassLoader());
+ }
+
+ @SuppressWarnings("unchecked")
+ static Class extends T> defineClass(String name, byte[] bytes, ClassLoader loader){
+ return (Class extends T>) ((Unsafe)unsafe).defineClass (name, bytes, 0, bytes.length, loader, null);
+ }
+}
diff --git a/build.gradle b/build.gradle
index 874ff01..c1b3fe0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,26 +2,21 @@ plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '2.0.4'
}
-apply plugin: 'maven-publish'
-group 'com.github.EB-wilson'
-version '1.4-B1'
+apply plugin: 'maven-publish'
-repositories {
- mavenCentral()
- maven{ url 'https://www.jitpack.io' }
+ext{
+ JDERVersion = 'V1.9-A1'
}
-dependencies {
- implementation 'org.ow2.asm:asm:9.3'
-
- annotationProcessor "com.github.Anuken:jabel:0.7.0"
-}
+group 'com.github.EB-wilson'
+version JDERVersion
publishing {
publications {
maven(MavenPublication) {
from components.java
+ org.gradle.api.internal.tasks.compile.JdkJavaCompiler
}
}
}
@@ -35,7 +30,9 @@ generateMetadataFileForMavenPublication{
}
allprojects{
- tasks.withType(JavaCompile){
- options.compilerArgs.addAll(['--release', '8'])
+ tasks.withType(JavaCompile).tap {
+ configureEach {
+ options.encoding = "UTF-8"
+ }
}
}
diff --git a/core/build.gradle b/core/build.gradle
new file mode 100644
index 0000000..088c356
--- /dev/null
+++ b/core/build.gradle
@@ -0,0 +1,40 @@
+plugins {
+ id 'java'
+}
+apply plugin: 'maven-publish'
+
+sourceSets.main.java.srcDirs = ["src/main/java"]
+sourceSets.test.java.srcDirs = ["src/test/java"]
+
+repositories {
+ mavenCentral()
+ maven{ url 'https://www.jitpack.io' }
+}
+
+sourceCompatibility = 17
+targetCompatibility = 8
+
+tasks.withType(JavaCompile).configureEach {
+ options.compilerArgs.addAll([
+ "--release", "8"
+ ])
+}
+
+publishing {
+ publications {
+ maven(MavenPublication) {
+ groupId = 'com.github.EB-wilson.JavaDynamilizer'
+ artifactId = 'core'
+ version = "$JDERVersion"
+ from components.java
+ }
+ }
+}
+
+dependencies {
+ implementation 'org.ow2.asm:asm:9.3'
+ apiElements 'org.ow2.asm:asm:9.3'
+
+ annotationProcessor 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2'
+ compileOnly 'com.github.bsideup.jabel:jabel-javac-plugin:0.4.2'
+}
diff --git a/src/main/java/dynamilize/ArgumentList.java b/core/src/main/java/dynamilize/ArgumentList.java
similarity index 100%
rename from src/main/java/dynamilize/ArgumentList.java
rename to core/src/main/java/dynamilize/ArgumentList.java
diff --git a/core/src/main/java/dynamilize/Calculator.java b/core/src/main/java/dynamilize/Calculator.java
new file mode 100644
index 0000000..f9a4df0
--- /dev/null
+++ b/core/src/main/java/dynamilize/Calculator.java
@@ -0,0 +1,17 @@
+package dynamilize;
+
+/**变量计算器,函数式接口,用于对变量的当前值进行一系列处理后提供回调
+ *
+ * @author EBwilson */
+@FunctionalInterface
+public interface Calculator{
+ Type calculate(Type input);
+
+ @FunctionalInterface interface BoolCalculator{ boolean calculate(boolean input); }
+ @FunctionalInterface interface ByteCalculator{ byte calculate(byte input); }
+ @FunctionalInterface interface ShortCalculator{ short calculate(short input); }
+ @FunctionalInterface interface IntCalculator{ int calculate(int input); }
+ @FunctionalInterface interface LongCalculator{ long calculate(long input); }
+ @FunctionalInterface interface FloatCalculator{ float calculate(float input); }
+ @FunctionalInterface interface DoubleCalculator{ double calculate(double input); }
+}
diff --git a/src/main/java/dynamilize/ClassImplements.java b/core/src/main/java/dynamilize/ClassImplements.java
similarity index 61%
rename from src/main/java/dynamilize/ClassImplements.java
rename to core/src/main/java/dynamilize/ClassImplements.java
index e44ed24..3149020 100644
--- a/src/main/java/dynamilize/ClassImplements.java
+++ b/core/src/main/java/dynamilize/ClassImplements.java
@@ -3,16 +3,21 @@
import java.util.Arrays;
import java.util.Objects;
+/**保存类的超类及实现接口的容器,用于快速确认委托的构造类型
+ *
+ * @author EBwilson */
class ClassImplements{
final Class base;
final Class>[] interfaces;
+ final Class>[] aspects;
private int hash;
- public ClassImplements(Class base, Class>[] interfaces){
+ public ClassImplements(Class base, Class>[] interfaces, Class>[] aspects){
this.base = base;
this.interfaces = interfaces;
+ this.aspects = aspects;
this.hash = Objects.hash(base);
- hash = 31*hash + Arrays.hashCode(interfaces);
+ hash = 31*hash + Arrays.hashCode(interfaces)^Arrays.hashCode(aspects);
}
@Override
@@ -24,7 +29,7 @@ public String toString(){
public boolean equals(Object o){
if(this == o) return true;
if(!(o instanceof ClassImplements> that)) return false;
- return base.equals(that.base) && interfaces.length == that.interfaces.length && hash == ((ClassImplements>) o).hash;
+ return base.equals(that.base) && interfaces.length == that.interfaces.length && (aspects != null && that.aspects != null && aspects.length == that.aspects.length) && hash == that.hash;
}
@Override
diff --git a/src/main/java/dynamilize/DataPool.java b/core/src/main/java/dynamilize/DataPool.java
similarity index 94%
rename from src/main/java/dynamilize/DataPool.java
rename to core/src/main/java/dynamilize/DataPool.java
index e79bf95..c5ef53b 100644
--- a/src/main/java/dynamilize/DataPool.java
+++ b/core/src/main/java/dynamilize/DataPool.java
@@ -23,7 +23,7 @@ public class DataPool{
private final Map varPool = new HashMap<>();
/**创建一个池对象并绑定到父池,父池可为null,这种情况下此池应当为被委托类型的方法/字段引用。
- * 你不应该在外部使用时调用此类型
+ *
通常来说你不应该在{@link DynamicMaker}之外的任何地方实例化此类型
*
* @param superPool 此池的父池*/
public DataPool(DataPool superPool){
@@ -35,8 +35,10 @@ public void init(DynamicObject> self, Object... args){
HashSet varSetted = new HashSet<>();
while(curr != null){
- for(Map.Entry> entry: curr.getVarInit().entrySet()){
- if(varSetted.add(entry.getKey())) self.setVar(entry.getKey(), entry.getValue());
+ for (IVariable var : curr.getVariables()) {
+ if (varSetted.add(var.name())){
+ var.init(self);
+ }
}
curr = curr.superDyClass();
@@ -79,19 +81,16 @@ public void setConstructor(Function, ?> function, Class>... argType){
public void setFunction(String name, Function, ?> function, Class>... argsType){
FunctionType type = FunctionType.inst(argsType);
funcPool.computeIfAbsent(name, n -> new HashMap<>())
- .put(type, new FunctionEntry<>(name, true, function, type, this));
+ .put(type, new FunctionEntry<>(name, function, type));
}
public void setFunction(String name, Function.SuperGetFunction func, Class>[] argTypes){
FunctionType type = FunctionType.inst(argTypes);
funcPool.computeIfAbsent(name, n -> new HashMap<>())
- .put(type, new FunctionEntry<>(name, true, func, type, this));
+ .put(type, new FunctionEntry<>(name, func, type, this));
}
public void setFunction(IFunctionEntry functionEntry){
- if(functionEntry.owner() != this)
- throw new IllegalHandleException("function owner pool must equal added pool");
-
funcPool.computeIfAbsent(functionEntry.getName(), e -> new HashMap<>()).put(functionEntry.getType(), functionEntry);
}
diff --git a/src/main/java/dynamilize/Func.java b/core/src/main/java/dynamilize/Delegate.java
similarity index 70%
rename from src/main/java/dynamilize/Func.java
rename to core/src/main/java/dynamilize/Delegate.java
index 0c3387a..4da3e6e 100644
--- a/src/main/java/dynamilize/Func.java
+++ b/core/src/main/java/dynamilize/Delegate.java
@@ -1,6 +1,8 @@
package dynamilize;
-public interface Func{
+/**经过包装的委托调用函数接口,与{@linkplain Function 函数}不同,委托不接收this指针*/
+@FunctionalInterface
+public interface Delegate{
R invoke(ArgumentList args);
default R invoke(Object... args){
diff --git a/src/main/java/dynamilize/DynamicClass.java b/core/src/main/java/dynamilize/DynamicClass.java
similarity index 67%
rename from src/main/java/dynamilize/DynamicClass.java
rename to core/src/main/java/dynamilize/DynamicClass.java
index 4a89856..70b8ca1 100644
--- a/src/main/java/dynamilize/DynamicClass.java
+++ b/core/src/main/java/dynamilize/DynamicClass.java
@@ -1,12 +1,15 @@
package dynamilize;
-import dynamilize.annotation.Exclude;
+import dynamilize.runtimeannos.Exclude;
+import dynamilize.runtimeannos.Super;
+import dynamilize.runtimeannos.This;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.lang.reflect.Parameter;
+import java.util.ArrayList;
import java.util.HashMap;
-import java.util.Map;
/**保存动态对象行为信息的动态类型,描述了对象的共有行为和变量信息。
* 在{@link DynamicMaker}的构造实例方法里使用动态类型构造动态对象,动态对象会具有其类型描述的行为,对于基类与动态类中描述的同一方法会正常的处理覆盖关系。
@@ -16,7 +19,7 @@
*
当动态类的超类的方法行为发生变更时,若类的行为中引用了超类方法,则类的行为会随之改变
* 仅在动态对象的方法来自动态类描述的行为时,上述变更才会生效
*
- *
描述动态类的行为需要{@linkplain DynamicClass#visitClass(Class) 行为样版}或者函数表达式,以增量模式编辑类型行为,方法和默认变量只能新增/变更,不可删除
+ *
描述动态类的行为需要{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 行为样版}或者函数表达式,以增量模式编辑类型行为,方法和默认变量只能新增/变更,不可删除
*
{@code
* 下面是一个简单的样例:
* public class Template{
@@ -28,24 +31,16 @@
* }
*
* 引用:
+ * DynamicMaker maker = DynamicMaker.getDefault();
* DynamicClass dyClass = DynamicClass.get("Sample");
- * dyClass.visitClass(Template.class);
- * DynamicObject dyObject = DynamicMaker.getDefault().newInstance(dyClass);
+ * dyClass.visitClass(Template.class, maker.getHelper());
+ * DynamicObject dyObject = maker.newInstance(dyClass);
* dyObject.invokeFunc("method", "str");
*
* >>> string0
* }
*
- *
- * 注意,动态类型的行为变更是有时效的,这遵循以下规则:
- *
- * 在一个动态对象被创建之前的所有对动态类型的变更,都对新创建的动态对象有效
- * 对于一个已被创建的动态对象,在动态类型中声明新的函数和变量,以及修改动态类型中的变量初始值都不会对已存在的对象产生直接影响
- * 对于一个已被创建的动态对象,若它的某一函数没有通过对象的{@link DynamicObject#setFunc(String, Function, Class[])}方法变更,则对动态类型的此方法进行变更将会改变这个对象的该函数行为
- * 若一个已存在的动态对象的某一函数已经被{@link DynamicObject#setFunc(String, Function, Class[])}方法变更,则其动态类型的行为变更对该对象的此函数行为没有直接影响
- * 对象的变量初始值只和被创建时有关,比如对于变量的样版,变量初始值或者初始值函数只和被创建时,该字段的值或函数有关;对于函数,变量初始值的函数只在被创建时调用并返回值。
- *
- *
+ * 动态类型声明的变量初始值只在对象被创建时有效,任何时候改变类的变量初始值都不会对已有实例造成影响
*
* @see DynamicMaker#newInstance(Class, Class[], DynamicClass, Object...)
* @see DynamicMaker#newInstance(DynamicClass)
@@ -64,7 +59,6 @@ public class DynamicClass{
private final DynamicClass superDyClass;
private final DataPool data;
- private final Map> varInit = new HashMap<>();
/**废弃标记,在类型已废弃后,不可再实例化此类型*/
private boolean isObsoleted;
@@ -94,8 +88,14 @@ public static DynamicClass get(String name){
return classPool.computeIfAbsent(name, n -> new DynamicClass(n, null));
}
+ public static DynamicClass visit(String name, Class> clazz, DynamicClass superDyClass, JavaHandleHelper helper){
+ DynamicClass res = superDyClass == null? get(name): declare(name, superDyClass);
+ res.visitClass(clazz, helper);
+ return res;
+ }
+
/**创建类型实例,不应从外部调用此方法构造实例*/
- private DynamicClass(String name, DynamicClass superDyClass){
+ DynamicClass(String name, DynamicClass superDyClass){
this.name = name;
this.superDyClass = superDyClass;
this.data = new DataPool(superDyClass == null? null: superDyClass.data);
@@ -128,10 +128,6 @@ public DynamicClass superDyClass(){
return superDyClass;
}
- public Map> getVarInit(){
- return varInit;
- }
-
public DataPool genPool(DataPool basePool){
return new DataPool(data){
@Override
@@ -164,20 +160,18 @@ public IVariable[] getVariables(){
*
* 方法 :为动态类型描述实例共有方法,对于同名同参数的方法若重复传入,则旧的方法会被新的覆盖。
* 方法样版会创建为方法入口,当实例的此方法被调用时实际上调用会被转入这个样版方法,this指针会作为一个参数被传递(可选)
- *
要接收this指针,你需要使用{@link dynamilize.annotation.This}注解标记样版方法的第一个参数且参数应当为final,
+ *
要接收this指针,你需要使用{@link dynamilize.runtimeannos.This}注解标记样版方法的第一个参数且参数应当为final,
* 被标记为this指针的参数类型必须为可分配类型(动态实例可确保已实现了接口DynamicObject),此参数不会占据参数表匹配位置:
*
例如方法
{@code sample(@This final DynamicObject self, String str)} 可以正确的匹配到对象的函数{@code sample(String str)}
- * 若方法带有final修饰符(尽管这可能会让你收到IDE环境的警告),则此方法在类的行为中将变得不可变更,但是对于对象的此函数依然可以正常替换
* 仅有被替换的方法可以改变实例的行为,对于新增的行为将不会影响已存在的实例的行为,新增行为只会使新产生的实例具有此默认函数
*
- *
字段 :为动态类型描述默认变量表,并以字段的当前值作为函数的默认初始化数值。
+ * 字段 :为动态类型描述默认变量表,并以字段在动态对象实例化时存储的值作为该变量的初始数据。
* 若字段的类型为{@link dynamilize.Initializer.Producer},则会将此函数作为值的工厂,初始化动态实例时以函数生产的数据作为变量默认值。
- *
如果字段携带final修饰符,那么此变量将被标记为常量,不可变更。
*
除作为行为样版被访问之外,其他任何时机变量的值变化都不会对类型的行为产生直接影响
*
* 如果模板里存在不希望被作为样版的字段或者方法,你可以使用{@link Exclude}注解标记此目标以排除。
* 所有描述动态类行为的方法和变量都必须具有public static修饰符 */
- public void visitClass(Class> template){
+ public void visitClass(Class> template, JavaHandleHelper helper){
checkFinalized();
for(Method method: template.getDeclaredMethods()){
@@ -185,7 +179,7 @@ public void visitClass(Class> template){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers())) continue;
- data.setFunction(new JavaMethodEntry(method, data));
+ setFunctionWithMethod(helper, method);
}
for(Field field: template.getDeclaredFields()){
@@ -197,19 +191,19 @@ public void visitClass(Class> template){
}
}
- /**访问一个方法样版,不同于{@link DynamicClass#visitClass(Class)},此方法只访问一个单独的方法并创建其行为样版。
- *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class) 方法部分}
+ /**访问一个方法样版,不同于{@link DynamicClass#visitClass(Class,JavaHandleHelper)},此方法只访问一个单独的方法并创建其行为样版。
+ *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 方法部分}
*
* @param method 访问的方法样版*/
- public void visitMethod(Method method){
+ public void visitMethod(Method method, JavaHandleHelper helper){
if(!Modifier.isStatic(method.getModifiers()) || !Modifier.isPublic(method.getModifiers()))
throw new IllegalHandleException("method template must be public and static");
- data.setFunction(new JavaMethodEntry(method, data));
+ setFunctionWithMethod(helper, method);
}
- /**访问一个字段样版,不同于{@link DynamicClass#visitClass(Class)},此方法只访问一个单独的字段并创建其行为样版。
- *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class) 字段部分}
+ /**访问一个字段样版,不同于{@link DynamicClass#visitClass(Class,JavaHandleHelper)},此方法只访问一个单独的字段并创建其行为样版。
+ *
关于此方法的具体行为,请参阅访问行为样版类型的{@linkplain DynamicClass#visitClass(Class,JavaHandleHelper) 字段部分}
*
* @param field 访问的字段样版*/
public void visitField(Field field){
@@ -219,7 +213,7 @@ public void visitField(Field field){
setVariableWithField(field);
}
- /**以lambda模式设置函数,使用匿名函数描述类型行为,对类型行为变更的效果与{@link DynamicClass#visitClass(Class)}的方法部分相同
+ /**以lambda模式设置函数,使用匿名函数描述类型行为,对类型行为变更的效果与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}的方法部分相同
*
* @param name 函数名称
* @param func 描述函数行为的匿名函数
@@ -248,22 +242,80 @@ public void setFunction(String name, Function.NonRetSuperGetFunc func, Cl
}, argTypes);
}
- /**常量模式设置变量初始值,行为与{@link DynamicClass#visitClass(Class)}字段部分相同
+ /**常量模式设置变量初始值,行为与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}字段部分相同
*
* @param name 变量名称
- * @param value 常量值
- * @param isConst 此变量是否是一个不可变常量*/
- public void setVariable(String name, Object value, boolean isConst){
- setVariable(name, () -> value, isConst);
+ * @param value 常量值*/
+ public void setVariable(String name, Object value){
+ setVariable(name, () -> value);
}
- /**函数模式设置变量初始化工厂,行为与{@link DynamicClass#visitClass(Class)}字段部分相同
+ /**函数模式设置变量初始化工厂,行为与{@link DynamicClass#visitClass(Class,JavaHandleHelper)}字段部分相同
*
* @param name 变量名称
- * @param prov 生产变量初始值的工厂函数
- * @param isConst 此变量是否是一个不可变常量*/
- public void setVariable(String name, Initializer.Producer> prov, boolean isConst){
- varInit.put(name, new Initializer<>(prov, isConst));
+ * @param prov 生产变量初始值的工厂函数*/
+ public void setVariable(String name, Initializer.Producer> prov){
+ data.setVariable(new Variable(name, new Initializer<>(prov)));
+ }
+
+ private void setFunctionWithMethod(JavaHandleHelper helper, Method method) {
+ if(!Modifier.isStatic(method.getModifiers()))
+ throw new IllegalHandleException("cannot assign a non-static method to function");
+
+ Parameter[] parameters = method.getParameters();
+ ArrayList> arg = new ArrayList<>();
+
+ boolean thisPointer = false, superPointer = false;
+ for(int i = 0; i < parameters.length; i++){
+ Parameter param = parameters[i];
+ if(param.getAnnotation(This.class) != null){
+ if(thisPointer)
+ throw new IllegalHandleException("only one self-pointer can exist");
+ if(i != 0)
+ throw new IllegalHandleException("self-pointer must be the first in parameters");
+
+ thisPointer = true;
+ }
+ else if(param.getAnnotation(Super.class) != null){
+ if(superPointer)
+ throw new IllegalHandleException("only one super-pointer can exist");
+ if(i != (thisPointer? 1: 0))
+ throw new IllegalHandleException("super-pointer must be the first in parameters or the next of self-pointer(if self pointer was existed)");
+
+ superPointer = true;
+ }
+ else arg.add(param.getType());
+ }
+
+ boolean thisP = thisPointer;
+ boolean superP = superPointer;
+
+ Function v = helper.genJavaMethodRef(method).getFunction();
+
+ int offset = thisP? superP? 2: 1: 0;
+ FunctionType type = FunctionType.inst(method);
+
+ data.setFunction(name, (self, args) -> {
+ Object[] argsArray = args.args();
+ Object[] realArgArr = ArgumentList.getList(argsArray.length + offset);
+
+ if(thisP) realArgArr[0] = self;
+
+ DataPool.ReadOnlyPool superPool = null;
+ if(thisP && superP) realArgArr[1] = data.getSuper(self, superPool = self.baseSuperPointer());
+ else if(!thisP && superP) realArgArr[0] = data.getSuper(self, superPool = self.baseSuperPointer());
+
+ if(argsArray.length != 0) System.arraycopy(argsArray, 0, realArgArr, offset, argsArray.length);
+
+ try{
+ Object res = v.invoke(self, type, realArgArr);
+ ArgumentList.recycleList(realArgArr);
+ if(superPool != null) superPool.recycle();
+ return res;
+ }catch(Throwable e){
+ throw new RuntimeException(e);
+ }
+ }, arg.toArray(new Class[0]));
}
@SuppressWarnings({"unchecked"})
@@ -275,8 +327,13 @@ private void setVariableWithField(Field field){
throw new RuntimeException(e);
}
- varInit.put(field.getName(), new Initializer<>(value instanceof Initializer.Producer? (Initializer.Producer super Object>) value: () -> value,
- Modifier.isFinal(field.getModifiers())));
+ data.setVariable(new Variable(field.getName(), new Initializer<>(value instanceof Initializer.Producer? (Initializer.Producer super Object>) value: () -> {
+ try {
+ return field.get(null);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ })));
}
private void checkFinalized(){
@@ -286,6 +343,6 @@ private void checkFinalized(){
@Override
public String toString(){
- return "dyC:" + name;
+ return "dynamic class:" + name;
}
}
diff --git a/core/src/main/java/dynamilize/DynamicMaker.java b/core/src/main/java/dynamilize/DynamicMaker.java
new file mode 100644
index 0000000..9b03db2
--- /dev/null
+++ b/core/src/main/java/dynamilize/DynamicMaker.java
@@ -0,0 +1,1350 @@
+package dynamilize;
+
+import dynamilize.classmaker.*;
+import dynamilize.classmaker.code.*;
+import dynamilize.classmaker.code.annotation.AnnotationType;
+import dynamilize.runtimeannos.AspectInterface;
+import dynamilize.runtimeannos.FuzzyMatch;
+
+import java.lang.annotation.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.regex.Pattern;
+
+import static dynamilize.classmaker.ClassInfo.*;
+import static dynamilize.classmaker.CodeBlock.stack;
+import static dynamilize.runtimeannos.FuzzyMatch.Exact.INSTANCE;
+
+/**
+ * 动态类型运作的核心工厂类型,用于将传入的动态类型与委托基类等构造出动态委托类型以及其实例。
+ * 定义了基于{@link ASMGenerator}的默认生成器实现
+ *
若需要特殊的实现,则需要重写/实现此类的方法,主要的方法:
+ *
+ * {@link DynamicMaker#makeClassInfo(Class, Class[], Class[])} :决定此工厂如何构造委托类的描述信息
+ * {@link DynamicMaker#generateClass(Class, Class[], Class[])} :决定如何解析描述信息生成字节码以及如何加载字节码为java类
+ *
+ * 实施时必须按照方法的描述给出基本的实现,不应该改变原定的最低上下文请求。
+ *
+ * 使用方法可参阅:
+ * {@link DynamicClass}
+ * DynamicMaker的方法:
+ * {@link DynamicMaker#newInstance(DynamicClass)}
+ * {@link DynamicMaker#newInstance(Class[], Class[], DynamicClass)}
+ * {@link DynamicMaker#newInstance(Class, Class[], DynamicClass, Object...)}
+ * {@link DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)}
+ *
+ *
+ * @author EBwilson
+ * @see DynamicClass
+ * @see AspectInterface
+ * @see DynamicObject
+ * @see DataPool
+ */
+@SuppressWarnings({"rawtypes", "DuplicatedCode"})
+public abstract class DynamicMaker {
+ public static final String CALLSUPER = "$super";
+
+ private static final HashSet INTERNAL_FIELD = new HashSet<>(Arrays.asList(
+ "$dynamic_type$",
+ "$datapool$",
+ "$varValuePool$",
+ "$superbasepointer$"
+ ));
+
+ public static final ClassInfo DYNAMIC_CLASS_TYPE = asType(DynamicClass.class);
+ public static final ClassInfo DYNAMIC_OBJECT_TYPE = asType(DynamicObject.class);
+ public static final ClassInfo DATA_POOL_TYPE = asType(DataPool.class);
+ public static final ClassInfo FUNCTION_TYPE_TYPE = asType(FunctionType.class);
+ public static final MethodInfo TYPE_INST = FUNCTION_TYPE_TYPE.getMethod(
+ FUNCTION_TYPE_TYPE,
+ "inst",
+ CLASS_TYPE.asArray());
+ public static final ClassInfo FUNCTION_TYPE = asType(Function.class);
+ public static final ClassInfo READONLY_POOL_TYPE = asType(DataPool.ReadOnlyPool.class);
+ public static final ClassInfo INTEGER_CLASS_TYPE = asType(Integer.class);
+ public static final ClassInfo HASH_MAP_TYPE = asType(HashMap.class);
+ public static final ClassInfo VAR_TYPE = ClassInfo.asType(IVariable.class);
+ public static final ClassInfo NOSUCH_METHOD = asType(NoSuchMethodException.class);
+ public static final ClassInfo ARG_LIST_TYPE = asType(ArgumentList.class);
+ public static final ClassInfo SUPER_GET_FUNC_TYPE = ClassInfo.asType(Function.SuperGetFunction.class);
+ public static final ClassInfo FUNC_ENTRY_TYPE = ClassInfo.asType(IFunctionEntry.class);
+
+ public static final IMethod GET_READER = DATA_POOL_TYPE.getMethod(READONLY_POOL_TYPE, "getReader", DYNAMIC_OBJECT_TYPE);
+ public static final IMethod MAP_GET = HASH_MAP_TYPE.getMethod(OBJECT_TYPE, "get", OBJECT_TYPE);
+ public static final IMethod MAP_GET_DEF = HASH_MAP_TYPE.getMethod(OBJECT_TYPE, "getOrDefault", OBJECT_TYPE, OBJECT_TYPE);
+ public static final IMethod VALUE_OF = INTEGER_CLASS_TYPE.getMethod(INTEGER_CLASS_TYPE, "valueOf", INT_TYPE);
+ public static final IMethod MAP_PUT = HASH_MAP_TYPE.getMethod(OBJECT_TYPE, "put", OBJECT_TYPE, OBJECT_TYPE);
+ public static final IMethod GET_VAR = DATA_POOL_TYPE.getMethod(VAR_TYPE, "getVariable", STRING_TYPE);
+ public static final IMethod SET_VAR = DATA_POOL_TYPE.getMethod(ClassInfo.VOID_TYPE, "setVariable", VAR_TYPE);
+ public static final IMethod SETFUNC = DATA_POOL_TYPE.getMethod(ClassInfo.VOID_TYPE, "setFunction", STRING_TYPE, FUNCTION_TYPE, ClassInfo.CLASS_TYPE.asArray());
+ public static final IMethod SETFUNC2 = DATA_POOL_TYPE.getMethod(ClassInfo.VOID_TYPE, "setFunction", STRING_TYPE, SUPER_GET_FUNC_TYPE, ClassInfo.CLASS_TYPE.asArray());
+ public static final IMethod SELECT = DATA_POOL_TYPE.getMethod(FUNC_ENTRY_TYPE, "select", STRING_TYPE, FUNCTION_TYPE_TYPE);
+ public static final IMethod INIT = DATA_POOL_TYPE.getMethod(VOID_TYPE, "init", DYNAMIC_OBJECT_TYPE, OBJECT_TYPE.asArray());
+ public static final IMethod INVOKE = DYNAMIC_OBJECT_TYPE.getMethod(OBJECT_TYPE, "invokeFunc", FUNCTION_TYPE_TYPE, STRING_TYPE, OBJECT_TYPE.asArray());
+ public static final IMethod GET_LIST = ARG_LIST_TYPE.getMethod(OBJECT_TYPE.asArray(), "getList", INT_TYPE);
+ public static final IMethod RECYCLE_LIST = ARG_LIST_TYPE.getMethod(VOID_TYPE, "recycleList", OBJECT_TYPE.asArray());
+
+ private static final Map> OVERRIDES = new HashMap<>();
+ private static final Map> FINALS = new HashMap<>();
+ private static final Map> ABSTRACTS = new HashMap<>();
+ private static final Set> INTERFACE_TEMP = new HashSet<>();
+ private static final Stack> INTERFACE_STACK = new Stack<>();
+ private static final Class[] EMPTY_CLASSES = new Class[0];
+ public static final ILocal[] LOCALS_EMP = new ILocal[0];
+ public static final HashSet EMP_SET = new HashSet<>();
+ public static final HashMap EMP_MAP = new HashMap<>();
+ public static final String ANY = "ANY";
+ private final JavaHandleHelper helper;
+
+ private final HashMap, Class>> classPool = new HashMap<>();
+ private final HashMap, DataPool> classPoolsMap = new HashMap<>();
+ private final HashMap, HashMap>> constructors = new HashMap<>();
+
+ private final HashMap, DataPool> wrapClassPoolMap = new HashMap<>();
+
+ /**
+ * 创建一个实例,并传入其要使用的{@linkplain JavaHandleHelper java行为支持器},子类引用此构造器可能直接设置默认的行为支持器而无需外部传入
+ */
+ protected DynamicMaker(JavaHandleHelper helper) {
+ this.helper = helper;
+ }
+
+ public void clearAllCache(){
+ classPool.clear();
+ classPoolsMap.clear();
+ constructors.clear();
+ wrapClassPoolMap.clear();
+ }
+
+ /**将传入的对象包装为一个{@link WrappedObject}*/
+ public DynamicObject wrapInstance(T object){
+ Class> curr = object.getClass();
+
+ LinkedList> l = new LinkedList<>();
+ while (curr != null) {
+ if (curr.getAnnotation(DynamicType.class) != null)
+ throw new IllegalHandleException("Cannot wrap a dynamic type instance");
+
+ l.addFirst(curr);
+ curr = curr.getSuperclass();
+ }
+
+ DataPool res = null;
+ for (Class> clazz : l){
+ DataPool fr = res;
+ res = wrapClassPoolMap.computeIfAbsent(clazz, c -> {
+ DataPool r = new DataPool(fr);
+
+ for (Method method : clazz.getDeclaredMethods()) {
+ if (Modifier.isStatic(method.getModifiers())) continue;
+
+ r.setFunction(helper.genJavaMethodRef(method));
+ }
+
+ for (Field field : clazz.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers())) continue;
+
+ r.setVariable(helper.genJavaVariableRef(field));
+ }
+
+ return r;
+ });
+ }
+
+ return new WrappedObject<>(object, res);
+ }
+
+ /**
+ * 构造一个派生自{@link Object}的全委托动态实例
+ *
+ * @see DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)
+ */
+ public DynamicObject newInstance(DynamicClass dynamicClass) {
+ return newInstance(Object.class, dynamicClass);
+ }
+
+ /**
+ * 从给出的参数列表构造一个全委托动态实例
+ *
+ * @see DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)
+ */
+ public DynamicObject newInstance(Class>[] interfaces, DynamicClass dynamicClass) {
+ return newInstance(Object.class, interfaces, (Class>[]) null, dynamicClass);
+ }
+
+ /**
+ * 用给出的接口列表构造动态实例
+ * 给出的{@linkplain AspectInterface 切面接口}表会决定这个实例被动态化的行为,若为null(非空数组,空数组表明不执行委托 )则为全委托。
+ *
+ * @see DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)
+ */
+ public DynamicObject newInstance(Class>[] interfaces, Class>[] aspects, DynamicClass dynamicClass) {
+ return newInstance(Object.class, interfaces, aspects, dynamicClass);
+ }
+
+ /**
+ * 用给出的构造函数参数构造全委托动态类的实例,参数表必须可以在委托的java类型中存在匹配的可用构造器。实例无额外接口,类型委托由参数确定
+ *
+ * @see DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)
+ */
+ public DynamicObject newInstance(Class base, DynamicClass dynamicClass, Object... args) {
+ return newInstance(base, EMPTY_CLASSES, null, dynamicClass, args);
+ }
+
+ /**
+ * 用给出的构造函数参数构造动态类的实例,参数表必须可以在委托的java类型中存在匹配的可用构造器。实例无额外接口,类型委托由参数确定
+ * 给出的{@linkplain AspectInterface 切面接口}表会决定这个实例被动态化的行为,若为null(非空数组,空数组表明不执行委托 )则为全委托。
+ *
+ * @see DynamicMaker#newInstance(Class, Class[], Class[], DynamicClass, Object...)
+ */
+ public DynamicObject newInstance(Class base, Class>[] aspects, DynamicClass dynamicClass, Object... args) {
+ return newInstance(base, EMPTY_CLASSES, aspects, dynamicClass, args);
+ }
+
+ /**
+ * 用给出的构造函数参数构造动态类的实例,参数表必须可以在委托的java类型中存在匹配的可用构造器。实例实现给出的接口列表,类型委托由参数确定
+ * 给出的{@linkplain AspectInterface 切面接口}表会决定这个实例被动态化的行为,若为null(非空数组,空数组表明不执行委托 )则为全委托。
+ *
详见{@link AspectInterface}
+ *
+ *
注意,在您使用切面接口限定委托范围时,必须保证所有的抽象方法(来自抽象类委托及实现的接口)都在切面范围内,否则会抛出错误
+ *
+ * @param base 执行委托的java类型,这将决定此实例可分配到的类型
+ * @param interfaces 实例实现的接口列表
+ * @param aspects 切面接口列表
+ * @param dynamicClass 用于实例化的动态类型
+ * @param args 构造函数实参
+ * @return 构造出的动态实例
+ * @throws IllegalHandleException 若构造函数实参无法匹配到相应的构造器,或者有抽象方法未被处理
+ * @see AspectInterface
+ */
+ @SuppressWarnings("unchecked")
+ public DynamicObject newInstance(Class base, Class>[] interfaces, Class>[] aspects, DynamicClass dynamicClass, Object... args) {
+ checkBase(base);
+
+ Class extends T> clazz = getDynamicBase(base, interfaces, aspects);
+ try {
+ List argsLis = new ArrayList<>(Arrays.asList(
+ dynamicClass,
+ genPool(clazz, dynamicClass),
+ classPoolsMap.get(clazz)
+ ));
+ argsLis.addAll(Arrays.asList(args));
+
+ Constructor> cstr = null;
+ for (Constructor> constructor : clazz.getDeclaredConstructors()) {
+ FunctionType t;
+ if ((t = FunctionType.from(constructor)).match(argsLis.toArray())) {
+ cstr = constructor;
+ break;
+ }
+ t.recycle();
+ }
+ if (cstr == null)
+ throw new NoSuchMethodError("no matched constructor found with parameter " + Arrays.toString(args));
+
+ FunctionType type = FunctionType.inst(cstr.getParameterTypes());
+ Constructor c = cstr;
+ DynamicObject inst = (DynamicObject) constructors.computeIfAbsent(clazz, e -> new HashMap<>())
+ .computeIfAbsent(type, t -> {
+ helper.makeAccess(c);
+ return c;
+ }).newInstance(argsLis.toArray());
+
+ type.recycle();
+
+ return inst;
+ } catch (Throwable e) {
+ throw new IllegalHandleException(e);
+ }
+ }
+
+ /**
+ * 获取此maker的{@linkplain JavaHandleHelper java行为支持器}
+ */
+ public JavaHandleHelper getHelper() {
+ return helper;
+ }
+
+ /**
+ * 检查委托基类的可用性,基类若为final或者基类为接口则抛出异常
+ */
+ protected void checkBase(Class base) {
+ if (base.isInterface())
+ throw new IllegalHandleException("interface cannot use to derive a dynamic class, please write it in parameter \"interfaces\" to implement this interface");
+
+ if (Modifier.isFinal(base.getModifiers()))
+ throw new IllegalHandleException("cannot derive a dynamic class with a final class");
+ }
+
+ /**
+ * 生成动态类型相应的数据池,数据池完成动态类型向上对超类的迭代逐级分配数据池信息,同时对委托产生的动态类型生成所有方法和字段的函数/变量入口并放入数据池
+ *
+ * @param base 动态委托类
+ * @param dynamicClass 描述行为的动态类型
+ * @return 生成的动态类型数据池
+ */
+ protected DataPool genPool(Class extends T> base, DynamicClass dynamicClass) {
+ DataPool basePool = classPoolsMap.computeIfAbsent(base, clazz -> {
+ AtomicBoolean immutable = new AtomicBoolean();
+ DataPool res = new DataPool(null) {
+ @Override
+ public void setFunction(String name, Function, ?> function, Class>... argsType) {
+ if (immutable.get())
+ throw new IllegalHandleException("immutable pool");
+
+ super.setFunction(name, function, argsType);
+ }
+
+ @Override
+ public void setVariable(IVariable var) {
+ if (immutable.get())
+ throw new IllegalHandleException("immutable pool");
+
+ super.setVariable(var);
+ }
+ };
+
+ Class> curr = clazz;
+ while (curr != null) {
+ if (curr.getAnnotation(DynamicType.class) != null) {
+ for (Method method : curr.getDeclaredMethods()) {
+ DynamicMethod callSuper = method.getAnnotation(DynamicMethod.class);
+ if (callSuper != null) {
+ String signature = FunctionType.signature(method.getName(), method.getParameterTypes());
+ res.setFunction(
+ method.getName(),
+ (self, args) -> ((SuperInvoker) self).invokeSuper(signature, args.args()),
+ method.getParameterTypes()
+ );
+ }
+ }
+ curr = curr.getSuperclass();
+ continue;
+ }
+
+ for (Field field : curr.getDeclaredFields()) {
+ if (Modifier.isStatic(field.getModifiers()) || isInternalField(field.getName())) continue;
+
+ res.setVariable(helper.genJavaVariableRef(field));
+ }
+ curr = curr.getSuperclass();
+ }
+
+ immutable.set(true);
+
+ return res;
+ });
+
+ return dynamicClass.genPool(basePool);
+ }
+
+ private static boolean isInternalField(String name) {
+ return INTERNAL_FIELD.contains(name);
+ }
+
+ /**
+ * 根据委托基类和实现的接口获取生成的动态类型实例的类型,类型会生成并放入池,下一次获取会直接从池中取出该类型
+ *
+ * @param base 委托的基类
+ * @param interfaces 需要实现的接口列表
+ */
+ @SuppressWarnings("unchecked")
+ protected Class extends T> getDynamicBase(Class base, Class>[] interfaces, Class>[] aspects) {
+ return (Class extends T>) classPool.computeIfAbsent(new ClassImplements<>(base, interfaces, aspects), e -> {
+ Class> c = base;
+
+ while (c != null) {
+ helper.makeAccess(c);
+ c = c.getSuperclass();
+ }
+
+ return generateClass(handleBaseClass(base), interfaces, aspects);
+ });
+ }
+
+ /**
+ * 由基类与接口列表建立动态类的打包名称,打包名称具有唯一性(或者足够高的离散性,不应出现频繁的碰撞)和不变性
+ *
+ * @param baseClass 基类
+ * @param interfaces 接口列表
+ * @return 由基类名称与全部接口名称的哈希值构成的打包名称
+ */
+ public static String getDynamicName(Class baseClass, Class>... interfaces) {
+ return ensurePackage(baseClass.getName()) + "$dynamic$" + FunctionType.typeNameHash(interfaces);
+ }
+
+ private static String ensurePackage(String name) {
+ if (name.startsWith("java.")) {
+ return name.replaceFirst("java\\.", "lava.");
+ }
+ return name;
+ }
+
+ /**
+ * 对动态委托产生的类型进行继续委托创建代码的方法,应当将首要处理过程向上传递给超类。
+ * 与{@link DynamicMaker#makeClassInfo(Class, Class[], Class[])}的行为相似,但需要将部分行为适应到已经具备委托行为的超类
+ */
+ @SuppressWarnings({"unchecked"})
+ protected ClassInfo extends T> makeClassInfoOnDynamic(Class baseClass, Class>[] interfaces, Class>[] aspects) {
+ LinkedHashSet> inter = new LinkedHashSet<>();
+ inter.add(asType(DynamicObject.class));
+ inter.add(asType(SuperInvoker.class));
+
+ for (Class> i : interfaces) {
+ inter.add(asType(i));
+ }
+
+ INTERFACE_STACK.clear();
+ INTERFACE_TEMP.clear();
+ HashMap> aspectPoints = new HashMap<>();
+ if (aspects != null) {
+ for (Class> i : aspects) {
+ inter.add(asType(i));
+ INTERFACE_STACK.push(i);
+ }
+
+ while (!INTERFACE_STACK.isEmpty()) {
+ Class> i = INTERFACE_STACK.pop();
+ if (i.getAnnotation(AspectInterface.class) == null)
+ throw new IllegalHandleException("aspect interfaces must has AspectInterface annotated, but " + i + " doesn't");
+
+ if (INTERFACE_TEMP.add(i)) {
+ for (Class> ai : i.getInterfaces()) {
+ INTERFACE_STACK.push(ai);
+ }
+
+ for (Method method : i.getMethods()) {
+ if (method.isDefault())
+ throw new IllegalHandleException("aspect interface must be full-abstract, but method " + method + " in " + i + " was implemented");
+
+ aspectPoints.computeIfAbsent(method.getName(), e -> new HashMap())
+ .computeIfAbsent(FunctionType.from(method), e -> {
+ FuzzyMatch match = method.getAnnotation(FuzzyMatch.class);
+ java.lang.reflect.Parameter[] parameters = method.getParameters();
+ Annotation[] argMatchers = new Annotation[parameters.length];
+
+ if (match != null) {
+ for (int l = 0; l < parameters.length; l++) {
+ Annotation[] alternatives = parameters[l].getAnnotations();
+ for (Annotation ann : alternatives) {
+ if (ann instanceof FuzzyMatch.AnyType || ann instanceof FuzzyMatch.TypeAssignable || ann instanceof FuzzyMatch.Exact) {
+ if (argMatchers[l] != null)
+ throw new IllegalHandleException("cannot declare parameter matcher twice on a parameter");
+
+ argMatchers[l] = ann;
+ }
+ else argMatchers[l] = INSTANCE;
+ }
+ }
+ }
+
+ return new FuzzyMatcher(parameters, match, argMatchers);
+ });
+ }
+ }
+ }
+ } else {
+ aspectPoints.put(ANY, null);
+ }
+
+ ClassInfo extends T> classInfo = new ClassInfo<>(
+ Modifier.PUBLIC,
+ ensurePackage(baseClass.getName()) + "$" + FunctionType.typeNameHash(interfaces),
+ asType(baseClass),
+ inter.toArray(new ClassInfo[0])
+ );
+ FieldInfo methodIndex = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
+ "$methodIndex$",
+ HASH_MAP_TYPE,
+ null
+ );
+
+ CodeBlock clinit = classInfo.getClinitBlock();
+ ILocal caseIndex = clinit.local(HASH_MAP_TYPE);
+ clinit.newInstance(
+ asType(HashMap.class).getConstructor(),
+ caseIndex
+ );
+ clinit.assign(null, caseIndex, methodIndex);
+
+ HashMap, Integer> callSuperCaseMap = new HashMap<>();
+
+ // public (*parameters*){
+ // super(*parameters*);
+ // }
+ for (Constructor> cstr : baseClass.getDeclaredConstructors()) {
+ if ((cstr.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) continue;
+ if (Modifier.isFinal(cstr.getModifiers())) continue;
+
+ ArrayList> args = new ArrayList<>();
+ for (Class> type : cstr.getParameterTypes()) {
+ args.add(ClassInfo.asType(type));
+ }
+ IClass>[] argArr = args.toArray(new IClass[0]);
+ IMethod, Void> constructor = classInfo.superClass().getConstructor(argArr);
+
+ CodeBlock code = classInfo.declareConstructor(Modifier.PUBLIC, Parameter.trans(argArr));
+ code.invokeSuper(code.getThis(), constructor, null, code.getParamList().toArray(new ILocal>[0]));
+ }
+
+ OVERRIDES.clear();
+ FINALS.clear();
+
+ //排除已被标识为final的方法,由于继续委托的类型不向上迭代,提前将final方法排除
+ Class> curr = baseClass;
+ while (curr != null) {
+ for (Method method : curr.getDeclaredMethods()) {
+ filterMethod(method);
+ }
+
+ curr = curr.getSuperclass();
+ }
+
+ OVERRIDES.clear();
+
+ //仅处理新实现的接口以及切面接口
+ ArrayList> lis = new ArrayList<>(Arrays.asList(interfaces));
+ if (aspects != null) lis.addAll(Arrays.asList(aspects));
+
+ for (Class> interf : lis) {
+ ClassInfo> typeClass = asType(interf);
+ for (Method method : interf.getDeclaredMethods()) {
+ if (!filterMethod(method)) continue;
+
+ String methodName = method.getName();
+ ClassInfo> returnType = asType(method.getReturnType());
+
+ MethodInfo, ?> superMethod = !Modifier.isAbstract(method.getModifiers()) || (interf.isInterface() && method.isDefault()) ? typeClass.getMethod(
+ returnType,
+ methodName,
+ Arrays.stream(method.getParameterTypes()).map(ClassInfo::asType).toArray(ClassInfo[]::new)
+ ) : null;
+
+ if (!aspectPoints.containsKey(ANY) && !aspectPoints.getOrDefault(method.getName(), EMP_MAP).containsKey(FunctionType.from(method))
+ && aspectPoints.getOrDefault(method.getName(), ((HashMap) EMP_MAP)).values().stream().noneMatch(e -> e.match(method,
+ INTERFACE_TEMP.contains(interf),
+ superMethod == null))
+ ){
+ if (superMethod == null)
+ throw new IllegalHandleException("method " + method + " in " + interf + " was abstract, but no aspects handle this action");
+
+ continue;
+ }
+
+ if (superMethod != null) callSuperCaseMap.put(superMethod, callSuperCaseMap.size());
+
+ String typeF = methodName + "$" + FunctionType.typeNameHash(method.getParameterTypes());
+ FieldInfo funType = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
+ typeF,
+ FUNCTION_TYPE_TYPE,
+ null
+ );
+
+ // private static final FunctionType FUNCTION_TYPE$*name*;
+ // static {
+ // ...
+ // FUNCTION_TYPE$*signature* = FunctionType.as(*paramTypes*);
+ // methodIndex.put(*signature*, *index*);
+ // ...
+ // }
+ Integer index = callSuperCaseMap.get(superMethod);
+ genCinit(method, clinit, funType, methodIndex, index == null? -1: index);
+
+ // @DynamicMethod
+ // public *returnType* *name*(*parameters*){
+ // *[return]* this.invokeFunc(FUNCTION_TYPE$*signature* ,"*name*", parameters);
+ // }
+ invokeProxy(classInfo, method, methodName, returnType, funType);
+ }
+ }
+
+ //switch super
+ // public Object invokeSuper(String signature, Object... args);{
+ // Integer ind = methodIndex.get(signature);
+ // if(ind == null) return super.invokeSuper(signature, args)
+ // switch(ind){
+ // ...
+ // case *index*: super.*method*(args[0], args[1],...); break;
+ // ...
+ // }
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "invokeSuper",
+ OBJECT_TYPE,
+ new ClassInfo[]{
+ ClassInfo.asType(NoSuchMethodException.class)
+ },
+ Parameter.trans(
+ STRING_TYPE,
+ OBJECT_TYPE.asArray()
+ )
+ );
+
+ IMethod superCaller = (IMethod) classInfo.superClass().getMethod(code.owner().returnType(), code.owner().name(),
+ code.owner().parameters().stream().map(Parameter::getType).toArray(IClass[]::new));
+
+ Label end = code.label();
+ code.assign(null, methodIndex, stack(HASH_MAP_TYPE));
+ code.assign(code.getRealParam(0), stack(OBJECT_TYPE));
+ code.loadConstant(stack(INT_TYPE), -1);
+ code.invokeStatic(VALUE_OF, stack(INTEGER_CLASS_TYPE), stack(INT_TYPE));
+
+ code.invoke(
+ stack(HASH_MAP_TYPE),
+ MAP_GET_DEF,
+ stack(OBJECT_TYPE),
+ stack(OBJECT_TYPE)
+ );
+
+ code.cast(stack(OBJECT_TYPE), stack(INTEGER_CLASS_TYPE));
+ code.invoke(
+ stack(INTEGER_CLASS_TYPE),
+ INTEGER_CLASS_TYPE.getMethod(INT_TYPE, "intValue"),
+ stack(INT_TYPE)
+ );
+
+ ISwitch iSwitch = code.switchDef(stack(INT_TYPE), end);
+
+ ILocal args = code.getRealParam(1);
+ makeSwitch(classInfo, callSuperCaseMap, code, iSwitch, args);
+
+ code.markLabel(end);
+ code.assign(code.getThis(), stack(classInfo));
+
+ code.invokeSuper(stack(classInfo), superCaller, stack(superCaller.returnType()), code.getParamList().toArray(new ILocal[0]));
+ code.returnValue(stack(OBJECT_TYPE));
+ }
+
+ return classInfo;
+ }
+
+ /**
+ * 创建动态实例类型的类型标识,这应当覆盖所有委托目标类的方法和实现的接口中的方法,若超类的某一成员方法不是抽象的,需保留对超类方法的入口,
+ * 再重写本方法,对超类方法的入口需要有一定的标识以供生成基类数据池的引用函数时使用。
+ * 对于给定的基类和接口列表,生成的动态实例基类的名称是唯一的(或者足够的离散以至于几乎不可能碰撞)。
+ *
关于此方法实现需要完成的工作,请参阅{@link DynamicObject}中的描述
+ *
+ * @param baseClass 委托基类
+ * @param interfaces 实现的接口列表
+ * @return 完成了所有必要描述的类型标识
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ protected ClassInfo extends T> makeClassInfo(Class baseClass, Class>[] interfaces, Class>[] aspects) {
+ if (baseClass.getAnnotation(DynamicType.class) != null)
+ return makeClassInfoOnDynamic(baseClass, interfaces, aspects);
+
+ LinkedHashSet> inter = new LinkedHashSet<>();
+ inter.add(asType(DynamicObject.class));
+ inter.add(asType(SuperInvoker.class));
+
+ for (Class> i : interfaces) {
+ inter.add(asType(i));
+ }
+
+ INTERFACE_STACK.clear();
+ INTERFACE_TEMP.clear();
+ HashMap> aspectPoints = new HashMap<>();
+ if (aspects != null) {
+ for (Class> i : aspects) {
+ inter.add(asType(i));
+ INTERFACE_STACK.push(i);
+ }
+
+ while (!INTERFACE_STACK.isEmpty()) {
+ Class> i = INTERFACE_STACK.pop();
+ if (!i.isInterface())
+ throw new IllegalHandleException("aspects must be interface, but find class: " + i);
+
+ if (i.getAnnotation(AspectInterface.class) == null)
+ throw new IllegalHandleException("aspect interfaces must has AspectInterface annotated, but " + i + " doesn't");
+
+ if (INTERFACE_TEMP.add(i)) {
+ for (Class> ai : i.getInterfaces()) {
+ INTERFACE_STACK.push(ai);
+ }
+
+ for (Method method : i.getMethods()) {
+ if (method.isDefault())
+ throw new IllegalHandleException("aspect interface must be full-abstract, but method " + method + " in " + i + " was implemented");
+
+ aspectPoints.computeIfAbsent(method.getName(), e -> new HashMap())
+ .computeIfAbsent(FunctionType.from(method), e -> {
+ FuzzyMatch match = method.getAnnotation(FuzzyMatch.class);
+ java.lang.reflect.Parameter[] parameters = method.getParameters();
+ Annotation[] argMatchers = new Annotation[parameters.length];
+
+ if (match != null) {
+ for (int l = 0; l < parameters.length; l++) {
+ Annotation[] alternatives = parameters[l].getAnnotations();
+ for (Annotation ann : alternatives) {
+ if (ann instanceof FuzzyMatch.AnyType || ann instanceof FuzzyMatch.TypeAssignable || ann instanceof FuzzyMatch.Exact) {
+ if (argMatchers[l] != null)
+ throw new IllegalHandleException("cannot declare parameter matcher twice on a parameter");
+
+ argMatchers[l] = ann;
+ }
+ else argMatchers[l] = INSTANCE;
+ }
+ }
+ }
+
+ return new FuzzyMatcher(parameters, match, argMatchers);
+ });
+ }
+ }
+ }
+ } else {
+ aspectPoints.put(ANY, null);
+ }
+
+ ClassInfo extends T> classInfo = new ClassInfo<>(
+ Modifier.PUBLIC,
+ getDynamicName(baseClass, interfaces),
+ asType(baseClass),
+ inter.toArray(new ClassInfo[0])
+ );
+
+ FieldInfo dyType = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.FINAL,
+ "$dynamic_type$",
+ DYNAMIC_CLASS_TYPE,
+ null
+ );
+ FieldInfo dataPool = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.FINAL,
+ "$datapool$",
+ DATA_POOL_TYPE,
+ null
+ );
+ FieldInfo> varPool = (FieldInfo) classInfo.declareField(
+ Modifier.PRIVATE | Modifier.FINAL,
+ "$varValuePool$",
+ HASH_MAP_TYPE,
+ null
+ );
+ FieldInfo basePoolPointer = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.FINAL,
+ "$superbasepointer$",
+ READONLY_POOL_TYPE,
+ null
+ );
+ FieldInfo methodIndex = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
+ "$methodIndex$",
+ HASH_MAP_TYPE,
+ null
+ );
+
+ CodeBlock clinit = classInfo.getClinitBlock();
+ ILocal caseIndex = clinit.local(HASH_MAP_TYPE);
+ clinit.newInstance(
+ asType(HashMap.class).getConstructor(),
+ caseIndex
+ );
+ clinit.assign(null, caseIndex, methodIndex);
+
+ HashMap, Integer> callSuperCaseMap = new HashMap<>();
+
+ // public (DynamicClass $dyC$, DataPool $datP$, DataPool.ReadOnlyPool $basePool$, *parameters*){
+ // this.$dynamic_type$ = $dyC$;
+ // this.$datapool$ = $datP$;
+ // this.$varValuePool$ = new HashMap<>();
+ // super(*parameters*);
+ // this.$superbasepointer$ = $datapool$.getReader(this);
+ //
+ // this.$datapool$.init(this, *parameters*);
+ // }
+ for (Constructor> cstr : baseClass.getDeclaredConstructors()) {
+ if ((cstr.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) continue;
+ if (Modifier.isFinal(cstr.getModifiers())) continue;
+
+ List> params = new ArrayList<>(Arrays.asList(Parameter.as(
+ 0, DynamicClass.class, "$dyc$",
+ 0, DataPool.class, "$datP$",
+ 0, DataPool.class, "$basePool$"
+ )));
+ List> superParams = Arrays.asList(Parameter.asParameter(cstr.getParameters()));
+ params.addAll(superParams);
+
+ IMethod, Void> constructor = classInfo.superClass().getConstructor(superParams.stream().map(Parameter::getType).toArray(IClass[]::new));
+
+ CodeBlock code = classInfo.declareConstructor(Modifier.PUBLIC, params.toArray(new Parameter[0]));
+ List> l = code.getParamList();
+ ILocal self = code.getThis();
+
+ ILocal dyC = code.getParam(1);
+ ILocal datP = code.getParam(2);
+ code.assign(self, dyC, dyType);
+ code.assign(self, datP, dataPool);
+
+ code.assign(self, stack(classInfo));
+ code.newInstance(HASH_MAP_TYPE.getConstructor(), stack(HASH_MAP_TYPE));
+ code.assign(stack(classInfo), stack(HASH_MAP_TYPE), varPool);
+
+ code.invokeSuper(self, constructor, null, l.subList(3, l.size()).toArray(LOCALS_EMP));
+
+ code.assign(self, stack(classInfo));
+ code.invoke(code.getParam(3), GET_READER, stack(READONLY_POOL_TYPE), self);
+ code.assign(stack(classInfo), stack(READONLY_POOL_TYPE), basePoolPointer);
+
+ ILocal argList = code.local(OBJECT_TYPE.asArray());
+ code.loadConstant(stack(INT_TYPE), cstr.getParameterCount());
+ code.invoke(null, GET_LIST, argList, stack(INT_TYPE));
+ if (cstr.getParameterCount() > 0) {
+ for (int i = 3; i < code.getParamList().size(); i++) {
+ code.assign(argList, stack(OBJECT_TYPE.asArray()));
+ code.loadConstant(stack(INT_TYPE), i - 3);
+ code.arrayPut(stack(OBJECT_TYPE.asArray()), stack(INT_TYPE), code.getRealParam(i));
+ }
+ }
+ code.invoke(datP, INIT, null, self, argList);
+
+ code.invoke(null, RECYCLE_LIST, null, argList);
+ }
+
+ OVERRIDES.clear();
+ FINALS.clear();
+ INTERFACE_TEMP.clear();
+
+ ArrayList> lis = new ArrayList<>(Arrays.asList(interfaces));
+ if (aspects != null) lis.addAll(Arrays.asList(aspects));
+
+ for (Class> ic : lis) {
+ INTERFACE_STACK.push(ic);
+ INTERFACE_TEMP.add(ic);
+ }
+
+ Class> curr = baseClass;
+ while (curr != null || !INTERFACE_STACK.empty()) {
+ if (curr != null) {
+ for (Class> i : curr.getInterfaces()) {
+ if (INTERFACE_TEMP.add(i)) INTERFACE_STACK.push(i);
+ }
+ } else curr = INTERFACE_STACK.pop();
+
+ ClassInfo> typeClass = asType(curr);
+ for (Method method : curr.getDeclaredMethods()) {
+ if (!filterMethod(method)) continue;
+
+ String methodName = method.getName();
+ ClassInfo> returnType = asType(method.getReturnType());
+
+ MethodInfo, ?> superMethod = !Modifier.isAbstract(method.getModifiers()) || (curr.isInterface() && method.isDefault()) ? typeClass.getMethod(
+ returnType,
+ methodName,
+ Arrays.stream(method.getParameterTypes()).map(ClassInfo::asType).toArray(ClassInfo[]::new)
+ ) : null;
+
+ Class> finalCurr = curr;
+ if (!aspectPoints.containsKey(ANY) && !aspectPoints.getOrDefault(method.getName(), EMP_MAP).containsKey(FunctionType.from(method))
+ && aspectPoints.getOrDefault(method.getName(), ((HashMap) EMP_MAP)).values().stream().noneMatch(e -> e.match(method,
+ finalCurr == baseClass || INTERFACE_TEMP.contains(finalCurr),
+ superMethod == null
+ ))
+ ) {
+ if (superMethod == null)
+ throw new IllegalHandleException("method " + method + " in " + curr + " was abstract, but no aspects handle this action");
+
+ continue;
+ }
+
+ if (superMethod != null) callSuperCaseMap.put(superMethod, callSuperCaseMap.size());
+
+ String typeF = methodName + "$" + FunctionType.typeNameHash(method.getParameterTypes());
+ FieldInfo funType = classInfo.declareField(
+ Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL,
+ typeF,
+ FUNCTION_TYPE_TYPE,
+ null
+ );
+
+ // private static final FunctionType FUNCTION_TYPE$*name*;
+ // static {
+ // ...
+ // FUNCTION_TYPE$*signature* = FunctionType.as(*paramTypes*);
+ // methodIndex.put(*signature*, *index*);
+ // ...
+ // }
+ Integer index = callSuperCaseMap.get(superMethod);
+ genCinit(method, clinit, funType, methodIndex, index == null? -1: index);
+
+ // @DynamicMethod
+ // public *returnType* *name*(*parameters*){
+ // *[return]* this.invokeFunc(FUNCTION_TYPE$*signature* ,"*name*", parameters);
+ // }
+ invokeProxy(classInfo, method, methodName, returnType, funType);
+ }
+
+ if (!curr.isInterface()) {
+ curr = curr.getSuperclass();
+ } else curr = null;
+ }
+
+ // public Object invokeSuper(String signature, Object... args);{
+ // return switch(methodIndex.get(signature)){
+ // ...
+ // case *index* -> super.*method*(args[0], args[1],...);
+ // ...
+ // }
+ // }
+ genCallSuper(classInfo, methodIndex, callSuperCaseMap);
+
+ // public DataPool.ReadOnlyPool baseSuperPool(){
+ // return this.$superbasepointer$;
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "baseSuperPointer",
+ READONLY_POOL_TYPE
+ );
+ code.assign(code.getThis(), basePoolPointer, stack(READONLY_POOL_TYPE));
+ code.returnValue(stack(READONLY_POOL_TYPE));
+ }
+
+ // public DynamicClass getDyClass(){
+ // return this.$dynamic_type$;
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "getDyClass",
+ DYNAMIC_CLASS_TYPE
+ );
+ code.assign(code.getThis(), dyType, stack(DYNAMIC_CLASS_TYPE));
+ code.returnValue(stack(DYNAMIC_CLASS_TYPE));
+ }
+
+ // public T varValueGet(String name){
+ // return this.$varValuePool$.get(name);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "varValueGet",
+ OBJECT_TYPE,
+ Parameter.trans(STRING_TYPE)
+ );
+ code.assign(code.getThis(), varPool, stack(HASH_MAP_TYPE));
+ code.invoke(stack(HASH_MAP_TYPE), MAP_GET, stack(OBJECT_TYPE), code.getRealParam(0));
+ code.returnValue(stack(OBJECT_TYPE));
+ }
+
+ // public varValueSet(String name, Object value){
+ // return this.$varValuePool$.put(name, value);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "varValueSet",
+ VOID_TYPE,
+ Parameter.trans(
+ STRING_TYPE,
+ OBJECT_TYPE
+ )
+ );
+ code.assign(code.getThis(), varPool, stack(HASH_MAP_TYPE));
+ code.invoke(stack(HASH_MAP_TYPE), MAP_PUT, null, code.getRealParam(0), code.getRealParam(1));
+ }
+
+ // public IVariable getVariable(String name){
+ // return this.$datapool$.getVariable(name);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "getVariable",
+ VAR_TYPE,
+ Parameter.as(0, STRING_TYPE, "name")
+ );
+ code.assign(code.getThis(), dataPool, stack(DATA_POOL_TYPE));
+ code.invoke(stack(DATA_POOL_TYPE), GET_VAR, stack(VAR_TYPE), code.getParam(1));
+ code.returnValue(stack(VAR_TYPE));
+ }
+
+ // public void setVariable(IVariable var){
+ // this.$datapool$.setVariable(var);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "setVariable",
+ VOID_TYPE,
+ Parameter.as(0, VAR_TYPE, "var")
+ );
+ code.assign(code.getThis(), dataPool, stack(DATA_POOL_TYPE));
+ code.invoke(stack(DATA_POOL_TYPE), SET_VAR, null, code.getParam(1));
+ code.returnVoid();
+ }
+
+ // public IFunctionEntry getFunc(String name, FunctionType type){
+ // return this.$datapool$.select(name, type);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "getFunc",
+ FUNC_ENTRY_TYPE,
+ Parameter.as(
+ 0, STRING_TYPE, "name",
+ 0, FUNCTION_TYPE_TYPE, "type"
+ )
+ );
+ code.assign(code.getThis(), dataPool, stack(DATA_POOL_TYPE));
+
+ code.invoke(stack(DATA_POOL_TYPE), SELECT, stack(FUNC_ENTRY_TYPE), code.getParam(1), code.getParam(2));
+ code.returnValue(stack(FUNC_ENTRY_TYPE));
+ }
+
+ // public void setFunc(String name, Function func, Class>... argTypes){
+ // this.$datapool$.set(name, func, argTypes);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "setFunc",
+ VOID_TYPE,
+ Parameter.as(
+ 0, STRING_TYPE, "name",
+ 0, FUNCTION_TYPE, "func",
+ 0, CLASS_TYPE.asArray(), "argTypes"
+ )
+ );
+
+ code.assign(code.getThis(), dataPool, stack(DATA_POOL_TYPE));
+ code.invoke(stack(DATA_POOL_TYPE), SETFUNC, null, code.getParam(1), code.getParam(2), code.getParam(3));
+ }
+
+ // public void setFunc(String name, Function func, Class>... argTypes){
+ // this.$datapool$.set(name, func, argTypes);
+ // }
+ {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "setFunc",
+ VOID_TYPE,
+ Parameter.as(
+ 0, STRING_TYPE, "name",
+ 0, SUPER_GET_FUNC_TYPE, "func",
+ 0, CLASS_TYPE.asArray(), "argTypes"
+ )
+ );
+
+ ILocal pool = code.local(DATA_POOL_TYPE);
+ code.assign(code.getThis(), dataPool, pool);
+
+ code.invoke(pool, SETFUNC2, null, code.getParam(1), code.getParam(2), code.getParam(3));
+ }
+
+ AnnotationType dycAnno = AnnotationType.asAnnotationType(DynamicType.class);
+ dycAnno.annotateTo(classInfo, null);
+
+ return classInfo;
+ }
+
+ @SuppressWarnings("unchecked")
+ private void genCallSuper(ClassInfo extends T> classInfo, FieldInfo methodIndex, HashMap, Integer> callSuperCaseMap) {
+ CodeBlock code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ "invokeSuper",
+ OBJECT_TYPE,
+ new ClassInfo[]{
+ ClassInfo.asType(NoSuchMethodException.class)
+ },
+ Parameter.trans(
+ STRING_TYPE,
+ OBJECT_TYPE.asArray()
+ )
+ );
+
+ Label end = code.label();
+ code.assign(null, methodIndex, stack(HASH_MAP_TYPE));
+ code.assign(code.getRealParam(0), stack(OBJECT_TYPE));
+ code.loadConstant(stack(INT_TYPE), -1);
+ code.invokeStatic(VALUE_OF, stack(INTEGER_CLASS_TYPE), stack(INT_TYPE));
+
+ code.invoke(
+ stack(HASH_MAP_TYPE),
+ MAP_GET_DEF,
+ stack(OBJECT_TYPE),
+ stack(OBJECT_TYPE)
+ );
+
+ code.cast(stack(OBJECT_TYPE), stack(INTEGER_CLASS_TYPE));
+ code.invoke(
+ stack(INTEGER_CLASS_TYPE),
+ INTEGER_CLASS_TYPE.getMethod(INT_TYPE, "intValue"),
+ stack(INT_TYPE)
+ );
+
+ ISwitch iSwitch = code.switchDef(stack(INT_TYPE), end);
+
+ ILocal args = code.getRealParam(1);
+ makeSwitch(classInfo, callSuperCaseMap, code, iSwitch, args);
+
+ code.markLabel(end);
+
+ ILocal msg = code.local(STRING_TYPE);
+ code.loadConstant(stack(STRING_TYPE), "no such method in baseclass signature with ");
+ code.operate(stack(STRING_TYPE), IOperate.OPCode.ADD, code.getRealParam(0), msg);
+ code.newInstance(
+ NOSUCH_METHOD.getConstructor(STRING_TYPE),
+ stack(NOSUCH_METHOD),
+ msg
+ );
+ code.thr(stack(NOSUCH_METHOD));
+ }
+
+ private static void genCinit(Method method, CodeBlock clinit, FieldInfo funType, FieldInfo methodIndex, int callSuperIndex) {
+ String signature = FunctionType.signature(method);
+ clinit.loadConstant(stack(INT_TYPE), method.getParameterCount());
+ clinit.newArray(
+ CLASS_TYPE,
+ stack(CLASS_TYPE.asArray()),
+ stack(INT_TYPE)
+ );
+
+ Class>[] paramTypes = method.getParameterTypes();
+ for (int i = 0; i < paramTypes.length; i++) {
+ clinit.assign(stack(CLASS_TYPE.asArray()), stack(CLASS_TYPE.asArray()));
+ clinit.loadConstant(stack(INT_TYPE), i);
+ clinit.loadConstant(stack(CLASS_TYPE), paramTypes[i]);
+
+ clinit.arrayPut(stack(CLASS_TYPE.asArray()), stack(INT_TYPE), stack(CLASS_TYPE));
+ }
+
+ clinit.invoke(
+ null,
+ TYPE_INST,
+ stack(FUNCTION_TYPE_TYPE),
+ stack(CLASS_TYPE.asArray())
+ );
+
+ clinit.assign(null, stack(FUNCTION_TYPE_TYPE), funType);
+
+ if (callSuperIndex == -1) return;
+
+ clinit.assign(null, methodIndex, stack(HASH_MAP_TYPE));
+ clinit.loadConstant(stack(STRING_TYPE), signature);
+
+ clinit.loadConstant(stack(INT_TYPE), callSuperIndex);
+ clinit.invoke(
+ null,
+ VALUE_OF,
+ stack(INTEGER_CLASS_TYPE),
+ stack(INT_TYPE)
+ );
+
+ clinit.invoke(
+ stack(HASH_MAP_TYPE),
+ MAP_PUT,
+ null,
+ stack(OBJECT_TYPE)
+ );
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void invokeProxy(ClassInfo extends T> classInfo, Method method, String methodName, ClassInfo> returnType, FieldInfo funType) {
+ CodeBlock> code = classInfo.declareMethod(
+ Modifier.PUBLIC,
+ methodName,
+ returnType,
+ Parameter.asParameter(method.getParameters())
+ );
+ AnnotationDef anno = new AnnotationDef<>(
+ ClassInfo.asType(DynamicMethod.class).asAnnotation(EMP_MAP),
+ code.owner(),
+ EMP_MAP
+ );
+ code.owner().addAnnotation(anno);
+
+ code.loadConstant(stack(INT_TYPE), method.getParameterCount());
+ code.invoke(null, GET_LIST, stack(OBJECT_TYPE.asArray()), stack(INT_TYPE));
+
+ if (method.getParameterCount() > 0) {
+ for (int i = 0; i < code.getParamList().size(); i++) {
+ code.assign(stack(OBJECT_TYPE), stack(OBJECT_TYPE.asArray()));
+ code.loadConstant(stack(INT_TYPE), i);
+ code.arrayPut(stack(OBJECT_TYPE.asArray()), stack(INT_TYPE), code.getRealParam(i));
+ }
+ }
+
+ ILocal argList = code.local(OBJECT_TYPE.asArray());
+ code.assign(stack(OBJECT_TYPE.asArray()), argList);
+
+ if (returnType != VOID_TYPE) {
+ code.assign(code.getThis(), stack(classInfo));
+ code.assign(null, funType, stack(FUNCTION_TYPE_TYPE));
+ code.loadConstant(stack(STRING_TYPE), method.getName());
+ code.assign(argList, stack(OBJECT_TYPE.asArray()));
+
+ code.invoke(stack(classInfo), INVOKE, stack(OBJECT_TYPE), stack(OBJECT_TYPE));
+ code.invoke(null, RECYCLE_LIST, null, argList);
+ code.cast(stack(OBJECT_TYPE), stack(returnType));
+ code.returnValue(stack((IClass) returnType));
+ } else {
+ code.assign(code.getThis(), stack(classInfo));
+ code.assign(null, funType, stack(FUNCTION_TYPE_TYPE));
+ code.loadConstant(stack(STRING_TYPE), method.getName());
+ code.assign(argList, stack(OBJECT_TYPE.asArray()));
+
+ code.invoke(stack(classInfo), INVOKE, null, stack(OBJECT_TYPE));
+ code.invoke(null, RECYCLE_LIST, null, argList);
+ }
+ }
+
+ private static boolean filterMethod(Method method) {
+ //对于已经被声明为final的方法将被添加到排除列表
+ if (Modifier.isFinal(method.getModifiers())) {
+ DynamicMaker.FINALS.computeIfAbsent(method.getName(), e -> new HashSet<>()).add(FunctionType.from(method));
+ return false;
+ }
+
+ // 如果方法是静态的,或者方法不对子类可见则不重写此方法
+ if (Modifier.isStatic(method.getModifiers())) return false;
+ if ((method.getModifiers() & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0) return false;
+
+ return !DynamicMaker.FINALS.computeIfAbsent(method.getName(), e -> new HashSet<>()).contains(FunctionType.from(method))
+ && DynamicMaker.OVERRIDES.computeIfAbsent(method.getName(), e -> new HashSet<>()).add(FunctionType.from(method));
+ }
+
+ protected void makeSwitch(IClass> owner, HashMap, Integer> callSuperCaseMap, CodeBlock code, ISwitch iSwitch, ILocal