Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Bitwuzla solver support #71

Merged
merged 72 commits into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
2a26cd9
Fp 16 fixes && eval for fp.add
Saloed Jan 25, 2023
f348bea
Fix fp 16
Saloed Jan 27, 2023
878ba3e
KAst structural equality methods
Saloed Jan 17, 2023
28708b9
tmp
Saloed Jan 17, 2023
642d517
KInternedObject
Saloed Jan 18, 2023
1961d8a
Optimizations
Saloed Jan 18, 2023
e328f36
ConcurrentWeakHashMap
Saloed Jan 18, 2023
84806be
Ast interner
Saloed Jan 18, 2023
88cd4eb
remove caffeine
Saloed Jan 18, 2023
d5d3120
Faster cache
Saloed Jan 19, 2023
e39833f
Parametrize ast management modes
Saloed Jan 19, 2023
4c093d9
Single thread weak caches
Saloed Jan 19, 2023
d472ffd
Bv compare
Saloed Jan 31, 2023
80c6f7e
Fix after rebase
Saloed Feb 2, 2023
2517bd8
Comment empty arith add simplified args
Saloed Feb 17, 2023
e723c10
JNA to JNI migration (#69)
DKARAGODIN Feb 6, 2023
3f6d231
Initial native part fix
Saloed Feb 6, 2023
69d26f4
Timeouts
Saloed Feb 6, 2023
006b789
check exception handling
Saloed Feb 7, 2023
f9d5c18
better timeout handling
Saloed Feb 7, 2023
b66c9d4
enable ipo
Saloed Feb 7, 2023
0b29768
Fix default array value handling
Saloed Feb 7, 2023
f54375d
Jni bindings
Saloed Feb 7, 2023
8ee97cc
Fix Native documentation
Saloed Feb 7, 2023
fbd04c3
Enum wrappers
Saloed Feb 7, 2023
4d68757
Cleanup
Saloed Feb 7, 2023
825f3fc
Remove dummy test
Saloed Feb 7, 2023
7361b30
Fix timeout test
Saloed Feb 7, 2023
be4759d
Fix detekt issues
Saloed Feb 7, 2023
bc30f08
Rework unsupported theories for Bitwuzla
Saloed Feb 7, 2023
8ffea7a
Support quantifiers in bitwuzla
Saloed Feb 7, 2023
34f93d2
Fix nested quantifiers conversion
Saloed Feb 7, 2023
8f2c173
Small fixes
Saloed Feb 7, 2023
e0240c1
Better Bitwuzla bv bits api
Saloed Feb 7, 2023
f068d93
New API based converter
Saloed Feb 7, 2023
8c0550d
New API based internalizer
Saloed Feb 7, 2023
df32c30
Update docs
Saloed Feb 7, 2023
8ed1ea2
axioms
Saloed Feb 7, 2023
304feae
Minor
Saloed Feb 8, 2023
8979662
fix bigInt to bits
Saloed Feb 8, 2023
c844f24
fix bigInt to bits
Saloed Feb 8, 2023
bba6a02
Fix fp64 conversion
Saloed Feb 8, 2023
1dc5633
Use KSMT based model evaluation
Saloed Feb 8, 2023
9a5671c
Better model evaluator for partial functions
Saloed Feb 8, 2023
aede677
Fix bv bit utils
Saloed Feb 8, 2023
96cf82b
Better handling of as-array expressions in model evaluator
Saloed Feb 8, 2023
8fbcedf
Fix bit utils
Saloed Feb 8, 2023
1ce7211
Better doc for bits
Saloed Feb 8, 2023
affaf0b
m
Saloed Feb 8, 2023
e8d5c0e
Fix as-array rewrite loops
Saloed Feb 8, 2023
67708ba
Special test data-source for Bitwuzla model conversion
Saloed Feb 8, 2023
f04efda
Fix detekt issues
Saloed Feb 8, 2023
103267f
Ensure bitwuzla ctx is active
Saloed Feb 8, 2023
825dc43
Rebase
Saloed Feb 10, 2023
5aa72de
Skip Z3 fma failures
Saloed Feb 10, 2023
ebec86d
Skip fp max/min with +/- 0
Saloed Feb 10, 2023
a39692e
Fix Z3 fma test issues
Saloed Feb 10, 2023
fc2a859
minor change
Saloed Feb 10, 2023
0118ddc
fix vars management
Saloed Feb 10, 2023
3637e72
Move comment
Saloed Feb 13, 2023
ec7a9dd
Use unsat assumptions instead of core
Saloed Feb 13, 2023
82f0e34
Support for uninterpreted sorts
Saloed Feb 13, 2023
8b2e66e
Rework declaration scoping
Saloed Feb 13, 2023
525574c
Better tests parametrization
Saloed Feb 13, 2023
2854d7d
Fix model detach
Saloed Feb 13, 2023
14f5976
Fix detekt issues
Saloed Feb 13, 2023
a855f76
Minor fix
Saloed Feb 14, 2023
284eda3
Use adapter for uninterpreted sort conversion
Saloed Feb 14, 2023
c83e78f
rebase
Saloed Feb 14, 2023
3597679
Fix pointer formatting
Saloed Feb 17, 2023
e8c95dc
Fixes
Saloed Feb 17, 2023
e73a487
Rebase
Saloed Feb 17, 2023
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
Prev Previous commit
Next Next commit
Ast interner
  • Loading branch information
Saloed committed Feb 17, 2023
commit 84806be4cd93cc227118c8bd6e0f2d4fa36c1a3b
66 changes: 66 additions & 0 deletions ksmt-core/src/main/kotlin/org/ksmt/cache/ConcurrentWeakCache.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.ksmt.cache

import java.lang.ref.Reference
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference

class ConcurrentWeakCache<K : KInternedObject, V : Any> : ConcurrentWeakHashMapCache<K, V>() {
override fun lookupKey(key: K): Any = LookupCacheKey(key)

override fun newNode(key: K, referenceQueue: ReferenceQueue<K>, value: V): KeyRefNode<K, V> {
val keyRef = WeakCacheKey(key, referenceQueue)
return CacheNode(keyRef, value)
}

private class CacheNode<T : KInternedObject, V : Any>(
keyRef: Reference<T>,
private var value: V
) : KeyRefNode<T, V>(keyRef) {

override fun getValue(): V = value

override fun setValue(value: V) {
this.value = value
}
}

private interface CacheKey<K : KInternedObject> {
fun get(): K?
}

private class WeakCacheKey<K : KInternedObject>(
key: K?, queue: ReferenceQueue<K>?
) : WeakReference<K>(key, queue), CacheKey<K> {
private val hashCode: Int = System.identityHashCode(key)

override fun equals(other: Any?): Boolean = when {
other === this -> true
other is CacheKey<*> -> get() === other.get()
else -> false
}

override fun hashCode(): Int = hashCode

override fun toString(): String =
"{key=${get()} hash=$hashCode}"
}

private class LookupCacheKey<K : KInternedObject>(
private val key: K
) : CacheKey<K> {
private val hashCode: Int = System.identityHashCode(key)

override fun get(): K = key

override fun equals(other: Any?): Boolean = when {
other === this -> true
other is CacheKey<*> -> get() === other.get()
else -> false
}

override fun hashCode(): Int = hashCode

override fun toString(): String =
"{key=${get()} hash=$hashCode}"
}
}
Original file line number Diff line number Diff line change
@@ -1,78 +1,84 @@
package org.ksmt.cache

import java.lang.ref.Reference
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.locks.ReentrantLock

abstract class Node<K : Any, V : Any> {
abstract fun getKeyReference(): Any
abstract fun getKey(): K?
abstract fun getValue(): V
abstract fun setValue(value: V)
abstract fun isAlive(): Boolean
abstract fun isDead(): Boolean
abstract fun retire()
abstract fun die()
}
abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
private val data = ConcurrentHashMap<Any, KeyRefNode<K, V>>()
private val keyReferenceQueue = ReferenceQueue<K>()
private val cleanupLock = ReentrantLock()
private val cleanupStatus = AtomicInteger(IDLE)
private var removeHandler: CacheRemoveHandler<K, V>? = null

interface RemoveHandler<K, V> {
fun onRemove(key: K?, value: V)
}
abstract fun lookupKey(key: K): Any

/** A cleanup is not taking place. */
private const val IDLE = 0
abstract fun newNode(key: K, referenceQueue: ReferenceQueue<K>, value: V): KeyRefNode<K, V>

/** A cleanup is required due to write modification. */
private const val REQUIRED = 1
abstract class KeyRefNode<K : Any, V : Any>(keyRef: Reference<K>) {
@Volatile
private var keyReference: Reference<out K> = keyRef

/** A cleanup is in progress and will transition to idle. */
private const val PROCESSING_TO_IDLE = 2
fun getKeyReference(): Any = keyReference

/** A cleanup is in progress and will transition to required. */
private const val PROCESSING_TO_REQUIRED = 3
fun getKey(): K? = keyReference.get()

abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
private val data = ConcurrentHashMap<Any, Node<K, V>>()
private val keyReferenceQueue = ReferenceQueue<K>()
private val cleanupLock = ReentrantLock()
private val cleanupStatus = AtomicInteger(IDLE)
private var removeHandler: RemoveHandler<K, V>? = null

abstract fun lookupKey(key: K): Any
abstract fun getValue(): V
abstract fun setValue(value: V)

fun isAlive(): Boolean {
val keyRef = keyReference
return keyRef !== deadRef && keyRef !== retiredRef
}

fun isDead(): Boolean = keyReference === deadRef

abstract fun newNode(key: K, referenceQueue: ReferenceQueue<K>, value: V): Node<K, V>
fun retire() {
val keyRef = keyReference
keyReference = deadRef
keyRef.clear()
}

fun addRemoveHandler(handler: RemoveHandler<K, V>) {
fun die() {
val keyRef = keyReference
keyReference = retiredRef
keyRef.clear()
}

companion object {
@JvmStatic
private val deadRef: Reference<Nothing> = WeakReference(null)

@JvmStatic
private val retiredRef: Reference<Nothing> = WeakReference(null)
}
}

fun addRemoveHandler(handler: CacheRemoveHandler<K, V>) {
removeHandler = handler
}

fun get(key: K): V? = getNode(key)?.getValue()

fun put(key: K, value: V, onlyIfAbsent: Boolean): V? {
val lookupKey = lookupKey(key)
return putUtil(key, value, onlyIfAbsent, lookupKey)
}
fun put(key: K, value: V, onlyIfAbsent: Boolean): V? = putUtil(key, value, onlyIfAbsent)

fun internKey(key: K, valueStub: V): K {
val lookupKey = lookupKey(key)
return internUtil(key, valueStub, lookupKey)
}
fun internKey(key: K, valueStub: V): K = internUtil(key, valueStub)

private fun getNode(key: K): Node<K, V>? {
private fun getNode(key: K): KeyRefNode<K, V>? {
val lookupKey = lookupKey(key)
val node = data.get(lookupKey)
afterRead()
return node
}

private fun putUtil(
key: K,
value: V,
onlyIfAbsent: Boolean,
lookupKey: Any,
): V? {
var node: Node<K, V>? = null
@Suppress("LoopWithTooManyJumpStatements")
private fun putUtil(key: K, value: V, onlyIfAbsent: Boolean): V? {
var node: KeyRefNode<K, V>? = null
val lookupKey = lookupKey(key)

while (true) {
var current = data.get(lookupKey)
Expand Down Expand Up @@ -126,12 +132,10 @@ abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
}
}

private fun internUtil(
key: K,
value: V,
lookupKey: Any
): K {
var node: Node<K, V>? = null
@Suppress("NestedBlockDepth")
private fun internUtil(key: K, value: V): K {
var node: KeyRefNode<K, V>? = null
val lookupKey = lookupKey(key)

while (true) {
var current = data.get(lookupKey)
Expand Down Expand Up @@ -168,7 +172,7 @@ abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
}
}

private fun updateValueIfAlive(node: Node<K, V>, value: V): V? = synchronized(node) {
private fun updateValueIfAlive(node: KeyRefNode<K, V>, value: V): V? = synchronized(node) {
if (!node.isAlive()) return null
val oldValue = node.getValue()
node.setValue(value)
Expand Down Expand Up @@ -255,7 +259,7 @@ abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
}
}

private fun cleanupEntry(node: Node<K, V>) {
private fun cleanupEntry(node: KeyRefNode<K, V>) {
val keyRef = node.getKeyReference()
val key = node.getKey()
var nodeResurrected = false
Expand Down Expand Up @@ -288,8 +292,22 @@ abstract class ConcurrentWeakHashMapCache<K : Any, V : Any> {
}
}

private fun makeDead(node: Node<K, V>) = synchronized(node) {
private fun makeDead(node: KeyRefNode<K, V>) = synchronized(node) {
if (node.isDead()) return
node.die()
}

companion object {
/** A cleanup is not taking place. */
private const val IDLE = 0

/** A cleanup is required due to write modification. */
private const val REQUIRED = 1

/** A cleanup is in progress and will transition to idle. */
private const val PROCESSING_TO_IDLE = 2

/** A cleanup is in progress and will transition to required. */
private const val PROCESSING_TO_REQUIRED = 3
}
}
69 changes: 69 additions & 0 deletions ksmt-core/src/main/kotlin/org/ksmt/cache/ConcurrentWeakInterner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.ksmt.cache

import java.lang.ref.Reference
import java.lang.ref.ReferenceQueue
import java.lang.ref.WeakReference

class ConcurrentWeakInterner<T : KInternedObject> : ConcurrentWeakHashMapCache<T, Any>() {

fun intern(obj: T): T = internKey(obj, valueStub)

override fun lookupKey(key: T): Any = LookupInternerKey(key)

override fun newNode(key: T, referenceQueue: ReferenceQueue<T>, value: Any): KeyRefNode<T, Any> {
val keyRef = WeakInternerKey(key, referenceQueue)
return InternerNode(keyRef)
}

private class InternerNode<T : KInternedObject>(keyRef: Reference<T>) : KeyRefNode<T, Any>(keyRef) {

override fun getValue(): Any = valueStub

override fun setValue(value: Any) {
}
}

private interface InternerKey<T : KInternedObject> {
fun get(): T?
}

private class WeakInternerKey<T : KInternedObject>(
key: T?, queue: ReferenceQueue<T>?
) : WeakReference<T>(key, queue), InternerKey<T> {
private val hashCode: Int = key?.internHashCode() ?: 0

override fun equals(other: Any?): Boolean = when {
other === this -> true
other is InternerKey<*> -> KInternedObject.objectEquality(get(), other.get())
else -> false
}

override fun hashCode(): Int = hashCode

override fun toString(): String =
"{key=${get()} hash=$hashCode}"
}

private class LookupInternerKey<T : KInternedObject>(
private val key: T
) : InternerKey<T> {
private val hashCode: Int = key.internHashCode()

override fun get(): T = key

override fun equals(other: Any?): Boolean = when {
other === this -> true
other is InternerKey<*> -> KInternedObject.objectEquality(get(), other.get())
else -> false
}

override fun hashCode(): Int = hashCode

override fun toString(): String =
"{key=${get()} hash=$hashCode}"
}

companion object {
private val valueStub = Any()
}
}