diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TRuntime.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TRuntime.java index 66375de9e..da09f6ade 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TRuntime.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TRuntime.java @@ -15,6 +15,9 @@ */ package org.teavm.classlib.java.lang; +import org.teavm.interop.DelegateTo; +import org.teavm.runtime.GC; + /** * A dummy class for compatibility. Currently these methods don't actually * do anything. @@ -35,10 +38,15 @@ public class TRuntime { * Returns the amount of free memory in the system. Calling the gc method * may result in increasing the value returned by freeMemory. */ + @DelegateTo("freeMemoryLowLevel") public long freeMemory() { return Integer.MAX_VALUE; } + private long freeMemoryLowLevel() { + return GC.getFreeMemory(); + } + /** * Runs the garbage collector. Calling this method suggests that the Java * Virtual Machine expend effort toward recycling unused objects in order to @@ -51,6 +59,7 @@ public class TRuntime { * means of invoking this method. */ public void gc() { + System.gc(); } /** @@ -68,7 +77,12 @@ public class TRuntime { * environment. Note that the amount of memory required to hold an object of * any given type may be implementation-dependent. */ + @DelegateTo("totalMemoryLowLevel") public long totalMemory() { return Integer.MAX_VALUE; } + + private long totalMemoryLowLevel() { + return GC.availableBytes(); + } } \ No newline at end of file diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java index fc03d11ed..8ad18df67 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TSystem.java @@ -26,6 +26,7 @@ import org.teavm.interop.DelegateTo; import org.teavm.interop.Import; import org.teavm.interop.Unmanaged; import org.teavm.runtime.Allocator; +import org.teavm.runtime.GC; import org.teavm.runtime.RuntimeArray; import org.teavm.runtime.RuntimeClass; @@ -126,10 +127,15 @@ public final class TSystem extends TObject { @PluggableDependency(SystemNativeGenerator.class) public static native void setOut(TPrintStream err); + @DelegateTo("gcLowLevel") public static void gc() { // Do nothing } + private static void gcLowLevel() { + GC.collectGarbage(0); + } + public static void runFinalization() { // Do nothing } diff --git a/core/src/main/java/org/teavm/runtime/GC.java b/core/src/main/java/org/teavm/runtime/GC.java index c9b67ccac..aaef08171 100644 --- a/core/src/main/java/org/teavm/runtime/GC.java +++ b/core/src/main/java/org/teavm/runtime/GC.java @@ -30,6 +30,7 @@ public final class GC { static FreeChunk currentChunk; static FreeChunkHolder currentChunkPointer; static int freeChunks; + static int freeMemory = (int) availableBytes(); static native Address gcStorageAddress(); @@ -41,10 +42,14 @@ public final class GC { private static native int regionMaxCount(); - private static native long availableBytes(); + public static native long availableBytes(); private static native int regionSize(); + public static int getFreeMemory() { + return freeMemory; + } + static { currentChunk = heapAddress().toStructure(); currentChunk.classReference = 0; @@ -71,6 +76,7 @@ public final class GC { currentChunk.classReference = 0; currentChunk.size = freeSize; } + freeMemory -= size; return current; } @@ -93,6 +99,7 @@ public final class GC { if (--freeChunks == 0) { return false; } + freeMemory -= currentChunk.size; currentChunkPointer = Structure.add(FreeChunkHolder.class, currentChunkPointer, 1); currentChunk = currentChunkPointer.value; currentChunkLimit = currentChunk.toAddress().add(currentChunk.size); @@ -100,9 +107,10 @@ public final class GC { return true; } - private static boolean collectGarbage(int size) { + public static boolean collectGarbage(int size) { mark(); sweep(); + updateFreeMemory(); return true; } @@ -268,6 +276,15 @@ public final class GC { currentChunkLimit = currentChunk.toAddress().add(currentChunk.size); } + private static void updateFreeMemory() { + freeMemory = 0; + FreeChunkHolder freeChunkPtr = currentChunkPointer; + for (int i = 0; i < freeChunks; ++i) { + freeMemory += freeChunkPtr.value.size; + freeChunkPtr = Structure.add(FreeChunkHolder.class, freeChunkPtr, 1); + } + } + private static void sortFreeChunks(int lower, int upper) { int start = lower; int end = upper;