/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library 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 Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.vm.classmgr; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.jnode.vm.facade.VmUtils; /** * @author epr */ public final class VmByteCode extends AbstractCode { /** * The method i'm a part of */ private final VmMethod method; /** * The constant pool where indexes in my bytecode refer to */ private final VmCP cp; /** * Number of local variables for this method */ private char noLocals; /** * Max. number of slots taken by this method on the stack */ private char maxStack; /** * Bytecode of this method. This is a ByteBuffer or byte[] */ private Object bytecode; /** * Exception handler table */ private VmInterpretedExceptionHandler[] eTable; /** * Line number table */ private VmLineNumberMap lnTable; /** * Local variable table */ private final VmLocalVariableTable lvTable; /** * Data used by the native code compilers */ private transient Object compilerData; /** * Create a new instance * * @param method * @param bytecode * @param noLocals * @param maxStack * @param eTable * @param lnTable */ public VmByteCode(VmMethod method, ByteBuffer bytecode, int noLocals, int maxStack, VmInterpretedExceptionHandler[] eTable, VmLineNumberMap lnTable, VmLocalVariableTable lvTable) { this.method = method; this.cp = method.getDeclaringClass().getCP(); if (VmUtils.isWritingImage()) { final byte[] buildBytecode = new byte[bytecode.limit()]; bytecode.get(buildBytecode); bytecode.rewind(); this.bytecode = buildBytecode; } else { this.bytecode = bytecode; } this.noLocals = (char) noLocals; this.maxStack = (char) maxStack; this.eTable = eTable; this.lnTable = lnTable; this.lvTable = (lvTable != null) ? lvTable : VmLocalVariableTable.EMPTY; //this.locked = false; } /** * Gets the actual bytecode. * Do not change the contents of the given array! * * @return the code */ public ByteBuffer getBytecode() { final Object bytecode = this.bytecode; if (bytecode instanceof ByteBuffer) { return ((ByteBuffer) bytecode).duplicate(); } else { final ByteBuffer buf = ByteBuffer.wrap((byte[]) bytecode); if (VmUtils.isRunningVm()) { this.bytecode = buf; } return buf.duplicate(); } } /** * Gets the length of the bytecode * * @return the length */ public int getLength() { final Object bytecode = this.bytecode; if (bytecode instanceof ByteBuffer) { return ((ByteBuffer) bytecode).limit(); } else { return ((byte[]) bytecode).length; } } /** * Gets the maximum stack size * * @return The maximum stack size */ public int getMaxStack() { return maxStack; } /** * Gets the number of local variables * * @return the number of local variables */ public int getNoLocals() { return noLocals; } /** * Get the number of exception handlers * * @return The number of exception handlers */ public int getNoExceptionHandlers() { return (eTable == null) ? 0 : eTable.length; } /** * Get the handler PC of the exception handler at a given index * * @param index * @return The exception handler */ public VmInterpretedExceptionHandler getExceptionHandler(int index) { if (eTable != null) { return eTable[index]; } else { throw new IndexOutOfBoundsException("eTable is null; index " + index); } } /** * Gets all exception handler as unmodifiable list of VmInterpretedExceptionHandler * instances. * * @return The handlers */ public List<VmInterpretedExceptionHandler> getExceptionHandlers() { if (eTable == null) { return Collections.emptyList(); } else { return Arrays.asList(eTable); } } /** * Gets the line number table, or {@code null} if no line number table exists * for this bytecode. * * @return the line number table */ public VmLineNumberMap getLineNrs() { return lnTable; } /** * Gets the line number corresponding to a given program counter value. * * @param pc * @return The line number for the given pc, or {@code -1} if no line * number can be found. */ public int getLineNr(int pc) { final VmLineNumberMap lnTable = this.lnTable; if (lnTable != null) { return lnTable.findLineNr(pc); } else { return -1; } } /** * Lock this object. * This will make future modifications on this object fail. */ final void lock() { //this.locked = true; } /** * Gets the constant pool, where indexes in this bytecode refer to * * @return The constant pool */ public VmCP getCP() { return cp; } /** * Gets the method where this bytecode is a part of * * @return The method */ public VmMethod getMethod() { return method; } /** * @return Returns the compilerData. */ public final Object getCompilerData() { return this.compilerData; } /** * @param compilerData The compilerData to set. */ public final void setCompilerData(Object compilerData) { this.compilerData = compilerData; } /** * Find the local variable at the given program counter (index * in bytecode) and the given index. * * @param pc * @param index * @return The variable or {@code null} if not found. */ public final VmLocalVariable getVariable(int pc, int index) { return lvTable.getVariable(pc, index); } public final VmLocalVariableTable getLocalVariableTable() { return lvTable; } }