Skip to content

Commit

Permalink
Update readme
Browse files Browse the repository at this point in the history
Also, rename reflectionremoval to unreflect
  • Loading branch information
CalebFenton committed Sep 28, 2015
1 parent c767091 commit 6de52eb
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 53 deletions.
50 changes: 19 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,43 +31,32 @@ Building

To build the jar, use `./gradlew shadowJar`


Troubleshooting
---------------

Simplify is still in early stages of development. If you encounter a failure, try these recommendations, in order:

1. Limit the target methods and classes to just the essentials with `-it`. Simplify will try and run over the entire app by default, which means more possibility for failure. Limiting to just one class or a few important methods improves chances significantly.
2. If methods fail to simplify because of errors related to maximum visits exceeded, try using higher `--max-address-visits`, `--max-call-depth`, and `--max-method-visits`.
1. Limit to just a few methods or classes `-it`.
2. If failure is because of maximum visits exceeded, try using higher `--max-address-visits`, `--max-call-depth`, and `--max-method-visits`.
3. Try with `-v` or `-vv` and report the issue.
4. Try again, but do not break eye contact. Simpify can sense fear.


Reporting Issues
----------------

Two main things are needed to reproduce and fix problems:

1. The APK. If it's legal and possible, please link to the APK.
1. If you can, link the **APK** or **DEX**.
2. The full command used.
3. *Optional*: verbose logs

Optional, but still useful, is a verbose log output around the error.


Reporting Success
-----------------

Did Simplify just save you a few hours of suffering? Send an e-mail to calebjfenton (AT) gmail [dot] com. If that's not your thing, send a pull request with bug fixes.



### Optimization Example
Optimization Example
--------------------
### Before Optimization
```smali
.method public static test1()I
.locals 2
new-instance v0, Ljava/lang/Integer;
const/4 v1, 0x1
invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V
Expand All @@ -78,33 +67,30 @@ Did Simplify just save you a few hours of suffering? Send an e-mail to calebjfen
.end method
```

The above code is an obtuse way to say `v0 = 1`. This is sometimes used as an obfuscation technique.
All this does is `v0 = 1`.


###After Constant Propagation
### After Constant Propagation
```smali
.method public static test1()I
.locals 2
new-instance v0, Ljava/lang/Integer;
const/4 v1, 0x1
invoke-direct {v0, v1}, Ljava/lang/Integer;-><init>(I)V
invoke-virtual {v0}, Ljava/lang/Integer;->intValue()I
# move-result replaced with const/4
const/4 v0, 0x1
# known return register value prepended with const
const/4 v0, 0x1
return v0
.end method
```

Some single assignment instructions can be replaced with constant instructions when there is consensus of the value being assigned of all the possible executions of that instruction. If the instruction is outside of a loop, there will only be one node in the graph for that instruction.
In the above example, `move-result` is constantized, so is `return`, because there is only one possible value (consensus) and it is not unknown.
The `move-result v0` is replaced with `const/4 v0, 0x1`. This is because there is only one possible return value for `intValue()I` and the return type can be made a constant. The arguments `v0` and `v1` are unambiguous and do not change. That is to say, there's a consensus of values for every possible execution path at `intValue()I`. Other types of values that can be turned into constants:

* numbers - `const/4`, `const/16`, etc.
* strings - `const-string`
* classes - `const-class`

###After Dead Code Removal
```smali
Expand All @@ -117,11 +103,13 @@ In the above example, `move-result` is constantized, so is `return`, because the
.end method
```

Dead code includes:
Because the code above `const/4 v0, 0x1` does not affect state outside of the method (no side-effects) it can be removed without changing behavior. If there was a method call that wrote something to the file system or network, it couldn't be removed because it affects state outside the method. Or if `test()I` took a mutable argument, such as a `LinkedList`, any instructions that accessed it couldn't be considered dead.

Some other examples of dead code:

* unreferenced assignments - assigning registers and not using them
* unreached / unreachable instructions - `if (false) { dead_code(); }`

* unreferenced assignments - assigning something and never using it
* method calls with no side-effects - `Ljava/lang/Integer;->intValue()I` has no side-effects
* unreached / unreachable instructions - code inside of an `if (false)` block, none in this example

Related Works
-------------
Expand Down
4 changes: 2 additions & 2 deletions simplify/src/main/java/org/cf/simplify/Optimizer.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import org.cf.simplify.strategy.DeadRemovalStrategy;
import org.cf.simplify.strategy.OptimizationStrategy;
import org.cf.simplify.strategy.PeepholeStrategy;
import org.cf.simplify.strategy.ReflectionRemovalStrategy;
import org.cf.simplify.strategy.UnreflectionStrategy;
import org.cf.smalivm.VirtualMachine;
import org.cf.smalivm.context.ExecutionGraph;
import org.jf.dexlib2.util.ReferenceUtil;
Expand Down Expand Up @@ -52,7 +52,7 @@ public Optimizer(ExecutionGraph graph, BuilderMethod method, VirtualMachine vm,
performRepeatedlyStrategies.add(strategy);

methodReexecuteStrategies = new LinkedList<OptimizationStrategy>();
methodReexecuteStrategies.add(new ReflectionRemovalStrategy(mbgraph));
methodReexecuteStrategies.add(new UnreflectionStrategy(mbgraph));

allStrategies = new LinkedList<OptimizationStrategy>();
allStrategies.addAll(performOnceStrategies);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ReflectionRemovalStrategy implements OptimizationStrategy {
public class UnreflectionStrategy implements OptimizationStrategy {

@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(ReflectionRemovalStrategy.class.getSimpleName());
private static final Logger log = LoggerFactory.getLogger(UnreflectionStrategy.class.getSimpleName());

private static final String MethodInvokeSignature = "Ljava/lang/reflect/Method;->invoke(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;";

Expand Down Expand Up @@ -120,7 +120,7 @@ static Opcode getGetOpcode(String type, boolean isStatic) {

private boolean madeChanges;

public ReflectionRemovalStrategy(MethodBackedGraph mbgraph) {
public UnreflectionStrategy(MethodBackedGraph mbgraph) {
this.mbgraph = mbgraph;
unreflectCount = 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,27 +343,27 @@ public static class TestProtectedMethods {
@Test
public void testInstanceGetOpcodes() {
boolean isStatic = false;
assertEquals(Opcode.IGET, ReflectionRemovalStrategy.getGetOpcode("I", isStatic));
assertEquals(Opcode.IGET_BOOLEAN, ReflectionRemovalStrategy.getGetOpcode("Z", isStatic));
assertEquals(Opcode.IGET_BYTE, ReflectionRemovalStrategy.getGetOpcode("B", isStatic));
assertEquals(Opcode.IGET_CHAR, ReflectionRemovalStrategy.getGetOpcode("C", isStatic));
assertEquals(Opcode.IGET_OBJECT, ReflectionRemovalStrategy.getGetOpcode("Ljava/lang/Object;", isStatic));
assertEquals(Opcode.IGET_SHORT, ReflectionRemovalStrategy.getGetOpcode("S", isStatic));
assertEquals(Opcode.IGET_WIDE, ReflectionRemovalStrategy.getGetOpcode("J", isStatic));
assertEquals(Opcode.IGET_WIDE, ReflectionRemovalStrategy.getGetOpcode("D", isStatic));
assertEquals(Opcode.IGET, UnreflectionStrategy.getGetOpcode("I", isStatic));
assertEquals(Opcode.IGET_BOOLEAN, UnreflectionStrategy.getGetOpcode("Z", isStatic));
assertEquals(Opcode.IGET_BYTE, UnreflectionStrategy.getGetOpcode("B", isStatic));
assertEquals(Opcode.IGET_CHAR, UnreflectionStrategy.getGetOpcode("C", isStatic));
assertEquals(Opcode.IGET_OBJECT, UnreflectionStrategy.getGetOpcode("Ljava/lang/Object;", isStatic));
assertEquals(Opcode.IGET_SHORT, UnreflectionStrategy.getGetOpcode("S", isStatic));
assertEquals(Opcode.IGET_WIDE, UnreflectionStrategy.getGetOpcode("J", isStatic));
assertEquals(Opcode.IGET_WIDE, UnreflectionStrategy.getGetOpcode("D", isStatic));
}

@Test
public void testStaticGetOpcodes() {
boolean isStatic = true;
assertEquals(Opcode.SGET, ReflectionRemovalStrategy.getGetOpcode("I", isStatic));
assertEquals(Opcode.SGET_BOOLEAN, ReflectionRemovalStrategy.getGetOpcode("Z", isStatic));
assertEquals(Opcode.SGET_BYTE, ReflectionRemovalStrategy.getGetOpcode("B", isStatic));
assertEquals(Opcode.SGET_CHAR, ReflectionRemovalStrategy.getGetOpcode("C", isStatic));
assertEquals(Opcode.SGET_OBJECT, ReflectionRemovalStrategy.getGetOpcode("Ljava/lang/Object;", isStatic));
assertEquals(Opcode.SGET_SHORT, ReflectionRemovalStrategy.getGetOpcode("S", isStatic));
assertEquals(Opcode.SGET_WIDE, ReflectionRemovalStrategy.getGetOpcode("J", isStatic));
assertEquals(Opcode.SGET_WIDE, ReflectionRemovalStrategy.getGetOpcode("D", isStatic));
assertEquals(Opcode.SGET, UnreflectionStrategy.getGetOpcode("I", isStatic));
assertEquals(Opcode.SGET_BOOLEAN, UnreflectionStrategy.getGetOpcode("Z", isStatic));
assertEquals(Opcode.SGET_BYTE, UnreflectionStrategy.getGetOpcode("B", isStatic));
assertEquals(Opcode.SGET_CHAR, UnreflectionStrategy.getGetOpcode("C", isStatic));
assertEquals(Opcode.SGET_OBJECT, UnreflectionStrategy.getGetOpcode("Ljava/lang/Object;", isStatic));
assertEquals(Opcode.SGET_SHORT, UnreflectionStrategy.getGetOpcode("S", isStatic));
assertEquals(Opcode.SGET_WIDE, UnreflectionStrategy.getGetOpcode("J", isStatic));
assertEquals(Opcode.SGET_WIDE, UnreflectionStrategy.getGetOpcode("D", isStatic));
}

}
Expand Down Expand Up @@ -391,7 +391,7 @@ private static Method getMethod(Class<?> klazz, String methodName, Class<?>[] pa
private static MethodBackedGraph getOptimizedGraph(String methodName, Object... args) {
TIntObjectMap<HeapItem> initial = VMTester.buildRegisterState(args);
MethodBackedGraph mbgraph = OptimizerTester.getMethodBackedGraph(CLASS_NAME, methodName, initial);
ReflectionRemovalStrategy strategy = new ReflectionRemovalStrategy(mbgraph);
UnreflectionStrategy strategy = new UnreflectionStrategy(mbgraph);
strategy.perform();

return mbgraph;
Expand Down

0 comments on commit 6de52eb

Please sign in to comment.