mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 00:04: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;
|
||||
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.NoGC;
|
||||
import org.teavm.interop.StaticInit;
|
||||
import org.teavm.interop.Structure;
|
||||
|
||||
|
@ -24,24 +25,17 @@ public final class Allocator {
|
|||
private Allocator() {
|
||||
}
|
||||
|
||||
static Address address = initialize();
|
||||
|
||||
private static native Address initialize();
|
||||
|
||||
public static Address allocate(RuntimeClass tag) {
|
||||
Address result = address;
|
||||
address = result.add(tag.size);
|
||||
fillZero(result, tag.size);
|
||||
RuntimeObject object = result.toStructure();
|
||||
RuntimeObject object = GC.alloc(tag.size);
|
||||
fillZero(object.toAddress(), tag.size);
|
||||
object.classReference = tag.toAddress().toInt() >> 3;
|
||||
return result;
|
||||
return object.toAddress();
|
||||
}
|
||||
|
||||
public static Address allocateArray(RuntimeClass tag, int size) {
|
||||
Address result = address;
|
||||
int sizeInBytes = tag.itemType.size * size + Structure.sizeOf(RuntimeArray.class);
|
||||
sizeInBytes = Address.align(Address.fromInt(sizeInBytes), 4).toInt();
|
||||
address = result.add(sizeInBytes);
|
||||
Address result = GC.alloc(sizeInBytes).toAddress();
|
||||
fillZero(result, sizeInBytes);
|
||||
|
||||
RuntimeArray array = result.toStructure();
|
||||
|
@ -51,19 +45,12 @@ public final class Allocator {
|
|||
return result;
|
||||
}
|
||||
|
||||
@NoGC
|
||||
public static native void fillZero(Address address, int count);
|
||||
|
||||
@NoGC
|
||||
public static native void moveMemoryBlock(Address source, Address target, int count);
|
||||
|
||||
@NoGC
|
||||
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 boolean isLessThan(Address other);
|
||||
|
||||
public native int toInt();
|
||||
|
||||
public native long toLong();
|
||||
|
@ -56,6 +58,10 @@ public final class Address {
|
|||
|
||||
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 fromLong(long value);
|
||||
|
|
Loading…
Reference in New Issue
Block a user