FIR2IR: Rework resulted overridden-relation structure

The difference is how we deal with intermediate fake overrides
E.g., in case

interface A { /* $1 */ fun foo() }
interface B : A {
     /* $2 */ fake_override fun foo()
}
interface C : B {
   /* $3 */ override fun foo()
}

We've got FIR declarations only for $1 and $3, but we've got
a fake override for $2 in IR.

Previously, override $3 had $1 as its overridden IR symbol, just because
FIR declaration of $3 doesn't know anything about $2.

Now, when generating IR for $2, we save the necessary information
and using it for $3, so it has $2 as overridden.

So, it's consistent with the overridden structure of FE 1.0 and this
structure is necessary prerequisite for proper building of bridges
for special built-ins.
This commit is contained in:
Denis.Zharkov
2021-02-18 09:53:54 +03:00
parent fd146e3eed
commit a750d9466e
24 changed files with 389 additions and 69 deletions
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: STDLIB_COLLECTIONS
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
import java.util.AbstractMap
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: STDLIB_COLLECTIONS
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: NATIVE
class A : HashSet<Long>()
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: STDLIB_COLLECTIONS
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: NATIVE
class A : HashMap<String, Double>()
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: STDLIB_COLLECTIONS
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: NATIVE
class A : HashSet<Long>()
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// WITH_RUNTIME
@@ -1,5 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
abstract class AbstractAdd {
abstract fun add(s: String): Any
}
@@ -23,4 +21,4 @@ fun test2(a: AbstractStringCollection) =
a.add("K") as String
fun box() =
test1(StringCollection()) + test2(StringCollection())
test1(StringCollection()) + test2(StringCollection())
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
// WITH_RUNTIME
// FILE: javaCollectionWithRemovePrimitiveInt.kt
@@ -1,6 +1,5 @@
// DONT_TARGET_EXACT_BACKEND: WASM
// WASM_MUTE_REASON: STDLIB_COLLECTIONS
// IGNORE_BACKEND_FIR: JVM_IR
// KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: NATIVE
@@ -0,0 +1,131 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// binary representation of fractional part of phi = (sqrt(5) - 1) / 2
private const val MAGIC: Int = 0x9E3779B9L.toInt() // ((sqrt(5.0) - 1) / 2 * pow(2.0, 32.0)).toLong().toString(16)
private const val MAX_SHIFT = 27
private const val THRESHOLD = ((1L shl 31) - 1).toInt() // 50% fill factor for speed
private val EMPTY_ARRAY = arrayOf<Any?>()
// For more details see for Knuth's multiplicative hash with golden ratio
// Shortly, we're trying to keep distribution of it uniform independently of input
// It's necessary because we use very simple linear probing
@Suppress("NOTHING_TO_INLINE")
private inline fun Any.computeHash(shift: Int) = ((hashCode() * MAGIC) ushr shift) shl 1
internal class OpenAddressLinearProbingHashTable<K : Any, V : Any> : AbstractMutableMap<K, V>() {
// fields be initialized later in `clear()`
// capacity = 1 << (32 - shift)
private var shift = 0
// keys are stored in even elements, values are in odd ones
private var array = EMPTY_ARRAY
private var size_ = 0
init {
clear()
}
override val size
get() = size_
override fun get(key: K): V? {
var i = key.computeHash(shift)
var k = array[i]
while (true) {
if (k === null) return null
@Suppress("UNCHECKED_CAST")
if (k == key) return array[i + 1] as V
if (i == 0) {
i = array.size
}
i -= 2
k = array[i]
}
}
/**
* Never returns previous values
*/
override fun put(key: K, value: V): V? {
if (put(array, shift, key, value)) {
if (++size_ >= (THRESHOLD ushr shift)) {
rehash()
}
}
return null
}
private fun rehash() {
val newShift = maxOf(shift - 3, 0)
val newArraySize = 1 shl (33 - newShift)
val newArray = arrayOfNulls<Any>(newArraySize)
var i = 0
val arraySize = array.size
while (i < arraySize) {
val key = array[i]
if (key != null) {
put(newArray, newShift, key, array[i + 1])
}
i += 2
}
shift = newShift
array = newArray
}
override fun clear() {
shift = MAX_SHIFT
array = arrayOfNulls(1 shl (33 - shift))
size_ = 0
}
override val entries: MutableSet<MutableMap.MutableEntry<K, V>>
get() {
throw IllegalStateException("OpenAddressLinearProbingHashTable::entries is not supported and hardly will be")
}
private class Entry<K, V>(override val key: K, override val value: V) : MutableMap.MutableEntry<K, V> {
override fun setValue(newValue: V): V = throw UnsupportedOperationException("This Entry is not mutable.")
}
companion object {
// Change to "true" to be able to see the contents of the map in debugger views
private const val DEBUG = false
}
}
private fun put(array: Array<Any?>, aShift: Int, key: Any, value: Any?): Boolean {
var i = key.computeHash(aShift)
while (true) {
val k = array[i]
if (k == null) {
array[i] = key
array[i + 1] = value
return true
}
if (k == key) break
if (i == 0) {
i = array.size
}
i -= 2
}
array[i + 1] = value
return false
}
fun box(): String {
val map = OpenAddressLinearProbingHashTable<String, String>()
map.put("O", "K")
return "O" + map["O"]
}
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM
// IGNORE_BACKEND_FIR: JVM_IR
import java.util.AbstractMap
@@ -1,5 +1,4 @@
// !JVM_DEFAULT_MODE: disable
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// First item on Android is `java.lang.Thread.getStackTrace`
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
abstract class A3<W> : java.util.AbstractList<W>()
abstract class A4<W> : java.util.AbstractList<W>() {
override fun contains(o: W): Boolean {
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A {
fun foo() = 42
}
+1 -2
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// JVM_TARGET: 1.8
// WITH_RUNTIME
// FULL_JDK
@@ -38,4 +37,4 @@ class MyMap: TestMap<String, String>()
// JVM_IR_TEMPLATES:
// 1 public bridge getOrDefault\(Ljava/lang/String;Ljava/lang/String;\)Ljava/lang/String;
// 1 public final bridge getOrDefault\(Ljava/lang/Object;Ljava/lang/String;\)Ljava/lang/String;
// 1 public final bridge getOrDefault\(Ljava/lang/Object;Ljava/lang/String;\)Ljava/lang/String;