romainguy / kotlin-explorer

Desktop tool to quickly explore disassembled Kotlin code.
Apache License 2.0
782 stars 23 forks source link

ByteCode Parser Crashes #45

Closed alonalbert closed 4 months ago

alonalbert commented 4 months ago

Exception:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
    at java.base/java.util.Collections$SingletonList.get(Collections.java:4959)
    at dev.romainguy.kotlin.explorer.bytecode.ByteCodeParser.readInstructions(ByteCodeParser.kt:92)
    at dev.romainguy.kotlin.explorer.bytecode.ByteCodeParser.readMethod(ByteCodeParser.kt:79)
    at dev.romainguy.kotlin.explorer.bytecode.ByteCodeParser.readClass(ByteCodeParser.kt:65)
    at dev.romainguy.kotlin.explorer.bytecode.ByteCodeParser.parse(ByteCodeParser.kt:53)
    at dev.romainguy.kotlin.explorer.DisassemblyKt$buildAndDisassemble$2$1$4.invokeSuspend(Disassembly.kt:137)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:111)
    at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:99)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:585)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:802)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:706)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:693)

Code:

inline fun Int.uncheckedCoerceIn(minimumValue: Int, maximumValue: Int) =
    this.coerceAtLeast(minimumValue).coerceAtMost(maximumValue)

inline fun Rect(l: Int, t: Int, r: Int, b: Int) =
    Rect((
        ((l.uncheckedCoerceIn(0, 8) and 0xf) shl 12) or
        ((t.uncheckedCoerceIn(0, 8) and 0xf) shl  8) or
        ((r.uncheckedCoerceIn(0, 8) and 0xf) shl  4) or
        ((b.uncheckedCoerceIn(0, 8) and 0xf)       )
    ).toShort())

@JvmInline
value class Rect @PublishedApi internal constructor(@PublishedApi internal val points: Short) {
    inline val l: Int get() = points.toInt() ushr 12
    inline val t: Int get() = (points.toInt() shr 8) and 0xf
    inline val r: Int get() = (points.toInt() shr 4) and 0xf
    inline val b: Int get() = points.toInt() and 0xf

    override fun toString() = "Rect($l, $t, $r, $b)"
}

inline fun Grid() = Grid(0L)
inline fun Grid(r: Rect) = Grid(rasterize(r.l, r.t, r.r, r.b))
inline fun Grid(l: Int, t: Int, r: Int, b: Int) = Grid(rasterize(l, t, r, b))

@JvmInline
value class Grid @PublishedApi internal constructor(@PublishedApi internal val cells: Long) {
    inline fun forEach(block: (Int, Int) -> Unit) {
        var v = cells
        while (v.hasNext()) {
            val index = v.get()
            block(index and 0x7, index ushr 3)
            v = v.next()
        }
    }

    inline operator fun get(x: Int, y: Int) =
        ((cells ushr ((7 - y) shl 3)) and (0x1L shl (7 - x))) != 0L

    inline operator fun plus(r: Rect) =
        Grid(cells or rasterize(r.l, r.t, r.r, r.b))

    inline operator fun minus(r: Rect) =
        Grid(cells and rasterize(r.l, r.t, r.r, r.b).inv())

    inline infix fun and(r: Rect) =
        Grid(cells and rasterize(r.l, r.t, r.r, r.b))

    inline fun intersects(r: Rect) =
        (cells and rasterize(r.l, r.t, r.r, r.b)) != 0L

    override fun toString() = buildString {
        for (y in 0..7) {
            val line = (cells ushr (56 - y shl 3) and 0xffL).toString(2).padStart(8, '0')
            appendLine(line)
        }
    }
}

@PublishedApi
internal inline fun Long.get() = 63 - countTrailingZeroBits()

@PublishedApi
internal inline fun Long.hasNext() = this != 0L
@PublishedApi
internal inline fun Long.next() = this and (this - 1L)

@PublishedApi
internal fun rasterize(l: Int, t: Int, r: Int, b: Int): Long {
    val w = r - l
    val h = b - t
    val scanline = 0xffL ushr (8 - w) shl (8 - r)
    val rows = 0x01_01_01_01_01_01_01_01L ushr ((8 - h) shl 3) shl ((8 - b) shl 3)
    return rows * scanline
}

fun main() {
    val grid = Grid(1, 1, 5, 5)
    println(grid)
}