/* * $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.io.PrintWriter; import java.nio.ByteOrder; import org.jnode.annotation.MagicPermission; import org.jnode.assembler.Label; import org.jnode.assembler.ObjectResolver; import org.jnode.vm.VmAddress; import org.jnode.vm.facade.ObjectVisitor; import org.jnode.vm.facade.VmArchitecture; import org.jnode.vm.facade.VmUtils; import org.vmmagic.unboxed.Address; import org.vmmagic.unboxed.ObjectReference; import org.vmmagic.unboxed.UnboxedObject; /** * @author Ewout Prangsma (epr@users.sourceforge.net) */ @MagicPermission public abstract class VmStatics extends VmStaticsBase { private int[] statics; private transient Object[] objects; private final int slotLength; private final boolean lsbFirst; private transient ObjectResolver resolver; private transient boolean locked; private final VmStaticsAllocator allocator; /** * Initialize this instance */ public VmStatics(VmArchitecture arch, ObjectResolver resolver, int size) { this(new VmStaticsAllocator(size), arch, resolver); } /** * Initialize this instance */ protected VmStatics(VmStaticsAllocator allocator, VmArchitecture arch, ObjectResolver resolver) { this.statics = new int[allocator.getCapacity()]; this.allocator = allocator; this.objects = new Object[allocator.getCapacity()]; this.lsbFirst = (arch.getByteOrder() == ByteOrder.LITTLE_ENDIAN); this.slotLength = arch.getReferenceSize() >> 2; this.resolver = resolver; } /** * Allocate an int/float type entry. * * @return the index of the allocated entry. */ final int allocIntField() { return allocator.alloc(TYPE_INT, 1); } /** * Allocate an long/double type entry. * * @return the index of the allocated entry. */ final int allocLongField() { return allocator.alloc(TYPE_LONG, 2); } /** * Allocate an Object type entry. * * @return the index of the allocated entry. */ final int allocObjectField() { return allocator.alloc(TYPE_OBJECT, slotLength); } /** * Allocate an String type entry. * * @return the index of the allocated entry. */ final int allocConstantStringField(String value) { final int idx = allocator.alloc(TYPE_STRING, slotLength); setRawObject(idx, value); return idx; } /** * Allocate an org.jnode.vm.Address type entry. * * @return the index of the allocated entry. */ public final int allocAddressField() { return allocator.alloc(TYPE_ADDRESS, slotLength); } /** * Allocate an method code type entry. * * @return the index of the allocated entry. */ final int allocMethodCode() { final int idx = allocator.alloc(TYPE_METHOD_CODE, slotLength); return idx; } /** * Set the pointer of the native code of a method in the table at the given index. * * @param idx * @param nativeCode */ final void setMethodCode(int idx, VmAddress nativeCode) { allocator.testType(idx, TYPE_METHOD_CODE); setRawObject(idx, nativeCode); } /** * Allocate an {@link org.jnode.vm.classmgr.VmType} type entry. * * @return the index of the allocated entry. */ final int allocClass(VmType type) { final int idx = allocator.alloc(TYPE_CLASS, slotLength); setRawObject(idx, type); return idx; } /** * Gets the type at the given index. * * @param idx * @return the type entry */ final VmType getTypeEntry(int idx) { allocator.testType(idx, TYPE_CLASS); return (VmType) getRawObject(idx); } /** * Get a String entry at the given index. * * @param idx * @return the string */ public final String getStringEntry(int idx) { allocator.testType(idx, TYPE_STRING); return (String) getRawObject(idx); } public final void setInt(int idx, int value) { allocator.testType(idx, TYPE_INT); if (statics[idx] != value) { if (locked) { throw new RuntimeException("Locked"); } statics[idx] = value; } } public final int getInt(int idx) { allocator.testType(idx, TYPE_INT); return statics[idx]; } public final void setObject(int idx, Object value) { allocator.testType(idx, TYPE_OBJECT); if (setRawObject(idx, value)) { if (locked) { throw new RuntimeException("Locked"); } } } public final void setAddress(int idx, Label value) { if (!VmUtils.isWritingImage()) { throw new IllegalStateException("Only allowed during bootimage creation."); } allocator.testType(idx, TYPE_ADDRESS); if (setRawObject(idx, value)) { if (locked) { throw new RuntimeException("Locked"); } } } public final void setAddress(int idx, UnboxedObject value) { if (!VmUtils.isWritingImage()) { throw new IllegalStateException("Only allowed during bootimage creation."); } allocator.testType(idx, TYPE_ADDRESS); if (setRawObject(idx, value)) { if (locked) { throw new RuntimeException("Locked"); } } } /*final void setMethod(int idx, VmMethod value) { if (locked) { throw new RuntimeException("Locked"); } if (types[idx] != TYPE_METHOD) { throw new IllegalArgumentException("Type error " + types[idx]); } setRawObject(idx, value); }*/ private final boolean setRawObject(int idx, Object value) { if (objects != null) { if (objects[idx] != value) { objects[idx] = value; return true; } else { return false; } } else { final Address valuePtr = ObjectReference.fromObject(value).toAddress(); if (slotLength == 1) { statics[idx] = valuePtr.toInt(); } else { final long lvalue = valuePtr.toLong(); if (lsbFirst) { statics[idx + 0] = (int) (lvalue & 0xFFFFFFFFL); statics[idx + 1] = (int) ((lvalue >>> 32) & 0xFFFFFFFFL); } else { statics[idx + 1] = (int) (lvalue & 0xFFFFFFFFL); statics[idx + 0] = (int) ((lvalue >>> 32) & 0xFFFFFFFFL); } } return true; } } private final Object getRawObject(int idx) { if (objects != null) { return objects[idx]; } else { final Address ptr; if (slotLength == 1) { ptr = Address.fromIntZeroExtend(statics[idx]); } else { final long lsb; final long msb; if (lsbFirst) { lsb = statics[idx + 0] & 0xFFFFFFFFL; msb = statics[idx + 1] & 0xFFFFFFFFL; } else { lsb = statics[idx + 1] & 0xFFFFFFFFL; msb = statics[idx + 0] & 0xFFFFFFFFL; } ptr = Address.fromLong(lsb | (msb << 32)); } return ptr.toObjectReference().toObject(); } } public final void setLong(int idx, long value) { if (locked) { throw new RuntimeException("Locked"); } allocator.testType(idx, TYPE_LONG); if (lsbFirst) { statics[idx + 0] = (int) (value & 0xFFFFFFFFL); statics[idx + 1] = (int) ((value >>> 32) & 0xFFFFFFFFL); } else { statics[idx + 1] = (int) (value & 0xFFFFFFFFL); statics[idx + 0] = (int) ((value >>> 32) & 0xFFFFFFFFL); } } /** * Get the full statics table. * * @return The statics table. */ public final Object getTable() { return statics; } /** * Get the statics type at a given index * * @return int */ public final int getType(int index) { return allocator.getType(index); } /** * Let all objects in this statics-table make a visit to the given visitor. * * @param visitor */ public boolean walk(ObjectVisitor visitor) { return walk(TYPE_OBJECT, visitor); } /** * Let all objects in this statics-table make a visit to the given visitor. * * @param visitor * @return false if the last visit returned false, true otherwise. */ private boolean walk(int visitType, ObjectVisitor visitor) { final int[] table; final byte[] types; final int length; table = this.statics; types = allocator.getTypes(); length = allocator.getLength(); if (slotLength == 1) { for (int i = 0; i < length; i++) { final byte type = types[i]; if (type == visitType) { final Object object; object = Address.fromIntZeroExtend(table[i]).toObjectReference().toObject(); if (object != null) { final boolean rc = visitor.visit(object); if (!rc) { return false; } } } } } else { for (int i = 0; i < length; i++) { final byte type = types[i]; if (type == visitType) { final Object object; final long lsb = table[i + 0] & 0xFFFFFFFFL; final long msb = table[i + 1] & 0xFFFFFFFFL; i++; object = Address.fromLong(lsb | (msb << 32)).toObjectReference().toObject(); if (object != null) { final boolean rc = visitor.visit(object); if (!rc) { return false; } } } } } return true; } public final void dumpStatistics(PrintWriter out) { allocator.dumpStatistics(out); } /** * @see org.jnode.vm.objects.VmSystemObject#verifyBeforeEmit() */ public void verifyBeforeEmit() { //System.out.println("VmStatics#verifyBeforeEmit " + slotLength + ", " + resolver); final int max = statics.length; int count = 0; for (int i = 0; i < max; i++) { final Object value = objects[i]; if (value != null) { count++; if (slotLength == 1) { statics[i] = resolver.addressOf32(value); if ((statics[i] == 0) && (allocator.getType(i) != TYPE_ADDRESS)) { throw new RuntimeException("addressof32(" + value + ") is null"); } } else { final long lvalue = resolver.addressOf64(value); if ((lvalue == 0L) && (allocator.getType(i) != TYPE_ADDRESS)) { throw new RuntimeException("addressof64(" + value + ") is null"); } if (lsbFirst) { statics[i + 0] = (int) (lvalue & 0xFFFFFFFFL); statics[i + 1] = (int) ((lvalue >>> 32) & 0xFFFFFFFFL); } else { statics[i + 1] = (int) (lvalue & 0xFFFFFFFFL); statics[i + 0] = (int) ((lvalue >>> 32) & 0xFFFFFFFFL); } } } else if (allocator.getType(i) == TYPE_METHOD_CODE) { throw new RuntimeException("Method is null"); } } objects = null; locked = true; //System.out.println("VmStatics#verifyBeforeEmit count=" + count); } /** * Gets my statics allocator. * * @return the allocator */ protected final VmStaticsAllocator getAllocator() { return allocator; } }