mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-31 12:24:10 -08:00
Implementing simple mark&sweep GC
This commit is contained in:
parent
f7296e0389
commit
ae5d701aac
|
@ -16,6 +16,7 @@
|
||||||
package org.teavm.runtime;
|
package org.teavm.runtime;
|
||||||
|
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.NoGC;
|
||||||
import org.teavm.interop.StaticInit;
|
import org.teavm.interop.StaticInit;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
@ -24,24 +25,17 @@ public final class Allocator {
|
||||||
private Allocator() {
|
private Allocator() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Address address = initialize();
|
|
||||||
|
|
||||||
private static native Address initialize();
|
|
||||||
|
|
||||||
public static Address allocate(RuntimeClass tag) {
|
public static Address allocate(RuntimeClass tag) {
|
||||||
Address result = address;
|
RuntimeObject object = GC.alloc(tag.size);
|
||||||
address = result.add(tag.size);
|
fillZero(object.toAddress(), tag.size);
|
||||||
fillZero(result, tag.size);
|
|
||||||
RuntimeObject object = result.toStructure();
|
|
||||||
object.classReference = tag.toAddress().toInt() >> 3;
|
object.classReference = tag.toAddress().toInt() >> 3;
|
||||||
return result;
|
return object.toAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Address allocateArray(RuntimeClass tag, int size) {
|
public static Address allocateArray(RuntimeClass tag, int size) {
|
||||||
Address result = address;
|
|
||||||
int sizeInBytes = tag.itemType.size * size + Structure.sizeOf(RuntimeArray.class);
|
int sizeInBytes = tag.itemType.size * size + Structure.sizeOf(RuntimeArray.class);
|
||||||
sizeInBytes = Address.align(Address.fromInt(sizeInBytes), 4).toInt();
|
sizeInBytes = Address.align(Address.fromInt(sizeInBytes), 4).toInt();
|
||||||
address = result.add(sizeInBytes);
|
Address result = GC.alloc(sizeInBytes).toAddress();
|
||||||
fillZero(result, sizeInBytes);
|
fillZero(result, sizeInBytes);
|
||||||
|
|
||||||
RuntimeArray array = result.toStructure();
|
RuntimeArray array = result.toStructure();
|
||||||
|
@ -51,19 +45,12 @@ public final class Allocator {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoGC
|
||||||
public static native void fillZero(Address address, int count);
|
public static native void fillZero(Address address, int count);
|
||||||
|
|
||||||
|
@NoGC
|
||||||
public static native void moveMemoryBlock(Address source, Address target, int count);
|
public static native void moveMemoryBlock(Address source, Address target, int count);
|
||||||
|
|
||||||
|
@NoGC
|
||||||
public static native boolean isInitialized(Class<?> cls);
|
public static native boolean isInitialized(Class<?> cls);
|
||||||
|
|
||||||
public static native void allocStack(int size);
|
|
||||||
|
|
||||||
public static native void registerGcRoot(int index, Object object);
|
|
||||||
|
|
||||||
public static native void removeGcRoot(int index);
|
|
||||||
|
|
||||||
public static native void releaseStack(int size);
|
|
||||||
|
|
||||||
public static native Address getStaticGcRoots();
|
|
||||||
}
|
}
|
||||||
|
|
20
core/src/main/java/org/teavm/runtime/FreeChunk.java
Normal file
20
core/src/main/java/org/teavm/runtime/FreeChunk.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.runtime;
|
||||||
|
|
||||||
|
class FreeChunk extends RuntimeObject {
|
||||||
|
int size;
|
||||||
|
}
|
22
core/src/main/java/org/teavm/runtime/FreeChunkHolder.java
Normal file
22
core/src/main/java/org/teavm/runtime/FreeChunkHolder.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.runtime;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
class FreeChunkHolder extends Structure {
|
||||||
|
FreeChunk value;
|
||||||
|
}
|
169
core/src/main/java/org/teavm/runtime/GC.java
Normal file
169
core/src/main/java/org/teavm/runtime/GC.java
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.runtime;
|
||||||
|
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.NoGC;
|
||||||
|
import org.teavm.interop.StaticInit;
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
@NoGC
|
||||||
|
@StaticInit
|
||||||
|
public final class GC {
|
||||||
|
private GC() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static Address currentChunkLimit;
|
||||||
|
static FreeChunk currentChunk;
|
||||||
|
static FreeChunkHolder currentChunkPointer;
|
||||||
|
static int freeChunks;
|
||||||
|
|
||||||
|
private static native Address gcStorageAddress();
|
||||||
|
|
||||||
|
private static native Address heapAddress();
|
||||||
|
|
||||||
|
private static native Region regionsAddress();
|
||||||
|
|
||||||
|
private static native int regionMaxCount();
|
||||||
|
|
||||||
|
private static native int availableBytes();
|
||||||
|
|
||||||
|
private static native int regionSize();
|
||||||
|
|
||||||
|
static {
|
||||||
|
currentChunk = heapAddress().toStructure();
|
||||||
|
currentChunk.classReference = 0;
|
||||||
|
currentChunk.size = availableBytes();
|
||||||
|
currentChunkLimit = currentChunk.toAddress().add(currentChunk.size);
|
||||||
|
currentChunkPointer = gcStorageAddress().toStructure();
|
||||||
|
currentChunkPointer.value = currentChunk;
|
||||||
|
freeChunks = 1;
|
||||||
|
getAvailableChunkIfPossible(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RuntimeObject alloc(int size) {
|
||||||
|
FreeChunk current = currentChunk;
|
||||||
|
Address next = currentChunk.toAddress().add(size);
|
||||||
|
if (!next.add(Structure.sizeOf(FreeChunk.class) + 1).isLessThan(currentChunkLimit)) {
|
||||||
|
getAvailableChunk(size);
|
||||||
|
}
|
||||||
|
int oldSize = current.size;
|
||||||
|
Address result = current.toAddress();
|
||||||
|
currentChunk = next.toStructure();
|
||||||
|
currentChunk.classReference = 0;
|
||||||
|
currentChunk.size = oldSize - size;
|
||||||
|
return result.toStructure();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void getAvailableChunk(int size) {
|
||||||
|
if (getAvailableChunkIfPossible(size)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
collectGarbage(size);
|
||||||
|
getAvailableChunkIfPossible(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean getAvailableChunkIfPossible(int size) {
|
||||||
|
while (!currentChunk.toAddress().add(size).isLessThan(currentChunkLimit)) {
|
||||||
|
if (--size == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentChunkPointer = currentChunkPointer.toAddress().add(FreeChunkHolder.class, 1).toStructure();
|
||||||
|
currentChunk = currentChunkPointer.value;
|
||||||
|
currentChunkLimit = currentChunk.toAddress().add(currentChunk.size);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean collectGarbage(int size) {
|
||||||
|
mark();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mark() {
|
||||||
|
MarkQueue.init();
|
||||||
|
Allocator.fillZero(regionsAddress().toAddress(), regionMaxCount() * Structure.sizeOf(Region.class));
|
||||||
|
|
||||||
|
Address staticRoots = Mutator.getStaticGcRoots();
|
||||||
|
int staticCount = staticRoots.getInt();
|
||||||
|
staticRoots.add(8);
|
||||||
|
while (staticCount-- > 0) {
|
||||||
|
RuntimeObject object = staticRoots.getAddress().toStructure();
|
||||||
|
if (object != null) {
|
||||||
|
mark(object);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Address stackRoots = Mutator.getStackGcRoots(); stackRoots != null;
|
||||||
|
stackRoots = Mutator.getNextStackRoots(stackRoots)) {
|
||||||
|
int count = Mutator.getStackRootCount(stackRoots);
|
||||||
|
Address stackRootsPtr = Mutator.getStackRootPointer(stackRoots);
|
||||||
|
while (count-- > 0) {
|
||||||
|
RuntimeObject obj = stackRootsPtr.getAddress().toStructure();
|
||||||
|
mark(obj);
|
||||||
|
stackRootsPtr = stackRootsPtr.add(Address.sizeOf());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mark(RuntimeObject object) {
|
||||||
|
if (object == null || isMarked(object)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkQueue.enqueue(object);
|
||||||
|
while (!MarkQueue.isEmpty()) {
|
||||||
|
object = MarkQueue.dequeue();
|
||||||
|
if (isMarked(object)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
object.classReference |= RuntimeObject.GC_MARKED;
|
||||||
|
|
||||||
|
long offset = object.toAddress().toLong() - heapAddress().toLong();
|
||||||
|
Region region = regionsAddress().toAddress().add(Region.class, (int) (offset / regionSize()))
|
||||||
|
.toStructure();
|
||||||
|
short relativeOffset = (short) (offset % regionSize() + 1);
|
||||||
|
if (region.start == 0 || region.start > relativeOffset) {
|
||||||
|
region.start = relativeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeClass cls = RuntimeClass.getClass(object);
|
||||||
|
while (cls != null) {
|
||||||
|
Address layout = cls.layout;
|
||||||
|
if (layout != null) {
|
||||||
|
short fieldCount = layout.getShort();
|
||||||
|
while (fieldCount-- > 0) {
|
||||||
|
layout = layout.add(2);
|
||||||
|
int fieldOffset = layout.getShort();
|
||||||
|
RuntimeObject reference = object.toAddress().add(fieldOffset).toStructure();
|
||||||
|
if (reference != null && !isMarked(reference)) {
|
||||||
|
MarkQueue.enqueue(reference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cls = cls.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isMarked(RuntimeObject object) {
|
||||||
|
return (object.classReference & RuntimeObject.GC_MARKED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Region extends Structure {
|
||||||
|
short start;
|
||||||
|
}
|
||||||
|
}
|
54
core/src/main/java/org/teavm/runtime/MarkQueue.java
Normal file
54
core/src/main/java/org/teavm/runtime/MarkQueue.java
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.runtime;
|
||||||
|
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
|
||||||
|
final class MarkQueue {
|
||||||
|
private MarkQueue() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int head;
|
||||||
|
private static int tail;
|
||||||
|
|
||||||
|
static void init() {
|
||||||
|
head = 0;
|
||||||
|
tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native Address getBase();
|
||||||
|
|
||||||
|
private static native int getSize();
|
||||||
|
|
||||||
|
static void enqueue(RuntimeObject object) {
|
||||||
|
getBase().add(Address.sizeOf() * tail).putAddress(object.toAddress());
|
||||||
|
if (++tail >= getSize()) {
|
||||||
|
tail = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static RuntimeObject dequeue() {
|
||||||
|
Address result = getBase().add(Address.sizeOf() * head).getAddress();
|
||||||
|
if (++head >= getSize()) {
|
||||||
|
head = 0;
|
||||||
|
}
|
||||||
|
return result.toStructure();
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isEmpty() {
|
||||||
|
return head == tail;
|
||||||
|
}
|
||||||
|
}
|
43
core/src/main/java/org/teavm/runtime/Mutator.java
Normal file
43
core/src/main/java/org/teavm/runtime/Mutator.java
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2016 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.runtime;
|
||||||
|
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.NoGC;
|
||||||
|
|
||||||
|
@NoGC
|
||||||
|
public final class Mutator {
|
||||||
|
private Mutator() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static native void allocStack(int size);
|
||||||
|
|
||||||
|
public static native void registerGcRoot(int index, Object object);
|
||||||
|
|
||||||
|
public static native void removeGcRoot(int index);
|
||||||
|
|
||||||
|
public static native void releaseStack(int size);
|
||||||
|
|
||||||
|
public static native Address getStaticGcRoots();
|
||||||
|
|
||||||
|
public static native Address getStackGcRoots();
|
||||||
|
|
||||||
|
public static native Address getNextStackRoots(Address address);
|
||||||
|
|
||||||
|
public static native int getStackRootCount(Address address);
|
||||||
|
|
||||||
|
public static native Address getStackRootPointer(Address address);
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ public final class Address {
|
||||||
|
|
||||||
public native Address add(long offset);
|
public native Address add(long offset);
|
||||||
|
|
||||||
|
public native boolean isLessThan(Address other);
|
||||||
|
|
||||||
public native int toInt();
|
public native int toInt();
|
||||||
|
|
||||||
public native long toLong();
|
public native long toLong();
|
||||||
|
@ -56,6 +58,10 @@ public final class Address {
|
||||||
|
|
||||||
public native void putDouble(double value);
|
public native void putDouble(double value);
|
||||||
|
|
||||||
|
public native Address getAddress();
|
||||||
|
|
||||||
|
public native void putAddress(Address value);
|
||||||
|
|
||||||
public static native Address fromInt(int value);
|
public static native Address fromInt(int value);
|
||||||
|
|
||||||
public static native Address fromLong(long value);
|
public static native Address fromLong(long value);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user