Skip to content
Open
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,8 +30,8 @@
import heros.flowfunc.Identity;
import heros.flowfunc.KillAll;
import java.util.*;
import sootup.core.jimple.Jimple;
import sootup.core.jimple.common.Immediate;
import sootup.core.jimple.common.Local;
import sootup.core.jimple.common.Value;
import sootup.core.jimple.common.constant.StringConstant;
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
Expand Down Expand Up @@ -93,7 +93,7 @@ public FlowFunction<Value> getCallToReturnFlowFunction(Stmt callSite, Stmt retur

@Override
protected Value createZeroValue() {
return new Local("<<zero>>", NullType.getInstance());
return Jimple.newLocal("<<zero>>", NullType.getInstance());
}

FlowFunction<Value> getNormalFlow(Stmt curr, Stmt succ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import java.util.List;
import org.junit.jupiter.api.Test;
import sootup.core.IdentifierFactory;
import sootup.core.jimple.Jimple;
import sootup.core.jimple.common.Immediate;
import sootup.core.jimple.common.Local;
import sootup.core.jimple.common.Value;
import sootup.core.jimple.common.constant.BooleanConstant;
import sootup.core.jimple.common.constant.DoubleConstant;
Expand Down Expand Up @@ -168,17 +168,17 @@ private void fillList(List<Value> listWithAllValues, View view) {
listWithAllValues.add(new JXorExpr(stringConstant, stringConstant));
listWithAllValues.add(
new JSpecialInvokeExpr(
new Local("a", StringClass),
Jimple.newLocal("a", StringClass),
toStringMethod,
Collections.singletonList(stringConstant)));
listWithAllValues.add(
new JVirtualInvokeExpr(
new Local("a", StringClass),
Jimple.newLocal("a", StringClass),
toStringMethod,
Collections.singletonList(stringConstant)));
listWithAllValues.add(
new JInterfaceInvokeExpr(
new Local("a", StringClass),
Jimple.newLocal("a", StringClass),
toStringMethod,
Collections.singletonList(stringConstant)));
listWithAllValues.add(
Expand All @@ -196,13 +196,14 @@ private void fillList(List<Value> listWithAllValues, View view) {
listWithAllValues.add(new JLengthExpr(stringConstant));
listWithAllValues.add(new JNegExpr(stringConstant));
listWithAllValues.add(new JStaticFieldRef(stringField));
listWithAllValues.add(new JInstanceFieldRef(new Local("a", StringClass), stringField));
listWithAllValues.add(new JArrayRef(new Local("a", StringClass), stringConstant));
listWithAllValues.add(new JInstanceFieldRef(Jimple.newLocal("a", StringClass), stringField));
listWithAllValues.add(new JArrayRef(Jimple.newLocal("a", StringClass), stringConstant));
listWithAllValues.add(new JParameterRef(StringClass, 3));
listWithAllValues.add(new JCaughtExceptionRef(StringClass));
listWithAllValues.add(new JThisRef(StringClass));
listWithAllValues.add(new Local("a", StringClass));
listWithAllValues.add(Jimple.newLocal("a", StringClass));
listWithAllValues.add(
new JPhiExpr(Collections.singletonList(new Local("a", StringClass)), new HashMap<>()));
new JPhiExpr(
Collections.singletonList(Jimple.newLocal("a", StringClass)), new HashMap<>()));
}
}
90 changes: 89 additions & 1 deletion sootup.core/src/main/java/sootup/core/jimple/Jimple.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*/

import java.util.*;
import org.jspecify.annotations.NonNull;
import sootup.core.IdentifierFactory;
import sootup.core.graph.BasicBlock;
import sootup.core.jimple.basic.*;
Expand Down Expand Up @@ -477,7 +478,27 @@ public static JSwitchStmt newLookupSwitchStmt(

/** Constructs a Local with the given name and type. */
public static Local newLocal(String name, Type t) {
return new Local(name, t);
return new LocalImpl(name, t);
}

/**
* Constructs a local from a bytecode slot index, or a generic local for {@code -1}.
*
* @deprecated Use {@link #newSlotLocal(String, Type, int)} or {@link #newLocal(String, Type)}.
*/
@Deprecated
public static Local newLocal(String name, Type t, int slotIndex) {
return slotIndex == -1 ? newLocal(name, t) : newSlotLocal(name, t, slotIndex);
}

/** Constructs a temporary originating from the JVM operand stack. */
public static StackLocal newStackLocal(String name, Type t) {
return new StackLocalImpl(name, t);
}

/** Constructs a local originating from the given nonnegative JVM local variable slot. */
public static SlotLocal newSlotLocal(String name, Type t, int slotIndex) {
return new SlotLocalImpl(name, t, slotIndex);
}

/** Constructs a JStaticFieldRef(FieldSignature) grammar chunk. */
Expand Down Expand Up @@ -517,4 +538,71 @@ public static JNewMultiArrayExpr newNewMultiArrayExpr(ArrayType type, List<Immed
public static Trap newTrap(ClassType exception, Stmt beginStmt, Stmt endStmt, Stmt handlerStmt) {
return new Trap(exception, beginStmt, endStmt, handlerStmt);
}

/** Generic local without JVM slot or operand stack provenance. */
private static class LocalImpl extends AbstractLocal {
private LocalImpl(@NonNull String name, @NonNull Type type) {
super(name, type);
}

@Override
public @NonNull Local withName(@NonNull String name) {
return new LocalImpl(name, getType());
}

@Override
public @NonNull Local withType(@NonNull Type type) {
return new LocalImpl(getName(), type);
}
}

/** Temporary materialized from the JVM operand stack. */
private static final class StackLocalImpl extends LocalImpl implements StackLocal {
private StackLocalImpl(@NonNull String name, @NonNull Type type) {
super(name, type);
}

@Override
public @NonNull StackLocal withName(@NonNull String name) {
return new StackLocalImpl(name, getType());
}

@Override
public @NonNull StackLocal withType(@NonNull Type type) {
return new StackLocalImpl(getName(), type);
}
}

/** Local preserving its original JVM local variable slot index. */
private static final class SlotLocalImpl extends LocalImpl implements SlotLocal {
private final int slotIndex;

private SlotLocalImpl(@NonNull String name, @NonNull Type type, int slotIndex) {
super(name, type);
if (slotIndex < 0) {
throw new IllegalArgumentException("Slot index must be nonnegative");
}
this.slotIndex = slotIndex;
}

@Override
public int getSlotIndex() {
return slotIndex;
}

@Override
public @NonNull SlotLocal withName(@NonNull String name) {
return new SlotLocalImpl(name, getType(), slotIndex);
}

@Override
public @NonNull SlotLocal withType(@NonNull Type type) {
return new SlotLocalImpl(getName(), type, slotIndex);
}

@Override
public @NonNull SlotLocal withSlotIndex(int slotIndex) {
return new SlotLocalImpl(getName(), getType(), slotIndex);
}
}
}
177 changes: 177 additions & 0 deletions sootup.core/src/main/java/sootup/core/jimple/common/AbstractLocal.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package sootup.core.jimple.common;

/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 1999-2020 Patrick Lam, Linghui Luo, Markus Schmidt and others
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

import java.util.*;
import org.jspecify.annotations.NonNull;
import sootup.core.graph.ControlFlowGraph;
import sootup.core.jimple.Jimple;
import sootup.core.jimple.basic.JimpleComparator;
import sootup.core.jimple.common.stmt.AbstractDefinitionStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.jimple.visitor.ImmediateVisitor;
import sootup.core.types.Type;
import sootup.core.types.VoidType;
import sootup.core.util.printer.StmtPrinter;

/**
* Shared immutable implementation of {@link Local}.
*
* <p>Prefer to use the factory methods in {@link Jimple}.
*
* @author Linghui Luo
*/
public abstract class AbstractLocal implements Local {

@NonNull private final String name;
@NonNull private final Type type;

/** Constructs a local with the given name and type. */
protected AbstractLocal(@NonNull String name, @NonNull Type type) {
this.name = name;
if (type instanceof VoidType) {
throw new RuntimeException("Type should not be VoidType");
} else {
this.type = type;
}
}

@Override
public final boolean equals(Object o) {
if (!(o instanceof Local)) {
return false;
}
return name.equals(((Local) o).getName());
}

@Override
public final int hashCode() {
return Objects.hashCode(name);
}

@Override
public boolean equivTo(@NonNull Object o, @NonNull JimpleComparator comparator) {
return comparator.caseLocal(this, o);
}

@Override
public int equivHashCode() {
return Objects.hash(name, type);
}

/** Returns the name of this object. */
@NonNull
public String getName() {
return name;
}

/** Returns the type of this local. */
@NonNull
@Override
public Type getType() {
return type;
}

@Override
public String toString() {
return getName();
}

@Override
public void toString(@NonNull StmtPrinter up) {
up.local(this);
}

@Override
public void collectUses(List<Value> collector) {}

/** returns a List that can contain: Locals, JFieldRefs, JArrayRefs */
public List<AbstractDefinitionStmt> getDefs(Collection<Stmt> defs) {
List<AbstractDefinitionStmt> localDefs = new ArrayList<>();
for (Stmt stmt : defs) {
if (stmt instanceof AbstractDefinitionStmt
&& ((AbstractDefinitionStmt) stmt).getLeftOp().equals(this)) {
localDefs.add((AbstractDefinitionStmt) stmt);
}
}
return localDefs;
}

/**
* Get all definition-stmts which define the given local used by the given stmt.
*
* @param graph a stmt graph which contains the given stmts.
* @param stmt a stmt which uses the given local.
*/
public List<Stmt> getDefsForLocalUse(ControlFlowGraph<?> graph, Stmt stmt) {
if (stmt.getUses().stream().noneMatch(v -> v == this)) {
throw new RuntimeException(stmt + " doesn't use the local " + this);
}
List<Stmt> defStmts = new ArrayList<>();
Set<Stmt> visited = new HashSet<>();

Deque<Stmt> queue = new ArrayDeque<>();
// Seed the search queue with predecessors of 'stmt' rather than 'stmt' itself.
// When a statement both uses and defines the same local (e.g. `x = x + 1`), starting at `stmt`
// immediately matched `stmt` as a definition, short-circuiting and erroneously reporting that
// `x` is defined by `stmt` itself before it is evaluated. Seeding with predecessors searches
// the reaching definitions flowing into `stmt`.
if (graph.containsNode(stmt)) {
queue.addAll(graph.predecessors(stmt));
}
while (!queue.isEmpty()) {
Stmt s = queue.removeFirst();
if (!visited.contains(s)) {
visited.add(s);
if (s instanceof AbstractDefinitionStmt && s.getDef().get().equivTo(this)) {
defStmts.add(s);
} else {
if (graph.containsNode(s)) {
queue.addAll(graph.predecessors(s));
}
}
}
}
return defStmts;
}

public List<Stmt> getStmtsUsingOrDefiningthisLocal(Collection<Stmt> stmts, Stmt removedStmt) {
List<Stmt> localOccurrences = new ArrayList<>();
for (Stmt stmt : stmts) {
if (stmt.equivTo(removedStmt)) continue;
List<Value> stmtUsesAndDefs = stmt.getUsesAndDefs();
for (Value stmtUse : stmtUsesAndDefs) {
if (stmtUse instanceof Local && stmtUse.equivTo(this)) {
localOccurrences.add(stmt);
}
}
}
return localOccurrences;
}

@Override
public <V extends ImmediateVisitor> V accept(@NonNull V v) {
v.caseLocal(this);
return v;
}
}
Loading