Skip to content

Commit

Permalink
Merge pull request #666 from soot-oss/fix/InvokeDynamics
Browse files Browse the repository at this point in the history
fix invoke dynamics
  • Loading branch information
swissiety authored Oct 20, 2023
2 parents e8526af + 1ed3ab1 commit 62a1d02
Show file tree
Hide file tree
Showing 22 changed files with 393 additions and 107 deletions.
Binary file added shared-test-resources/bugfixes/Indy.class
Binary file not shown.
17 changes: 17 additions & 0 deletions shared-test-resources/bugfixes/Indy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import java.time.LocalDate;
import java.time.Period;
import java.util.stream.Stream;
import java.util.stream.IntStream;

/** conversion failed when there is a merge (here: after the if) and an invokedynamic followed */
class Indy{
public IntStream test(IntStream s) {
int sign;
if (s.isParallel()) {
sign = 1;
}else{
sign = -1;
}
return s.map(n -> n+42);
}
}
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
record RecordTest(int a, String b) {
public RecordTest(int a, String b) {
this.a = a;
this.b = b;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@
import sootup.core.jimple.basic.Local;
import sootup.core.jimple.basic.Value;
import sootup.core.jimple.common.constant.BooleanConstant;
import sootup.core.jimple.common.constant.ClassConstant;
import sootup.core.jimple.common.constant.DoubleConstant;
import sootup.core.jimple.common.constant.EnumConstant;
import sootup.core.jimple.common.constant.FloatConstant;
import sootup.core.jimple.common.constant.IntConstant;
import sootup.core.jimple.common.constant.LongConstant;
import sootup.core.jimple.common.constant.MethodHandle;
import sootup.core.jimple.common.constant.MethodType;
import sootup.core.jimple.common.constant.StringConstant;
import sootup.core.jimple.common.expr.JAddExpr;
Expand Down Expand Up @@ -70,6 +67,7 @@
import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation;
import sootup.java.core.JavaProject;
import sootup.java.core.JavaSootClass;
import sootup.java.core.language.JavaJimple;
import sootup.java.core.language.JavaLanguage;

@Category(Java8Test.class)
Expand Down Expand Up @@ -153,10 +151,10 @@ private void fillList(List<Value> listWithAllValues, View<JavaSootClass> view) {
listWithAllValues.add(FloatConstant.getInstance(2.5f));
listWithAllValues.add(IntConstant.getInstance(3));
listWithAllValues.add(LongConstant.getInstance(3L));
listWithAllValues.add(new StringConstant("String", StringClass));
listWithAllValues.add(new EnumConstant("3", StringClass));
listWithAllValues.add(new ClassConstant("java/lang/String", StringClass));
listWithAllValues.add(new MethodHandle(toStringMethod, 3, StringClass));
listWithAllValues.add(stringConstant);
listWithAllValues.add(JavaJimple.getInstance().newEnumConstant("3", "EnumTest"));
listWithAllValues.add(JavaJimple.getInstance().newClassConstant("java/lang/String"));
listWithAllValues.add(JavaJimple.getInstance().newMethodHandle(toStringMethod, 5));
listWithAllValues.add(new MethodType(toStringMethod.getSubSignature(), StringClass));
listWithAllValues.add(new JAddExpr(stringConstant, stringConstant));
listWithAllValues.add(new JAndExpr(stringConstant, stringConstant));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2005-2020 Jennifer Lhotak, Andreas Dann, Linghui Luo and others
* Copyright (C) 2005-2023 Jennifer Lhotak, Andreas Dann, Linghui, Luo Jonas Klauke 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
Expand All @@ -23,14 +23,16 @@
*/

import javax.annotation.Nonnull;
import sootup.core.jimple.common.ref.JFieldRef;
import sootup.core.jimple.visitor.ConstantVisitor;
import sootup.core.signatures.FieldSignature;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.SootClassMemberSignature;
import sootup.core.signatures.SootClassMemberSubSignature;
import sootup.core.types.Type;

public class MethodHandle implements Constant {

private final Type type;
@Nonnull private final Type type;

public enum Kind {
REF_GET_FIELD(1, "REF_GET_FIELD"),
Expand Down Expand Up @@ -60,6 +62,10 @@ public int getValue() {
return val;
}

public String getValueName() {
return valStr;
}

public static Kind getKind(int kind) {
for (Kind k : Kind.values()) {
if (k.getValue() == kind) {
Expand All @@ -69,48 +75,71 @@ public static Kind getKind(int kind) {
throw new RuntimeException("Error: No method handle kind for value '" + kind + "'.");
}

public static Kind getKind(String kind) {
public static Kind getKind(String kindName) {
for (Kind k : Kind.values()) {
if (k.toString().equals(kind)) {
if (k.getValueName().equals(kindName)) {
return k;
}
}
throw new RuntimeException("Error: No method handle kind for value '" + kind + "'.");
throw new RuntimeException("Error: No method handle kind for value name '" + kindName + "'.");
}
}

private final MethodSignature methodSignature;
private final JFieldRef fieldRef;
@Nonnull
private final SootClassMemberSignature<? extends SootClassMemberSubSignature> referenceSignature;

public int tag;
@Nonnull private final Kind kind;

public MethodHandle(MethodSignature methodSignature, int tag, Type type) {
this.methodSignature = methodSignature;
this.tag = tag;
this.fieldRef = null;
this.type = type;
public MethodHandle(
@Nonnull SootClassMemberSignature<? extends SootClassMemberSubSignature> referenceSignature,
int tag,
@Nonnull Type type) {
this(referenceSignature, Kind.getKind(tag), type);
}

public MethodHandle(JFieldRef ref, int tag, Type type) {
this.fieldRef = ref;
this.tag = tag;
this.methodSignature = null;
public MethodHandle(
@Nonnull SootClassMemberSignature<? extends SootClassMemberSubSignature> referenceSignature,
@Nonnull MethodHandle.Kind kind,
@Nonnull Type type) {
this.kind = kind;
this.type = type;
this.referenceSignature = referenceSignature;
if ((this.isMethodRef() && !(referenceSignature instanceof MethodSignature))
|| (this.isFieldRef() && !(referenceSignature instanceof FieldSignature))) {
throw new IllegalArgumentException(
"Kind:"
+ kind.valStr
+ " does not match with the given signature:"
+ referenceSignature.getClass());
}
}

public static boolean isMethodRef(int tag) {
return tag == Kind.REF_INVOKE_VIRTUAL.getValue()
|| tag == Kind.REF_INVOKE_STATIC.getValue()
|| tag == Kind.REF_INVOKE_SPECIAL.getValue()
|| tag == Kind.REF_INVOKE_CONSTRUCTOR.getValue()
|| tag == Kind.REF_INVOKE_INTERFACE.getValue();
}

public static boolean isFieldRef(int tag) {
return tag == Kind.REF_GET_FIELD.getValue()
|| tag == Kind.REF_PUT_FIELD.getValue()
|| tag == Kind.REF_PUT_FIELD_STATIC.getValue()
|| tag == Kind.REF_GET_FIELD_STATIC.getValue();
}

public boolean isMethodRef() {
return MethodHandle.isMethodRef(this.kind.getValue());
}

public static boolean isMethodRef(int kind) {
return kind == Kind.REF_INVOKE_VIRTUAL.getValue()
|| kind == Kind.REF_INVOKE_STATIC.getValue()
|| kind == Kind.REF_INVOKE_SPECIAL.getValue()
|| kind == Kind.REF_INVOKE_CONSTRUCTOR.getValue()
|| kind == Kind.REF_INVOKE_INTERFACE.getValue();
public boolean isFieldRef() {
return MethodHandle.isFieldRef(this.kind.getValue());
}

@Override
// FIXME: [ms] serialize in a way it can be restored with the same parameters; adapt Jimple.g4 and
// JimpleConverter.java
public String toString() {
return "handle: " + methodSignature;
return "methodhandle: \"" + kind.valStr + "\" " + referenceSignature;
}

@Nonnull
Expand All @@ -119,8 +148,12 @@ public Type getType() {
return type;
}

public MethodSignature getMethodSignature() {
return methodSignature;
public Kind getKind() {
return kind;
}

public SootClassMemberSignature<? extends SootClassMemberSubSignature> getReferenceSignature() {
return referenceSignature;
}

@Override
Expand All @@ -130,9 +163,9 @@ public void accept(@Nonnull ConstantVisitor v) {

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((methodSignature == null) ? 0 : methodSignature.hashCode());
int result = type.hashCode();
result = 31 * result + referenceSignature.hashCode();
result = 31 * result + kind.hashCode();
return result;
}

Expand All @@ -148,10 +181,6 @@ public boolean equals(Object obj) {
return false;
}
MethodHandle other = (MethodHandle) obj;
if (methodSignature == null) {
return other.methodSignature == null;
} else {
return methodSignature.equals(other.methodSignature);
}
return referenceSignature.equals(other.referenceSignature);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public JAssignStmt(
}
if (!validateValue(rValue)) {
throw new RuntimeException(
"Illegal Assignment statement. Make sure that right hand side has a valid operand.");
"Illegal Assignment statement. Make sure that right hand side ("
+ rValue
+ ") is a valid operand.");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package sootup.core.jimple.common.constant;

import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThrows;

import categories.Java8Test;
import java.util.Collections;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import sootup.core.jimple.common.constant.MethodHandle.Kind;
import sootup.core.signatures.FieldSignature;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.PackageName;
import sootup.core.types.ClassType;
import sootup.core.types.PrimitiveType.IntType;
import sootup.core.types.VoidType;

@Category(Java8Test.class)
public class MethodHandleTest extends TestCase {

@Test
public void testMethodHandle() {
assertEquals(Kind.REF_GET_FIELD.toString(), "REF_GET_FIELD");
assertEquals(Kind.REF_GET_FIELD.getValueName(), "REF_GET_FIELD");
assertEquals(Kind.REF_GET_FIELD.getValue(), 1);

for (Kind currentKind : Kind.values()) {
assertEquals(currentKind, Kind.getKind(currentKind.getValueName()));
assertEquals(currentKind, Kind.getKind(currentKind.getValue()));
}
// not valid kinds
assertThrows(RuntimeException.class, () -> Kind.getKind(0));
assertThrows(RuntimeException.class, () -> Kind.getKind("invalid"));

assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_VIRTUAL.getValue()));
assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_STATIC.getValue()));
assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_SPECIAL.getValue()));
assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_CONSTRUCTOR.getValue()));
assertTrue(MethodHandle.isMethodRef(Kind.REF_INVOKE_INTERFACE.getValue()));
assertFalse(MethodHandle.isMethodRef(Kind.REF_GET_FIELD.getValue()));
assertFalse(MethodHandle.isMethodRef(Kind.REF_PUT_FIELD.getValue()));
assertFalse(MethodHandle.isMethodRef(Kind.REF_PUT_FIELD_STATIC.getValue()));
assertFalse(MethodHandle.isMethodRef(Kind.REF_GET_FIELD_STATIC.getValue()));

assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_VIRTUAL.getValue()));
assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_STATIC.getValue()));
assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_SPECIAL.getValue()));
assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_CONSTRUCTOR.getValue()));
assertFalse(MethodHandle.isFieldRef(Kind.REF_INVOKE_INTERFACE.getValue()));
assertTrue(MethodHandle.isFieldRef(Kind.REF_GET_FIELD.getValue()));
assertTrue(MethodHandle.isFieldRef(Kind.REF_PUT_FIELD.getValue()));
assertTrue(MethodHandle.isFieldRef(Kind.REF_PUT_FIELD_STATIC.getValue()));
assertTrue(MethodHandle.isFieldRef(Kind.REF_GET_FIELD_STATIC.getValue()));

ClassType classType =
new ClassType() {
@Override
public boolean isBuiltInClass() {
return false;
}

@Override
public String getFullyQualifiedName() {
return "test.A";
}

@Override
public String getClassName() {
return "A";
}

@Override
public PackageName getPackageName() {
return new PackageName("test");
}
};
MethodSignature ms =
new MethodSignature(classType, "m1", Collections.emptyList(), VoidType.getInstance());
FieldSignature fs = new FieldSignature(classType, "f", IntType.getInstance());

MethodHandle mhms = new MethodHandle(ms, Kind.REF_INVOKE_VIRTUAL.getValue(), classType);
MethodHandle mhfs = new MethodHandle(fs, Kind.REF_GET_FIELD, classType);

// not valid Method handles
assertThrows(
IllegalArgumentException.class,
() -> new MethodHandle(fs, Kind.REF_INVOKE_CONSTRUCTOR, classType));
assertThrows(
IllegalArgumentException.class, () -> new MethodHandle(ms, Kind.REF_GET_FIELD, classType));

assertTrue(mhms.isMethodRef());
assertFalse(mhms.isFieldRef());

assertFalse(mhfs.isMethodRef());
assertTrue(mhfs.isFieldRef());

assertEquals(mhfs.getType(), classType);
assertEquals(
mhfs.toString(),
"methodhandle: \"" + mhfs.getKind() + "\" " + mhfs.getReferenceSignature());

MethodHandle mhms2 = new MethodHandle(ms, Kind.REF_INVOKE_VIRTUAL.getValue(), classType);
assertTrue(mhfs.equals(mhfs));
assertFalse(mhfs.equals(mhms));
assertFalse(mhfs.equals(null));
assertFalse(mhfs.equals(classType));
assertFalse(mhfs.equals(mhms2));

assertEquals(mhfs.hashCode(), mhfs.hashCode());
assertEquals(mhms.hashCode(), mhms2.hashCode());
assertNotEquals(mhfs.hashCode(), mhms.hashCode());
}
}
Loading

0 comments on commit 62a1d02

Please sign in to comment.