feat: cache constructor parameter types for efficiency

This commit is contained in:
金戟
2022-12-12 08:20:58 +08:00
parent d5c1f780de
commit ab87ef1fd0
2 changed files with 17 additions and 7 deletions

View File

@@ -5,13 +5,16 @@ import com.alibaba.testable.agent.handler.test.JUnit5Framework;
import com.alibaba.testable.agent.util.AnnotationUtil; import com.alibaba.testable.agent.util.AnnotationUtil;
import com.alibaba.testable.agent.util.BytecodeUtil; import com.alibaba.testable.agent.util.BytecodeUtil;
import com.alibaba.testable.agent.util.ClassUtil; import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.core.exception.ClassConstructionException;
import com.alibaba.testable.core.util.CollectionUtil; import com.alibaba.testable.core.util.CollectionUtil;
import com.alibaba.testable.core.util.LogUtil;
import com.alibaba.testable.core.util.StringUtil; import com.alibaba.testable.core.util.StringUtil;
import com.alibaba.testable.core.util.TypeUtil; import com.alibaba.testable.core.util.TypeUtil;
import org.objectweb.asm.Label; import org.objectweb.asm.Label;
import org.objectweb.asm.Type; import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*; import org.objectweb.asm.tree.*;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -45,6 +48,8 @@ public class OmniClassHandler extends BaseClassHandler {
JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST JUnit4Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_TEST, JUnit5Framework.ANNOTATION_PARAMETERIZED_TEST
}; };
private static final Map<String, Class<?>[]> constructorParameterCache = new HashMap<String, Class<?>[]>();
@Override @Override
protected void transform(ClassNode cn) { protected void transform(ClassNode cn) {
if (isInterfaceOrAtom(cn) || isUniqueConstructorClass(cn) || isUninstantiableClass(cn) || if (isInterfaceOrAtom(cn) || isUniqueConstructorClass(cn) || isUninstantiableClass(cn) ||
@@ -66,8 +71,12 @@ public class OmniClassHandler extends BaseClassHandler {
extraParameterCount = PRELOADED_CLASSES.get(cn.superName).length; extraParameterCount = PRELOADED_CLASSES.get(cn.superName).length;
} else if (cn.superName.startsWith("java/")) { } else if (cn.superName.startsWith("java/")) {
try { try {
Class<?> superClazz = Class.forName(ClassUtil.toDotSeparatedName(cn.superName)); Class<?>[] constructorParameterTypes = constructorParameterCache.get(cn.superName);
Class<?>[] constructorParameterTypes = TypeUtil.getBestConstructor(superClazz).getParameterTypes(); if (constructorParameterTypes == null) {
Class<?> superClazz = Class.forName(ClassUtil.toDotSeparatedName(cn.superName));
constructorParameterTypes = TypeUtil.getBestConstructor(superClazz).getParameterTypes();
constructorParameterCache.put(superClazz.getName(), constructorParameterTypes);
}
if (constructorParameterTypes.length == 0) { if (constructorParameterTypes.length == 0) {
constructor.instructions = invokeSuperWithoutTestableParameter(cn.superName, new String[0], start, end); constructor.instructions = invokeSuperWithoutTestableParameter(cn.superName, new String[0], start, end);
extraParameterCount = 0; extraParameterCount = 0;
@@ -80,7 +89,8 @@ public class OmniClassHandler extends BaseClassHandler {
extraParameterCount = constructorParameterTypes.length; extraParameterCount = constructorParameterTypes.length;
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
constructor.instructions = invokeSuperWithTestableVoidParameter(cn.superName, start, end); LogUtil.warn("[OmniConstructor] Failed to load class " + cn.superName);
constructor.instructions = invokeSuperWithoutTestableParameter(cn.superName, new String[0], start, end);
} }
} else { } else {
constructor.instructions = invokeSuperWithTestableVoidParameter(cn.superName, start, end); constructor.instructions = invokeSuperWithTestableVoidParameter(cn.superName, start, end);

View File

@@ -188,7 +188,7 @@ public class BytecodeUtil {
}}; }};
/** /**
* Java primitive type name to bytecode mapping * java primitive type name to bytecode mapping
*/ */
public static Map<String, String> PRIMITIVE_TYPE_NAME_MAP = new HashMap<String, String>() {{ public static Map<String, String> PRIMITIVE_TYPE_NAME_MAP = new HashMap<String, String>() {{
put("byte", String.valueOf((char)TYPE_BYTE)); put("byte", String.valueOf((char)TYPE_BYTE));
@@ -202,7 +202,7 @@ public class BytecodeUtil {
}}; }};
/** /**
* Get stack impact of a specified ops code * get stack impact of a specified ops code
* @param bytecode ops code to check * @param bytecode ops code to check
* @return stack change * @return stack change
*/ */
@@ -211,7 +211,7 @@ public class BytecodeUtil {
} }
/** /**
* Make sure method has public access * make sure method has public access
* @param access original access mark * @param access original access mark
* @return access mark with public flag * @return access mark with public flag
*/ */
@@ -223,7 +223,7 @@ public class BytecodeUtil {
} }
/** /**
* Dump byte code to specified class file * dump byte code to specified class file
* @param cn original class node * @param cn original class node
* @param dumpPath folder to store class file * @param dumpPath folder to store class file
* @param bytes original class bytes * @param bytes original class bytes