feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link jdk.internal.org.objectweb.asm.MethodVisitor} to insert before, after and around
|
||||
* advices in methods and constructors.
|
||||
* <p>
|
||||
* The behavior for constructors is like this:
|
||||
* <ol>
|
||||
*
|
||||
* <li>as long as the INVOKESPECIAL for the object initialization has not been
|
||||
* reached, every bytecode instruction is dispatched in the ctor code visitor</li>
|
||||
*
|
||||
* <li>when this one is reached, it is only added in the ctor code visitor and a
|
||||
* JP invoke is added</li>
|
||||
*
|
||||
* <li>after that, only the other code visitor receives the instructions</li>
|
||||
*
|
||||
* </ol>
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
|
||||
|
||||
private static final Object THIS = new Object();
|
||||
|
||||
private static final Object OTHER = new Object();
|
||||
|
||||
protected int methodAccess;
|
||||
|
||||
protected String methodDesc;
|
||||
|
||||
private boolean constructor;
|
||||
|
||||
private boolean superInitialized;
|
||||
|
||||
private List<Object> stackFrame;
|
||||
|
||||
private Map<Label, List<Object>> branches;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AdviceAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}).
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
*/
|
||||
protected AdviceAdapter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc) {
|
||||
super(api, mv, access, name, desc);
|
||||
methodAccess = access;
|
||||
methodDesc = desc;
|
||||
constructor = "<init>".equals(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitCode() {
|
||||
mv.visitCode();
|
||||
if (constructor) {
|
||||
stackFrame = new ArrayList<Object>();
|
||||
branches = new HashMap<Label, List<Object>>();
|
||||
} else {
|
||||
superInitialized = true;
|
||||
onMethodEnter();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
mv.visitLabel(label);
|
||||
if (constructor && branches != null) {
|
||||
List<Object> frame = branches.get(label);
|
||||
if (frame != null) {
|
||||
stackFrame = frame;
|
||||
branches.remove(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
if (constructor) {
|
||||
int s;
|
||||
switch (opcode) {
|
||||
case RETURN: // empty stack
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case IRETURN: // 1 before n/a after
|
||||
case FRETURN: // 1 before n/a after
|
||||
case ARETURN: // 1 before n/a after
|
||||
case ATHROW: // 1 before n/a after
|
||||
popValue();
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case LRETURN: // 2 before n/a after
|
||||
case DRETURN: // 2 before n/a after
|
||||
popValue();
|
||||
popValue();
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
case NOP:
|
||||
case LALOAD: // remove 2 add 2
|
||||
case DALOAD: // remove 2 add 2
|
||||
case LNEG:
|
||||
case DNEG:
|
||||
case FNEG:
|
||||
case INEG:
|
||||
case L2D:
|
||||
case D2L:
|
||||
case F2I:
|
||||
case I2B:
|
||||
case I2C:
|
||||
case I2S:
|
||||
case I2F:
|
||||
case ARRAYLENGTH:
|
||||
break;
|
||||
case ACONST_NULL:
|
||||
case ICONST_M1:
|
||||
case ICONST_0:
|
||||
case ICONST_1:
|
||||
case ICONST_2:
|
||||
case ICONST_3:
|
||||
case ICONST_4:
|
||||
case ICONST_5:
|
||||
case FCONST_0:
|
||||
case FCONST_1:
|
||||
case FCONST_2:
|
||||
case F2L: // 1 before 2 after
|
||||
case F2D:
|
||||
case I2L:
|
||||
case I2D:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case LCONST_0:
|
||||
case LCONST_1:
|
||||
case DCONST_0:
|
||||
case DCONST_1:
|
||||
pushValue(OTHER);
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case IALOAD: // remove 2 add 1
|
||||
case FALOAD: // remove 2 add 1
|
||||
case AALOAD: // remove 2 add 1
|
||||
case BALOAD: // remove 2 add 1
|
||||
case CALOAD: // remove 2 add 1
|
||||
case SALOAD: // remove 2 add 1
|
||||
case POP:
|
||||
case IADD:
|
||||
case FADD:
|
||||
case ISUB:
|
||||
case LSHL: // 3 before 2 after
|
||||
case LSHR: // 3 before 2 after
|
||||
case LUSHR: // 3 before 2 after
|
||||
case L2I: // 2 before 1 after
|
||||
case L2F: // 2 before 1 after
|
||||
case D2I: // 2 before 1 after
|
||||
case D2F: // 2 before 1 after
|
||||
case FSUB:
|
||||
case FMUL:
|
||||
case FDIV:
|
||||
case FREM:
|
||||
case FCMPL: // 2 before 1 after
|
||||
case FCMPG: // 2 before 1 after
|
||||
case IMUL:
|
||||
case IDIV:
|
||||
case IREM:
|
||||
case ISHL:
|
||||
case ISHR:
|
||||
case IUSHR:
|
||||
case IAND:
|
||||
case IOR:
|
||||
case IXOR:
|
||||
case MONITORENTER:
|
||||
case MONITOREXIT:
|
||||
popValue();
|
||||
break;
|
||||
case POP2:
|
||||
case LSUB:
|
||||
case LMUL:
|
||||
case LDIV:
|
||||
case LREM:
|
||||
case LADD:
|
||||
case LAND:
|
||||
case LOR:
|
||||
case LXOR:
|
||||
case DADD:
|
||||
case DMUL:
|
||||
case DSUB:
|
||||
case DDIV:
|
||||
case DREM:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case IASTORE:
|
||||
case FASTORE:
|
||||
case AASTORE:
|
||||
case BASTORE:
|
||||
case CASTORE:
|
||||
case SASTORE:
|
||||
case LCMP: // 4 before 1 after
|
||||
case DCMPL:
|
||||
case DCMPG:
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case LASTORE:
|
||||
case DASTORE:
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case DUP:
|
||||
pushValue(peekValue());
|
||||
break;
|
||||
case DUP_X1:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP_X2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2_X1:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 3, stackFrame.get(s - 1));
|
||||
break;
|
||||
case DUP2_X2:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 4, stackFrame.get(s - 1));
|
||||
stackFrame.add(s - 4, stackFrame.get(s - 1));
|
||||
break;
|
||||
case SWAP:
|
||||
s = stackFrame.size();
|
||||
stackFrame.add(s - 2, stackFrame.get(s - 1));
|
||||
stackFrame.remove(s);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (opcode) {
|
||||
case RETURN:
|
||||
case IRETURN:
|
||||
case FRETURN:
|
||||
case ARETURN:
|
||||
case LRETURN:
|
||||
case DRETURN:
|
||||
case ATHROW:
|
||||
onMethodExit(opcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
super.visitVarInsn(opcode, var);
|
||||
if (constructor) {
|
||||
switch (opcode) {
|
||||
case ILOAD:
|
||||
case FLOAD:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case LLOAD:
|
||||
case DLOAD:
|
||||
pushValue(OTHER);
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
case ALOAD:
|
||||
pushValue(var == 0 ? THIS : OTHER);
|
||||
break;
|
||||
case ASTORE:
|
||||
case ISTORE:
|
||||
case FSTORE:
|
||||
popValue();
|
||||
break;
|
||||
case LSTORE:
|
||||
case DSTORE:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||
if (constructor) {
|
||||
char c = desc.charAt(0);
|
||||
boolean longOrDouble = c == 'J' || c == 'D';
|
||||
switch (opcode) {
|
||||
case GETSTATIC:
|
||||
pushValue(OTHER);
|
||||
if (longOrDouble) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
break;
|
||||
case PUTSTATIC:
|
||||
popValue();
|
||||
if (longOrDouble) {
|
||||
popValue();
|
||||
}
|
||||
break;
|
||||
case PUTFIELD:
|
||||
popValue();
|
||||
if (longOrDouble) {
|
||||
popValue();
|
||||
popValue();
|
||||
}
|
||||
break;
|
||||
// case GETFIELD:
|
||||
default:
|
||||
if (longOrDouble) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
if (constructor && opcode != NEWARRAY) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
mv.visitLdcInsn(cst);
|
||||
if (constructor) {
|
||||
pushValue(OTHER);
|
||||
if (cst instanceof Double || cst instanceof Long) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
if (constructor) {
|
||||
for (int i = 0; i < dims; i++) {
|
||||
popValue();
|
||||
}
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
|
||||
if (constructor && opcode == NEW) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc,
|
||||
opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
if (constructor) {
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
popValue();
|
||||
if (types[i].getSize() == 2) {
|
||||
popValue();
|
||||
}
|
||||
}
|
||||
switch (opcode) {
|
||||
// case INVOKESTATIC:
|
||||
// break;
|
||||
case INVOKEINTERFACE:
|
||||
case INVOKEVIRTUAL:
|
||||
popValue(); // objectref
|
||||
break;
|
||||
case INVOKESPECIAL:
|
||||
Object type = popValue(); // objectref
|
||||
if (type == THIS && !superInitialized) {
|
||||
onMethodEnter();
|
||||
superInitialized = true;
|
||||
// once super has been initialized it is no longer
|
||||
// necessary to keep track of stack state
|
||||
constructor = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType != Type.VOID_TYPE) {
|
||||
pushValue(OTHER);
|
||||
if (returnType.getSize() == 2) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
if (constructor) {
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
popValue();
|
||||
if (types[i].getSize() == 2) {
|
||||
popValue();
|
||||
}
|
||||
}
|
||||
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType != Type.VOID_TYPE) {
|
||||
pushValue(OTHER);
|
||||
if (returnType.getSize() == 2) {
|
||||
pushValue(OTHER);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
mv.visitJumpInsn(opcode, label);
|
||||
if (constructor) {
|
||||
switch (opcode) {
|
||||
case IFEQ:
|
||||
case IFNE:
|
||||
case IFLT:
|
||||
case IFGE:
|
||||
case IFGT:
|
||||
case IFLE:
|
||||
case IFNULL:
|
||||
case IFNONNULL:
|
||||
popValue();
|
||||
break;
|
||||
case IF_ICMPEQ:
|
||||
case IF_ICMPNE:
|
||||
case IF_ICMPLT:
|
||||
case IF_ICMPGE:
|
||||
case IF_ICMPGT:
|
||||
case IF_ICMPLE:
|
||||
case IF_ACMPEQ:
|
||||
case IF_ACMPNE:
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case JSR:
|
||||
pushValue(OTHER);
|
||||
break;
|
||||
}
|
||||
addBranch(label);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
if (constructor) {
|
||||
popValue();
|
||||
addBranches(dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
if (constructor) {
|
||||
popValue();
|
||||
addBranches(dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type) {
|
||||
super.visitTryCatchBlock(start, end, handler, type);
|
||||
if (constructor && !branches.containsKey(handler)) {
|
||||
List<Object> stackFrame = new ArrayList<Object>();
|
||||
stackFrame.add(OTHER);
|
||||
branches.put(handler, stackFrame);
|
||||
}
|
||||
}
|
||||
|
||||
private void addBranches(final Label dflt, final Label[] labels) {
|
||||
addBranch(dflt);
|
||||
for (int i = 0; i < labels.length; i++) {
|
||||
addBranch(labels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private void addBranch(final Label label) {
|
||||
if (branches.containsKey(label)) {
|
||||
return;
|
||||
}
|
||||
branches.put(label, new ArrayList<Object>(stackFrame));
|
||||
}
|
||||
|
||||
private Object popValue() {
|
||||
return stackFrame.remove(stackFrame.size() - 1);
|
||||
}
|
||||
|
||||
private Object peekValue() {
|
||||
return stackFrame.get(stackFrame.size() - 1);
|
||||
}
|
||||
|
||||
private void pushValue(final Object o) {
|
||||
stackFrame.add(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called at the beginning of the method or after super class class call in
|
||||
* the constructor. <br>
|
||||
* <br>
|
||||
*
|
||||
* <i>Custom code can use or change all the local variables, but should not
|
||||
* change state of the stack.</i>
|
||||
*/
|
||||
protected void onMethodEnter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before explicit exit from the method using either return or throw.
|
||||
* Top element on the stack contains the return value or exception instance.
|
||||
* For example:
|
||||
*
|
||||
* <pre>
|
||||
* public void onMethodExit(int opcode) {
|
||||
* if(opcode==RETURN) {
|
||||
* visitInsn(ACONST_NULL);
|
||||
* } else if(opcode==ARETURN || opcode==ATHROW) {
|
||||
* dup();
|
||||
* } else {
|
||||
* if(opcode==LRETURN || opcode==DRETURN) {
|
||||
* dup2();
|
||||
* } else {
|
||||
* dup();
|
||||
* }
|
||||
* box(Type.getReturnType(this.methodDesc));
|
||||
* }
|
||||
* visitIntInsn(SIPUSH, opcode);
|
||||
* visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
|
||||
* }
|
||||
*
|
||||
* // an actual call back method
|
||||
* public static void onExit(Object param, int opcode) {
|
||||
* ...
|
||||
* </pre>
|
||||
*
|
||||
* <br>
|
||||
* <br>
|
||||
*
|
||||
* <i>Custom code can use or change all the local variables, but should not
|
||||
* change state of the stack.</i>
|
||||
*
|
||||
* @param opcode
|
||||
* one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
|
||||
* or ATHROW
|
||||
*
|
||||
*/
|
||||
protected void onMethodExit(int opcode) {
|
||||
}
|
||||
|
||||
// TODO onException, onMethodCall
|
||||
}
|
||||
@@ -0,0 +1,976 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that keeps track of stack map frame changes between
|
||||
* {@link #visitFrame(int, int, Object[], int, Object[]) visitFrame} calls. This
|
||||
* adapter must be used with the
|
||||
* {@link jdk.internal.org.objectweb.asm.ClassReader#EXPAND_FRAMES} option. Each
|
||||
* visit<i>X</i> instruction delegates to the next visitor in the chain, if any,
|
||||
* and then simulates the effect of this instruction on the stack map frame,
|
||||
* represented by {@link #locals} and {@link #stack}. The next visitor in the
|
||||
* chain can get the state of the stack map frame <i>before</i> each instruction
|
||||
* by reading the value of these fields in its visit<i>X</i> methods (this
|
||||
* requires a reference to the AnalyzerAdapter that is before it in the chain).
|
||||
* If this adapter is used with a class that does not contain stack map table
|
||||
* attributes (i.e., pre Java 6 classes) then this adapter may not be able to
|
||||
* compute the stack map frame for each instruction. In this case no exception
|
||||
* is thrown but the {@link #locals} and {@link #stack} fields will be null for
|
||||
* these instructions.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class AnalyzerAdapter extends MethodVisitor {
|
||||
|
||||
/**
|
||||
* <code>List</code> of the local variable slots for current execution
|
||||
* frame. Primitive types are represented by {@link Opcodes#TOP},
|
||||
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
|
||||
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
|
||||
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
|
||||
* two elements, the second one being TOP). Reference types are represented
|
||||
* by String objects (representing internal names), and uninitialized types
|
||||
* by Label objects (this label designates the NEW instruction that created
|
||||
* this uninitialized value). This field is <tt>null</tt> for unreachable
|
||||
* instructions.
|
||||
*/
|
||||
public List<Object> locals;
|
||||
|
||||
/**
|
||||
* <code>List</code> of the operand stack slots for current execution frame.
|
||||
* Primitive types are represented by {@link Opcodes#TOP},
|
||||
* {@link Opcodes#INTEGER}, {@link Opcodes#FLOAT}, {@link Opcodes#LONG},
|
||||
* {@link Opcodes#DOUBLE},{@link Opcodes#NULL} or
|
||||
* {@link Opcodes#UNINITIALIZED_THIS} (long and double are represented by
|
||||
* two elements, the second one being TOP). Reference types are represented
|
||||
* by String objects (representing internal names), and uninitialized types
|
||||
* by Label objects (this label designates the NEW instruction that created
|
||||
* this uninitialized value). This field is <tt>null</tt> for unreachable
|
||||
* instructions.
|
||||
*/
|
||||
public List<Object> stack;
|
||||
|
||||
/**
|
||||
* The labels that designate the next instruction to be visited. May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
private List<Label> labels;
|
||||
|
||||
/**
|
||||
* Information about uninitialized types in the current execution frame.
|
||||
* This map associates internal names to Label objects. Each label
|
||||
* designates a NEW instruction that created the currently uninitialized
|
||||
* types, and the associated internal name represents the NEW operand, i.e.
|
||||
* the final, initialized type value.
|
||||
*/
|
||||
public Map<Object, Object> uninitializedTypes;
|
||||
|
||||
/**
|
||||
* The maximum stack size of this method.
|
||||
*/
|
||||
private int maxStack;
|
||||
|
||||
/**
|
||||
* The maximum number of local variables of this method.
|
||||
*/
|
||||
private int maxLocals;
|
||||
|
||||
/**
|
||||
* The owner's class name.
|
||||
*/
|
||||
private String owner;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnalyzerAdapter}. <i>Subclasses must not use this
|
||||
* constructor</i>. Instead, they must use the
|
||||
* {@link #AnalyzerAdapter(int, String, int, String, String, MethodVisitor)}
|
||||
* version.
|
||||
*
|
||||
* @param owner
|
||||
* the owner's class name.
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}).
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls. May
|
||||
* be <tt>null</tt>.
|
||||
* @throws IllegalStateException
|
||||
* If a subclass calls this constructor.
|
||||
*/
|
||||
public AnalyzerAdapter(final String owner, final int access,
|
||||
final String name, final String desc, final MethodVisitor mv) {
|
||||
this(Opcodes.ASM5, owner, access, name, desc, mv);
|
||||
if (getClass() != AnalyzerAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnalyzerAdapter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param owner
|
||||
* the owner's class name.
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}).
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls. May
|
||||
* be <tt>null</tt>.
|
||||
*/
|
||||
protected AnalyzerAdapter(final int api, final String owner,
|
||||
final int access, final String name, final String desc,
|
||||
final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
this.owner = owner;
|
||||
locals = new ArrayList<Object>();
|
||||
stack = new ArrayList<Object>();
|
||||
uninitializedTypes = new HashMap<Object, Object>();
|
||||
|
||||
if ((access & Opcodes.ACC_STATIC) == 0) {
|
||||
if ("<init>".equals(name)) {
|
||||
locals.add(Opcodes.UNINITIALIZED_THIS);
|
||||
} else {
|
||||
locals.add(owner);
|
||||
}
|
||||
}
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; ++i) {
|
||||
Type type = types[i];
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
locals.add(Opcodes.INTEGER);
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
locals.add(Opcodes.FLOAT);
|
||||
break;
|
||||
case Type.LONG:
|
||||
locals.add(Opcodes.LONG);
|
||||
locals.add(Opcodes.TOP);
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
locals.add(Opcodes.DOUBLE);
|
||||
locals.add(Opcodes.TOP);
|
||||
break;
|
||||
case Type.ARRAY:
|
||||
locals.add(types[i].getDescriptor());
|
||||
break;
|
||||
// case Type.OBJECT:
|
||||
default:
|
||||
locals.add(types[i].getInternalName());
|
||||
}
|
||||
}
|
||||
maxLocals = locals.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(final int type, final int nLocal,
|
||||
final Object[] local, final int nStack, final Object[] stack) {
|
||||
if (type != Opcodes.F_NEW) { // uncompressed frame
|
||||
throw new IllegalStateException(
|
||||
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
|
||||
}
|
||||
|
||||
if (mv != null) {
|
||||
mv.visitFrame(type, nLocal, local, nStack, stack);
|
||||
}
|
||||
|
||||
if (this.locals != null) {
|
||||
this.locals.clear();
|
||||
this.stack.clear();
|
||||
} else {
|
||||
this.locals = new ArrayList<Object>();
|
||||
this.stack = new ArrayList<Object>();
|
||||
}
|
||||
visitFrameTypes(nLocal, local, this.locals);
|
||||
visitFrameTypes(nStack, stack, this.stack);
|
||||
maxStack = Math.max(maxStack, this.stack.size());
|
||||
}
|
||||
|
||||
private static void visitFrameTypes(final int n, final Object[] types,
|
||||
final List<Object> result) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
Object type = types[i];
|
||||
result.add(type);
|
||||
if (type == Opcodes.LONG || type == Opcodes.DOUBLE) {
|
||||
result.add(Opcodes.TOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
if (mv != null) {
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
execute(opcode, 0, null);
|
||||
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
|
||||
|| opcode == Opcodes.ATHROW) {
|
||||
this.locals = null;
|
||||
this.stack = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
if (mv != null) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
}
|
||||
execute(opcode, operand, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
if (mv != null) {
|
||||
mv.visitVarInsn(opcode, var);
|
||||
}
|
||||
execute(opcode, var, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
if (opcode == Opcodes.NEW) {
|
||||
if (labels == null) {
|
||||
Label l = new Label();
|
||||
labels = new ArrayList<Label>(3);
|
||||
labels.add(l);
|
||||
if (mv != null) {
|
||||
mv.visitLabel(l);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < labels.size(); ++i) {
|
||||
uninitializedTypes.put(labels.get(i), type);
|
||||
}
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
}
|
||||
execute(opcode, 0, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (mv != null) {
|
||||
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
execute(opcode, 0, desc);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc,
|
||||
opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
pop(desc);
|
||||
if (opcode != Opcodes.INVOKESTATIC) {
|
||||
Object t = pop();
|
||||
if (opcode == Opcodes.INVOKESPECIAL && name.charAt(0) == '<') {
|
||||
Object u;
|
||||
if (t == Opcodes.UNINITIALIZED_THIS) {
|
||||
u = this.owner;
|
||||
} else {
|
||||
u = uninitializedTypes.get(t);
|
||||
}
|
||||
for (int i = 0; i < locals.size(); ++i) {
|
||||
if (locals.get(i) == t) {
|
||||
locals.set(i, u);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < stack.size(); ++i) {
|
||||
if (stack.get(i) == t) {
|
||||
stack.set(i, u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pushDesc(desc);
|
||||
labels = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
if (mv != null) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
pop(desc);
|
||||
pushDesc(desc);
|
||||
labels = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
if (mv != null) {
|
||||
mv.visitJumpInsn(opcode, label);
|
||||
}
|
||||
execute(opcode, 0, null);
|
||||
if (opcode == Opcodes.GOTO) {
|
||||
this.locals = null;
|
||||
this.stack = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLabel(final Label label) {
|
||||
if (mv != null) {
|
||||
mv.visitLabel(label);
|
||||
}
|
||||
if (labels == null) {
|
||||
labels = new ArrayList<Label>(3);
|
||||
}
|
||||
labels.add(label);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
if (mv != null) {
|
||||
mv.visitLdcInsn(cst);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
if (cst instanceof Integer) {
|
||||
push(Opcodes.INTEGER);
|
||||
} else if (cst instanceof Long) {
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
} else if (cst instanceof Float) {
|
||||
push(Opcodes.FLOAT);
|
||||
} else if (cst instanceof Double) {
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
} else if (cst instanceof String) {
|
||||
push("java/lang/String");
|
||||
} else if (cst instanceof Type) {
|
||||
int sort = ((Type) cst).getSort();
|
||||
if (sort == Type.OBJECT || sort == Type.ARRAY) {
|
||||
push("java/lang/Class");
|
||||
} else if (sort == Type.METHOD) {
|
||||
push("java/lang/invoke/MethodType");
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
} else if (cst instanceof Handle) {
|
||||
push("java/lang/invoke/MethodHandle");
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
labels = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
if (mv != null) {
|
||||
mv.visitIincInsn(var, increment);
|
||||
}
|
||||
execute(Opcodes.IINC, var, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
if (mv != null) {
|
||||
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
execute(Opcodes.TABLESWITCH, 0, null);
|
||||
this.locals = null;
|
||||
this.stack = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
if (mv != null) {
|
||||
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
execute(Opcodes.LOOKUPSWITCH, 0, null);
|
||||
this.locals = null;
|
||||
this.stack = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
if (mv != null) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
execute(Opcodes.MULTIANEWARRAY, dims, desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
if (mv != null) {
|
||||
this.maxStack = Math.max(this.maxStack, maxStack);
|
||||
this.maxLocals = Math.max(this.maxLocals, maxLocals);
|
||||
mv.visitMaxs(this.maxStack, this.maxLocals);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private Object get(final int local) {
|
||||
maxLocals = Math.max(maxLocals, local + 1);
|
||||
return local < locals.size() ? locals.get(local) : Opcodes.TOP;
|
||||
}
|
||||
|
||||
private void set(final int local, final Object type) {
|
||||
maxLocals = Math.max(maxLocals, local + 1);
|
||||
while (local >= locals.size()) {
|
||||
locals.add(Opcodes.TOP);
|
||||
}
|
||||
locals.set(local, type);
|
||||
}
|
||||
|
||||
private void push(final Object type) {
|
||||
stack.add(type);
|
||||
maxStack = Math.max(maxStack, stack.size());
|
||||
}
|
||||
|
||||
private void pushDesc(final String desc) {
|
||||
int index = desc.charAt(0) == '(' ? desc.indexOf(')') + 1 : 0;
|
||||
switch (desc.charAt(index)) {
|
||||
case 'V':
|
||||
return;
|
||||
case 'Z':
|
||||
case 'C':
|
||||
case 'B':
|
||||
case 'S':
|
||||
case 'I':
|
||||
push(Opcodes.INTEGER);
|
||||
return;
|
||||
case 'F':
|
||||
push(Opcodes.FLOAT);
|
||||
return;
|
||||
case 'J':
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
return;
|
||||
case 'D':
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
return;
|
||||
case '[':
|
||||
if (index == 0) {
|
||||
push(desc);
|
||||
} else {
|
||||
push(desc.substring(index, desc.length()));
|
||||
}
|
||||
break;
|
||||
// case 'L':
|
||||
default:
|
||||
if (index == 0) {
|
||||
push(desc.substring(1, desc.length() - 1));
|
||||
} else {
|
||||
push(desc.substring(index + 1, desc.length() - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object pop() {
|
||||
return stack.remove(stack.size() - 1);
|
||||
}
|
||||
|
||||
private void pop(final int n) {
|
||||
int size = stack.size();
|
||||
int end = size - n;
|
||||
for (int i = size - 1; i >= end; --i) {
|
||||
stack.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
private void pop(final String desc) {
|
||||
char c = desc.charAt(0);
|
||||
if (c == '(') {
|
||||
int n = 0;
|
||||
Type[] types = Type.getArgumentTypes(desc);
|
||||
for (int i = 0; i < types.length; ++i) {
|
||||
n += types[i].getSize();
|
||||
}
|
||||
pop(n);
|
||||
} else if (c == 'J' || c == 'D') {
|
||||
pop(2);
|
||||
} else {
|
||||
pop(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void execute(final int opcode, final int iarg, final String sarg) {
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
}
|
||||
Object t1, t2, t3, t4;
|
||||
switch (opcode) {
|
||||
case Opcodes.NOP:
|
||||
case Opcodes.INEG:
|
||||
case Opcodes.LNEG:
|
||||
case Opcodes.FNEG:
|
||||
case Opcodes.DNEG:
|
||||
case Opcodes.I2B:
|
||||
case Opcodes.I2C:
|
||||
case Opcodes.I2S:
|
||||
case Opcodes.GOTO:
|
||||
case Opcodes.RETURN:
|
||||
break;
|
||||
case Opcodes.ACONST_NULL:
|
||||
push(Opcodes.NULL);
|
||||
break;
|
||||
case Opcodes.ICONST_M1:
|
||||
case Opcodes.ICONST_0:
|
||||
case Opcodes.ICONST_1:
|
||||
case Opcodes.ICONST_2:
|
||||
case Opcodes.ICONST_3:
|
||||
case Opcodes.ICONST_4:
|
||||
case Opcodes.ICONST_5:
|
||||
case Opcodes.BIPUSH:
|
||||
case Opcodes.SIPUSH:
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LCONST_0:
|
||||
case Opcodes.LCONST_1:
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FCONST_0:
|
||||
case Opcodes.FCONST_1:
|
||||
case Opcodes.FCONST_2:
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DCONST_0:
|
||||
case Opcodes.DCONST_1:
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.ALOAD:
|
||||
push(get(iarg));
|
||||
break;
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.DLOAD:
|
||||
push(get(iarg));
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.IALOAD:
|
||||
case Opcodes.BALOAD:
|
||||
case Opcodes.CALOAD:
|
||||
case Opcodes.SALOAD:
|
||||
pop(2);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LALOAD:
|
||||
case Opcodes.D2L:
|
||||
pop(2);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FALOAD:
|
||||
pop(2);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DALOAD:
|
||||
case Opcodes.L2D:
|
||||
pop(2);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.AALOAD:
|
||||
pop(1);
|
||||
t1 = pop();
|
||||
if (t1 instanceof String) {
|
||||
pushDesc(((String) t1).substring(1));
|
||||
} else {
|
||||
push("java/lang/Object");
|
||||
}
|
||||
break;
|
||||
case Opcodes.ISTORE:
|
||||
case Opcodes.FSTORE:
|
||||
case Opcodes.ASTORE:
|
||||
t1 = pop();
|
||||
set(iarg, t1);
|
||||
if (iarg > 0) {
|
||||
t2 = get(iarg - 1);
|
||||
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
|
||||
set(iarg - 1, Opcodes.TOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.LSTORE:
|
||||
case Opcodes.DSTORE:
|
||||
pop(1);
|
||||
t1 = pop();
|
||||
set(iarg, t1);
|
||||
set(iarg + 1, Opcodes.TOP);
|
||||
if (iarg > 0) {
|
||||
t2 = get(iarg - 1);
|
||||
if (t2 == Opcodes.LONG || t2 == Opcodes.DOUBLE) {
|
||||
set(iarg - 1, Opcodes.TOP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Opcodes.IASTORE:
|
||||
case Opcodes.BASTORE:
|
||||
case Opcodes.CASTORE:
|
||||
case Opcodes.SASTORE:
|
||||
case Opcodes.FASTORE:
|
||||
case Opcodes.AASTORE:
|
||||
pop(3);
|
||||
break;
|
||||
case Opcodes.LASTORE:
|
||||
case Opcodes.DASTORE:
|
||||
pop(4);
|
||||
break;
|
||||
case Opcodes.POP:
|
||||
case Opcodes.IFEQ:
|
||||
case Opcodes.IFNE:
|
||||
case Opcodes.IFLT:
|
||||
case Opcodes.IFGE:
|
||||
case Opcodes.IFGT:
|
||||
case Opcodes.IFLE:
|
||||
case Opcodes.IRETURN:
|
||||
case Opcodes.FRETURN:
|
||||
case Opcodes.ARETURN:
|
||||
case Opcodes.TABLESWITCH:
|
||||
case Opcodes.LOOKUPSWITCH:
|
||||
case Opcodes.ATHROW:
|
||||
case Opcodes.MONITORENTER:
|
||||
case Opcodes.MONITOREXIT:
|
||||
case Opcodes.IFNULL:
|
||||
case Opcodes.IFNONNULL:
|
||||
pop(1);
|
||||
break;
|
||||
case Opcodes.POP2:
|
||||
case Opcodes.IF_ICMPEQ:
|
||||
case Opcodes.IF_ICMPNE:
|
||||
case Opcodes.IF_ICMPLT:
|
||||
case Opcodes.IF_ICMPGE:
|
||||
case Opcodes.IF_ICMPGT:
|
||||
case Opcodes.IF_ICMPLE:
|
||||
case Opcodes.IF_ACMPEQ:
|
||||
case Opcodes.IF_ACMPNE:
|
||||
case Opcodes.LRETURN:
|
||||
case Opcodes.DRETURN:
|
||||
pop(2);
|
||||
break;
|
||||
case Opcodes.DUP:
|
||||
t1 = pop();
|
||||
push(t1);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP_X1:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t1);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP_X2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
push(t1);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2_X1:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.DUP2_X2:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
t3 = pop();
|
||||
t4 = pop();
|
||||
push(t2);
|
||||
push(t1);
|
||||
push(t4);
|
||||
push(t3);
|
||||
push(t2);
|
||||
push(t1);
|
||||
break;
|
||||
case Opcodes.SWAP:
|
||||
t1 = pop();
|
||||
t2 = pop();
|
||||
push(t1);
|
||||
push(t2);
|
||||
break;
|
||||
case Opcodes.IADD:
|
||||
case Opcodes.ISUB:
|
||||
case Opcodes.IMUL:
|
||||
case Opcodes.IDIV:
|
||||
case Opcodes.IREM:
|
||||
case Opcodes.IAND:
|
||||
case Opcodes.IOR:
|
||||
case Opcodes.IXOR:
|
||||
case Opcodes.ISHL:
|
||||
case Opcodes.ISHR:
|
||||
case Opcodes.IUSHR:
|
||||
case Opcodes.L2I:
|
||||
case Opcodes.D2I:
|
||||
case Opcodes.FCMPL:
|
||||
case Opcodes.FCMPG:
|
||||
pop(2);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LADD:
|
||||
case Opcodes.LSUB:
|
||||
case Opcodes.LMUL:
|
||||
case Opcodes.LDIV:
|
||||
case Opcodes.LREM:
|
||||
case Opcodes.LAND:
|
||||
case Opcodes.LOR:
|
||||
case Opcodes.LXOR:
|
||||
pop(4);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.FADD:
|
||||
case Opcodes.FSUB:
|
||||
case Opcodes.FMUL:
|
||||
case Opcodes.FDIV:
|
||||
case Opcodes.FREM:
|
||||
case Opcodes.L2F:
|
||||
case Opcodes.D2F:
|
||||
pop(2);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.DADD:
|
||||
case Opcodes.DSUB:
|
||||
case Opcodes.DMUL:
|
||||
case Opcodes.DDIV:
|
||||
case Opcodes.DREM:
|
||||
pop(4);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.LSHL:
|
||||
case Opcodes.LSHR:
|
||||
case Opcodes.LUSHR:
|
||||
pop(3);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.IINC:
|
||||
set(iarg, Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.I2L:
|
||||
case Opcodes.F2L:
|
||||
pop(1);
|
||||
push(Opcodes.LONG);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.I2F:
|
||||
pop(1);
|
||||
push(Opcodes.FLOAT);
|
||||
break;
|
||||
case Opcodes.I2D:
|
||||
case Opcodes.F2D:
|
||||
pop(1);
|
||||
push(Opcodes.DOUBLE);
|
||||
push(Opcodes.TOP);
|
||||
break;
|
||||
case Opcodes.F2I:
|
||||
case Opcodes.ARRAYLENGTH:
|
||||
case Opcodes.INSTANCEOF:
|
||||
pop(1);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.LCMP:
|
||||
case Opcodes.DCMPL:
|
||||
case Opcodes.DCMPG:
|
||||
pop(4);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.JSR:
|
||||
case Opcodes.RET:
|
||||
throw new RuntimeException("JSR/RET are not supported");
|
||||
case Opcodes.GETSTATIC:
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
case Opcodes.PUTSTATIC:
|
||||
pop(sarg);
|
||||
break;
|
||||
case Opcodes.GETFIELD:
|
||||
pop(1);
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
case Opcodes.PUTFIELD:
|
||||
pop(sarg);
|
||||
pop();
|
||||
break;
|
||||
case Opcodes.NEW:
|
||||
push(labels.get(0));
|
||||
break;
|
||||
case Opcodes.NEWARRAY:
|
||||
pop();
|
||||
switch (iarg) {
|
||||
case Opcodes.T_BOOLEAN:
|
||||
pushDesc("[Z");
|
||||
break;
|
||||
case Opcodes.T_CHAR:
|
||||
pushDesc("[C");
|
||||
break;
|
||||
case Opcodes.T_BYTE:
|
||||
pushDesc("[B");
|
||||
break;
|
||||
case Opcodes.T_SHORT:
|
||||
pushDesc("[S");
|
||||
break;
|
||||
case Opcodes.T_INT:
|
||||
pushDesc("[I");
|
||||
break;
|
||||
case Opcodes.T_FLOAT:
|
||||
pushDesc("[F");
|
||||
break;
|
||||
case Opcodes.T_DOUBLE:
|
||||
pushDesc("[D");
|
||||
break;
|
||||
// case Opcodes.T_LONG:
|
||||
default:
|
||||
pushDesc("[J");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Opcodes.ANEWARRAY:
|
||||
pop();
|
||||
pushDesc("[" + Type.getObjectType(sarg));
|
||||
break;
|
||||
case Opcodes.CHECKCAST:
|
||||
pop();
|
||||
pushDesc(Type.getObjectType(sarg).getDescriptor());
|
||||
break;
|
||||
// case Opcodes.MULTIANEWARRAY:
|
||||
default:
|
||||
pop(iarg);
|
||||
pushDesc(sarg);
|
||||
break;
|
||||
}
|
||||
labels = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that can be used to approximate method size.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
|
||||
|
||||
private int minSize;
|
||||
|
||||
private int maxSize;
|
||||
|
||||
public CodeSizeEvaluator(final MethodVisitor mv) {
|
||||
this(Opcodes.ASM5, mv);
|
||||
}
|
||||
|
||||
protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
}
|
||||
|
||||
public int getMinSize() {
|
||||
return this.minSize;
|
||||
}
|
||||
|
||||
public int getMaxSize() {
|
||||
return this.maxSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInsn(final int opcode) {
|
||||
minSize += 1;
|
||||
maxSize += 1;
|
||||
if (mv != null) {
|
||||
mv.visitInsn(opcode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntInsn(final int opcode, final int operand) {
|
||||
if (opcode == SIPUSH) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 2;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitIntInsn(opcode, operand);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
if (var < 4 && opcode != RET) {
|
||||
minSize += 1;
|
||||
maxSize += 1;
|
||||
} else if (var >= 256) {
|
||||
minSize += 4;
|
||||
maxSize += 4;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 2;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitVarInsn(opcode, var);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(final int opcode, final String type) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
if (mv != null) {
|
||||
mv.visitTypeInsn(opcode, type);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
if (mv != null) {
|
||||
mv.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc,
|
||||
opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (opcode == INVOKEINTERFACE) {
|
||||
minSize += 5;
|
||||
maxSize += 5;
|
||||
} else {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
minSize += 5;
|
||||
maxSize += 5;
|
||||
if (mv != null) {
|
||||
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label label) {
|
||||
minSize += 3;
|
||||
if (opcode == GOTO || opcode == JSR) {
|
||||
maxSize += 5;
|
||||
} else {
|
||||
maxSize += 8;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitJumpInsn(opcode, label);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(final Object cst) {
|
||||
if (cst instanceof Long || cst instanceof Double) {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
} else {
|
||||
minSize += 2;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitLdcInsn(cst);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
if (var > 255 || increment > 127 || increment < -128) {
|
||||
minSize += 6;
|
||||
maxSize += 6;
|
||||
} else {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitIincInsn(var, increment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableSwitchInsn(final int min, final int max,
|
||||
final Label dflt, final Label... labels) {
|
||||
minSize += 13 + labels.length * 4;
|
||||
maxSize += 16 + labels.length * 4;
|
||||
if (mv != null) {
|
||||
mv.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
|
||||
final Label[] labels) {
|
||||
minSize += 9 + keys.length * 8;
|
||||
maxSize += 12 + keys.length * 8;
|
||||
if (mv != null) {
|
||||
mv.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(final String desc, final int dims) {
|
||||
minSize += 4;
|
||||
maxSize += 4;
|
||||
if (mv != null) {
|
||||
mv.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,781 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.tree.AbstractInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.InsnList;
|
||||
import jdk.internal.org.objectweb.asm.tree.InsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.JumpInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.LabelNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.LocalVariableNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.LookupSwitchInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.TableSwitchInsnNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
|
||||
/**
|
||||
* A {@link jdk.internal.org.objectweb.asm.MethodVisitor} that removes JSR instructions and
|
||||
* inlines the referenced subroutines.
|
||||
*
|
||||
* <b>Explanation of how it works</b> TODO
|
||||
*
|
||||
* @author Niko Matsakis
|
||||
*/
|
||||
public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
|
||||
private static final boolean LOGGING = false;
|
||||
|
||||
/**
|
||||
* For each label that is jumped to by a JSR, we create a BitSet instance.
|
||||
*/
|
||||
private final Map<LabelNode, BitSet> subroutineHeads = new HashMap<LabelNode, BitSet>();
|
||||
|
||||
/**
|
||||
* This subroutine instance denotes the line of execution that is not
|
||||
* contained within any subroutine; i.e., the "subroutine" that is executing
|
||||
* when a method first begins.
|
||||
*/
|
||||
private final BitSet mainSubroutine = new BitSet();
|
||||
|
||||
/**
|
||||
* This BitSet contains the index of every instruction that belongs to more
|
||||
* than one subroutine. This should not happen often.
|
||||
*/
|
||||
final BitSet dualCitizens = new BitSet();
|
||||
|
||||
/**
|
||||
* Creates a new JSRInliner. <i>Subclasses must not use this
|
||||
* constructor</i>. Instead, they must use the
|
||||
* {@link #JSRInlinerAdapter(int, MethodVisitor, int, String, String, String, String[])}
|
||||
* version.
|
||||
*
|
||||
* @param mv
|
||||
* the <code>MethodVisitor</code> to send the resulting inlined
|
||||
* method code to (use <code>null</code> for none).
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}). This
|
||||
* parameter also indicates if the method is synthetic and/or
|
||||
* deprecated.
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type}).
|
||||
* @param signature
|
||||
* the method's signature. May be <tt>null</tt>.
|
||||
* @param exceptions
|
||||
* the internal names of the method's exception classes (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
* @throws IllegalStateException
|
||||
* If a subclass calls this constructor.
|
||||
*/
|
||||
public JSRInlinerAdapter(final MethodVisitor mv, final int access,
|
||||
final String name, final String desc, final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions);
|
||||
if (getClass() != JSRInlinerAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new JSRInliner.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param mv
|
||||
* the <code>MethodVisitor</code> to send the resulting inlined
|
||||
* method code to (use <code>null</code> for none).
|
||||
* @param access
|
||||
* the method's access flags (see {@link Opcodes}). This
|
||||
* parameter also indicates if the method is synthetic and/or
|
||||
* deprecated.
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type}).
|
||||
* @param signature
|
||||
* the method's signature. May be <tt>null</tt>.
|
||||
* @param exceptions
|
||||
* the internal names of the method's exception classes (see
|
||||
* {@link Type#getInternalName() getInternalName}). May be
|
||||
* <tt>null</tt>.
|
||||
*/
|
||||
protected JSRInlinerAdapter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc,
|
||||
final String signature, final String[] exceptions) {
|
||||
super(api, access, name, desc, signature, exceptions);
|
||||
this.mv = mv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects a JSR instruction and sets a flag to indicate we will need to do
|
||||
* inlining.
|
||||
*/
|
||||
@Override
|
||||
public void visitJumpInsn(final int opcode, final Label lbl) {
|
||||
super.visitJumpInsn(opcode, lbl);
|
||||
LabelNode ln = ((JumpInsnNode) instructions.getLast()).label;
|
||||
if (opcode == JSR && !subroutineHeads.containsKey(ln)) {
|
||||
subroutineHeads.put(ln, new BitSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If any JSRs were seen, triggers the inlining process. Otherwise, forwards
|
||||
* the byte codes untouched.
|
||||
*/
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (!subroutineHeads.isEmpty()) {
|
||||
markSubroutines();
|
||||
if (LOGGING) {
|
||||
log(mainSubroutine.toString());
|
||||
Iterator<BitSet> it = subroutineHeads.values().iterator();
|
||||
while (it.hasNext()) {
|
||||
BitSet sub = it.next();
|
||||
log(sub.toString());
|
||||
}
|
||||
}
|
||||
emitCode();
|
||||
}
|
||||
|
||||
// Forward the translate opcodes on if appropriate:
|
||||
if (mv != null) {
|
||||
accept(mv);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Walks the method and determines which internal subroutine(s), if any,
|
||||
* each instruction is a method of.
|
||||
*/
|
||||
private void markSubroutines() {
|
||||
BitSet anyvisited = new BitSet();
|
||||
|
||||
// First walk the main subroutine and find all those instructions which
|
||||
// can be reached without invoking any JSR at all
|
||||
markSubroutineWalk(mainSubroutine, 0, anyvisited);
|
||||
|
||||
// Go through the head of each subroutine and find any nodes reachable
|
||||
// to that subroutine without following any JSR links.
|
||||
for (Iterator<Map.Entry<LabelNode, BitSet>> it = subroutineHeads
|
||||
.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry<LabelNode, BitSet> entry = it.next();
|
||||
LabelNode lab = entry.getKey();
|
||||
BitSet sub = entry.getValue();
|
||||
int index = instructions.indexOf(lab);
|
||||
markSubroutineWalk(sub, index, anyvisited);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a depth first search walking the normal byte code path starting
|
||||
* at <code>index</code>, and adding each instruction encountered into the
|
||||
* subroutine <code>sub</code>. After this walk is complete, iterates over
|
||||
* the exception handlers to ensure that we also include those byte codes
|
||||
* which are reachable through an exception that may be thrown during the
|
||||
* execution of the subroutine. Invoked from <code>markSubroutines()</code>.
|
||||
*
|
||||
* @param sub
|
||||
* the subroutine whose instructions must be computed.
|
||||
* @param index
|
||||
* an instruction of this subroutine.
|
||||
* @param anyvisited
|
||||
* indexes of the already visited instructions, i.e. marked as
|
||||
* part of this subroutine or any previously computed subroutine.
|
||||
*/
|
||||
private void markSubroutineWalk(final BitSet sub, final int index,
|
||||
final BitSet anyvisited) {
|
||||
if (LOGGING) {
|
||||
log("markSubroutineWalk: sub=" + sub + " index=" + index);
|
||||
}
|
||||
|
||||
// First find those instructions reachable via normal execution
|
||||
markSubroutineWalkDFS(sub, index, anyvisited);
|
||||
|
||||
// Now, make sure we also include any applicable exception handlers
|
||||
boolean loop = true;
|
||||
while (loop) {
|
||||
loop = false;
|
||||
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
|
||||
.hasNext();) {
|
||||
TryCatchBlockNode trycatch = it.next();
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("Scanning try/catch " + trycatch);
|
||||
}
|
||||
|
||||
// If the handler has already been processed, skip it.
|
||||
int handlerindex = instructions.indexOf(trycatch.handler);
|
||||
if (sub.get(handlerindex)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int startindex = instructions.indexOf(trycatch.start);
|
||||
int endindex = instructions.indexOf(trycatch.end);
|
||||
int nextbit = sub.nextSetBit(startindex);
|
||||
if (nextbit != -1 && nextbit < endindex) {
|
||||
if (LOGGING) {
|
||||
log("Adding exception handler: " + startindex + '-'
|
||||
+ endindex + " due to " + nextbit + " handler "
|
||||
+ handlerindex);
|
||||
}
|
||||
markSubroutineWalkDFS(sub, handlerindex, anyvisited);
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a simple DFS of the instructions, assigning each to the
|
||||
* subroutine <code>sub</code>. Starts from <code>index</code>. Invoked only
|
||||
* by <code>markSubroutineWalk()</code>.
|
||||
*
|
||||
* @param sub
|
||||
* the subroutine whose instructions must be computed.
|
||||
* @param index
|
||||
* an instruction of this subroutine.
|
||||
* @param anyvisited
|
||||
* indexes of the already visited instructions, i.e. marked as
|
||||
* part of this subroutine or any previously computed subroutine.
|
||||
*/
|
||||
private void markSubroutineWalkDFS(final BitSet sub, int index,
|
||||
final BitSet anyvisited) {
|
||||
while (true) {
|
||||
AbstractInsnNode node = instructions.get(index);
|
||||
|
||||
// don't visit a node twice
|
||||
if (sub.get(index)) {
|
||||
return;
|
||||
}
|
||||
sub.set(index);
|
||||
|
||||
// check for those nodes already visited by another subroutine
|
||||
if (anyvisited.get(index)) {
|
||||
dualCitizens.set(index);
|
||||
if (LOGGING) {
|
||||
log("Instruction #" + index + " is dual citizen.");
|
||||
}
|
||||
}
|
||||
anyvisited.set(index);
|
||||
|
||||
if (node.getType() == AbstractInsnNode.JUMP_INSN
|
||||
&& node.getOpcode() != JSR) {
|
||||
// we do not follow recursively called subroutines here; but any
|
||||
// other sort of branch we do follow
|
||||
JumpInsnNode jnode = (JumpInsnNode) node;
|
||||
int destidx = instructions.indexOf(jnode.label);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
if (node.getType() == AbstractInsnNode.TABLESWITCH_INSN) {
|
||||
TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
|
||||
int destidx = instructions.indexOf(tsnode.dflt);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = tsnode.labels.get(i);
|
||||
destidx = instructions.indexOf(l);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
}
|
||||
if (node.getType() == AbstractInsnNode.LOOKUPSWITCH_INSN) {
|
||||
LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
|
||||
int destidx = instructions.indexOf(lsnode.dflt);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
|
||||
LabelNode l = lsnode.labels.get(i);
|
||||
destidx = instructions.indexOf(l);
|
||||
markSubroutineWalkDFS(sub, destidx, anyvisited);
|
||||
}
|
||||
}
|
||||
|
||||
// check to see if this opcode falls through to the next instruction
|
||||
// or not; if not, return.
|
||||
switch (instructions.get(index).getOpcode()) {
|
||||
case GOTO:
|
||||
case RET:
|
||||
case TABLESWITCH:
|
||||
case LOOKUPSWITCH:
|
||||
case IRETURN:
|
||||
case LRETURN:
|
||||
case FRETURN:
|
||||
case DRETURN:
|
||||
case ARETURN:
|
||||
case RETURN:
|
||||
case ATHROW:
|
||||
/*
|
||||
* note: this either returns from this subroutine, or a parent
|
||||
* subroutine which invoked it
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
// Use tail recursion here in the form of an outer while loop to
|
||||
// avoid our stack growing needlessly:
|
||||
index++;
|
||||
|
||||
// We implicitly assumed above that execution can always fall
|
||||
// through to the next instruction after a JSR. But a subroutine may
|
||||
// never return, in which case the code after the JSR is unreachable
|
||||
// and can be anything. In particular, it can seem to fall off the
|
||||
// end of the method, so we must handle this case here (we could
|
||||
// instead detect whether execution can return or not from a JSR,
|
||||
// but this is more complicated).
|
||||
if (index >= instructions.size()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the new instructions, inlining each instantiation of each
|
||||
* subroutine until the code is fully elaborated.
|
||||
*/
|
||||
private void emitCode() {
|
||||
LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
|
||||
// Create an instantiation of the "root" subroutine, which is just the
|
||||
// main routine
|
||||
worklist.add(new Instantiation(null, mainSubroutine));
|
||||
|
||||
// Emit instantiations of each subroutine we encounter, including the
|
||||
// main subroutine
|
||||
InsnList newInstructions = new InsnList();
|
||||
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
|
||||
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
|
||||
while (!worklist.isEmpty()) {
|
||||
Instantiation inst = worklist.removeFirst();
|
||||
emitSubroutine(inst, worklist, newInstructions, newTryCatchBlocks,
|
||||
newLocalVariables);
|
||||
}
|
||||
instructions = newInstructions;
|
||||
tryCatchBlocks = newTryCatchBlocks;
|
||||
localVariables = newLocalVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits one instantiation of one subroutine, specified by
|
||||
* <code>instant</code>. May add new instantiations that are invoked by this
|
||||
* one to the <code>worklist</code> parameter, and new try/catch blocks to
|
||||
* <code>newTryCatchBlocks</code>.
|
||||
*
|
||||
* @param instant
|
||||
* the instantiation that must be performed.
|
||||
* @param worklist
|
||||
* list of the instantiations that remain to be done.
|
||||
* @param newInstructions
|
||||
* the instruction list to which the instantiated code must be
|
||||
* appended.
|
||||
* @param newTryCatchBlocks
|
||||
* the exception handler list to which the instantiated handlers
|
||||
* must be appended.
|
||||
*/
|
||||
private void emitSubroutine(final Instantiation instant,
|
||||
final List<Instantiation> worklist, final InsnList newInstructions,
|
||||
final List<TryCatchBlockNode> newTryCatchBlocks,
|
||||
final List<LocalVariableNode> newLocalVariables) {
|
||||
LabelNode duplbl = null;
|
||||
|
||||
if (LOGGING) {
|
||||
log("--------------------------------------------------------");
|
||||
log("Emitting instantiation of subroutine " + instant.subroutine);
|
||||
}
|
||||
|
||||
// Emit the relevant instructions for this instantiation, translating
|
||||
// labels and jump targets as we go:
|
||||
for (int i = 0, c = instructions.size(); i < c; i++) {
|
||||
AbstractInsnNode insn = instructions.get(i);
|
||||
Instantiation owner = instant.findOwner(i);
|
||||
|
||||
// Always remap labels:
|
||||
if (insn.getType() == AbstractInsnNode.LABEL) {
|
||||
// Translate labels into their renamed equivalents.
|
||||
// Avoid adding the same label more than once. Note
|
||||
// that because we own this instruction the gotoTable
|
||||
// and the rangeTable will always agree.
|
||||
LabelNode ilbl = (LabelNode) insn;
|
||||
LabelNode remap = instant.rangeLabel(ilbl);
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("Translating lbl #" + i + ':' + ilbl + " to " + remap);
|
||||
}
|
||||
if (remap != duplbl) {
|
||||
newInstructions.add(remap);
|
||||
duplbl = remap;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// We don't want to emit instructions that were already
|
||||
// emitted by a subroutine higher on the stack. Note that
|
||||
// it is still possible for a given instruction to be
|
||||
// emitted twice because it may belong to two subroutines
|
||||
// that do not invoke each other.
|
||||
if (owner != instant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (LOGGING) {
|
||||
log("Emitting inst #" + i);
|
||||
}
|
||||
|
||||
if (insn.getOpcode() == RET) {
|
||||
// Translate RET instruction(s) to a jump to the return label
|
||||
// for the appropriate instantiation. The problem is that the
|
||||
// subroutine may "fall through" to the ret of a parent
|
||||
// subroutine; therefore, to find the appropriate ret label we
|
||||
// find the lowest subroutine on the stack that claims to own
|
||||
// this instruction. See the class javadoc comment for an
|
||||
// explanation on why this technique is safe (note: it is only
|
||||
// safe if the input is verifiable).
|
||||
LabelNode retlabel = null;
|
||||
for (Instantiation p = instant; p != null; p = p.previous) {
|
||||
if (p.subroutine.get(i)) {
|
||||
retlabel = p.returnLabel;
|
||||
}
|
||||
}
|
||||
if (retlabel == null) {
|
||||
// This is only possible if the mainSubroutine owns a RET
|
||||
// instruction, which should never happen for verifiable
|
||||
// code.
|
||||
throw new RuntimeException("Instruction #" + i
|
||||
+ " is a RET not owned by any subroutine");
|
||||
}
|
||||
newInstructions.add(new JumpInsnNode(GOTO, retlabel));
|
||||
} else if (insn.getOpcode() == JSR) {
|
||||
LabelNode lbl = ((JumpInsnNode) insn).label;
|
||||
BitSet sub = subroutineHeads.get(lbl);
|
||||
Instantiation newinst = new Instantiation(instant, sub);
|
||||
LabelNode startlbl = newinst.gotoLabel(lbl);
|
||||
|
||||
if (LOGGING) {
|
||||
log(" Creating instantiation of subr " + sub);
|
||||
}
|
||||
|
||||
// Rather than JSRing, we will jump to the inline version and
|
||||
// push NULL for what was once the return value. This hack
|
||||
// allows us to avoid doing any sort of data flow analysis to
|
||||
// figure out which instructions manipulate the old return value
|
||||
// pointer which is now known to be unneeded.
|
||||
newInstructions.add(new InsnNode(ACONST_NULL));
|
||||
newInstructions.add(new JumpInsnNode(GOTO, startlbl));
|
||||
newInstructions.add(newinst.returnLabel);
|
||||
|
||||
// Insert this new instantiation into the queue to be emitted
|
||||
// later.
|
||||
worklist.add(newinst);
|
||||
} else {
|
||||
newInstructions.add(insn.clone(instant));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit try/catch blocks that are relevant to this method.
|
||||
for (Iterator<TryCatchBlockNode> it = tryCatchBlocks.iterator(); it
|
||||
.hasNext();) {
|
||||
TryCatchBlockNode trycatch = it.next();
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log("try catch block original labels=" + trycatch.start + '-'
|
||||
+ trycatch.end + "->" + trycatch.handler);
|
||||
}
|
||||
|
||||
final LabelNode start = instant.rangeLabel(trycatch.start);
|
||||
final LabelNode end = instant.rangeLabel(trycatch.end);
|
||||
|
||||
// Ignore empty try/catch regions
|
||||
if (start == end) {
|
||||
if (LOGGING) {
|
||||
log(" try catch block empty in this subroutine");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final LabelNode handler = instant.gotoLabel(trycatch.handler);
|
||||
|
||||
if (LOGGING) {
|
||||
// TODO use of default toString().
|
||||
log(" try catch block new labels=" + start + '-' + end + "->"
|
||||
+ handler);
|
||||
}
|
||||
|
||||
if (start == null || end == null || handler == null) {
|
||||
throw new RuntimeException("Internal error!");
|
||||
}
|
||||
|
||||
newTryCatchBlocks.add(new TryCatchBlockNode(start, end, handler,
|
||||
trycatch.type));
|
||||
}
|
||||
|
||||
for (Iterator<LocalVariableNode> it = localVariables.iterator(); it
|
||||
.hasNext();) {
|
||||
LocalVariableNode lvnode = it.next();
|
||||
if (LOGGING) {
|
||||
log("local var " + lvnode.name);
|
||||
}
|
||||
final LabelNode start = instant.rangeLabel(lvnode.start);
|
||||
final LabelNode end = instant.rangeLabel(lvnode.end);
|
||||
if (start == end) {
|
||||
if (LOGGING) {
|
||||
log(" local variable empty in this sub");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
newLocalVariables.add(new LocalVariableNode(lvnode.name,
|
||||
lvnode.desc, lvnode.signature, start, end, lvnode.index));
|
||||
}
|
||||
}
|
||||
|
||||
private static void log(final String str) {
|
||||
System.err.println(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* A class that represents an instantiation of a subroutine. Each
|
||||
* instantiation has an associate "stack" --- which is a listing of those
|
||||
* instantiations that were active when this particular instance of this
|
||||
* subroutine was invoked. Each instantiation also has a map from the
|
||||
* original labels of the program to the labels appropriate for this
|
||||
* instantiation, and finally a label to return to.
|
||||
*/
|
||||
private class Instantiation extends AbstractMap<LabelNode, LabelNode> {
|
||||
|
||||
/**
|
||||
* Previous instantiations; the stack must be statically predictable to
|
||||
* be inlinable.
|
||||
*/
|
||||
final Instantiation previous;
|
||||
|
||||
/**
|
||||
* The subroutine this is an instantiation of.
|
||||
*/
|
||||
public final BitSet subroutine;
|
||||
|
||||
/**
|
||||
* This table maps Labels from the original source to Labels pointing at
|
||||
* code specific to this instantiation, for use in remapping try/catch
|
||||
* blocks,as well as gotos.
|
||||
*
|
||||
* Note that in the presence of dual citizens instructions, that is,
|
||||
* instructions which belong to more than one subroutine due to the
|
||||
* merging of control flow without a RET instruction, we will map the
|
||||
* target label of a GOTO to the label used by the instantiation lowest
|
||||
* on the stack. This avoids code duplication during inlining in most
|
||||
* cases.
|
||||
*
|
||||
* @see #findOwner(int)
|
||||
*/
|
||||
public final Map<LabelNode, LabelNode> rangeTable = new HashMap<LabelNode, LabelNode>();
|
||||
|
||||
/**
|
||||
* All returns for this instantiation will be mapped to this label
|
||||
*/
|
||||
public final LabelNode returnLabel;
|
||||
|
||||
Instantiation(final Instantiation prev, final BitSet sub) {
|
||||
previous = prev;
|
||||
subroutine = sub;
|
||||
for (Instantiation p = prev; p != null; p = p.previous) {
|
||||
if (p.subroutine == sub) {
|
||||
throw new RuntimeException("Recursive invocation of " + sub);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the label to return to when this subroutine terminates
|
||||
// via RET: note that the main subroutine never terminates via RET.
|
||||
if (prev != null) {
|
||||
returnLabel = new LabelNode();
|
||||
} else {
|
||||
returnLabel = null;
|
||||
}
|
||||
|
||||
// Each instantiation will remap the labels from the code above to
|
||||
// refer to its particular copy of its own instructions. Note that
|
||||
// we collapse labels which point at the same instruction into one:
|
||||
// this is fairly common as we are often ignoring large chunks of
|
||||
// instructions, so what were previously distinct labels become
|
||||
// duplicates.
|
||||
LabelNode duplbl = null;
|
||||
for (int i = 0, c = instructions.size(); i < c; i++) {
|
||||
AbstractInsnNode insn = instructions.get(i);
|
||||
|
||||
if (insn.getType() == AbstractInsnNode.LABEL) {
|
||||
LabelNode ilbl = (LabelNode) insn;
|
||||
|
||||
if (duplbl == null) {
|
||||
// if we already have a label pointing at this spot,
|
||||
// don't recreate it.
|
||||
duplbl = new LabelNode();
|
||||
}
|
||||
|
||||
// Add an entry in the rangeTable for every label
|
||||
// in the original code which points at the next
|
||||
// instruction of our own to be emitted.
|
||||
rangeTable.put(ilbl, duplbl);
|
||||
} else if (findOwner(i) == this) {
|
||||
// We will emit this instruction, so clear the 'duplbl' flag
|
||||
// since the next Label will refer to a distinct
|
||||
// instruction.
|
||||
duplbl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "owner" of a particular instruction relative to this
|
||||
* instantiation: the owner referes to the Instantiation which will emit
|
||||
* the version of this instruction that we will execute.
|
||||
*
|
||||
* Typically, the return value is either <code>this</code> or
|
||||
* <code>null</code>. <code>this</code> indicates that this
|
||||
* instantiation will generate the version of this instruction that we
|
||||
* will execute, and <code>null</code> indicates that this instantiation
|
||||
* never executes the given instruction.
|
||||
*
|
||||
* Sometimes, however, an instruction can belong to multiple
|
||||
* subroutines; this is called a "dual citizen" instruction (though it
|
||||
* may belong to more than 2 subroutines), and occurs when multiple
|
||||
* subroutines branch to common points of control. In this case, the
|
||||
* owner is the subroutine that appears lowest on the stack, and which
|
||||
* also owns the instruction in question.
|
||||
*
|
||||
* @param i
|
||||
* the index of the instruction in the original code
|
||||
* @return the "owner" of a particular instruction relative to this
|
||||
* instantiation.
|
||||
*/
|
||||
public Instantiation findOwner(final int i) {
|
||||
if (!subroutine.get(i)) {
|
||||
return null;
|
||||
}
|
||||
if (!dualCitizens.get(i)) {
|
||||
return this;
|
||||
}
|
||||
Instantiation own = this;
|
||||
for (Instantiation p = previous; p != null; p = p.previous) {
|
||||
if (p.subroutine.get(i)) {
|
||||
own = p;
|
||||
}
|
||||
}
|
||||
return own;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the label <code>l</code> in the <code>gotoTable</code>, thus
|
||||
* translating it from a Label in the original code, to a Label in the
|
||||
* inlined code that is appropriate for use by an instruction that
|
||||
* branched to the original label.
|
||||
*
|
||||
* @param l
|
||||
* The label we will be translating
|
||||
* @return a label for use by a branch instruction in the inlined code
|
||||
* @see #rangeLabel
|
||||
*/
|
||||
public LabelNode gotoLabel(final LabelNode l) {
|
||||
// owner should never be null, because owner is only null
|
||||
// if an instruction cannot be reached from this subroutine
|
||||
Instantiation owner = findOwner(instructions.indexOf(l));
|
||||
return owner.rangeTable.get(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the label <code>l</code> in the <code>rangeTable</code>,
|
||||
* thus translating it from a Label in the original code, to a Label in
|
||||
* the inlined code that is appropriate for use by an try/catch or
|
||||
* variable use annotation.
|
||||
*
|
||||
* @param l
|
||||
* The label we will be translating
|
||||
* @return a label for use by a try/catch or variable annotation in the
|
||||
* original code
|
||||
* @see #rangeTable
|
||||
*/
|
||||
public LabelNode rangeLabel(final LabelNode l) {
|
||||
return rangeTable.get(l);
|
||||
}
|
||||
|
||||
// AbstractMap implementation
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<LabelNode, LabelNode>> entrySet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LabelNode get(final Object o) {
|
||||
return gotoLabel((LabelNode) o);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that renumbers local variables in their order of
|
||||
* appearance. This adapter allows one to easily add new local variables to a
|
||||
* method. It may be used by inheriting from this class, but the preferred way
|
||||
* of using it is via delegation: the next visitor in the chain can indeed add
|
||||
* new locals when needed by calling {@link #newLocal} on this adapter (this
|
||||
* requires a reference back to this {@link LocalVariablesSorter}).
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Eugene Kuleshov
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class LocalVariablesSorter extends MethodVisitor {
|
||||
|
||||
private static final Type OBJECT_TYPE = Type
|
||||
.getObjectType("java/lang/Object");
|
||||
|
||||
/**
|
||||
* Mapping from old to new local variable indexes. A local variable at index
|
||||
* i of size 1 is remapped to 'mapping[2*i]', while a local variable at
|
||||
* index i of size 2 is remapped to 'mapping[2*i+1]'.
|
||||
*/
|
||||
private int[] mapping = new int[40];
|
||||
|
||||
/**
|
||||
* Array used to store stack map local variable types after remapping.
|
||||
*/
|
||||
private Object[] newLocals = new Object[20];
|
||||
|
||||
/**
|
||||
* Index of the first local variable, after formal parameters.
|
||||
*/
|
||||
protected final int firstLocal;
|
||||
|
||||
/**
|
||||
* Index of the next local variable to be created by {@link #newLocal}.
|
||||
*/
|
||||
protected int nextLocal;
|
||||
|
||||
/**
|
||||
* Indicates if at least one local variable has moved due to remapping.
|
||||
*/
|
||||
private boolean changed;
|
||||
|
||||
/**
|
||||
* Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
|
||||
*
|
||||
* @param access
|
||||
* access flags of the adapted method.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
* @throws IllegalStateException
|
||||
* If a subclass calls this constructor.
|
||||
*/
|
||||
public LocalVariablesSorter(final int access, final String desc,
|
||||
final MethodVisitor mv) {
|
||||
this(Opcodes.ASM5, access, desc, mv);
|
||||
if (getClass() != LocalVariablesSorter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link LocalVariablesSorter}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param access
|
||||
* access flags of the adapted method.
|
||||
* @param desc
|
||||
* the method's descriptor (see {@link Type Type}).
|
||||
* @param mv
|
||||
* the method visitor to which this adapter delegates calls.
|
||||
*/
|
||||
protected LocalVariablesSorter(final int api, final int access,
|
||||
final String desc, final MethodVisitor mv) {
|
||||
super(api, mv);
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
nextLocal += args[i].getSize();
|
||||
}
|
||||
firstLocal = nextLocal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
Type type;
|
||||
switch (opcode) {
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.LSTORE:
|
||||
type = Type.LONG_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.DLOAD:
|
||||
case Opcodes.DSTORE:
|
||||
type = Type.DOUBLE_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.FLOAD:
|
||||
case Opcodes.FSTORE:
|
||||
type = Type.FLOAT_TYPE;
|
||||
break;
|
||||
|
||||
case Opcodes.ILOAD:
|
||||
case Opcodes.ISTORE:
|
||||
type = Type.INT_TYPE;
|
||||
break;
|
||||
|
||||
default:
|
||||
// case Opcodes.ALOAD:
|
||||
// case Opcodes.ASTORE:
|
||||
// case RET:
|
||||
type = OBJECT_TYPE;
|
||||
break;
|
||||
}
|
||||
mv.visitVarInsn(opcode, remap(var, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
mv.visitMaxs(maxStack, nextLocal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(final String name, final String desc,
|
||||
final String signature, final Label start, final Label end,
|
||||
final int index) {
|
||||
int newIndex = remap(index, Type.getType(desc));
|
||||
mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||
String desc, boolean visible) {
|
||||
Type t = Type.getType(desc);
|
||||
int[] newIndex = new int[index.length];
|
||||
for (int i = 0; i < newIndex.length; ++i) {
|
||||
newIndex[i] = remap(index[i], t);
|
||||
}
|
||||
return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
|
||||
newIndex, desc, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(final int type, final int nLocal,
|
||||
final Object[] local, final int nStack, final Object[] stack) {
|
||||
if (type != Opcodes.F_NEW) { // uncompressed frame
|
||||
throw new IllegalStateException(
|
||||
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
|
||||
}
|
||||
|
||||
if (!changed) { // optimization for the case where mapping = identity
|
||||
mv.visitFrame(type, nLocal, local, nStack, stack);
|
||||
return;
|
||||
}
|
||||
|
||||
// creates a copy of newLocals
|
||||
Object[] oldLocals = new Object[newLocals.length];
|
||||
System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
|
||||
|
||||
updateNewLocals(newLocals);
|
||||
|
||||
// copies types from 'local' to 'newLocals'
|
||||
// 'newLocals' already contains the variables added with 'newLocal'
|
||||
|
||||
int index = 0; // old local variable index
|
||||
int number = 0; // old local variable number
|
||||
for (; number < nLocal; ++number) {
|
||||
Object t = local[number];
|
||||
int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
|
||||
if (t != Opcodes.TOP) {
|
||||
Type typ = OBJECT_TYPE;
|
||||
if (t == Opcodes.INTEGER) {
|
||||
typ = Type.INT_TYPE;
|
||||
} else if (t == Opcodes.FLOAT) {
|
||||
typ = Type.FLOAT_TYPE;
|
||||
} else if (t == Opcodes.LONG) {
|
||||
typ = Type.LONG_TYPE;
|
||||
} else if (t == Opcodes.DOUBLE) {
|
||||
typ = Type.DOUBLE_TYPE;
|
||||
} else if (t instanceof String) {
|
||||
typ = Type.getObjectType((String) t);
|
||||
}
|
||||
setFrameLocal(remap(index, typ), t);
|
||||
}
|
||||
index += size;
|
||||
}
|
||||
|
||||
// removes TOP after long and double types as well as trailing TOPs
|
||||
|
||||
index = 0;
|
||||
number = 0;
|
||||
for (int i = 0; index < newLocals.length; ++i) {
|
||||
Object t = newLocals[index++];
|
||||
if (t != null && t != Opcodes.TOP) {
|
||||
newLocals[i] = t;
|
||||
number = i + 1;
|
||||
if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
|
||||
index += 1;
|
||||
}
|
||||
} else {
|
||||
newLocals[i] = Opcodes.TOP;
|
||||
}
|
||||
}
|
||||
|
||||
// visits remapped frame
|
||||
mv.visitFrame(type, number, newLocals, nStack, stack);
|
||||
|
||||
// restores original value of 'newLocals'
|
||||
newLocals = oldLocals;
|
||||
}
|
||||
|
||||
// -------------
|
||||
|
||||
/**
|
||||
* Creates a new local variable of the given type.
|
||||
*
|
||||
* @param type
|
||||
* the type of the local variable to be created.
|
||||
* @return the identifier of the newly created local variable.
|
||||
*/
|
||||
public int newLocal(final Type type) {
|
||||
Object t;
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
case Type.INT:
|
||||
t = Opcodes.INTEGER;
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
t = Opcodes.FLOAT;
|
||||
break;
|
||||
case Type.LONG:
|
||||
t = Opcodes.LONG;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
t = Opcodes.DOUBLE;
|
||||
break;
|
||||
case Type.ARRAY:
|
||||
t = type.getDescriptor();
|
||||
break;
|
||||
// case Type.OBJECT:
|
||||
default:
|
||||
t = type.getInternalName();
|
||||
break;
|
||||
}
|
||||
int local = newLocalMapping(type);
|
||||
setLocalType(local, type);
|
||||
setFrameLocal(local, t);
|
||||
changed = true;
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies subclasses that a new stack map frame is being visited. The
|
||||
* array argument contains the stack map frame types corresponding to the
|
||||
* local variables added with {@link #newLocal}. This method can update
|
||||
* these types in place for the stack map frame being visited. The default
|
||||
* implementation of this method does nothing, i.e. a local variable added
|
||||
* with {@link #newLocal} will have the same type in all stack map frames.
|
||||
* But this behavior is not always the desired one, for instance if a local
|
||||
* variable is added in the middle of a try/catch block: the frame for the
|
||||
* exception handler should have a TOP type for this new local.
|
||||
*
|
||||
* @param newLocals
|
||||
* the stack map frame types corresponding to the local variables
|
||||
* added with {@link #newLocal} (and null for the others). The
|
||||
* format of this array is the same as in
|
||||
* {@link MethodVisitor#visitFrame}, except that long and double
|
||||
* types use two slots. The types for the current stack map frame
|
||||
* must be updated in place in this array.
|
||||
*/
|
||||
protected void updateNewLocals(Object[] newLocals) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies subclasses that a local variable has been added or remapped. The
|
||||
* default implementation of this method does nothing.
|
||||
*
|
||||
* @param local
|
||||
* a local variable identifier, as returned by {@link #newLocal
|
||||
* newLocal()}.
|
||||
* @param type
|
||||
* the type of the value being stored in the local variable.
|
||||
*/
|
||||
protected void setLocalType(final int local, final Type type) {
|
||||
}
|
||||
|
||||
private void setFrameLocal(final int local, final Object type) {
|
||||
int l = newLocals.length;
|
||||
if (local >= l) {
|
||||
Object[] a = new Object[Math.max(2 * l, local + 1)];
|
||||
System.arraycopy(newLocals, 0, a, 0, l);
|
||||
newLocals = a;
|
||||
}
|
||||
newLocals[local] = type;
|
||||
}
|
||||
|
||||
private int remap(final int var, final Type type) {
|
||||
if (var + type.getSize() <= firstLocal) {
|
||||
return var;
|
||||
}
|
||||
int key = 2 * var + type.getSize() - 1;
|
||||
int size = mapping.length;
|
||||
if (key >= size) {
|
||||
int[] newMapping = new int[Math.max(2 * size, key + 1)];
|
||||
System.arraycopy(mapping, 0, newMapping, 0, size);
|
||||
mapping = newMapping;
|
||||
}
|
||||
int value = mapping[key];
|
||||
if (value == 0) {
|
||||
value = newLocalMapping(type);
|
||||
setLocalType(value, type);
|
||||
mapping[key] = value + 1;
|
||||
} else {
|
||||
value--;
|
||||
}
|
||||
if (value != var) {
|
||||
changed = true;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
protected int newLocalMapping(final Type type) {
|
||||
int local = nextLocal;
|
||||
nextLocal += type.getSize();
|
||||
return local;
|
||||
}
|
||||
}
|
||||
311
jdkSrc/jdk8/jdk/internal/org/objectweb/asm/commons/Method.java
Normal file
311
jdkSrc/jdk8/jdk/internal/org/objectweb/asm/commons/Method.java
Normal file
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
|
||||
/**
|
||||
* A named method descriptor.
|
||||
*
|
||||
* @author Juozas Baliuka
|
||||
* @author Chris Nokleberg
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class Method {
|
||||
|
||||
/**
|
||||
* The method name.
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* The method descriptor.
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* Maps primitive Java type names to their descriptors.
|
||||
*/
|
||||
private static final Map<String, String> DESCRIPTORS;
|
||||
|
||||
static {
|
||||
DESCRIPTORS = new HashMap<String, String>();
|
||||
DESCRIPTORS.put("void", "V");
|
||||
DESCRIPTORS.put("byte", "B");
|
||||
DESCRIPTORS.put("char", "C");
|
||||
DESCRIPTORS.put("double", "D");
|
||||
DESCRIPTORS.put("float", "F");
|
||||
DESCRIPTORS.put("int", "I");
|
||||
DESCRIPTORS.put("long", "J");
|
||||
DESCRIPTORS.put("short", "S");
|
||||
DESCRIPTORS.put("boolean", "Z");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Method}.
|
||||
*
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param desc
|
||||
* the method's descriptor.
|
||||
*/
|
||||
public Method(final String name, final String desc) {
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Method}.
|
||||
*
|
||||
* @param name
|
||||
* the method's name.
|
||||
* @param returnType
|
||||
* the method's return type.
|
||||
* @param argumentTypes
|
||||
* the method's argument types.
|
||||
*/
|
||||
public Method(final String name, final Type returnType,
|
||||
final Type[] argumentTypes) {
|
||||
this(name, Type.getMethodDescriptor(returnType, argumentTypes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Method}.
|
||||
*
|
||||
* @param m
|
||||
* a java.lang.reflect method descriptor
|
||||
* @return a {@link Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*/
|
||||
public static Method getMethod(java.lang.reflect.Method m) {
|
||||
return new Method(m.getName(), Type.getMethodDescriptor(m));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link Method}.
|
||||
*
|
||||
* @param c
|
||||
* a java.lang.reflect constructor descriptor
|
||||
* @return a {@link Method} corresponding to the given Java constructor
|
||||
* declaration.
|
||||
*/
|
||||
public static Method getMethod(java.lang.reflect.Constructor<?> c) {
|
||||
return new Method("<init>", Type.getConstructorDescriptor(c));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*
|
||||
* @param method
|
||||
* a Java method declaration, without argument names, of the form
|
||||
* "returnType name (argumentType1, ... argumentTypeN)", where
|
||||
* the types are in plain Java (e.g. "int", "float",
|
||||
* "java.util.List", ...). Classes of the java.lang package can
|
||||
* be specified by their unqualified name; all other classes
|
||||
* names must be fully qualified.
|
||||
* @return a {@link Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>method</code> could not get parsed.
|
||||
*/
|
||||
public static Method getMethod(final String method)
|
||||
throws IllegalArgumentException {
|
||||
return getMethod(method, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
*
|
||||
* @param method
|
||||
* a Java method declaration, without argument names, of the form
|
||||
* "returnType name (argumentType1, ... argumentTypeN)", where
|
||||
* the types are in plain Java (e.g. "int", "float",
|
||||
* "java.util.List", ...). Classes of the java.lang package may
|
||||
* be specified by their unqualified name, depending on the
|
||||
* defaultPackage argument; all other classes names must be fully
|
||||
* qualified.
|
||||
* @param defaultPackage
|
||||
* true if unqualified class names belong to the default package,
|
||||
* or false if they correspond to java.lang classes. For instance
|
||||
* "Object" means "Object" if this option is true, or
|
||||
* "java.lang.Object" otherwise.
|
||||
* @return a {@link Method} corresponding to the given Java method
|
||||
* declaration.
|
||||
* @throws IllegalArgumentException
|
||||
* if <code>method</code> could not get parsed.
|
||||
*/
|
||||
public static Method getMethod(final String method,
|
||||
final boolean defaultPackage) throws IllegalArgumentException {
|
||||
int space = method.indexOf(' ');
|
||||
int start = method.indexOf('(', space) + 1;
|
||||
int end = method.indexOf(')', start);
|
||||
if (space == -1 || start == -1 || end == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
String returnType = method.substring(0, space);
|
||||
String methodName = method.substring(space + 1, start - 1).trim();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('(');
|
||||
int p;
|
||||
do {
|
||||
String s;
|
||||
p = method.indexOf(',', start);
|
||||
if (p == -1) {
|
||||
s = map(method.substring(start, end).trim(), defaultPackage);
|
||||
} else {
|
||||
s = map(method.substring(start, p).trim(), defaultPackage);
|
||||
start = p + 1;
|
||||
}
|
||||
sb.append(s);
|
||||
} while (p != -1);
|
||||
sb.append(')');
|
||||
sb.append(map(returnType, defaultPackage));
|
||||
return new Method(methodName, sb.toString());
|
||||
}
|
||||
|
||||
private static String map(final String type, final boolean defaultPackage) {
|
||||
if ("".equals(type)) {
|
||||
return type;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int index = 0;
|
||||
while ((index = type.indexOf("[]", index) + 1) > 0) {
|
||||
sb.append('[');
|
||||
}
|
||||
|
||||
String t = type.substring(0, type.length() - sb.length() * 2);
|
||||
String desc = DESCRIPTORS.get(t);
|
||||
if (desc != null) {
|
||||
sb.append(desc);
|
||||
} else {
|
||||
sb.append('L');
|
||||
if (t.indexOf('.') < 0) {
|
||||
if (!defaultPackage) {
|
||||
sb.append("java/lang/");
|
||||
}
|
||||
sb.append(t);
|
||||
} else {
|
||||
sb.append(t.replace('.', '/'));
|
||||
}
|
||||
sb.append(';');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the method described by this object.
|
||||
*
|
||||
* @return the name of the method described by this object.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the descriptor of the method described by this object.
|
||||
*
|
||||
* @return the descriptor of the method described by this object.
|
||||
*/
|
||||
public String getDescriptor() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the return type of the method described by this object.
|
||||
*
|
||||
* @return the return type of the method described by this object.
|
||||
*/
|
||||
public Type getReturnType() {
|
||||
return Type.getReturnType(desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the argument types of the method described by this object.
|
||||
*
|
||||
* @return the argument types of the method described by this object.
|
||||
*/
|
||||
public Type[] getArgumentTypes() {
|
||||
return Type.getArgumentTypes(desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + desc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (!(o instanceof Method)) {
|
||||
return false;
|
||||
}
|
||||
Method other = (Method) o;
|
||||
return name.equals(other.name) && desc.equals(other.desc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ desc.hashCode();
|
||||
}
|
||||
}
|
||||
252
jdkSrc/jdk8/jdk/internal/org/objectweb/asm/commons/Remapper.java
Normal file
252
jdkSrc/jdk8/jdk/internal/org/objectweb/asm/commons/Remapper.java
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.signature.SignatureReader;
|
||||
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
|
||||
import jdk.internal.org.objectweb.asm.signature.SignatureWriter;
|
||||
|
||||
/**
|
||||
* A class responsible for remapping types and names. Subclasses can override
|
||||
* the following methods:
|
||||
*
|
||||
* <ul>
|
||||
* <li>{@link #map(String)} - map type</li>
|
||||
* <li>{@link #mapFieldName(String, String, String)} - map field name</li>
|
||||
* <li>{@link #mapMethodName(String, String, String)} - map method name</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public abstract class Remapper {
|
||||
|
||||
public String mapDesc(String desc) {
|
||||
Type t = Type.getType(desc);
|
||||
switch (t.getSort()) {
|
||||
case Type.ARRAY:
|
||||
String s = mapDesc(t.getElementType().getDescriptor());
|
||||
for (int i = 0; i < t.getDimensions(); ++i) {
|
||||
s = '[' + s;
|
||||
}
|
||||
return s;
|
||||
case Type.OBJECT:
|
||||
String newType = map(t.getInternalName());
|
||||
if (newType != null) {
|
||||
return 'L' + newType + ';';
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
private Type mapType(Type t) {
|
||||
switch (t.getSort()) {
|
||||
case Type.ARRAY:
|
||||
String s = mapDesc(t.getElementType().getDescriptor());
|
||||
for (int i = 0; i < t.getDimensions(); ++i) {
|
||||
s = '[' + s;
|
||||
}
|
||||
return Type.getType(s);
|
||||
case Type.OBJECT:
|
||||
s = map(t.getInternalName());
|
||||
return s != null ? Type.getObjectType(s) : t;
|
||||
case Type.METHOD:
|
||||
return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public String mapType(String type) {
|
||||
if (type == null) {
|
||||
return null;
|
||||
}
|
||||
return mapType(Type.getObjectType(type)).getInternalName();
|
||||
}
|
||||
|
||||
public String[] mapTypes(String[] types) {
|
||||
String[] newTypes = null;
|
||||
boolean needMapping = false;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
String type = types[i];
|
||||
String newType = map(type);
|
||||
if (newType != null && newTypes == null) {
|
||||
newTypes = new String[types.length];
|
||||
if (i > 0) {
|
||||
System.arraycopy(types, 0, newTypes, 0, i);
|
||||
}
|
||||
needMapping = true;
|
||||
}
|
||||
if (needMapping) {
|
||||
newTypes[i] = newType == null ? type : newType;
|
||||
}
|
||||
}
|
||||
return needMapping ? newTypes : types;
|
||||
}
|
||||
|
||||
public String mapMethodDesc(String desc) {
|
||||
if ("()V".equals(desc)) {
|
||||
return desc;
|
||||
}
|
||||
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
StringBuilder sb = new StringBuilder("(");
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
sb.append(mapDesc(args[i].getDescriptor()));
|
||||
}
|
||||
Type returnType = Type.getReturnType(desc);
|
||||
if (returnType == Type.VOID_TYPE) {
|
||||
sb.append(")V");
|
||||
return sb.toString();
|
||||
}
|
||||
sb.append(')').append(mapDesc(returnType.getDescriptor()));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public Object mapValue(Object value) {
|
||||
if (value instanceof Type) {
|
||||
return mapType((Type) value);
|
||||
}
|
||||
if (value instanceof Handle) {
|
||||
Handle h = (Handle) value;
|
||||
return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
|
||||
h.getOwner(), h.getName(), h.getDesc()),
|
||||
mapMethodDesc(h.getDesc()));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param typeSignature
|
||||
* true if signature is a FieldTypeSignature, such as the
|
||||
* signature parameter of the ClassVisitor.visitField or
|
||||
* MethodVisitor.visitLocalVariable methods
|
||||
*/
|
||||
public String mapSignature(String signature, boolean typeSignature) {
|
||||
if (signature == null) {
|
||||
return null;
|
||||
}
|
||||
SignatureReader r = new SignatureReader(signature);
|
||||
SignatureWriter w = new SignatureWriter();
|
||||
SignatureVisitor a = createRemappingSignatureAdapter(w);
|
||||
if (typeSignature) {
|
||||
r.acceptType(a);
|
||||
} else {
|
||||
r.accept(a);
|
||||
}
|
||||
return w.toString();
|
||||
}
|
||||
|
||||
protected SignatureVisitor createRemappingSignatureAdapter(
|
||||
SignatureVisitor v) {
|
||||
return new RemappingSignatureAdapter(v, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map method name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param owner
|
||||
* owner of the method.
|
||||
* @param name
|
||||
* name of the method.
|
||||
* @param desc
|
||||
* descriptor of the method.
|
||||
* @return new name of the method
|
||||
*/
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map invokedynamic method name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param name
|
||||
* name of the invokedynamic.
|
||||
* @param desc
|
||||
* descriptor of the invokedynamic.
|
||||
* @return new invokdynamic name.
|
||||
*/
|
||||
public String mapInvokeDynamicMethodName(String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map field name to the new name. Subclasses can override.
|
||||
*
|
||||
* @param owner
|
||||
* owner of the field.
|
||||
* @param name
|
||||
* name of the field
|
||||
* @param desc
|
||||
* descriptor of the field
|
||||
* @return new name of the field.
|
||||
*/
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map type name to the new name. Subclasses can override.
|
||||
*/
|
||||
public String map(String typeName) {
|
||||
return typeName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* An {@link AnnotationVisitor} adapter for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingAnnotationAdapter extends AnnotationVisitor {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
public RemappingAnnotationAdapter(final AnnotationVisitor av,
|
||||
final Remapper remapper) {
|
||||
this(Opcodes.ASM5, av, remapper);
|
||||
}
|
||||
|
||||
protected RemappingAnnotationAdapter(final int api,
|
||||
final AnnotationVisitor av, final Remapper remapper) {
|
||||
super(api, av);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
av.visit(name, remapper.mapValue(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
av.visitEnum(name, remapper.mapDesc(desc), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
|
||||
return v == null ? null : (v == av ? this
|
||||
: new RemappingAnnotationAdapter(v, remapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
AnnotationVisitor v = av.visitArray(name);
|
||||
return v == null ? null : (v == av ? this
|
||||
: new RemappingAnnotationAdapter(v, remapper));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
* A {@link ClassVisitor} for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingClassAdapter extends ClassVisitor {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
protected String className;
|
||||
|
||||
public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
|
||||
this(Opcodes.ASM5, cv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingClassAdapter(final int api, final ClassVisitor cv,
|
||||
final Remapper remapper) {
|
||||
super(api, cv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature,
|
||||
String superName, String[] interfaces) {
|
||||
this.className = name;
|
||||
super.visit(version, access, remapper.mapType(name), remapper
|
||||
.mapSignature(signature, false), remapper.mapType(superName),
|
||||
interfaces == null ? null : remapper.mapTypes(interfaces));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
|
||||
visible);
|
||||
return av == null ? null : createRemappingAnnotationAdapter(av);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? null : createRemappingAnnotationAdapter(av);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc,
|
||||
String signature, Object value) {
|
||||
FieldVisitor fv = super.visitField(access,
|
||||
remapper.mapFieldName(className, name, desc),
|
||||
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
|
||||
remapper.mapValue(value));
|
||||
return fv == null ? null : createRemappingFieldAdapter(fv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc,
|
||||
String signature, String[] exceptions) {
|
||||
String newDesc = remapper.mapMethodDesc(desc);
|
||||
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
|
||||
className, name, desc), newDesc, remapper.mapSignature(
|
||||
signature, false),
|
||||
exceptions == null ? null : remapper.mapTypes(exceptions));
|
||||
return mv == null ? null : createRemappingMethodAdapter(access,
|
||||
newDesc, mv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName,
|
||||
String innerName, int access) {
|
||||
// TODO should innerName be changed?
|
||||
super.visitInnerClass(remapper.mapType(name), outerName == null ? null
|
||||
: remapper.mapType(outerName), innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
super.visitOuterClass(remapper.mapType(owner), name == null ? null
|
||||
: remapper.mapMethodName(owner, name, desc),
|
||||
desc == null ? null : remapper.mapMethodDesc(desc));
|
||||
}
|
||||
|
||||
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
|
||||
return new RemappingFieldAdapter(fv, remapper);
|
||||
}
|
||||
|
||||
protected MethodVisitor createRemappingMethodAdapter(int access,
|
||||
String newDesc, MethodVisitor mv) {
|
||||
return new RemappingMethodAdapter(access, newDesc, mv, remapper);
|
||||
}
|
||||
|
||||
protected AnnotationVisitor createRemappingAnnotationAdapter(
|
||||
AnnotationVisitor av) {
|
||||
return new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
* A {@link FieldVisitor} adapter for type remapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingFieldAdapter extends FieldVisitor {
|
||||
|
||||
private final Remapper remapper;
|
||||
|
||||
public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
|
||||
this(Opcodes.ASM5, fv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
|
||||
final Remapper remapper) {
|
||||
super(api, fv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
|
||||
visible);
|
||||
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
* A {@link LocalVariablesSorter} for type mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingMethodAdapter extends LocalVariablesSorter {
|
||||
|
||||
protected final Remapper remapper;
|
||||
|
||||
public RemappingMethodAdapter(final int access, final String desc,
|
||||
final MethodVisitor mv, final Remapper remapper) {
|
||||
this(Opcodes.ASM5, access, desc, mv, remapper);
|
||||
}
|
||||
|
||||
protected RemappingMethodAdapter(final int api, final int access,
|
||||
final String desc, final MethodVisitor mv, final Remapper remapper) {
|
||||
super(api, access, desc, mv);
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
AnnotationVisitor av = super.visitAnnotationDefault();
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
|
||||
visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
||||
String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitParameterAnnotation(parameter,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
|
||||
Object[] stack) {
|
||||
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
|
||||
remapEntries(nStack, stack));
|
||||
}
|
||||
|
||||
private Object[] remapEntries(int n, Object[] entries) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (entries[i] instanceof String) {
|
||||
Object[] newEntries = new Object[n];
|
||||
if (i > 0) {
|
||||
System.arraycopy(entries, 0, newEntries, 0, i);
|
||||
}
|
||||
do {
|
||||
Object t = entries[i];
|
||||
newEntries[i++] = t instanceof String ? remapper
|
||||
.mapType((String) t) : t;
|
||||
} while (i < n);
|
||||
return newEntries;
|
||||
}
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name,
|
||||
String desc) {
|
||||
super.visitFieldInsn(opcode, remapper.mapType(owner),
|
||||
remapper.mapFieldName(owner, name, desc),
|
||||
remapper.mapDesc(desc));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc,
|
||||
opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(final int opcode, final String owner,
|
||||
final String name, final String desc, final boolean itf) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(int opcode, String owner, String name,
|
||||
String desc, boolean itf) {
|
||||
// Calling super.visitMethodInsn requires to call the correct version
|
||||
// depending on this.api (otherwise infinite loops can occur). To
|
||||
// simplify and to make it easier to automatically remove the backward
|
||||
// compatibility code, we inline the code of the overridden method here.
|
||||
// IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
|
||||
// LocalVariableSorter.
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, remapper.mapType(owner),
|
||||
remapper.mapMethodName(owner, name, desc),
|
||||
remapper.mapMethodDesc(desc), itf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
|
||||
Object... bsmArgs) {
|
||||
for (int i = 0; i < bsmArgs.length; i++) {
|
||||
bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
|
||||
}
|
||||
super.visitInvokeDynamicInsn(
|
||||
remapper.mapInvokeDynamicMethodName(name, desc),
|
||||
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
|
||||
bsmArgs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
super.visitTypeInsn(opcode, remapper.mapType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object cst) {
|
||||
super.visitLdcInsn(remapper.mapValue(cst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitInsnAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler,
|
||||
String type) {
|
||||
super.visitTryCatchBlock(start, end, handler, type == null ? null
|
||||
: remapper.mapType(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
|
||||
TypePath typePath, String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
|
||||
remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String desc, String signature,
|
||||
Label start, Label end, int index) {
|
||||
super.visitLocalVariable(name, remapper.mapDesc(desc),
|
||||
remapper.mapSignature(signature, true), start, end, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
|
||||
TypePath typePath, Label[] start, Label[] end, int[] index,
|
||||
String desc, boolean visible) {
|
||||
AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
|
||||
typePath, start, end, index, remapper.mapDesc(desc), visible);
|
||||
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
/**
|
||||
* A {@link SignatureVisitor} adapter for type mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class RemappingSignatureAdapter extends SignatureVisitor {
|
||||
|
||||
private final SignatureVisitor v;
|
||||
|
||||
private final Remapper remapper;
|
||||
|
||||
private String className;
|
||||
|
||||
public RemappingSignatureAdapter(final SignatureVisitor v,
|
||||
final Remapper remapper) {
|
||||
this(Opcodes.ASM5, v, remapper);
|
||||
}
|
||||
|
||||
protected RemappingSignatureAdapter(final int api,
|
||||
final SignatureVisitor v, final Remapper remapper) {
|
||||
super(api);
|
||||
this.v = v;
|
||||
this.remapper = remapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitClassType(String name) {
|
||||
className = name;
|
||||
v.visitClassType(remapper.mapType(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(String name) {
|
||||
String remappedOuter = remapper.mapType(className) + '$';
|
||||
className = className + '$' + name;
|
||||
String remappedName = remapper.mapType(className);
|
||||
int index = remappedName.startsWith(remappedOuter) ? remappedOuter
|
||||
.length() : remappedName.lastIndexOf('$') + 1;
|
||||
v.visitInnerClassType(remappedName.substring(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFormalTypeParameter(String name) {
|
||||
v.visitFormalTypeParameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeVariable(String name) {
|
||||
v.visitTypeVariable(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitArrayType() {
|
||||
v.visitArrayType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBaseType(char descriptor) {
|
||||
v.visitBaseType(descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitClassBound() {
|
||||
v.visitClassBound();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitExceptionType() {
|
||||
v.visitExceptionType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterface() {
|
||||
v.visitInterface();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
v.visitInterfaceBound();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
v.visitParameterType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
v.visitReturnType();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
v.visitSuperclass();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeArgument() {
|
||||
v.visitTypeArgument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SignatureVisitor visitTypeArgument(char wildcard) {
|
||||
v.visitTypeArgument(wildcard);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
v.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link ClassVisitor} that adds a serial version unique identifier to a
|
||||
* class if missing. Here is typical usage of this class:
|
||||
*
|
||||
* <pre>
|
||||
* ClassWriter cw = new ClassWriter(...);
|
||||
* ClassVisitor sv = new SerialVersionUIDAdder(cw);
|
||||
* ClassVisitor ca = new MyClassAdapter(sv);
|
||||
* new ClassReader(orginalClass).accept(ca, false);
|
||||
* </pre>
|
||||
*
|
||||
* The SVUID algorithm can be found <a href=
|
||||
* "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
|
||||
* >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
|
||||
*
|
||||
* <pre>
|
||||
* The serialVersionUID is computed using the signature of a stream of bytes
|
||||
* that reflect the class definition. The National Institute of Standards and
|
||||
* Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
|
||||
* signature for the stream. The first two 32-bit quantities are used to form a
|
||||
* 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
|
||||
* types to a sequence of bytes. The values input to the stream are defined by
|
||||
* the Java Virtual Machine (VM) specification for classes.
|
||||
*
|
||||
* The sequence of items in the stream is as follows:
|
||||
*
|
||||
* 1. The class name written using UTF encoding.
|
||||
* 2. The class modifiers written as a 32-bit integer.
|
||||
* 3. The name of each interface sorted by name written using UTF encoding.
|
||||
* 4. For each field of the class sorted by field name (except private static
|
||||
* and private transient fields):
|
||||
* 1. The name of the field in UTF encoding.
|
||||
* 2. The modifiers of the field written as a 32-bit integer.
|
||||
* 3. The descriptor of the field in UTF encoding
|
||||
* 5. If a class initializer exists, write out the following:
|
||||
* 1. The name of the method, <clinit>, in UTF encoding.
|
||||
* 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
|
||||
* written as a 32-bit integer.
|
||||
* 3. The descriptor of the method, ()V, in UTF encoding.
|
||||
* 6. For each non-private constructor sorted by method name and signature:
|
||||
* 1. The name of the method, <init>, in UTF encoding.
|
||||
* 2. The modifiers of the method written as a 32-bit integer.
|
||||
* 3. The descriptor of the method in UTF encoding.
|
||||
* 7. For each non-private method sorted by method name and signature:
|
||||
* 1. The name of the method in UTF encoding.
|
||||
* 2. The modifiers of the method written as a 32-bit integer.
|
||||
* 3. The descriptor of the method in UTF encoding.
|
||||
* 8. The SHA-1 algorithm is executed on the stream of bytes produced by
|
||||
* DataOutputStream and produces five 32-bit values sha[0..4].
|
||||
*
|
||||
* 9. The hash value is assembled from the first and second 32-bit values of
|
||||
* the SHA-1 message digest. If the result of the message digest, the five
|
||||
* 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
|
||||
* sha, the hash value would be computed as follows:
|
||||
*
|
||||
* long hash = ((sha[0] >>> 24) & 0xFF) |
|
||||
* ((sha[0] >>> 16) & 0xFF) << 8 |
|
||||
* ((sha[0] >>> 8) & 0xFF) << 16 |
|
||||
* ((sha[0] >>> 0) & 0xFF) << 24 |
|
||||
* ((sha[1] >>> 24) & 0xFF) << 32 |
|
||||
* ((sha[1] >>> 16) & 0xFF) << 40 |
|
||||
* ((sha[1] >>> 8) & 0xFF) << 48 |
|
||||
* ((sha[1] >>> 0) & 0xFF) << 56;
|
||||
* </pre>
|
||||
*
|
||||
* @author Rajendra Inamdar, Vishal Vishnoi
|
||||
*/
|
||||
public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* Flag that indicates if we need to compute SVUID.
|
||||
*/
|
||||
private boolean computeSVUID;
|
||||
|
||||
/**
|
||||
* Set to true if the class already has SVUID.
|
||||
*/
|
||||
private boolean hasSVUID;
|
||||
|
||||
/**
|
||||
* Classes access flags.
|
||||
*/
|
||||
private int access;
|
||||
|
||||
/**
|
||||
* Internal name of the class
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Interfaces implemented by the class.
|
||||
*/
|
||||
private String[] interfaces;
|
||||
|
||||
/**
|
||||
* Collection of fields. (except private static and private transient
|
||||
* fields)
|
||||
*/
|
||||
private Collection<Item> svuidFields;
|
||||
|
||||
/**
|
||||
* Set to true if the class has static initializer.
|
||||
*/
|
||||
private boolean hasStaticInitializer;
|
||||
|
||||
/**
|
||||
* Collection of non-private constructors.
|
||||
*/
|
||||
private Collection<Item> svuidConstructors;
|
||||
|
||||
/**
|
||||
* Collection of non-private methods.
|
||||
*/
|
||||
private Collection<Item> svuidMethods;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
|
||||
* this constructor</i>. Instead, they must use the
|
||||
* {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
|
||||
*
|
||||
* @param cv
|
||||
* a {@link ClassVisitor} to which this visitor will delegate
|
||||
* calls.
|
||||
* @throws IllegalStateException
|
||||
* If a subclass calls this constructor.
|
||||
*/
|
||||
public SerialVersionUIDAdder(final ClassVisitor cv) {
|
||||
this(Opcodes.ASM5, cv);
|
||||
if (getClass() != SerialVersionUIDAdder.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SerialVersionUIDAdder}.
|
||||
*
|
||||
* @param api
|
||||
* the ASM API version implemented by this visitor. Must be one
|
||||
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
|
||||
* @param cv
|
||||
* a {@link ClassVisitor} to which this visitor will delegate
|
||||
* calls.
|
||||
*/
|
||||
protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
|
||||
super(api, cv);
|
||||
svuidFields = new ArrayList<Item>();
|
||||
svuidConstructors = new ArrayList<Item>();
|
||||
svuidMethods = new ArrayList<Item>();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Overridden methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Visit class header and get class name, access , and interfaces
|
||||
* information (step 1,2, and 3) for SVUID computation.
|
||||
*/
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
computeSVUID = (access & Opcodes.ACC_INTERFACE) == 0;
|
||||
|
||||
if (computeSVUID) {
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.interfaces = new String[interfaces.length];
|
||||
System.arraycopy(interfaces, 0, this.interfaces, 0,
|
||||
interfaces.length);
|
||||
}
|
||||
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
/*
|
||||
* Visit the methods and get constructor and method information (step 5 and
|
||||
* 7). Also determine if there is a class initializer (step 6).
|
||||
*/
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
if (computeSVUID) {
|
||||
if ("<clinit>".equals(name)) {
|
||||
hasStaticInitializer = true;
|
||||
}
|
||||
/*
|
||||
* Remembers non private constructors and methods for SVUID
|
||||
* computation For constructor and method modifiers, only the
|
||||
* ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
|
||||
* ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
|
||||
* are used.
|
||||
*/
|
||||
int mods = access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
||||
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
||||
| Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
|
||||
| Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
|
||||
|
||||
// all non private methods
|
||||
if ((access & Opcodes.ACC_PRIVATE) == 0) {
|
||||
if ("<init>".equals(name)) {
|
||||
svuidConstructors.add(new Item(name, mods, desc));
|
||||
} else if (!"<clinit>".equals(name)) {
|
||||
svuidMethods.add(new Item(name, mods, desc));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets class field information for step 4 of the algorithm. Also determines
|
||||
* if the class already has a SVUID.
|
||||
*/
|
||||
@Override
|
||||
public FieldVisitor visitField(final int access, final String name,
|
||||
final String desc, final String signature, final Object value) {
|
||||
if (computeSVUID) {
|
||||
if ("serialVersionUID".equals(name)) {
|
||||
// since the class already has SVUID, we won't be computing it.
|
||||
computeSVUID = false;
|
||||
hasSVUID = true;
|
||||
}
|
||||
/*
|
||||
* Remember field for SVUID computation For field modifiers, only
|
||||
* the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
|
||||
* ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
|
||||
* computing serialVersionUID values.
|
||||
*/
|
||||
if ((access & Opcodes.ACC_PRIVATE) == 0
|
||||
|| (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
|
||||
int mods = access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
|
||||
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
|
||||
| Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
|
||||
svuidFields.add(new Item(name, mods, desc));
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a bizarre special case. Nested classes (static classes declared
|
||||
* inside another class) that are protected have their access bit set to
|
||||
* public in their class files to deal with some odd reflection situation.
|
||||
* Our SVUID computation must do as the JVM does and ignore access bits in
|
||||
* the class file in favor of the access bits InnerClass attribute.
|
||||
*/
|
||||
@Override
|
||||
public void visitInnerClass(final String aname, final String outerName,
|
||||
final String innerName, final int attr_access) {
|
||||
if ((name != null) && name.equals(aname)) {
|
||||
this.access = attr_access;
|
||||
}
|
||||
super.visitInnerClass(aname, outerName, innerName, attr_access);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the SVUID if class doesn't have one
|
||||
*/
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// compute SVUID and add it to the class
|
||||
if (computeSVUID && !hasSVUID) {
|
||||
try {
|
||||
addSVUID(computeSVUID());
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("Error while computing SVUID for "
|
||||
+ name, e);
|
||||
}
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Utility methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns true if the class already has a SVUID field. The result of this
|
||||
* method is only valid when visitEnd is or has been called.
|
||||
*
|
||||
* @return true if the class already has a SVUID field.
|
||||
*/
|
||||
public boolean hasSVUID() {
|
||||
return hasSVUID;
|
||||
}
|
||||
|
||||
protected void addSVUID(long svuid) {
|
||||
FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
|
||||
+ Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
|
||||
if (fv != null) {
|
||||
fv.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes and returns the value of SVUID.
|
||||
*
|
||||
* @return Returns the serial version UID
|
||||
* @throws IOException
|
||||
* if an I/O error occurs
|
||||
*/
|
||||
protected long computeSVUID() throws IOException {
|
||||
ByteArrayOutputStream bos;
|
||||
DataOutputStream dos = null;
|
||||
long svuid = 0;
|
||||
|
||||
try {
|
||||
bos = new ByteArrayOutputStream();
|
||||
dos = new DataOutputStream(bos);
|
||||
|
||||
/*
|
||||
* 1. The class name written using UTF encoding.
|
||||
*/
|
||||
dos.writeUTF(name.replace('/', '.'));
|
||||
|
||||
/*
|
||||
* 2. The class modifiers written as a 32-bit integer.
|
||||
*/
|
||||
dos.writeInt(access
|
||||
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
|
||||
| Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
|
||||
|
||||
/*
|
||||
* 3. The name of each interface sorted by name written using UTF
|
||||
* encoding.
|
||||
*/
|
||||
Arrays.sort(interfaces);
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
dos.writeUTF(interfaces[i].replace('/', '.'));
|
||||
}
|
||||
|
||||
/*
|
||||
* 4. For each field of the class sorted by field name (except
|
||||
* private static and private transient fields):
|
||||
*
|
||||
* 1. The name of the field in UTF encoding. 2. The modifiers of the
|
||||
* field written as a 32-bit integer. 3. The descriptor of the field
|
||||
* in UTF encoding
|
||||
*
|
||||
* Note that field signatures are not dot separated. Method and
|
||||
* constructor signatures are dot separated. Go figure...
|
||||
*/
|
||||
writeItems(svuidFields, dos, false);
|
||||
|
||||
/*
|
||||
* 5. If a class initializer exists, write out the following: 1. The
|
||||
* name of the method, <clinit>, in UTF encoding. 2. The modifier of
|
||||
* the method, java.lang.reflect.Modifier.STATIC, written as a
|
||||
* 32-bit integer. 3. The descriptor of the method, ()V, in UTF
|
||||
* encoding.
|
||||
*/
|
||||
if (hasStaticInitializer) {
|
||||
dos.writeUTF("<clinit>");
|
||||
dos.writeInt(Opcodes.ACC_STATIC);
|
||||
dos.writeUTF("()V");
|
||||
} // if..
|
||||
|
||||
/*
|
||||
* 6. For each non-private constructor sorted by method name and
|
||||
* signature: 1. The name of the method, <init>, in UTF encoding. 2.
|
||||
* The modifiers of the method written as a 32-bit integer. 3. The
|
||||
* descriptor of the method in UTF encoding.
|
||||
*/
|
||||
writeItems(svuidConstructors, dos, true);
|
||||
|
||||
/*
|
||||
* 7. For each non-private method sorted by method name and
|
||||
* signature: 1. The name of the method in UTF encoding. 2. The
|
||||
* modifiers of the method written as a 32-bit integer. 3. The
|
||||
* descriptor of the method in UTF encoding.
|
||||
*/
|
||||
writeItems(svuidMethods, dos, true);
|
||||
|
||||
dos.flush();
|
||||
|
||||
/*
|
||||
* 8. The SHA-1 algorithm is executed on the stream of bytes
|
||||
* produced by DataOutputStream and produces five 32-bit values
|
||||
* sha[0..4].
|
||||
*/
|
||||
byte[] hashBytes = computeSHAdigest(bos.toByteArray());
|
||||
|
||||
/*
|
||||
* 9. The hash value is assembled from the first and second 32-bit
|
||||
* values of the SHA-1 message digest. If the result of the message
|
||||
* digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
|
||||
* five int values named sha, the hash value would be computed as
|
||||
* follows:
|
||||
*
|
||||
* long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
|
||||
* << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
|
||||
* 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
|
||||
* 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
|
||||
* 56;
|
||||
*/
|
||||
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
|
||||
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
|
||||
}
|
||||
} finally {
|
||||
// close the stream (if open)
|
||||
if (dos != null) {
|
||||
dos.close();
|
||||
}
|
||||
}
|
||||
|
||||
return svuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA-1 message digest of the given value.
|
||||
*
|
||||
* @param value
|
||||
* the value whose SHA message digest must be computed.
|
||||
* @return the SHA-1 message digest of the given value.
|
||||
*/
|
||||
protected byte[] computeSHAdigest(final byte[] value) {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA").digest(value);
|
||||
} catch (Exception e) {
|
||||
throw new UnsupportedOperationException(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the items in the collection and writes it to the data output stream
|
||||
*
|
||||
* @param itemCollection
|
||||
* collection of items
|
||||
* @param dos
|
||||
* a <code>DataOutputStream</code> value
|
||||
* @param dotted
|
||||
* a <code>boolean</code> value
|
||||
* @exception IOException
|
||||
* if an error occurs
|
||||
*/
|
||||
private static void writeItems(final Collection<Item> itemCollection,
|
||||
final DataOutput dos, final boolean dotted) throws IOException {
|
||||
int size = itemCollection.size();
|
||||
Item[] items = itemCollection.toArray(new Item[size]);
|
||||
Arrays.sort(items);
|
||||
for (int i = 0; i < size; i++) {
|
||||
dos.writeUTF(items[i].name);
|
||||
dos.writeInt(items[i].access);
|
||||
dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
|
||||
: items[i].desc);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Inner classes
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private static class Item implements Comparable<Item> {
|
||||
|
||||
final String name;
|
||||
|
||||
final int access;
|
||||
|
||||
final String desc;
|
||||
|
||||
Item(final String name, final int access, final String desc) {
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public int compareTo(final Item other) {
|
||||
int retVal = name.compareTo(other.name);
|
||||
if (retVal == 0) {
|
||||
retVal = desc.compareTo(other.desc);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (o instanceof Item) {
|
||||
return compareTo((Item) o) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (name + desc).hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A {@link Remapper} using a {@link Map} to define its mapping.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class SimpleRemapper extends Remapper {
|
||||
|
||||
private final Map<String, String> mapping;
|
||||
|
||||
public SimpleRemapper(Map<String, String> mapping) {
|
||||
this.mapping = mapping;
|
||||
}
|
||||
|
||||
public SimpleRemapper(String oldName, String newName) {
|
||||
this.mapping = Collections.singletonMap(oldName, newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String desc) {
|
||||
String s = map(owner + '.' + name + desc);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String desc) {
|
||||
String s = map(owner + '.' + name);
|
||||
return s == null ? name : s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String key) {
|
||||
return mapping.get(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* A {@link ClassVisitor} that merges clinit methods into a single one.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class StaticInitMerger extends ClassVisitor {
|
||||
|
||||
private String name;
|
||||
|
||||
private MethodVisitor clinit;
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private int counter;
|
||||
|
||||
public StaticInitMerger(final String prefix, final ClassVisitor cv) {
|
||||
this(Opcodes.ASM5, prefix, cv);
|
||||
}
|
||||
|
||||
protected StaticInitMerger(final int api, final String prefix,
|
||||
final ClassVisitor cv) {
|
||||
super(api, cv);
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
MethodVisitor mv;
|
||||
if ("<clinit>".equals(name)) {
|
||||
int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
|
||||
String n = prefix + counter++;
|
||||
mv = cv.visitMethod(a, n, desc, signature, exceptions);
|
||||
|
||||
if (clinit == null) {
|
||||
clinit = cv.visitMethod(a, name, desc, null, null);
|
||||
}
|
||||
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc,
|
||||
false);
|
||||
} else {
|
||||
mv = cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
if (clinit != null) {
|
||||
clinit.visitInsn(Opcodes.RETURN);
|
||||
clinit.visitMaxs(0, 0);
|
||||
}
|
||||
cv.visitEnd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* A code generator for switch statements.
|
||||
*
|
||||
* @author Juozas Baliuka
|
||||
* @author Chris Nokleberg
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public interface TableSwitchGenerator {
|
||||
|
||||
/**
|
||||
* Generates the code for a switch case.
|
||||
*
|
||||
* @param key
|
||||
* the switch case key.
|
||||
* @param end
|
||||
* a label that corresponds to the end of the switch statement.
|
||||
*/
|
||||
void generateCase(int key, Label end);
|
||||
|
||||
/**
|
||||
* Generates the code for the default switch case.
|
||||
*/
|
||||
void generateDefault();
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package jdk.internal.org.objectweb.asm.commons;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.tree.MethodNode;
|
||||
import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
|
||||
* are sorted in a method innermost-to-outermost. This allows the programmer to
|
||||
* add handlers without worrying about ordering them correctly with respect to
|
||||
* existing, in-code handlers.
|
||||
*
|
||||
* Behavior is only defined for properly-nested handlers. If any "try" blocks
|
||||
* overlap (something that isn't possible in Java code) then this may not do
|
||||
* what you want. In fact, this adapter just sorts by the length of the "try"
|
||||
* block, taking advantage of the fact that a given try block must be larger
|
||||
* than any block it contains).
|
||||
*
|
||||
* @author Adrian Sampson
|
||||
*/
|
||||
public class TryCatchBlockSorter extends MethodNode {
|
||||
|
||||
public TryCatchBlockSorter(final MethodVisitor mv, final int access,
|
||||
final String name, final String desc, final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM5, mv, access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
|
||||
final int access, final String name, final String desc,
|
||||
final String signature, final String[] exceptions) {
|
||||
super(api, access, name, desc, signature, exceptions);
|
||||
this.mv = mv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
// Compares TryCatchBlockNodes by the length of their "try" block.
|
||||
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
|
||||
|
||||
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
|
||||
int len1 = blockLength(t1);
|
||||
int len2 = blockLength(t2);
|
||||
return len1 - len2;
|
||||
}
|
||||
|
||||
private int blockLength(TryCatchBlockNode block) {
|
||||
int startidx = instructions.indexOf(block.start);
|
||||
int endidx = instructions.indexOf(block.end);
|
||||
return endidx - startidx;
|
||||
}
|
||||
};
|
||||
Collections.sort(tryCatchBlocks, comp);
|
||||
// Updates the 'target' of each try catch block annotation.
|
||||
for (int i = 0; i < tryCatchBlocks.size(); ++i) {
|
||||
tryCatchBlocks.get(i).updateIndex(i);
|
||||
}
|
||||
if (mv != null) {
|
||||
accept(mv);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user