| /******************************************************************************* |
| * Copyright (c) 2010, 2014 Jesper Steen Moller and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Jesper Steen Moller - initial API and implementation |
| * IBM Corporation - Bug fixing |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.internal.debug.core.model; |
| |
| import com.sun.jdi.Method; |
| |
| /** |
| * Class for analysing Java methods while debugging. |
| * |
| * @author jmoeller2 |
| * |
| */ |
| public class JDIMethod { |
| |
| // Known Java byte codes, from the JVM spec |
| private static final int ALOAD_0 = 0x2a; |
| |
| private static final int ILOAD_1 = 0x1b; |
| private static final int LLOAD_1 = 0x1f; |
| private static final int FLOAD_1 = 0x23; |
| private static final int DLOAD_1 = 0x27; |
| private static final int ALOAD_1 = 0x2b; |
| |
| private static final int IRETURN = 0xac; |
| private static final int LRETURN = 0xad; |
| private static final int FRETURN = 0xae; |
| private static final int DRETURN = 0xaf; |
| private static final int ARETURN = 0xb0; |
| |
| private static final int GETFIELD = 0xb4; |
| private static final int PUTFIELD = 0xb5; |
| |
| private static final int RETURN = 0xb1; |
| |
| /** |
| * Determines if the opcode passes in is one of the value return |
| * instructions. |
| * |
| * @param opCode |
| * opCode to check |
| * @return If <code>opCode</code> is one of 'areturn', 'ireturn', etc. |
| */ |
| public static final boolean isXReturn(byte opCode) { |
| return (opCode & 0xFF) == IRETURN || (opCode & 0xFF) == LRETURN |
| || (opCode & 0xFF) == FRETURN || (opCode & 0xFF) == DRETURN |
| || (opCode & 0xFF) == ARETURN; |
| } |
| |
| /** |
| * Determines if the opcode passes in is one of the 'loado_1' instruxtions. |
| * |
| * @param opCode |
| * opCode to check |
| * @return If <code>opCode</code> is one of 'aload_1', 'iload_1', etc. |
| */ |
| public static final boolean isXLoad1(byte opCode) { |
| return (opCode & 0xFF) == ILOAD_1 || (opCode & 0xFF) == LLOAD_1 |
| || (opCode & 0xFF) == FLOAD_1 || (opCode & 0xFF) == DLOAD_1 |
| || (opCode & 0xFF) == ALOAD_1; |
| } |
| |
| /** |
| * Determines if the method in question is a simple getter, JavaBean style. |
| * |
| * Simple getters have byte code which look like this, and they start with |
| * "get" or "is": |
| * |
| * 0 aload_0 1 getfield 4 Xreturn |
| * |
| * @param method |
| * Method to check |
| * @return true if the method is a simple getter |
| */ |
| public static boolean isGetterMethod(Method method) { |
| if (!(method.name().startsWith("get") || method.name().startsWith("is"))) //$NON-NLS-1$ //$NON-NLS-2$ |
| { |
| return false; |
| } |
| |
| byte[] bytecodes = method.bytecodes(); |
| return bytecodes.length == 5 && (bytecodes[0] & 0xFF) == ALOAD_0 |
| && (bytecodes[1] & 0xFF) == GETFIELD && isXReturn(bytecodes[4]); |
| } |
| |
| /** |
| * Determines if the method in question is a simple getter, JavaBean style. |
| * |
| * Simple setters have byte code which look like this, and they start with |
| * "set": |
| * |
| * 0 aload_0 1 Xload_1 2 putfield 5 return |
| * |
| * @param method |
| * Method to check |
| * @return true if the method is a simple setter |
| */ |
| public static boolean isSetterMethod(Method method) { |
| if (!method.name().startsWith("set")) { //$NON-NLS-1$ |
| return false; |
| } |
| |
| byte[] bytecodes = method.bytecodes(); |
| return bytecodes.length == 6 && (bytecodes[0] & 0xFF) == ALOAD_0 |
| && isXLoad1(bytecodes[1]) && (bytecodes[2] & 0xFF) == PUTFIELD |
| && (bytecodes[5] & 0xFF) == RETURN; |
| } |
| } |