@Override
public void visitInvokeDynamicInsn(String name, String description, Handle bsm, Object... bsmArgs) {
// recode current instruction
record(INVOKEDYNAMIC);
Handle handle = (Handle) bsmArgs[1];
Type functionalInterfaceType = (Type) bsmArgs[2];
Type lambdaType = Type.getMethodType(handle.getDesc());
Type callerType = Type.getMethodType(description);
int parameterDiff = lambdaType.getArgumentTypes().length - functionalInterfaceType.getArgumentTypes().length;
boolean useContext = callerType.getArgumentTypes().length - Math.max(parameterDiff, 0) == 1;
// detect functional interface
Class interfaceClass = convert(callerType.getReturnType());
String interfaceClassName = Javascript.computeClass(interfaceClass);
// detect lambda method
Class lambdaClass = convert(handle.getOwner());
String lambdaMethodName = '"' + Javascript.computeMethodName(lambdaClass, handle.getName(), handle.getDesc()) + '"';
// build parameter from local environment
StringJoiner parameters = new StringJoiner(",", "[", "]");
for (int i = parameterDiff - 1; 0 <= i; i--) {
parameters.add(current.remove(i).toString());
}
// detect context
Object context = useContext ? current.remove(0) : "null";
// decide lambda context
Object holder = null;
switch (handle.getTag()) {
case H_INVOKESTATIC:
holder = Javascript.computeClassName(lambdaClass);
break;
case H_INVOKESPECIAL: