package vm; import icecaptools.IcecapCVar; import icecaptools.IcecapCompileMe; import java.util.ArrayList; import javax.realtime.MemoryArea; public class Memory { private int base; private int size; private int free; private String name; private MemoryInfo memoryInfo; private static class MemoryInfo { String name; int size; int maxUsed; private int instanceCount; public MemoryInfo(Memory m) { this.name = m.name; this.size = m.size; this.maxUsed = 0; instanceCount = 1; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(name); buffer.append("[" + instanceCount + "]"); buffer.append(": size = "); buffer.append(size); buffer.append(", max used = " + maxUsed); return buffer.toString(); } public void increaseInstanceCount() { instanceCount++; } } public static boolean memoryAreaTrackingEnabled; private static Memory areaToUseForTracking; private static ArrayList<MemoryInfo> createdMemories; @IcecapCompileMe private MemoryInfo addMemoryArea(Memory m) { Memory current; if (areaToUseForTracking == null) { areaToUseForTracking = m; } current = switchToArea(areaToUseForTracking); if (createdMemories == null) { createdMemories = new ArrayList<MemoryInfo>(); heapArea.name = "HEAP"; MemoryInfo memory = new MemoryInfo(heapArea); createdMemories.add(memory); heapArea.memoryInfo = memory; } for (MemoryInfo memory : createdMemories) { if (memory.name.compareTo(m.name) == 0) { memory.increaseInstanceCount(); switchToArea(current); return memory; } } MemoryInfo memory = new MemoryInfo(m); createdMemories.add(memory); switchToArea(current); return memory; } @IcecapCompileMe public static void reportMemoryUsage() { if (memoryAreaTrackingEnabled) { if (createdMemories != null) { Memory current = switchToArea(areaToUseForTracking); devices.Console.println("\nCreated " + createdMemories.size() + " memory area types:"); for (MemoryInfo memory : createdMemories) { devices.Console.println(memory.toString()); } devices.Console.println("Max backing store usage = " + (MemoryArea.getRemainingMemorySize())); switchToArea(current); } else { devices.Console.println("No created memories recorded"); } } else { devices.Console.println("Memory tracking disabled"); } } @IcecapCompileMe public Memory(int base, int size, String name) { this.base = base; this.size = size; this.free = 0; this.name = (name == null ? "Unknown" : name); if (memoryAreaTrackingEnabled) { this.memoryInfo = addMemoryArea(this); } } private Memory(int base, int size) { this.base = base; this.size = size; this.free = 0; this.name = "BackingStore"; } @Override public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(name); buffer.append(": size = "); buffer.append(size); buffer.append(", used = " + free); return buffer.toString(); } @IcecapCompileMe public static Memory switchToArea(Memory newScope) { Memory previousMemoryArea = (Memory) currentMemoryArea; currentMemoryArea = newScope; return previousMemoryArea; } @IcecapCompileMe public static Memory allocateInHeap(int size) { if (heapArea.free + size >= heapArea.size) { throw new OutOfMemoryError(); } int startPtr = heapArea.base + heapArea.free; heapArea.free += size; Memory memory = new Memory(startPtr, size); return memory; } @IcecapCVar private static Memory currentMemoryArea; @IcecapCVar private static Memory heapArea; /* * Returns the entire heap as a Memory object. This is used to allocate the * backing store inside the heap. * * The heap contains more than just the SCJ managed memories. It also * contains everything loaded by the class initializers and all the * constants. */ @IcecapCompileMe static public Memory getHeapArea() { return heapArea; } @IcecapCompileMe static public Memory getCurrentMemoryArea() { return currentMemoryArea; } /** * Resets the memory by setting free to the new free value newFree = 0 * means, that the whole memory is reset Precondition: 0 <= newFree < size * * @param newFree * the new free value */ public void reset(int newFree) { free = newFree; } public void resize(int newSize) { size = newSize; } public int consumedMemory() { return free; } public int getBase() { return base; } public int getSize() { return size; } @IcecapCompileMe public static void startMemoryAreaTracking() { updateMaxUsed(heapArea); memoryAreaTrackingEnabled = true; } @IcecapCompileMe public static void updateMaxUsed(Memory m) { if (m.memoryInfo != null) { if (m.free > m.memoryInfo.maxUsed) { m.memoryInfo.maxUsed = m.free; } } } @IcecapCompileMe public static void executeInHeap(Runnable logic) { Memory current = switchToArea(areaToUseForTracking); logic.run(); switchToArea(current); } public String getName() { return name; } private static int nameCount; public static String getNextMemoryName(String defaultName) { if (memoryAreaTrackingEnabled) { Memory current = switchToArea(areaToUseForTracking); String name = defaultName + nameCount; nameCount++; switchToArea(current); return name; } else { return defaultName; } } public static void dumpLiveMemories() { if (memoryAreaTrackingEnabled) { Memory current = switchToArea(areaToUseForTracking); MemoryArea.printMemoryAreas(); switchToArea(current); } else { } } public static void executeInTrackingArea(Runnable logic) { if (memoryAreaTrackingEnabled) { Memory current = switchToArea(areaToUseForTracking); logic.run(); switchToArea(current); } else { } } }