11package org.usvm.dataflow.ts.infer
22
3- import mu.KotlinLogging
43import org.jacodb.ets.base.EtsArrayAccess
54import org.jacodb.ets.base.EtsAssignStmt
65import org.jacodb.ets.base.EtsBinaryExpr
@@ -22,22 +21,29 @@ import org.jacodb.ets.base.EtsThis
2221import org.jacodb.ets.base.EtsUnaryExpr
2322import org.jacodb.ets.model.EtsClassSignature
2423import org.jacodb.ets.model.EtsMethod
24+ import kotlin.collections.ArrayDeque
2525
26- private val logger = KotlinLogging .logger {}
26+ interface StmtAliasInfo {
27+ fun getAliases (path : AccessPath ): Set <AccessPath >
28+ }
29+
30+ interface MethodAliasInfo {
31+ fun computeAliases (): List <StmtAliasInfo >
32+ }
2733
2834@OptIn(ExperimentalUnsignedTypes ::class )
29- class StmtAliasInfo (
35+ class StmtAliasInfoImpl (
3036 val baseToAlloc : IntArray ,
3137 val allocToFields : Array <ULongArray >,
32- val method : MethodAliasInfo ,
33- ) {
34- companion object {
35- const val NOT_PROCESSED = - 1
36- const val MULTIPLE_EDGE = - 2
38+ val method : MethodAliasInfoImpl ,
39+ ) : StmtAliasInfo {
40+ internal companion object {
41+ internal const val NOT_PROCESSED = - 1
42+ internal const val MULTIPLE_EDGE = - 2
3743
38- const val ELEMENT_ACCESSOR = - 3
44+ internal const val ELEMENT_ACCESSOR = - 3
3945
40- fun merge (first : Int , second : Int ): Int = when {
46+ internal fun merge (first : Int , second : Int ): Int = when {
4147 first == NOT_PROCESSED -> second
4248 second == NOT_PROCESSED -> first
4349 first == MULTIPLE_EDGE -> MULTIPLE_EDGE
@@ -46,19 +52,19 @@ class StmtAliasInfo(
4652 else -> MULTIPLE_EDGE
4753 }
4854
49- fun wrap (string : Int , alloc : Int ): ULong {
55+ internal fun wrap (string : Int , alloc : Int ): ULong {
5056 return (string.toULong() shl Int .SIZE_BITS ) or alloc.toULong()
5157 }
5258
53- fun unwrap (edge : ULong ): Pair <Int , Int > {
59+ internal fun unwrap (edge : ULong ): Pair <Int , Int > {
5460 val string = (edge shr Int .SIZE_BITS ).toInt()
5561 val allocation = (edge and UInt .MAX_VALUE .toULong()).toInt()
5662 return Pair (string, allocation)
5763 }
5864 }
5965
60- fun merge (other : StmtAliasInfo ): StmtAliasInfo {
61- val merged = StmtAliasInfo (
66+ internal fun merge (other : StmtAliasInfoImpl ): StmtAliasInfoImpl {
67+ val merged = StmtAliasInfoImpl (
6268 baseToAlloc = IntArray (method.bases.size) { NOT_PROCESSED },
6369 allocToFields = Array (method.allocations.size) { ulongArrayOf() },
6470 method = method
@@ -71,11 +77,11 @@ class StmtAliasInfo(
7177 val toFieldsMap = mutableMapOf<Int , Int >()
7278 allocToFields[i].forEach {
7379 val (s, a) = unwrap(it)
74- toFieldsMap.merge(s, a, ::merge)
80+ toFieldsMap.merge(s, a, Companion ::merge)
7581 }
7682 other.allocToFields[i].forEach {
7783 val (s, a) = unwrap(it)
78- toFieldsMap.merge(s, a, ::merge)
84+ toFieldsMap.merge(s, a, Companion ::merge)
7985 }
8086 merged.allocToFields[i] = toFieldsMap
8187 .map { (string, alloc) -> wrap(string, alloc) }
@@ -102,10 +108,9 @@ class StmtAliasInfo(
102108 nodes.add(MULTIPLE_EDGE )
103109 strings.add(ELEMENT_ACCESSOR )
104110 }
105-
106111 is FieldAccessor -> {
107112 val string = method.stringMap[accessor.name]
108- ? : error(" Unknown field name: ${accessor.name} " )
113+ ? : error(" Unknown field name" )
109114 strings.add(string)
110115
111116 node = allocToFields[node]
@@ -122,17 +127,17 @@ class StmtAliasInfo(
122127 return Pair (nodes, strings)
123128 }
124129
125- fun assign (lhv : AccessPath , rhv : AccessPath ): StmtAliasInfo {
130+ private fun assign (lhv : AccessPath , rhv : AccessPath ): StmtAliasInfoImpl {
126131 val (rhvNodes, _) = trace(rhv)
127132 val newAlloc = rhvNodes.last()
128133 return assign(lhv, newAlloc)
129134 }
130135
131- fun assign (lhv : AccessPath , newAlloc : Int ): StmtAliasInfo {
136+ private fun assign (lhv : AccessPath , newAlloc : Int ): StmtAliasInfoImpl {
132137 val (lhvNodes, lhvEdges) = trace(lhv)
133138 val from = lhvNodes.reversed().getOrNull(1 )
134139 if (from != null ) {
135- val updated = StmtAliasInfo (
140+ val updated = StmtAliasInfoImpl (
136141 baseToAlloc = baseToAlloc,
137142 allocToFields = allocToFields.copyOf(),
138143 method = method,
@@ -155,7 +160,7 @@ class StmtAliasInfo(
155160
156161 return updated
157162 } else {
158- val updated = StmtAliasInfo (
163+ val updated = StmtAliasInfoImpl (
159164 baseToAlloc = baseToAlloc.copyOf(),
160165 allocToFields = allocToFields,
161166 method = method,
@@ -169,66 +174,58 @@ class StmtAliasInfo(
169174 }
170175 }
171176
172- fun applyStmt (stmt : EtsStmt ): StmtAliasInfo ? {
177+ internal fun applyStmt (stmt : EtsStmt ): StmtAliasInfoImpl {
173178 if (stmt !is EtsAssignStmt ) {
174179 return this
175180 }
176181 when (val rhv = stmt.rhv) {
177182 is EtsParameterRef -> {
178- val alloc = method.allocationMap[MethodAliasInfo .Allocation .Arg (rhv.index)]
179- ? : error(" Unknown parameter ref in stmt: $stmt " )
183+ val alloc = method.allocationMap[MethodAliasInfoImpl .Allocation .Arg (rhv.index)]
184+ ? : error(" Unknown parameter ref" )
180185 return assign(stmt.lhv.toPath(), alloc)
181186 }
182-
183187 is EtsThis -> {
184- val alloc = method.allocationMap[MethodAliasInfo .Allocation .This ]
185- ? : error(" Unknown this in stmt: $stmt " )
188+ val alloc = method.allocationMap[MethodAliasInfoImpl .Allocation .This ]
189+ ? : error(" Uninitialized this" )
186190 return assign(stmt.lhv.toPath(), alloc)
187191 }
188-
189192 is EtsInstanceFieldRef , is EtsStaticFieldRef -> {
190193 val (rhvNodes, _) = trace(rhv.toPath())
191194 val alloc = rhvNodes.last()
192195 if (alloc == NOT_PROCESSED ) {
193- val fieldAlloc = method.allocationMap[MethodAliasInfo .Allocation .Imm (stmt)]
194- ? : error(" Unknown allocation in stmt: $stmt " )
196+ val fieldAlloc = method.allocationMap[MethodAliasInfoImpl .Allocation .Imm (stmt)]
197+ ? : error(" Unknown allocation" )
198+
195199 return this
196200 .assign(rhv.toPath(), fieldAlloc)
197201 .assign(stmt.lhv.toPath(), fieldAlloc)
198202 } else {
199203 return assign(stmt.lhv.toPath(), alloc)
200204 }
201205 }
202-
203206 is EtsLocal -> {
204207 return assign(stmt.lhv.toPath(), rhv.toPath())
205208 }
206-
207209 is EtsCastExpr -> {
208210 return assign(stmt.lhv.toPath(), rhv.arg.toPath())
209211 }
210-
211212 is EtsConstant , is EtsUnaryExpr , is EtsBinaryExpr , is EtsArrayAccess , is EtsInstanceOfExpr -> {
212- val imm = method.allocationMap[MethodAliasInfo .Allocation .Expr (stmt)]
213- ? : error(" Unknown expr in stmt: $stmt " )
213+ val imm = method.allocationMap[MethodAliasInfoImpl .Allocation .Expr (stmt)]
214+ ? : error(" Unknown constant " )
214215 return assign(stmt.lhv.toPath(), imm)
215216 }
216-
217217 is EtsCallExpr -> {
218- val callResult = method.allocationMap[MethodAliasInfo .Allocation .CallResult (stmt)]
219- ? : error(" Unknown call in stmt: $stmt " )
218+ val callResult = method.allocationMap[MethodAliasInfoImpl .Allocation .CallResult (stmt)]
219+ ? : error(" Unknown call" )
220220 return assign(stmt.lhv.toPath(), callResult)
221221 }
222-
223222 is EtsNewExpr , is EtsNewArrayExpr -> {
224- val new = method.allocationMap[MethodAliasInfo .Allocation .New (stmt)]
225- ? : error(" Unknown new in stmt: $stmt " )
223+ val new = method.allocationMap[MethodAliasInfoImpl .Allocation .New (stmt)]
224+ ? : error(" Unknown new" )
226225 return assign(stmt.lhv.toPath(), new)
227226 }
228-
229227 else -> {
230- logger.warn(" Could not process rhs in stmt: $stmt " )
231- return null
228+ error(" Unprocessable" )
232229 }
233230 }
234231 }
@@ -267,7 +264,7 @@ class StmtAliasInfo(
267264 get() = edge?.first
268265
269266 fun traceContains (other : Int ): Boolean =
270- alloc == other || (parent?.traceContains(other) == true )
267+ alloc == other || (parent?.traceContains(other) ? : false )
271268 }
272269
273270 private fun accessors (node : PathNode ): List <Accessor > {
@@ -285,7 +282,7 @@ class StmtAliasInfo(
285282 return accessors
286283 }
287284
288- fun getAliases (path : AccessPath ): Set <AccessPath > {
285+ override fun getAliases (path : AccessPath ): Set <AccessPath > {
289286 val alloc = trace(path).first.last()
290287 if (alloc == NOT_PROCESSED || alloc == MULTIPLE_EDGE ) {
291288 return setOf (path)
@@ -319,9 +316,9 @@ class StmtAliasInfo(
319316 }
320317}
321318
322- class MethodAliasInfo (
319+ class MethodAliasInfoImpl (
323320 val method : EtsMethod ,
324- ) {
321+ ) : MethodAliasInfo {
325322 sealed interface Allocation {
326323 data class New (val stmt : EtsStmt ) : Allocation
327324 data class CallResult (val stmt : EtsStmt ) : Allocation
@@ -341,7 +338,7 @@ class MethodAliasInfo(
341338 val baseMap = mutableMapOf<AccessPathBase , Int >()
342339 val bases = mutableListOf<AccessPathBase >()
343340
344- fun newString (str : String ) {
341+ private fun newString (str : String ) {
345342 stringMap.computeIfAbsent(str) {
346343 strings.add(str)
347344 stringMap.size
@@ -365,22 +362,16 @@ class MethodAliasInfo(
365362 is AccessPathBase .Local -> {
366363 newString(base.name)
367364 }
368-
369365 is AccessPathBase .This -> {
370366 newAllocation(Allocation .This )
371367 }
372-
373368 is AccessPathBase .Arg -> {
374369 newAllocation(Allocation .Arg (base.index))
375370 }
376-
377371 is AccessPathBase .Static -> {
378372 newAllocation(Allocation .Static (base.clazz))
379373 }
380-
381- is AccessPathBase .Const -> {
382- // TODO ?? may be some non-trivial
383- }
374+ is AccessPathBase .Const -> { /* TODO ?? may be some non-trivial */ }
384375 }
385376 }
386377
@@ -390,25 +381,20 @@ class MethodAliasInfo(
390381 initEntity(entity.instance)
391382 newString(entity.field.name)
392383 }
393-
394384 is EtsStaticFieldRef -> {
395385 newBase(AccessPathBase .Static (entity.field.enclosingClass))
396386 newString(entity.field.name)
397387 }
398-
399388 is EtsArrayAccess -> {
400389 initEntity(entity.array)
401390 initEntity(entity.index)
402391 }
403-
404392 is EtsLocal -> {
405393 newBase(AccessPathBase .Local (entity.name))
406394 }
407-
408395 is EtsParameterRef -> {
409396 newBase(AccessPathBase .Arg (entity.index))
410397 }
411-
412398 is EtsInstanceCallExpr -> {
413399 initEntity(entity.instance)
414400 newString(entity.method.name)
@@ -437,21 +423,16 @@ class MethodAliasInfo(
437423 is EtsNewExpr , is EtsNewArrayExpr -> {
438424 newAllocation(Allocation .New (stmt))
439425 }
440-
441426 is EtsParameterRef -> {
442427 newAllocation(Allocation .Arg (rhv.index))
443428 }
444-
445429 is EtsCallExpr -> {
446430 newAllocation(Allocation .CallResult (stmt))
447431 }
448-
449432 is EtsInstanceFieldRef , is EtsStaticFieldRef -> {
450433 newAllocation(Allocation .Imm (stmt))
451434 }
452-
453435 is EtsCastExpr -> {}
454-
455436 is EtsConstant , is EtsUnaryExpr , is EtsBinaryExpr , is EtsArrayAccess , is EtsInstanceOfExpr -> {
456437 newAllocation(Allocation .Expr (stmt))
457438 }
@@ -469,11 +450,11 @@ class MethodAliasInfo(
469450 initMaps()
470451 }
471452
472- private val preAliases: MutableMap <EtsStmt , StmtAliasInfo > = hashMapOf ()
453+ private val preAliases = mutableMapOf <EtsStmt , StmtAliasInfoImpl > ()
473454
474455 @OptIn(ExperimentalUnsignedTypes ::class )
475456 @Suppress(" UNCHECKED_CAST" )
476- fun computeAliases (): List <StmtAliasInfo > {
457+ override fun computeAliases (): List <StmtAliasInfo > {
477458 val visited: MutableSet <EtsStmt > = hashSetOf()
478459 val order: MutableList <EtsStmt > = mutableListOf ()
479460 val preds: MutableMap <EtsStmt , MutableList <EtsStmt >> = hashMapOf()
@@ -494,14 +475,14 @@ class MethodAliasInfo(
494475 postOrderDfs(root)
495476 order.reverse()
496477
497- fun computePreAliases (stmt : EtsStmt ): StmtAliasInfo {
478+ fun computePreAliases (stmt : EtsStmt ): StmtAliasInfoImpl {
498479 if (stmt in preAliases) return preAliases.getValue(stmt)
499480
500481 val merged = preds[stmt]
501- ?.mapNotNull { preAliases.getValue(it).applyStmt(it) }
482+ ?.map { preAliases.getValue(it).applyStmt(it) }
502483 ?.reduceOrNull { a, b -> a.merge(b) }
503- ? : StmtAliasInfo (
504- baseToAlloc = IntArray (bases.size) { StmtAliasInfo .NOT_PROCESSED },
484+ ? : StmtAliasInfoImpl (
485+ baseToAlloc = IntArray (bases.size) { StmtAliasInfoImpl .NOT_PROCESSED },
505486 allocToFields = Array (allocations.size) { ulongArrayOf() },
506487 method = this
507488 )
@@ -510,12 +491,24 @@ class MethodAliasInfo(
510491 return merged
511492 }
512493
513- val aliases = Array <StmtAliasInfo ?>(method.cfg.stmts.size) { null }
494+ val aliases = Array <StmtAliasInfoImpl ?>(method.cfg.stmts.size) { null }
514495 for (stmt in order) {
515496 aliases[stmt.location.index] = computePreAliases(stmt)
516497 }
517498
518499 assert (! aliases.contains(null ))
519- return (aliases as Array <StmtAliasInfo >).toList()
500+ return (aliases as Array <StmtAliasInfoImpl >).toList()
501+ }
502+ }
503+
504+ object NoStmtAliasInfo : StmtAliasInfo {
505+ override fun getAliases (path : AccessPath ): Set <AccessPath > {
506+ return setOf (path)
507+ }
508+ }
509+
510+ class NoMethodAliasInfo (val method : EtsMethod ) : MethodAliasInfo {
511+ override fun computeAliases (): List <StmtAliasInfo > {
512+ return method.cfg.stmts.map { NoStmtAliasInfo }
520513 }
521514}
0 commit comments