Fixes after review

This commit is contained in:
Denis Zharkov
2014-07-07 19:21:49 +04:00
committed by Alexander Udalov
parent d604b5de79
commit b1a54a424e
9 changed files with 143 additions and 118 deletions
@@ -115,6 +115,16 @@ public class RangeCodegenUtil {
return map.get(DescriptorUtils.getFqNameSafe(declarationDescriptor));
}
@Nullable
public static PrimitiveType getPrimitiveRangeOrProgressionElementType(@NotNull FqName rangeOrProgressionName) {
PrimitiveType result = RANGE_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
return result != null ? result : PROGRESSION_TO_ELEMENT_TYPE.get(rangeOrProgressionName);
}
public static boolean isRangeOrProgression(@NotNull FqName className) {
return getPrimitiveRangeOrProgressionElementType(className) != null;
}
public static boolean isOptimizableRangeTo(CallableDescriptor rangeTo) {
if ("rangeTo".equals(rangeTo.getName().asString())) {
if (isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) {
@@ -30,7 +30,7 @@ import java.util.ArrayList;
import java.util.List;
public class OptimizationMethodVisitor extends MethodVisitor {
private final MethodTransformer methodTransformer = new RedundantNullCheckMethodTransformer(
private static final MethodTransformer MAIN_METHOD_TRANSFORMER = new RedundantNullCheckMethodTransformer(
new RedundantBoxingMethodTransformer(null)
);
@@ -62,15 +62,14 @@ public class OptimizationMethodVisitor extends MethodVisitor {
super.visitEnd();
if (methodNode.instructions.size() > 0) {
methodTransformer.transform("fake", methodNode);
MAIN_METHOD_TRANSFORMER.transform("fake", methodNode);
}
methodNode.accept(new EndIgnoringMethodVisitorDecorator(OptimizationUtils.API, delegate));
/*
In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
So we just do it here
*/
// In case of empty instructions list MethodNode.accept doesn't call visitLocalVariables of delegate
// So we just do it here
if (methodNode.instructions.size() == 0) {
List<LocalVariableNode> localVariables = methodNode.localVariables;
// visits local variables
@@ -34,14 +34,18 @@ public class BoxedBasicValue extends BasicValue {
private final Set<Integer> associatedVariables = new HashSet<Integer>();
private final Set<BoxedBasicValue> mergedWith = new HashSet<BoxedBasicValue>();
private final Type primitiveType;
private final RangeIteratorBasicValue numberIterator;
private final ProgressionIteratorBasicValue progressionIterator;
private boolean isSafeToRemove = true;
public BoxedBasicValue(Type boxedType, AbstractInsnNode boxingInsn, @Nullable RangeIteratorBasicValue numberIterator) {
public BoxedBasicValue(
@NotNull Type boxedType,
@NotNull AbstractInsnNode boxingInsn,
@Nullable ProgressionIteratorBasicValue progressionIterator
) {
super(boxedType);
this.primitiveType = AsmUtil.unboxType(boxedType);
this.boxingInsn = boxingInsn;
this.numberIterator = numberIterator;
this.progressionIterator = progressionIterator;
}
@Override
@@ -122,12 +126,12 @@ public class BoxedBasicValue extends BasicValue {
return boxingInsn;
}
public boolean isFromNumberIterator() {
return numberIterator != null;
public boolean isFromProgressionIterator() {
return progressionIterator != null;
}
@Nullable
public RangeIteratorBasicValue getNumberIterator() {
return numberIterator;
public ProgressionIteratorBasicValue getProgressionIterator() {
return progressionIterator;
}
}
@@ -20,8 +20,11 @@ import com.google.common.collect.ImmutableSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.jet.codegen.RangeCodegenUtil;
import org.jetbrains.jet.codegen.optimization.common.OptimizationBasicInterpreter;
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.PrimitiveType;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
@@ -35,54 +38,58 @@ import java.util.List;
import java.util.Map;
public class BoxingInterpreter extends OptimizationBasicInterpreter {
private static boolean isProgressionClass(String internalName) {
return internalName.startsWith("kotlin/") && (
internalName.endsWith("Progression") ||
internalName.endsWith("Range")
private static final ImmutableSet<String> UNBOXING_METHOD_NAMES;
static {
UNBOXING_METHOD_NAMES = ImmutableSet.of(
"booleanValue", "charValue", "byteValue", "shortValue", "intValue", "floatValue", "longValue", "doubleValue"
);
}
private static boolean isProgressionClass(String internalClassName) {
return RangeCodegenUtil.isRangeOrProgression(buildFqNameByInternal(internalClassName));
}
/**
* e.g. for "kotlin/IntRange" it returns "Int"
*
* @param progressionClassInternalName
* @return
* @throws java.lang.AssertionError if progressionClassInternalName is not progression class internal name
*/
private static String getValuesTypePartOfProgressionClass(String progressionClassInternalName) {
progressionClassInternalName = progressionClassInternalName.substring("kotlin/".length());
@NotNull
private static String getValuesTypeOfProgressionClass(String progressionClassInternalName) {
PrimitiveType type = RangeCodegenUtil.getPrimitiveRangeOrProgressionElementType(
buildFqNameByInternal(progressionClassInternalName)
);
int cutAtTheEnd = (progressionClassInternalName.endsWith("Progression")) ? "Progression".length() : "Range".length();
return progressionClassInternalName.substring(0, progressionClassInternalName.length() - cutAtTheEnd);
assert type != null : "type should be not null";
return type.getTypeName().asString();
}
private static final ImmutableSet<String> wrappersClassNames;
static {
ImmutableSet.Builder<String> wrappersClassesBuilder = ImmutableSet.builder();
for (JvmPrimitiveType primitiveType : JvmPrimitiveType.values()) {
wrappersClassesBuilder.add(AsmUtil.internalNameByFqNameWithoutInnerClasses(primitiveType.getWrapperFqName()));
}
wrappersClassNames = wrappersClassesBuilder.build();
private static boolean isWrapperClassName(@NotNull String internalClassName) {
return JvmPrimitiveType.isWrapperClassName(
buildFqNameByInternal(internalClassName)
);
}
private static boolean isWrapperClassName(@NotNull String owner) {
return wrappersClassNames.contains(owner);
@NotNull
private static FqName buildFqNameByInternal(@NotNull String internalClassName) {
return new FqName(Type.getObjectType(internalClassName).getClassName());
}
private static boolean isWrapperClassNameOrNumber(@NotNull String owner) {
return isWrapperClassName(owner) || owner.equals(Type.getInternalName(Number.class));
private static boolean isWrapperClassNameOrNumber(@NotNull String internalClassName) {
return isWrapperClassName(internalClassName) || internalClassName.equals(Type.getInternalName(Number.class));
}
private static boolean isUnboxingMethodName(@NotNull String name) {
return name.endsWith("Value");
return UNBOXING_METHOD_NAMES.contains(name);
}
private static boolean isUnboxing(@NotNull AbstractInsnNode insn) {
if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) {
return false;
}
if (insn.getOpcode() != Opcodes.INVOKEVIRTUAL) return false;
MethodInsnNode methodInsn = (MethodInsnNode) insn;
@@ -90,13 +97,11 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
}
private static boolean isBoxing(@NotNull AbstractInsnNode insn) {
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
return false;
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC) return false;
MethodInsnNode methodInsnNode = (MethodInsnNode) insn;
return isWrapperClassName(methodInsnNode.owner) && methodInsnNode.name.equals("valueOf");
return isWrapperClassName(methodInsnNode.owner) && "valueOf".equals(methodInsnNode.name);
}
private static boolean isIteratorMethodCallOfProgression(
@@ -105,31 +110,32 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
return (insn.getOpcode() == Opcodes.INVOKEINTERFACE &&
values.get(0).getType() != null &&
isProgressionClass(values.get(0).getType().getInternalName()) &&
((MethodInsnNode) insn).name.equals("iterator"));
"iterator".equals(((MethodInsnNode) insn).name));
}
private static boolean isNextMethodCallOfProgressionIterator(
@NotNull AbstractInsnNode insn, @NotNull List<? extends BasicValue> values
) {
return (insn.getOpcode() == Opcodes.INVOKEINTERFACE &&
values.get(0) instanceof RangeIteratorBasicValue &&
((MethodInsnNode) insn).name.equals("next"));
values.get(0) instanceof ProgressionIteratorBasicValue &&
"next".equals(((MethodInsnNode) insn).name));
}
private final Map<Integer, BoxedBasicValue> boxingPlaces = new HashMap<Integer, BoxedBasicValue>();
private final InsnList insnList;
BoxingInterpreter(InsnList insnList) {
public BoxingInterpreter(InsnList insnList) {
this.insnList = insnList;
}
@NotNull
private BoxedBasicValue createNewBoxing(
@NotNull AbstractInsnNode insn, @NotNull Type type, @Nullable RangeIteratorBasicValue numberIterator
@NotNull AbstractInsnNode insn, @NotNull Type type,
@Nullable ProgressionIteratorBasicValue progressionIterator
) {
int index = insnList.indexOf(insn);
if (!boxingPlaces.containsKey(index)) {
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, numberIterator);
BoxedBasicValue boxedBasicValue = new BoxedBasicValue(type, insn, progressionIterator);
onNewBoxedValue(boxedBasicValue);
boxingPlaces.put(index, boxedBasicValue);
}
@@ -142,28 +148,37 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
public BasicValue naryOperation(@NotNull AbstractInsnNode insn, @NotNull List<? extends BasicValue> values) throws AnalyzerException {
BasicValue value = super.naryOperation(insn, values);
if (values.isEmpty()) return value;
BasicValue firstArg = values.get(0);
if (isBoxing(insn)) {
return createNewBoxing(insn, value.getType(), null);
}
else if (isUnboxing(insn) &&
values.get(0) instanceof BoxedBasicValue &&
value.getType().equals(((BoxedBasicValue) values.get(0)).getPrimitiveType())) {
onUnboxing((BoxedBasicValue) values.get(0), insn);
firstArg instanceof BoxedBasicValue &&
value.getType().equals(((BoxedBasicValue) firstArg).getPrimitiveType())) {
onUnboxing((BoxedBasicValue) firstArg, insn);
}
else if (isIteratorMethodCallOfProgression(insn, values)) {
return new RangeIteratorBasicValue(
getValuesTypePartOfProgressionClass(values.get(0).getType().getInternalName())
return new ProgressionIteratorBasicValue(
getValuesTypeOfProgressionClass(firstArg.getType().getInternalName())
);
}
else if (isNextMethodCallOfProgressionIterator(insn, values)) {
RangeIteratorBasicValue numberIterator = (RangeIteratorBasicValue) values.get(0);
assert firstArg instanceof ProgressionIteratorBasicValue : "firstArg should be progression iterator";
ProgressionIteratorBasicValue progressionIterator = (ProgressionIteratorBasicValue) firstArg;
return createNewBoxing(
insn,
AsmUtil.boxType(numberIterator.getValuesPrimitiveType()),
numberIterator
AsmUtil.boxType(progressionIterator.getValuesPrimitiveType()),
progressionIterator
);
}
else {
// nary operation should be a method call or multinewarray
// arguments for multinewarray could be only numeric
// so if there are boxed values in args, it's not a case of multinewarray
for (BasicValue arg : values) {
if (arg instanceof BoxedBasicValue) {
onMethodCallWithBoxedValue((BoxedBasicValue) arg);
@@ -175,7 +190,7 @@ public class BoxingInterpreter extends OptimizationBasicInterpreter {
}
private static boolean isExactValue(@NotNull BasicValue value) {
return value instanceof RangeIteratorBasicValue ||
return value instanceof ProgressionIteratorBasicValue ||
value instanceof BoxedBasicValue ||
(value.getType() != null && isProgressionClass(value.getType().getInternalName()));
}
@@ -16,41 +16,37 @@
package org.jetbrains.jet.codegen.optimization.boxing;
import com.google.common.collect.ImmutableMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.Type;
import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue;
public class RangeIteratorBasicValue extends BasicValue {
private static Type getValuesType(@NotNull String valuesTypeName) {
if (valuesTypeName.equals("Byte")) {
return Type.BYTE_TYPE;
}
if (valuesTypeName.equals("Char")) {
return Type.CHAR_TYPE;
}
if (valuesTypeName.equals("Short")) {
return Type.SHORT_TYPE;
}
if (valuesTypeName.equals("Int")) {
return Type.INT_TYPE;
}
if (valuesTypeName.equals("Long")) {
return Type.LONG_TYPE;
}
if (valuesTypeName.equals("Float")) {
return Type.FLOAT_TYPE;
}
if (valuesTypeName.equals("Double")) {
return Type.DOUBLE_TYPE;
}
public class ProgressionIteratorBasicValue extends BasicValue {
private final static ImmutableMap<String, Type> VALUES_TYPENAME_TO_TYPE;
throw new RuntimeException("Unexpected type " + valuesTypeName);
static {
VALUES_TYPENAME_TO_TYPE = ImmutableMap.<String, Type>builder().
put("Byte", Type.BYTE_TYPE).
put("Char", Type.CHAR_TYPE).
put("Short", Type.SHORT_TYPE).
put("Int", Type.INT_TYPE).
put("Long", Type.LONG_TYPE).
put("Float", Type.FLOAT_TYPE).
put("Double", Type.DOUBLE_TYPE).
build();
}
@NotNull
private static Type getValuesType(@NotNull String valuesTypeName) {
Type type = VALUES_TYPENAME_TO_TYPE.get(valuesTypeName);
assert type != null : "Unexpected type " + valuesTypeName;
return type;
}
private final Type valuesPrimitiveType;
private final String valuesPrimitiveTypeName;
public RangeIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
public ProgressionIteratorBasicValue(@NotNull String valuesPrimitiveTypeName) {
super(Type.getObjectType("kotlin/" + valuesPrimitiveTypeName + "Iterator"));
this.valuesPrimitiveType = getValuesType(valuesPrimitiveTypeName);
this.valuesPrimitiveTypeName = valuesPrimitiveTypeName;
@@ -70,7 +66,7 @@ public class RangeIteratorBasicValue extends BasicValue {
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
RangeIteratorBasicValue value = (RangeIteratorBasicValue) o;
ProgressionIteratorBasicValue value = (ProgressionIteratorBasicValue) o;
if (!valuesPrimitiveType.equals(value.valuesPrimitiveType)) return false;
@@ -30,7 +30,7 @@ import java.util.HashSet;
import java.util.Set;
class RedundantBoxingInterpreter extends BoxingInterpreter {
private static final ImmutableSet<Integer> unsafeOperationsOpcodes;
private static final ImmutableSet<Integer> UNSAFE_OPERATIONS_OPCODES;
static {
ImmutableSet.Builder<Integer> unsafeOperationsOpcodesBuilder = ImmutableSet.builder();
@@ -39,12 +39,12 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
Opcodes.IFNONNULL, Opcodes.IFNULL, Opcodes.IF_ACMPEQ, Opcodes.IF_ACMPNE
);
unsafeOperationsOpcodes = unsafeOperationsOpcodesBuilder.build();
UNSAFE_OPERATIONS_OPCODES = unsafeOperationsOpcodesBuilder.build();
}
private final Set<BoxedBasicValue> candidatesBoxedValues = new HashSet<BoxedBasicValue>();
RedundantBoxingInterpreter(InsnList insnList) {
public RedundantBoxingInterpreter(InsnList insnList) {
super(insnList);
}
@@ -60,7 +60,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
private static void processOperationWithBoxedValue(@Nullable BasicValue value, @NotNull AbstractInsnNode insnNode) {
if (value instanceof BoxedBasicValue) {
if (unsafeOperationsOpcodes.contains(insnNode.getOpcode())) {
if (UNSAFE_OPERATIONS_OPCODES.contains(insnNode.getOpcode())) {
markValueAsDirty((BoxedBasicValue) value);
}
else {
@@ -76,6 +76,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
@NotNull BasicValue value2
) throws AnalyzerException {
processOperationWithBoxedValue(value1, insn);
processOperationWithBoxedValue(value2, insn);
return super.binaryOperation(insn, value1, value2);
@@ -87,6 +88,7 @@ class RedundantBoxingInterpreter extends BoxingInterpreter {
@NotNull BasicValue value1, @NotNull BasicValue value2, @NotNull BasicValue value3
) throws AnalyzerException {
// in a valid code only aastore could happen with boxed value
processOperationWithBoxedValue(value3, insn);
return super.ternaryOperation(insn, value1, value2, value3);
@@ -36,27 +36,26 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
}
@Override
public void transform(@NotNull String owner, @NotNull MethodNode node) {
public void transform(@NotNull String internalClassName, @NotNull MethodNode node) {
RedundantBoxingInterpreter interpreter = new RedundantBoxingInterpreter(node.instructions);
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(interpreter);
Frame<BasicValue>[] frames = runAnalyzer(analyzer, owner, node);
Frame<BasicValue>[] frames = runAnalyzer(analyzer, internalClassName, node);
Set<BoxedBasicValue> valuesToOptimize = filterSafeToRemoveValues(interpreter.getCandidatesBoxedValues());
if (valuesToOptimize.size() > 0) {
if (!valuesToOptimize.isEmpty()) {
findValuesClashingWithVariables(node, frames);
valuesToOptimize = filterSafeToRemoveValues(valuesToOptimize);
adaptLocalVariableTableForBoxedValues(node, frames);
int[] remapping = buildVariablesRemapping(valuesToOptimize, node);
applyVariablesRemapping(node, remapping);
applyVariablesRemapping(node, buildVariablesRemapping(valuesToOptimize, node));
adaptInstructionsForBoxedValues(node, frames, valuesToOptimize);
}
super.transform(owner, node);
super.transform(internalClassName, node);
}
@NotNull
@@ -108,12 +107,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
private static void findValuesClashingWithVariables(
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
) {
while (findValuesClashingWithVariablesIteration(node, frames)) {
while (findValuesClashingWithVariablesPass(node, frames)) {
// do nothing
}
}
private static boolean findValuesClashingWithVariablesIteration(
private static boolean findValuesClashingWithVariablesPass(
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
) {
InsnList insnList = node.instructions;
@@ -154,7 +153,7 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
Type usedAsType = null;
for (int i = from; i <= to; i++) {
AbstractInsnNode insn = insnList.get(i);
AbstractInsnNode insn = insnList.get(i); //TODO: handle exception?
if (insn.getOpcode() == Opcodes.ASTORE && ((VarInsnNode) insn).var == varIndex) {
if (frames[i] == null) {
return true;
@@ -207,21 +206,21 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
@NotNull
private static int[] buildVariablesRemapping(@NotNull Iterable<BoxedBasicValue> values, @NotNull MethodNode node) {
Set<Integer> longTypesVars = new HashSet<Integer>();
Set<Integer> doubleSizedVars = new HashSet<Integer>();
for (BoxedBasicValue value : values) {
if (value.getPrimitiveType().getSize() == 2) {
longTypesVars.addAll(value.getVariablesIndexes());
doubleSizedVars.addAll(value.getVariablesIndexes());
}
}
node.maxLocals += longTypesVars.size();
node.maxLocals += doubleSizedVars.size();
int[] remapping = new int[node.maxLocals];
for (int i = 0; i < remapping.length; i++) {
remapping[i] = i;
}
for (int longVarIndex : longTypesVars) {
for (int i = longVarIndex + 1; i < remapping.length; i++) {
for (int varIndex : doubleSizedVars) {
for (int i = varIndex + 1; i < remapping.length; i++) {
remapping[i]++;
}
}
@@ -247,14 +246,14 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
private static void adaptInstructionsForBoxedValues(
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames, @NotNull Set<BoxedBasicValue> values
) {
collectPopInstructionsForBoxedValues(node, frames);
addPopInstructionsForBoxedValues(node, frames);
for (BoxedBasicValue value : values) {
adaptInstructionsForBoxedValue(node, value);
}
}
private static void collectPopInstructionsForBoxedValues(
private static void addPopInstructionsForBoxedValues(
@NotNull MethodNode node, @NotNull Frame<BasicValue>[] frames
) {
for (int i = 0; i < node.instructions.size(); i++) {
@@ -279,12 +278,12 @@ public class RedundantBoxingMethodTransformer extends MethodTransformer {
}
private static void adaptBoxingInstruction(@NotNull MethodNode node, @NotNull BoxedBasicValue value) {
if (!value.isFromNumberIterator()) {
if (!value.isFromProgressionIterator()) {
node.instructions.remove(value.getBoxingInsn());
}
else {
RangeIteratorBasicValue iterator = value.getNumberIterator();
assert iterator != null : "iterator should not be null because isFromNumberIterator returns true";
ProgressionIteratorBasicValue iterator = value.getProgressionIterator();
assert iterator != null : "iterator should not be null because isFromProgressionIterator returns true";
//add checkcast to kotlin/<T>Iterator before next() call
node.instructions.insertBefore(
@@ -36,22 +36,22 @@ public class RedundantNullCheckMethodTransformer extends MethodTransformer {
}
@Override
public void transform(@NotNull String owner, @NotNull MethodNode methodNode) {
while (removeRedundantNullCheck(owner, methodNode)) {
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
while (removeRedundantNullCheckPass(internalClassName, methodNode)) {
//do nothing
}
super.transform(owner, methodNode);
super.transform(internalClassName, methodNode);
}
private static boolean removeRedundantNullCheck(@NotNull String owner, @NotNull MethodNode methodNode) {
private static boolean removeRedundantNullCheckPass(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
InsnList insnList = methodNode.instructions;
Frame<BasicValue>[] frames = runAnalyzer(
new Analyzer<BasicValue>(
new BoxingInterpreter(insnList)
),
owner, methodNode
internalClassName, methodNode
);
List<AbstractInsnNode> insnsToOptimize = new ArrayList<AbstractInsnNode>();
@@ -32,20 +32,20 @@ public abstract class MethodTransformer {
protected static <V extends Value> Frame<V>[] runAnalyzer(
@NotNull Analyzer<V> analyzer,
@NotNull String owner,
@NotNull String internalClassName,
@NotNull MethodNode node
) {
try {
return analyzer.analyze(owner, node);
return analyzer.analyze(internalClassName, node);
}
catch (AnalyzerException e) {
throw new RuntimeException(e);
}
}
public void transform(@NotNull String owner, @NotNull MethodNode methodNode) {
public void transform(@NotNull String internalClassName, @NotNull MethodNode methodNode) {
if (delegate != null) {
delegate.transform(owner, methodNode);
delegate.transform(internalClassName, methodNode);
}
}
}