Skip to content
Merged
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 64 additions & 18 deletions src/org/sosy_lab/java_smt/solvers/z3/Z3FormulaCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@
import com.microsoft.z3.enumerations.Z3_sort_kind;
import com.microsoft.z3.enumerations.Z3_symbol_kind;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -120,8 +118,7 @@ class Z3FormulaCreator extends FormulaCreator<Long, Long, Long, Long> {
/** Automatic clean-up of Z3 ASTs. */
private final ReferenceQueue<Z3Formula> referenceQueue = new ReferenceQueue<>();

private final IdentityHashMap<PhantomReference<? extends Z3Formula>, Long> referenceMap =
new IdentityHashMap<>();
private final Z3AstReference referenceListHead;

// todo: getters for statistic.
private final Timer cleanupTimer = new Timer();
Expand All @@ -141,6 +138,18 @@ class Z3FormulaCreator extends FormulaCreator<Long, Long, Long, Long> {
super(pEnv, pBoolType, pIntegerType, pRealType, pStringType, pRegexType);
shutdownNotifier = pShutdownNotifier;
config.inject(this);

if (usePhantomReferences) {
// Setup sentinel nodes for doubly-linked phantom reference list.
Z3AstReference head = new Z3AstReference();
Z3AstReference tail = new Z3AstReference();
head.next = tail;
tail.prev = head;
referenceListHead = head;
} else {
referenceListHead = null;
}

}

final Z3Exception handleZ3Exception(Z3Exception e) throws Z3Exception, InterruptedException {
Expand Down Expand Up @@ -259,14 +268,6 @@ protected <TD extends Formula, TR extends Formula> ArrayFormula<TD, TR> encapsul
new Z3ArrayFormula<>(getEnv(), pTerm, pIndexType, pElementType), pTerm);
}

private <T extends Z3Formula> T storePhantomReference(T out, Long pTerm) {
if (usePhantomReferences) {
PhantomReference<T> ref = new PhantomReference<>(out, referenceQueue);
referenceMap.put(ref, pTerm);
}
return out;
}

@SuppressWarnings("unchecked")
@Override
public <T extends Formula> T encapsulate(FormulaType<T> pType, Long pTerm) {
Expand Down Expand Up @@ -386,16 +387,53 @@ public Long getFloatingPointType(FormulaType.FloatingPointType type) {
return fpSort;
}

private static final class Z3AstReference extends PhantomReference<Z3Formula> {
private final long z3Ast;
private @Nullable Z3AstReference prev;
private @Nullable Z3AstReference next;

// To generate dummy head and tail nodes
private Z3AstReference() {
this(null, null, 0);
}

private Z3AstReference(Z3Formula referent, ReferenceQueue<? super Z3Formula> q, long z3Ast) {
super(referent, q);
this.z3Ast = z3Ast;
}

private void insert(Z3AstReference ref) {
assert next != null;
ref.prev = this;
ref.next = this.next;
ref.next.prev = ref;
this.next = ref;
}

private void cleanup(long environment) {
Native.decRef(environment, z3Ast);
assert (prev != null && next != null);
prev.next = next;
next.prev = prev;
}
}

private <T extends Z3Formula> T storePhantomReference(T out, long pTerm) {
if (usePhantomReferences) {
referenceListHead.insert(new Z3AstReference(out, referenceQueue, pTerm));
}
return out;
}

private void cleanupReferences() {
if (!usePhantomReferences) {
return;
}
cleanupTimer.start();
try {
Reference<? extends Z3Formula> ref;
while ((ref = referenceQueue.poll()) != null) {
long z3ast = referenceMap.remove(ref);
Native.decRef(environment, z3ast);
Z3AstReference ref;
while ((ref = (Z3AstReference) referenceQueue.poll()) != null) {
ref.cleanup(environment);
}
} finally {
cleanupTimer.stop();
Expand Down Expand Up @@ -931,8 +969,16 @@ public void forceClose() {

// Force clean all ASTs, even those which were not GC'd yet.
// Is a no-op if phantom reference handling is not enabled.
Comment thread
ThomasHaas marked this conversation as resolved.
Outdated
for (long ast : referenceMap.values()) {
Native.decRef(getEnv(), ast);
if (usePhantomReferences) {
Z3AstReference cur = referenceListHead.next;
assert cur != null;
while (cur.next != null) {
Native.decRef(environment, cur.z3Ast);
Comment thread
ThomasHaas marked this conversation as resolved.
}
Z3AstReference tail = cur;
// Bulk delete everything between head and tail
referenceListHead.next = tail;
tail.prev = referenceListHead;
Comment thread
PhilippWendler marked this conversation as resolved.
}
}

Expand Down