Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class JIRLocalAliasAnalysis(
class MethodAliasInfo(
val aliasBeforeStatement: Array<Int2ObjectOpenHashMap<Array<Any>>?>?,
val aliasAfterStatement: Array<Int2ObjectOpenHashMap<Array<Any>>?>?,
val unboundBeforeStatement: Array<Array<Array<Any>>?>?,
)

private fun getLocalVarAliases(
Expand All @@ -46,10 +47,19 @@ class JIRLocalAliasAnalysis(
return getLocalVarAliases(aliasBefore, idx, base)
}

fun getAllAliasAtStatement(statement: CommonInst): Int2ObjectOpenHashMap<List<AliasInfo>> {
val aliasBefore = aliasInfo.aliasBeforeStatement ?: return Int2ObjectOpenHashMap()
fun getAllAliasAtStatement(statement: CommonInst): List<List<AliasInfo>> {
val result = mutableListOf<List<AliasInfo>>()
val idx = languageManager.getInstIndex(statement)
return aliasBefore[idx]?.let { wrapAllInfo(it) } ?: Int2ObjectOpenHashMap()

aliasInfo.aliasBeforeStatement?.let { aliasBefore ->
aliasBefore[idx]?.let { wrapAllInfo(it) }?.let { result.addAll(it.values) }
}

aliasInfo.unboundBeforeStatement?.let { unboundBefore ->
unboundBefore[idx]?.let { aliases -> aliases.map { wrapAliasSet(it) } }?.let { result.addAll(it) }
}

return result
}

fun findAliasAfterStatement(base: AccessPathBase.LocalVar, statement: CommonInst): List<AliasInfo>? {
Expand Down Expand Up @@ -89,21 +99,26 @@ class JIRLocalAliasAnalysis(
fun wrapAllInfo(info: Int2ObjectOpenHashMap<Array<Any>>): Int2ObjectOpenHashMap<List<AliasInfo>> {
val result = Int2ObjectOpenHashMap<List<AliasInfo>>()
for ((key, aliases) in info) {
result.put(key, List(aliases.size) { aliases[it].wrapAliasInfo() })
result.put(key, wrapAliasSet(aliases))
}
return result
}

fun wrapAliasSet(aliases: Array<Any>): List<AliasInfo> =
List(aliases.size) { aliases[it].wrapAliasInfo() }

fun unwrapAllInfo(info: Int2ObjectOpenHashMap<List<AliasInfo>>): Int2ObjectOpenHashMap<Array<Any>> {
val result = Int2ObjectOpenHashMap<Array<Any>>(info.size, 0.99f)
val iter = info.int2ObjectEntrySet().fastIterator()
while (iter.hasNext()) {
val entry = iter.next()
val value = entry.value
val unwrapped = Array(value.size) { value[it].unwrap() }
val unwrapped = unwrapAliasSet(entry.value)
result.put(entry.intKey, unwrapped)
}
return result
}

fun unwrapAliasSet(aliases: List<AliasInfo>): Array<Any> =
Array(aliases.size) { aliases[it].unwrap() }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,9 @@ class DSUAliasAnalysis(

is Stmt.Copy -> evalCopy(stmt, state)

is Stmt.FieldStore -> evalFieldStore(stmt, state)
is Stmt.FieldStore -> evalFieldStore(stmt, callFrame, state)

is Stmt.ArrayStore -> evalArrayStore(stmt, state)
is Stmt.ArrayStore -> evalArrayStore(stmt, callFrame, state)

// no effect on alias info
is Stmt.Return,
Expand Down Expand Up @@ -602,6 +602,23 @@ class DSUAliasAnalysis(
instance: RefValue,
value: ExprOrValue,
state: State,
stmt: Stmt,
callFrame: CallTreeNode,
heapAppender: (Int) -> HeapAlias
): State {
val valueInfo = when (value) {
is Expr -> evalExpr(value, stmt, callFrame, state)
is RefValue -> aliasSetFromInfo(value.aliasInfo())
}

return evalHeapStore(isFieldStore, instance, valueInfo, state, heapAppender)
}

private fun evalHeapStore(
isFieldStore: Boolean,
instance: RefValue,
value: AliasSet,
state: State,
heapAppender: (Int) -> HeapAlias
): State {
val instanceInfo = instance.aliasInfo()
Expand All @@ -614,18 +631,16 @@ class DSUAliasAnalysis(
resultState = resultState.remove(heapAlias)
}

if (value is RefValue) {
resultState = resultState.mergeWith(value.aliasInfo().index(), heapAlias)
}
resultState = resultState.mergeWith(value.repr, heapAlias)

return resultState
}

private fun evalArrayStore(stmt: Stmt.ArrayStore, state: State): State =
evalHeapStore(isFieldStore = false, stmt.instance, stmt.value, state, ::createArrayAlias)
private fun evalArrayStore(stmt: Stmt.ArrayStore, callFrame: CallTreeNode, state: State): State =
evalHeapStore(isFieldStore = false, stmt.instance, stmt.value, state, stmt, callFrame, ::createArrayAlias)

private fun evalFieldStore(stmt: Stmt.FieldStore, state: State): State =
evalHeapStore(isFieldStore = true, stmt.instance, stmt.value, state) { createFieldAlias(it, stmt.field) }
private fun evalFieldStore(stmt: Stmt.FieldStore, callFrame: CallTreeNode, state: State): State =
evalHeapStore(isFieldStore = true, stmt.instance, stmt.value, state, stmt, callFrame) { createFieldAlias(it, stmt.field) }

private fun State.containsMultipleConcreteOrOuterLocations(instance: AAInfo): Boolean =
containsMultipleConcreteOrOuterLocations(instance.index(), IntOpenHashSet())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ class JIRIntraProcAliasAnalysis(

JIRLocalAliasAnalysis.MethodAliasInfo(
aliasBeforeStatement = null,
aliasAfterStatement = null
aliasAfterStatement = null,
unboundBeforeStatement = null,
)
}
)
Expand All @@ -87,27 +88,65 @@ class JIRIntraProcAliasAnalysis(
val jig = getJIG(entryPoint)
val daa = DSUAliasAnalysis(CallResolver(), localVariableReachability, cancellation).analyze(jig)

val aliasBeforeStatement = Array(jig.statements.size) { i ->
resolveLocalVar(daa.statesBeforeStmt[i], localVariableReachability, i, cancellation)
}
val aliasBeforeStatement = Array(jig.statements.size) { Int2ObjectOpenHashMap<List<AliasInfo>>() }
val aliasAfterStatement = Array(jig.statements.size) { Int2ObjectOpenHashMap<List<AliasInfo>>() }

val unboundAliasBeforeStatement = Array(jig.statements.size) { mutableListOf<List<AliasInfo>>() }
val unboundAliasAfterStatement = Array(jig.statements.size) { mutableListOf<List<AliasInfo>>() }

val aliasAfterStatement = Array(jig.statements.size) { i ->
resolveLocalVar(daa.statesAfterStmt[i], localVariableReachability, i, cancellation)
for (i in jig.statements.indices) {
resolveLocalVar(
daa.statesBeforeStmt[i], localVariableReachability,
aliasBeforeStatement[i], unboundAliasBeforeStatement[i],
i, cancellation
)

resolveLocalVar(
daa.statesAfterStmt[i], localVariableReachability,
aliasAfterStatement[i], unboundAliasAfterStatement[i],
i, cancellation
)
}

return compressAliasInfo(aliasBeforeStatement, aliasAfterStatement)
return compressAliasInfo(aliasBeforeStatement, aliasAfterStatement, unboundAliasBeforeStatement)
}

private fun compressAliasInfo(
aliasBeforeStatement: Array<Int2ObjectOpenHashMap<List<AliasInfo>>>,
aliasAfterStatement: Array<Int2ObjectOpenHashMap<List<AliasInfo>>>
aliasAfterStatement: Array<Int2ObjectOpenHashMap<List<AliasInfo>>>,
unboundBeforeStatement: Array<MutableList<List<AliasInfo>>>,
): JIRLocalAliasAnalysis.MethodAliasInfo {
val compressedBefore = arrayOfNulls<Int2ObjectOpenHashMap<Array<Any>>>(aliasBeforeStatement.size)
val compressedAfter = arrayOfNulls<Int2ObjectOpenHashMap<Array<Any>>>(aliasAfterStatement.size)

compress(aliasBeforeStatement, compressedBefore, reference = null, referenceCompressed = null)
compress(aliasAfterStatement, compressedAfter, aliasBeforeStatement, compressedBefore)
return JIRLocalAliasAnalysis.MethodAliasInfo(compressedBefore, compressedAfter)

val compressedUnbound = compressUnboundAliases(unboundBeforeStatement)
return JIRLocalAliasAnalysis.MethodAliasInfo(compressedBefore, compressedAfter, compressedUnbound)
}

private fun compressUnboundAliases(
statementInfo: Array<MutableList<List<AliasInfo>>>
): Array<Array<Array<Any>>?>? {
if (statementInfo.all { it.isEmpty() }) return null

val compressed = arrayOfNulls<Array<Array<Any>>>(statementInfo.size)
for (i in statementInfo.indices) {
val current = statementInfo[i]
if (current.isEmpty()) continue

if (i > 0 && statementInfo[i - 1] == current) {
compressed[i] = compressed[i - 1]
continue
}

val unwrapped = Array(current.size) { i ->
JIRLocalAliasAnalysis.unwrapAliasSet(current[i])
}
compressed[i] = unwrapped
}
return compressed
}

private fun compress(
Expand Down Expand Up @@ -144,29 +183,33 @@ class JIRIntraProcAliasAnalysis(
private fun resolveLocalVar(
daa: ConnectedAliases,
reachableLocals: JIRLocalVariableReachability,
result: Int2ObjectOpenHashMap<List<AliasInfo>>,
unboundAliases: MutableList<List<AliasInfo>>,
instIdx: Int,
cancellation: AnalysisCancellation,
): Int2ObjectOpenHashMap<List<AliasInfo>> {
val result = Int2ObjectOpenHashMap<List<AliasInfo>>()
) {
daa.aliasGroups.forEach { (_, group) ->
val locals = group.filter {
it is LocalAlias.SimpleLoc && it.loc is Local && reachableLocals.isReachable(it.loc.idx, instIdx)
}
if (locals.isEmpty()) return@forEach

val converted = group
.flatMap { it.convertToAliasInfo(daa.aliasGroups, depth = 0, cancellation) }
.filter { it !is AliasApInfo || reachableLocals.isReachable(it.base, instIdx) }
.distinct()

// size == 1 means only local was converted to AliasInfo; not really meaningful
if (converted.size <= 1) return@forEach

val locals = converted.filterIsInstance<AliasApInfo>()
.filter { it.accessors.isEmpty() }
.mapNotNull { it.base as? AccessPathBase.LocalVar }

if (locals.isEmpty()) {
unboundAliases += converted
return@forEach
}

locals.forEach { local ->
val id = ((local as LocalAlias.SimpleLoc).loc as Local).idx
result[id] = converted
result[local.idx] = converted
}
}
return result
}

private fun AAInfo.convertToAliasInfo(
Expand Down Expand Up @@ -215,11 +258,13 @@ class JIRIntraProcAliasAnalysis(
}

is LocalAlias.Alloc -> {
val assign = cur.stmt as? Stmt.Assign ?: return null
val assignedExpr = cur.stmt.assignedExpr()
?: return null

val const = assignedExpr as? SimpleValue.RefConst

val const = assign.expr as? SimpleValue.RefConst
val stringConst = const?.expr as? JIRStringConstant
?: return AliasAllocInfo(assign.originalIdx)
?: return AliasAllocInfo(cur.stmt.originalIdx)

AccessPathBase.Constant("java.lang.String", stringConst.value)
}
Expand All @@ -232,4 +277,12 @@ class JIRIntraProcAliasAnalysis(

return AliasApInfo(base, emptyList())
}

private fun Stmt.assignedExpr(): Expr? = when (this) {
is Stmt.Assign -> expr
is Stmt.FieldStore -> value as? Expr
is Stmt.ArrayStore -> value as? Expr
is Stmt.WriteStatic -> value as? Expr
else -> null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ class JIRBasicAtomEvaluator(
}
} else {
val allAliases = aa.getAllAliasAtStatement(statement)
for ((_, aliasSet) in allAliases) {
for (aliasSet in allAliases) {
for (info in aliasSet) {
if (info !is AliasApInfo || info.base != base) continue
val singleAccessor = info.accessors.singleOrNull() ?: continue
Expand Down
Loading