completed

This commit is contained in:
jimcao 2022-01-06 15:13:32 +08:00
parent 17b31b39dd
commit 635cbf62fb
9 changed files with 189 additions and 218 deletions

View File

@ -0,0 +1,121 @@
package com.alibaba.demo.lambda;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author jim
*/
@SuppressWarnings("SimplifyStreamApiCallChains")
public class CollectionListCodeDemo implements BaseDemo {
public void list() {
List<User> userList = getUsers();
double d = userList.stream()
.map(v -> v)
.map(v -> Function.<User>identity().apply(v))
.map(User::getId)
.mapToDouble(Double::valueOf)
.reduce(0, Double::sum);
//.reduce(0, (v1, v2) -> v1 + v2);
blackHole(d);
blackHole(userList.stream()
.map(User::getId)
.mapToLong(Long::valueOf)
.reduce(0, Long::sum));
blackHole(userList.stream()
.map(User::getId)
.mapToInt(Long::intValue)
.reduce(0, Integer::sum));
Map<Long, User> map = userList.stream()
.filter(User::isActive)
.collect(Collectors.toMap(User::getId, Function.identity(), (v1, v2) -> v1));
blackHole(map);
List<User> l1 = userList.stream()
.collect(Collectors.toList())
.stream()
.collect(Collectors.toSet())
.stream()
.collect(Collectors.groupingBy(User::getName))
.entrySet()
.stream()
.filter(v -> v.getValue().stream().anyMatch(User::isActive))
.map(Map.Entry::getValue)
.flatMap(Collection::parallelStream)
.collect(Collectors.groupingBy(User::getId))
.values()
.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
blackHole(l1);
userList.stream()
.map(User::isActive)
.reduce(Boolean::logicalAnd)
.ifPresent(this::blackHole);
}
private List<User> getUsers() {
List<User> userList = new ArrayList<>();
for (int i=0; i<10; i++) {
userList.add(getUser(i));
}
return userList;
}
private User getUser(int index) {
User u1 = new User();
u1.id = (long)index;
u1.name = "u" + index;
u1.age = index;
u1.active = true;
return u1;
}
private static class User {
private Long id;
private String name;
private int age;
private boolean active;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
}
}

View File

@ -30,6 +30,8 @@ public class InvokeInterfaceDemo implements BaseDemo {
public Object collectionStreamTest() {
List<List<String>> testList = new ArrayList<>();
List<String> fooList = new ArrayList<>();
fooList.add("123");
fooList.add("456");
testList.add(fooList);
return testList.stream()
//.flatMap(v -> v.stream())

View File

@ -0,0 +1,28 @@
package com.alibaba.demo.lambda;
import com.alibaba.testable.core.annotation.MockDiagnose;
import com.alibaba.testable.core.annotation.MockInvoke;
import com.alibaba.testable.core.model.LogLevel;
import org.junit.jupiter.api.Test;
/**
* @author jim
*/
public class CollectionListCodeDemoTest {
private final CollectionListCodeDemo instance = new CollectionListCodeDemo();
//@MockDiagnose(LogLevel.VERBOSE)
public static class Mock {
@MockInvoke(targetClass = String.class, targetMethod = "contains")
public boolean mockContains(CharSequence s) {
return false;
}
}
@Test
public void listTest() {
instance.list();
}
}

View File

@ -20,7 +20,7 @@ public class InvokeInterfaceDemoTest {
private final InvokeInterfaceDemo instance = new InvokeInterfaceDemo();
@MockDiagnose(LogLevel.VERBOSE)
//@MockDiagnose(LogLevel.VERBOSE)
public static class Mock {
@MockInvoke(targetClass = InvokeInterfaceDemo.ILambda.class, targetMethod = "run")

View File

@ -15,7 +15,7 @@ public class StaticInstanceReferenceTest {
private final StaticInstanceReference instance = new StaticInstanceReference();
@MockDiagnose(LogLevel.VERBOSE)
//@MockDiagnose(LogLevel.VERBOSE)
public static class Mock {
@MockInvoke(targetClass = StaticInstanceReference.StaticClassA.class, targetMethod = "doIt")
private void mockDoIt() {

View File

@ -7,13 +7,10 @@ import com.alibaba.testable.agent.model.TravelStatus;
import com.alibaba.testable.agent.util.BytecodeUtil;
import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.agent.util.MethodUtil;
import com.alibaba.testable.agent.util.WrapperUtil;
import com.alibaba.testable.core.util.LogUtil;
import org.objectweb.asm.*;
import org.objectweb.asm.tree.*;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -63,12 +60,12 @@ public class SourceClassHandler extends BaseClassHandler {
resolveMethodReference(cn);
for (MethodNode m : cn.methods) {
transformMethod(m, memberInjectMethods, newOperatorInjectMethods, cn);
transformMethod(m, memberInjectMethods, newOperatorInjectMethods);
}
}
private void transformMethod(MethodNode mn, Set<MethodInfo> memberInjectMethods,
Set<MethodInfo> newOperatorInjectMethods, ClassNode cn) {
Set<MethodInfo> newOperatorInjectMethods) {
LogUtil.verbose(" Found method %s", mn.name);
if (mn.name.startsWith("$")) {
// skip methods e.g. "$jacocoInit"
@ -340,14 +337,6 @@ public class SourceClassHandler extends BaseClassHandler {
return Opcodes.INVOKEVIRTUAL == opcode && ClassUtil.isCompanionClassName(ownerClass);
}
public static void setFinalValue(Field ownerField, Object obj, Object value) throws Exception {
ownerField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(ownerField, ownerField.getModifiers() & ~Modifier.FINAL);
ownerField.set(obj, value);
}
private List<BsmArg> fetchInvokeDynamicHandle(MethodNode mn) {
List<BsmArg> handleList = new ArrayList<BsmArg>();
for (AbstractInsnNode instruction : mn.instructions) {
@ -385,10 +374,8 @@ public class SourceClassHandler extends BaseClassHandler {
boolean isStatic = bsmArg.isStatic();
Handle handle = bsmArg.getHandle();
Type handleDesc = bsmArg.getHandleDesc();
Type methodDesc = bsmArg.getMethodDesc();
String lambdaName = String.format("Lambda$_%s_%d", handle.getName(), atomicInteger.incrementAndGet());
String lambdaName = String.format("_Lambda$_%s_%d", handle.getName(), atomicInteger.incrementAndGet());
MethodVisitor mv = cn.visitMethod(isStatic ? ACC_PUBLIC + ACC_STATIC : ACC_PUBLIC, lambdaName, handleDesc.getDescriptor(), null, null);
mv.visitCode();
@ -399,109 +386,51 @@ public class SourceClassHandler extends BaseClassHandler {
mv.visitVarInsn(ALOAD, 0);
}
Type[] argumentTypes = handleDesc.getArgumentTypes();
Type[] methodArgs = methodDesc.getArgumentTypes();
for (int i = 0; i < argumentTypes.length; i++) {
String arg = argumentTypes[i].getDescriptor();
String methodArg = methodArgs[i].getDescriptor();
WrapperUtil.Boxed boxed = WrapperUtil.wrapper2Primitive(methodArg, arg);
if (boxed != null) {
mv.visitVarInsn(getLoadType(methodArg), isStatic ? i : i + 1);
mv.visitMethodInsn(INVOKEVIRTUAL, boxed.getOwner(), boxed.getW2pMethod(), boxed.getW2pMethodDesc(), false);
} else {
mv.visitVarInsn(getLoadType(arg), isStatic ? i : i + 1);
}
int nextVar = isStatic ? 0 : 1;
for (Type argumentType : argumentTypes) {
String arg = argumentType.getDescriptor();
mv.visitVarInsn(getLoadType(arg), nextVar);
nextVar = isLongByte(argumentType) ? nextVar + 2 : nextVar + 1;
}
// the method call is static ?
if (tag == H_INVOKEINTERFACE) {
mv.visitMethodInsn(INVOKEINTERFACE, handle.getOwner(), handle.getName(), bsmArg.getOriginalHandleDesc(), handle.isInterface());
} else {
mv.visitMethodInsn(Opcodes.H_INVOKESTATIC == tag ? INVOKESTATIC : INVOKEVIRTUAL, handle.getOwner(), handle.getName(), bsmArg.getOriginalHandleDesc(), handle.isInterface());
}
WrapperUtil.Boxed boxed = WrapperUtil.primitive2Wrapper(handleDesc.getReturnType().getDescriptor(), methodDesc.getReturnType().getDescriptor());
if (boxed != null) {
mv.visitMethodInsn(INVOKESTATIC, boxed.getOwner(), boxed.getP2wMethod(), boxed.getP2wMethodDesc(), false);
mv.visitInsn(getReturnType(methodDesc.getReturnType().getDescriptor()));
} else {
mv.visitInsn(getReturnType(handleDesc.getReturnType().getDescriptor()));
}
mv.visitInsn(getReturnType(handleDesc.getReturnType().getDescriptor()));
Label l1 = new Label();
mv.visitLabel(l1);
// static function was not required add this to first parameter
if (isStatic) {
for (int i = 0; i < argumentTypes.length; i++) {
String localVar = argumentTypes[i].getDescriptor();
// add local var
mv.visitLocalVariable(String.format("o%d", i), localVar, null, l0, l1, i);
}
visitLocalVariableByArguments(mv, 0, argumentTypes, l0, l1);
} else {
mv.visitLocalVariable("this", "L" + handle.getOwner() + ";", null, l0, l1, 0);
for (int i = 0; i < argumentTypes.length; i++) {
String localVar = argumentTypes[i].getDescriptor();
mv.visitLocalVariable(String.format("o%d", i), localVar, null, l0, l1, i + 1);
}
visitLocalVariableByArguments(mv, 1, argumentTypes, l0, l1);
}
// auto compute max
mv.visitMaxs(-1, -1);
mv.visitEnd();
bsmArg.complete(cn.name, lambdaName);
/*try {
// modify handle to the generation method
setFinalValue(handle.getClass().getDeclaredField("name"), handle, lambdaName);
// mark: should merge the below two if.
if (!handle.getOwner().equals(cn.name) && isStatic) {
setFinalValue(handle.getClass().getDeclaredField("owner"), handle, cn.name);
}
if (external) {
setFinalValue(handle.getClass().getDeclaredField("owner"), handle, cn.name);
setFinalValue(handle.getClass().getDeclaredField("descriptor"), handle, externalDesc);
setFinalValue(handle.getClass().getDeclaredField("tag"), handle, H_INVOKESTATIC);
}
} catch (Exception ignore) {
}*/
}
}
private String buildDesc(String[] refineParameterArray, String returnType) {
StringBuilder sb = new StringBuilder();
sb.append("(");
for (String s : refineParameterArray) {
sb.append(s);
if (!isPrimitive(s)) {
sb.append(";");
}
private void visitLocalVariableByArguments(MethodVisitor mv, final int initVar, Type[] argumentTypes, Label l0, Label l1) {
int nextLocalVar = initVar;
for (int i = 0; i < argumentTypes.length; i++) {
Type argumentType = argumentTypes[i];
String localVar = argumentType.getDescriptor();
mv.visitLocalVariable(String.format("o%d", i), localVar, null, l0, l1, nextLocalVar);
nextLocalVar = isLongByte(argumentType) ? nextLocalVar + 2 : nextLocalVar + 1;
}
sb.append(")");
sb.append(returnType);
return sb.toString();
}
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isPrimitive(String type) {
if (type.endsWith(";")) {
type = type.substring(0, type.length() - 1);
}
return BasicType.basicType(type.charAt(0)).isPrimitive();
}
private boolean isPrimitiveArray(String type) {
if (!type.startsWith("[")) {
return false;
}
if (type.endsWith(";")) {
type = type.substring(0, type.length() - 1);
}
type = type.replace("[", "");
return BasicType.basicType(type.charAt(0)).isPrimitive();
private boolean isLongByte(Type argumentType) {
return double.class.getName().equals(argumentType.getClassName()) || long.class.getName().equals(argumentType.getClassName());
}
private int getReturnType(String returnType) {

View File

@ -1,12 +1,10 @@
package com.alibaba.testable.agent.model;
import com.alibaba.testable.agent.util.StringUtil;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
/**
* @author jim
*/
@ -16,9 +14,9 @@ public class BsmArg {
private Handle handle;
private Object[] bsmArgs;
private final Object[] bsmArgs;
private String originalHandleDesc;
private final String originalHandleDesc;
public BsmArg(Object[] bsmArgs) {
this.bsmArgs = bsmArgs;
@ -56,21 +54,9 @@ public class BsmArg {
handleArgs[i] = handleArguments[i].getDescriptor();
}
return "(" + join("", handleArgs) + ")" + handleDesc.getReturnType().getDescriptor();
return "(" + StringUtil.join("", handleArgs) + ")" + handleDesc.getReturnType().getDescriptor();
}
private String join(String delimiter, String[] s) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < s.length; i++) {
stringBuilder.append(s[i]);
if (i != s.length - 1) {
stringBuilder.append(delimiter);
}
}
return stringBuilder.toString();
}
public Type getHandleDesc() {
return handleDesc;
}
@ -93,27 +79,6 @@ public class BsmArg {
}
public void complete(String owner, String methodName) {
//bsmArgs[1] = new Handle(isStatic()? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, owner, methodName, methodDesc.getDescriptor(), false);
//bsmArgs[1] = new Handle(isStatic()? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, owner, methodName, handleDesc.getDescriptor(), false);
Handle h = (Handle) bsmArgs[1];
try {
setFinalValue(Handle.class.getDeclaredField("tag"), h, isStatic()? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL);
setFinalValue(Handle.class.getDeclaredField("owner"), h, owner);
setFinalValue(Handle.class.getDeclaredField("name"), h, methodName);
setFinalValue(Handle.class.getDeclaredField("descriptor"), h, handleDesc.getDescriptor());
setFinalValue(Handle.class.getDeclaredField("isInterface"), h, false);
}catch (Exception e) {
e.printStackTrace();
}
}
public static void setFinalValue(Field ownerField, Object obj, Object value) throws Exception {
ownerField.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(ownerField, ownerField.getModifiers() & ~Modifier.FINAL);
ownerField.set(obj, value);
bsmArgs[1] = new Handle(isStatic()? Opcodes.H_INVOKESTATIC : Opcodes.H_INVOKEVIRTUAL, owner, methodName, handleDesc.getDescriptor(), false);
}
}

View File

@ -19,4 +19,15 @@ public class StringUtil {
return sb.toString();
}
public static String join(String delimiter, String[] s) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < s.length; i++) {
stringBuilder.append(s[i]);
if (i != s.length - 1) {
stringBuilder.append(delimiter);
}
}
return stringBuilder.toString();
}
}

View File

@ -1,85 +0,0 @@
package com.alibaba.testable.agent.util;
import com.alibaba.testable.agent.model.BasicType;
import com.alibaba.testable.agent.model.WrapperType;
/**
* @author jim
*/
public class WrapperUtil {
public static Boxed wrapper2Primitive(String from, String to) {
/*if ("Z".equals(to) && "Ljava/lang/Boolean;".equals(from)) {
return Boxed.BOOL;
}*/
return null;
}
public static Boxed primitive2Wrapper(String from, String to) {
/*if ("Ljava/lang/Boolean;".equals(to) && "Z".equals(from)) {
return Boxed.BOOL;
}*/
return null;
}
public enum Boxed {
BOOL(boolean.class, Boolean.class, "java/lang/Boolean", "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BYTE(byte.class, Byte.class, "java/lang/Byte","byteValue", "()B", "valueOf", "(B)Ljava/lang/Byte;"),
SHORT(short.class, Short.class, "java/lang/Short","shortValue", "()S", "valueOf", "(S)Ljava/lang/Short;"),
/*CHAR(boolean.class, Boolean.class, "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BOOL(boolean.class, Boolean.class, "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BOOL(boolean.class, Boolean.class, "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BOOL(boolean.class, Boolean.class, "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BOOL(boolean.class, Boolean.class, "booleanValue", "()Z", "valueOf", "(Z)Ljava/lang/Boolean;"),
BYTE(byte.class, Byte.class, "byteValue", "()B", "valueOf", "(B)Ljava/lang/Byte;")*/;
private Class<?> primitive;
private Class<?> wrapper;
private String owner;
private String w2pMethod;
private String w2pMethodDesc;
private String p2wMethod;
private String p2wMethodDesc;
Boxed(Class<?> primitive, Class<?> wrapper, String owner, String w2pMethod, String w2pMethodDesc, String p2wMethod, String p2wMethodDesc) {
this.primitive = primitive;
this.wrapper = wrapper;
this.owner = owner;
this.w2pMethod = w2pMethod;
this.w2pMethodDesc = w2pMethodDesc;
this.p2wMethod = p2wMethod;
this.p2wMethodDesc = p2wMethodDesc;
}
public Class<?> getPrimitive() {
return primitive;
}
public Class<?> getWrapper() {
return wrapper;
}
public String getOwner() {
return owner;
}
public String getW2pMethod() {
return w2pMethod;
}
public String getW2pMethodDesc() {
return w2pMethodDesc;
}
public String getP2wMethod() {
return p2wMethod;
}
public String getP2wMethodDesc() {
return p2wMethodDesc;
}
}
}