Skip to content

Commit

Permalink
#274 The garbage collector is not working correctly (#283)
Browse files Browse the repository at this point in the history
* #274 The garbage collector is not working correctly
  • Loading branch information
mirkosertic authored Nov 23, 2019
1 parent bc618ff commit f1578ba
Show file tree
Hide file tree
Showing 12 changed files with 362 additions and 132 deletions.
28 changes: 14 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ cache:
- $HOME/.cache/install-jdk

before_install:
- wget -N https://chromedriver.storage.googleapis.com/76.0.3809.68/chromedriver_linux64.zip -P ~/
- wget -N https://chromedriver.storage.googleapis.com/78.0.3904.105/chromedriver_linux64.zip -P ~/
- unzip ~/chromedriver_linux64.zip -d ~/
- rm ~/chromedriver_linux64.zip
- sudo chmod +x ~/chromedriver
Expand All @@ -41,34 +41,34 @@ install:
- git clone https://github.com/matcornic/hugo-theme-learn.git ./manual/themes/hugo-theme-learn

script:
- mvn clean package -P jvmtestsonly
- mvn -B clean package -P jvmtestsonly

jobs:
include:
- stage: "Compiler Target Tests"
name: "JS Target OpenJDK 8"
script: mvn -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
script: mvn -B -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
name: "JS Target OpenJDK 11"
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
name: "JS Target OpenJDK 12"
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P jstestsonly
name: "JS Target OpenJDK 13"
- script: mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
- script: mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
name: "WASM Target Reloop OpenJDK 8"
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
name: "WASM Target Reloop OpenJDK 11"
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
name: "WASM Target Reloop OpenJDK 12"
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_reloop
name: "WASM Target Reloop OpenJDK 13"
- script: mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
- script: mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
name: "WASM Target Stackify OpenJDK 8"
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
- script: mkdir /home/travis/openjdk11 && ~/install-jdk.sh -W /home/travis/openjdk11 -F 11 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
name: "WASM Target Stackify OpenJDK 11"
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
- script: mkdir /home/travis/openjdk12 && ~/install-jdk.sh -W /home/travis/openjdk12 -F 12 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
name: "WASM Target Stackify OpenJDK 12"
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
- script: mkdir /home/travis/openjdk13 && ~/install-jdk.sh -W /home/travis/openjdk13 -F 13 -L GPL && mvn -B -pl '!:bytecoder-integrationtest' clean test -P wasmtestsonly_stackify
name: "WASM Target Stackify OpenJDK 13"
- stage: "Deploy to Maven Central"
script: skip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,6 @@ public class Address {
public static native int getMemorySize();

public static native void unreachable();

public static native int ptrOf(final Object o);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
package de.mirkosertic.bytecoder.classlib;

import de.mirkosertic.bytecoder.api.Export;
import de.mirkosertic.bytecoder.api.Import;

/**
* A simple Memory Manager.
Expand All @@ -31,9 +30,6 @@ public static void initNative() {
initInternal(Address.getMemorySize());
}

@Import(module = "profiler", name = "logMemoryLayoutBlock")
public static native void logMemoryLayoutBlock(int aStart, int aUsed, int aNext);

private static void initInternal(final int aSize) {
// This is the list of free blocks
Address.setIntValue(4, 0, 28);
Expand Down Expand Up @@ -74,36 +70,6 @@ public static long usedMem() {
return theResult;
}

@Export("logMemoryLayout")
public static void logMemoryLayout() {

final int theFreeStart = 4;
final int theFreeStartPtr = Address.getIntValue(theFreeStart, 0);

int theCurrent = theFreeStartPtr;
while (theCurrent != 0) {
final int theNext = Address.getIntValue(theCurrent, 4);
final int theStart = theCurrent;

logMemoryLayoutBlock(theStart, 0, theNext);

theCurrent = theNext;
}

final int theUsedStart = 8;
final int theUsedStartPtr = Address.getIntValue(theUsedStart, 0);

theCurrent = theUsedStartPtr;
while (theCurrent != 0) {
final int theStart = theCurrent;
final int theNext = Address.getIntValue(theCurrent, 4);

logMemoryLayoutBlock(theStart, 1, theNext);

theCurrent = theNext;
}
}

private static void internalFree(final int aPointer) {

final int theStart = aPointer;
Expand Down Expand Up @@ -240,61 +206,54 @@ public static int newObject(final int aSize, final int aType, final int aVTableI
return theAddress;
}

private static boolean isUsed(final int aOwningBlock) {

final int theOwningStart = aOwningBlock;
final int theOwningData = theOwningStart + 8;
public static boolean isUsedByStack(final int aOwningBlock) {
final int theOwningData = aOwningBlock + 8;
return isUsedByStackUserSpace(theOwningData);
}

// First of all we check the stack
public static boolean isUsedByStackUserSpace(final int aPtrToObject) {
int theStackStart = Address.getStackTop();
final int theStackTop = Address.getMemorySize();
while(theStackStart < theStackTop) {
final int theCurrent = theStackStart;
final int theReference = Address.getIntValue(theCurrent, 0);
if (theReference == theOwningData) {
final int theMemorySize = Address.getMemorySize();
while(theStackStart + 4 < theMemorySize) {
if (Address.getIntValue(theStackStart, 0) == aPtrToObject) {
return true;
}
theStackStart += 4;
}

// Nothing on the stack, we check the allocated memory blovks
final int theAllocatedStart= 8;
final int theAllocatedStartPtr = Address.getIntValue(theAllocatedStart, 0);
return false;
}

int theCurrent = theAllocatedStartPtr;
while(theCurrent != 0) {
public static boolean isUsedByHeap(final int aAllocationPtr) {
return isUsedByHeapUserSpace(aAllocationPtr + 8);
}

final int theCurrentStart = theCurrent;
if (theOwningStart != theCurrentStart) {
final int theSize = Address.getIntValue(theCurrent, 0) - 8;
int thePosition = 8;
while(thePosition < theSize) {
final int theReference = Address.getIntValue(theCurrent, thePosition);
if (theReference == theOwningData) {
public static boolean isUsedByHeapUserSpace(final int aPtrToObject) {
final int theAllocationStart = aPtrToObject - 8;
int theCurrent = Address.getIntValue(8, 0);
while(theCurrent != 0) {
// Ignore self reference
if (theAllocationStart != theCurrent) {
final int theSize = Address.getIntValue(theCurrent, 0);
for (int i = 8; i < theSize; i += 4) {
if (Address.getIntValue(theCurrent, i) == aPtrToObject) {
return true;
}
thePosition += 4;
}
}

final int theNext = Address.getIntValue(theCurrent, 4);
theCurrent = theNext;
theCurrent = Address.getIntValue(theCurrent, 4);
}

return false;
}

@Export("GC")
public static void GC() {
final int theUsedStart = 8;

final int theUsedStartPtr = Address.getIntValue(theUsedStart, 0);
int theCurrent = theUsedStartPtr;
int theCurrent = Address.getIntValue(8, 0);
while(theCurrent != 0) {

final int theNext = Address.getIntValue(theCurrent, 4);

if (!isUsed(theCurrent)) {
if (!isUsedByHeap(theCurrent) && !isUsedByStack(theCurrent)) {
internalFree(theCurrent);
}

Expand All @@ -320,4 +279,53 @@ public static int newArray(final int aSize1, final int aSize2, final int aType,
}
return theResult;
}

public static int indexInAllocationList(final int aObjectPtr) {
final int theAllocation = aObjectPtr - 8;

final int theFreeStartPtr = Address.getIntValue(8, 0);

int theCurrent = theFreeStartPtr;
int index = 0;
while (theCurrent != 0) {
if (theCurrent == theAllocation) {
return index;
}
index++;
theCurrent = Address.getIntValue(theCurrent, 4);
}
return -1;
}

public static int indexInFreeList(final int aObjectPtr) {
final int theAllocation = aObjectPtr - 8;

final int theFreeStartPtr = Address.getIntValue(4, 0);

int theCurrent = theFreeStartPtr;
int index = 0;
while (theCurrent != 0) {
if (theCurrent == theAllocation) {
return index;
}
index++;
theCurrent = Address.getIntValue(theCurrent, 4);
}
return -1;
}

public static void printObjectDebug(final Object o) {
final int ptr = Address.ptrOf(o);
final int indexAllocation = indexInAllocationList(ptr);
final int indexFree = indexInFreeList(ptr);
final boolean usedByStack = isUsedByStackUserSpace(ptr);
final boolean usedByHeap = isUsedByHeapUserSpace(ptr);
printObjectDebugInternal(o, indexAllocation,
indexFree,
usedByStack,
usedByHeap);
}

public static native void printObjectDebugInternal(final Object o, int indexAlloc, int indexFree,
boolean usedByStack, boolean usedByHeap);
}
Original file line number Diff line number Diff line change
Expand Up @@ -1589,7 +1589,24 @@ public Function resolveCallsiteBootstrapFor(final BytecodeClass owningClass, fin
theWriter.println(" memorymanager: {");
theWriter.println(" logExceptionTextString : function(thisref, p1) {");
theWriter.println(" console.log('Exception with message : ' + bytecoder.toJSString(p1));");
theWriter.println(" },");

theWriter.println(" printObjectDebugInternalObjectINTINTBOOLEANBOOLEAN: function(thisref, ptr, indexAlloc, indexFree, usedByStack, usedByHeap) {");
theWriter.println(" console.log('Memory debug for ' + ptr);");
theWriter.println(" var theAllocatedBlock = ptr - 8;");
theWriter.println(" var theSize = bytecoder.intInMemory(theAllocatedBlock);");
theWriter.println(" var theNext = bytecoder.intInMemory(theAllocatedBlock + 4);");
theWriter.println(" console.log(' Allocation starts at '+ theAllocatedBlock);");
theWriter.println(" console.log(' Size = ' + theSize + ', Next = ' + theNext);");
theWriter.println(" console.log(' Index in allocation list : ' + indexAlloc);");
theWriter.println(" console.log(' Index in free list : ' + indexFree);");
theWriter.println(" console.log(' Used by STACK : ' + usedByStack);");
theWriter.println(" console.log(' Used by HEAP : ' + usedByHeap);");
theWriter.println(" for (var i=0;i<theSize;i+=4) {");
theWriter.println(" console.log(' Memory offset +' + i + ' = ' + bytecoder.intInMemory( theAllocatedBlock + i));");
theWriter.println(" }");
theWriter.println(" }");

theWriter.println(" },");
theWriter.println(" opaquearrays : {");
theWriter.println(" createIntArrayINT: function(thisref, p1) {");
Expand Down Expand Up @@ -1644,14 +1661,6 @@ public Function resolveCallsiteBootstrapFor(final BytecodeClass owningClass, fin
theWriter.println(" sqrtDOUBLE: function(thisref, p1) {return Math.sqrt(p1);},");
theWriter.println(" atan2DOUBLEDOUBLE: function(thisref, p1) {return Math.sqrt(p1);},");
theWriter.println(" },");
theWriter.println(" profiler: {");
theWriter.println(" logMemoryLayoutBlock: function(aCaller, aStart, aUsed, aNext) {");
theWriter.println(" if (aUsed == 1) return;");
theWriter.println(" console.log(' Block at ' + aStart + ' status is ' + aUsed + ' points to ' + aNext);");
theWriter.println(" console.log(' Block size is ' + bytecoder.intInMemory(aStart));");
theWriter.println(" console.log(' Object type ' + bytecoder.intInMemory(aStart + 12));");
theWriter.println(" },");
theWriter.println(" },");
theWriter.println(" runtime: {");
theWriter.println(" nativewindow: function(caller) {return bytecoder.toBytecoderReference(window);},");
theWriter.println(" nativeconsole: function(caller) {return bytecoder.toBytecoderReference(console);},");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
import de.mirkosertic.bytecoder.ssa.NullValue;
import de.mirkosertic.bytecoder.ssa.PHIValue;
import de.mirkosertic.bytecoder.ssa.Program;
import de.mirkosertic.bytecoder.ssa.PtrOfExpression;
import de.mirkosertic.bytecoder.ssa.PutFieldExpression;
import de.mirkosertic.bytecoder.ssa.PutStaticExpression;
import de.mirkosertic.bytecoder.ssa.RegionNode;
Expand Down Expand Up @@ -803,9 +804,16 @@ private WASMValue toValue(final Value aValue) {
if (aValue instanceof NewInstanceFromDefaultConstructorExpression) {
return newInstanceFromDefaultConstructor((NewInstanceFromDefaultConstructorExpression) aValue);
}
if (aValue instanceof PtrOfExpression) {
return ptrOfExpression((PtrOfExpression) aValue);
}
throw new IllegalStateException("Not supported : " + aValue);
}

private WASMValue ptrOfExpression(final PtrOfExpression aValue) {
return toValue(aValue.incomingDataFlows().get(0));
}

private WASMValue newInstanceFromDefaultConstructor(final NewInstanceFromDefaultConstructorExpression aValue) {
final Value theClassRef = aValue.incomingDataFlows().get(0);
return call(weakFunctionReference(NEWINSTANCEHELPER, null), Collections.singletonList(toValue(theClassRef)), null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@
import de.mirkosertic.bytecoder.classlib.Address;
import de.mirkosertic.bytecoder.core.BytecodeInstructionINVOKESTATIC;
import de.mirkosertic.bytecoder.core.BytecodeObjectTypeRef;
import de.mirkosertic.bytecoder.ssa.*;
import de.mirkosertic.bytecoder.ssa.ComputedMemoryLocationReadExpression;
import de.mirkosertic.bytecoder.ssa.ComputedMemoryLocationWriteExpression;
import de.mirkosertic.bytecoder.ssa.MemorySizeExpression;
import de.mirkosertic.bytecoder.ssa.ParsingHelper;
import de.mirkosertic.bytecoder.ssa.Program;
import de.mirkosertic.bytecoder.ssa.PtrOfExpression;
import de.mirkosertic.bytecoder.ssa.RegionNode;
import de.mirkosertic.bytecoder.ssa.SetMemoryLocationExpression;
import de.mirkosertic.bytecoder.ssa.StackTopExpression;
import de.mirkosertic.bytecoder.ssa.UnreachableExpression;
import de.mirkosertic.bytecoder.ssa.Value;

import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -63,6 +73,12 @@ public boolean intrinsify(final Program aProgram, final BytecodeInstructionINVOK
aTargetBlock.getExpressions().add(new UnreachableExpression(aProgram, aInstruction.getOpcodeAddress()));
return true;
}
case "ptrOf": {
final Value theTarget = aArguments.get(0);

aHelper.push(aInstruction.getOpcodeAddress(), new PtrOfExpression(aProgram, aInstruction.getOpcodeAddress(), theTarget));
return true;
}
default:
throw new IllegalStateException("Not implemented : " + aMethodName);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright 2019 Mirko Sertic
*
* 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 de.mirkosertic.bytecoder.ssa;

import de.mirkosertic.bytecoder.core.BytecodeOpcodeAddress;

public class PtrOfExpression extends Expression {

public PtrOfExpression(final Program aProgram, final BytecodeOpcodeAddress address, final Value aValue) {
super(aProgram, address);
receivesDataFrom(aValue);
}

@Override
public TypeRef resolveType() {
return incomingDataFlows().get(0).resolveType();
}
}
Loading

0 comments on commit f1578ba

Please sign in to comment.