/*
* $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 gnu.java.lang.VMClassHelper;
import java.util.ArrayList;
import java.util.HashMap;
/**
* @author epr
*/
public final class TIBBuilder implements TIBLayout {
private static final int DEFAULT_SIZE = MIN_TIB_LENGTH + 16;
private final ArrayList<Object> tibAsList;
private final HashMap<String, Integer> nameSignature2Index;
private Object[] tibAsArray;
/**
* Create a blank instance
*
* @param vmClass
*/
public TIBBuilder(VmClassType vmClass, int methodCount) {
tibAsList = new ArrayList<Object>(DEFAULT_SIZE);
for (int i = 0; i < MIN_TIB_LENGTH; i++) {
tibAsList.add(null);
}
tibAsList.set(VMTYPE_INDEX, vmClass);
nameSignature2Index = new HashMap<String, Integer>(methodCount);
}
/**
* Create a copied instance
*
* @param vmClass
* @param src
*/
public TIBBuilder(VmClassType vmClass, Object[] src, int methodCount) {
this(vmClass, src.length + methodCount);
final int length = src.length;
for (int i = FIRST_METHOD_INDEX; i < length; i++) {
tibAsList.add(src[i]);
nameSignature2Index.put(getNameSignature((VmInstanceMethod) src[i]), i);
}
}
/**
* Add an instance method to this VMT. The VMT offset of the method is
* adjusted.
*
* @param method
*/
public void add(VmInstanceMethod method) {
if (tibAsArray != null) {
throw new RuntimeException(
"This VMT is locked");
}
final int idx = tibAsList.size();
tibAsList.add(method);
nameSignature2Index.put(getNameSignature(method), idx);
method.setTibOffset(idx);
}
/**
* Overwrite a method at a given index The VMT offset of the method is
* adjusted.
*
* @param index
* @param method
*/
public void set(int index, VmInstanceMethod method) {
if (tibAsArray != null) {
throw new RuntimeException(
"This VMT is locked");
}
if (index < FIRST_METHOD_INDEX) {
throw new IndexOutOfBoundsException(
"Index (" + index + ")must be >= " + FIRST_METHOD_INDEX);
}
tibAsList.set(index, method);
nameSignature2Index.put(getNameSignature(method), index);
method.setTibOffset(index);
}
//todo review rules for overriding and do more testing
/**
* Check if the method has the correct visibility ofr overriding the method at index.
* It asumed that the signutares were already checked and they match
* @param index
* @param method
* @return
*/
boolean overrides(int index, VmInstanceMethod method) {
if (tibAsArray != null) {
throw new RuntimeException("This VMT is locked");
}
if (index < FIRST_METHOD_INDEX) {
throw new IndexOutOfBoundsException("Index (" + index + ")must be >= " + FIRST_METHOD_INDEX);
}
VmInstanceMethod met = (VmInstanceMethod) tibAsList.get(index);
return (met.isPublic() || met.isProtected() || (!met.isPrivate() &&
VMClassHelper.getPackagePortion(met.getDeclaringClass().getName()).
equals(VMClassHelper.getPackagePortion(method.getDeclaringClass().getName()))));
}
/**
* Search through a given VMT for a method with a given name & signature.
* Return the index in the VMT (0..length-1) if found, -1 otherwise.
*
* @param name
* @param signature
* @return int
*/
public int indexOf(String name, String signature) {
// Note that index 0 of the VMT contain the class, so
// skip index 0
final Object idx = nameSignature2Index.get(getNameSignature(name, signature));
if (idx != null) {
return (Integer) idx;
} else {
return -1;
}
/*final int hash = VmMember.calcHashCode(name, signature);
final int length = tibAsList.size();
for (int i = FIRST_METHOD_INDEX; i < length; i++) {
final VmInstanceMethod mts = (VmInstanceMethod) tibAsList.get(i);
if (hash == mts.getMemberHashCode()) {
final String mts_name = mts.getName();
final String mts_signature = mts.getSignature();
if (name.equals(mts_name) && signature.equals(mts_signature)) {
// We found it
return i; }
}
}
return -1;*/
}
/**
* Convert this TIB to a TIB array. After a call to this method, the TIB
* cannot be changed anymore.
*
* @return The TIB
*/
public Object[] toArray() {
if (tibAsArray == null) {
tibAsArray = new Object[tibAsList.size()];
tibAsList.toArray(tibAsArray);
}
return tibAsArray;
}
private final String getNameSignature(String name, String signature) {
return name + '#' + signature;
}
private final String getNameSignature(VmInstanceMethod method) {
return method.getName() + '#' + method.getSignature();
}
}