Test a jump with ASM in Java - java

I'm trying to prevent conditionals jumps from being useless for example by deleting that :
if(1 > 10) {
return;
}
So I decided to create a BasicInterpreter to check if the frame of the jump is null and if so remove it. And it's not null so it doesn't detect it as useless.
Code which doesn't work :
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
if(frames[i] == null) {
System.out.println("This jump is useless");
}
}
}
}
Then I tried to get some values of stack to manually calculate but without any success (I found that but I cannot port the code to use it on jumps ASM Get exact value from stack frame):
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
// getStackSize() returns 2 so -> 0 and 1
frames[i].getStack(0); // this is probably 1
frames[i].getStack(1); // this is probably 10
// but it returns a BasicValue so I can't check if the code works or not (we cannot get values)
}
}
}
And the last thing I tried was to get the size of the instructions which are used by the jump to delete them (of course it doesn't detect if it's a useless code but I can at least delete it).
In fact I tried to create a method which returns a constant int so I can detect if getValue is called in the instructions of the jump (if I detect the invoke, I delete the instructions of the jump and the jump itself of course):
Example:
if(1 > getValue()) { //getValue() returns 10
return;
}
Code:
Analyzer<BasicValue> an = new Analyzer<BasicValue>(new BasicInterpreter());
Frame<BasicValue>[] frames = an.analyze(cn.name, mn);
ArrayList<AbstractInsnNode> nodesR = new ArrayList<>();
for (int i = 0; i < frames.length; i++) {
if ((mn.instructions.get(i) instanceof JumpInsnNode)) {
if (mn.instructions.get(i).getOpcode() >= IFEQ && mn.instructions.get(i).getOpcode() <= IF_ACMPNE) {
ArrayList<AbstractInsnNode> toRemove = new ArrayList<>();
for (int ia = 1; ia < frames[i].getMaxStackSize() + 2; ia++) { // I started from 1 and added 2 to getMaxStackSize because I wasn't getting all the instructions
toRemove.add(mn.instructions.get(i - ia));
}
toRemove.add(mn.instructions.get(i)); // I add the jump to the list
for (AbstractInsnNode aaa : toRemove) {
if (aaa.getOpcode() == INVOKESTATIC) { // the invokestatic is getValue
for (AbstractInsnNode aaas : toRemove) {
nodesR.add(aaas);
}
break;
}
}
}
}
}
for (AbstractInsnNode aaas : nodesR) {
mn.instructions.remove(aaas);
}
} catch (AnalyzerException e) {
e.printStackTrace();
}
This code is probably horrible and not optimized but I tried a LOT of things without any success. The getMaxStackSize() doesn't return a number which is 100% correct (sometimes it doesn't take additions etc so it deletes instructions such as labels etc...).
What I'm trying to do:
Parsing through a method and check if a conditional jump will always be false (so the code inside will never gets executed) then remove it.
I tried two different way:
Use a BasicInterpreter to check if this jump will get executed with constant values then try it to see if it will always be false
Check if the jump contains a certain method (for example getValue() which returns 10 and compare if it's less than 1) then remove it
What I don't understand :
I think that there is frames in each instructions and that it contains the local variables table and the values that the frame is using – StackMap ? - ( for example if the instruction compare if an int is less than another it would return [II] right ?
I don't know if I can use a BasicInterpreter to test if the two constant ints always return the same result
StackMap = the Stack ? or it's different like the StackMap is a part of the stack which contains the needed values for the instruction ?

Related

first object of arraylist becomes null, cant seem to figure out why

So here is the issue. my concatinate function for intervals seems to be turning the first value passed into it to null, and i cant for the love of god figure out why.
public static ArrayList<Intervals> ConcatinateIntervals(ArrayList<Intervals> intervals) {
ArrayList<Intervals> concatinatedIntervals = new ArrayList<>();
for (int i=0; i<intervals.size(); i++){
for(int j=0; j<intervals.size(); j++){
if(i==j){
continue;
}
if(intervals.get(i).getMax() < intervals.get(j).getMin() || intervals.get(i).getMin()>intervals.get(j).getMax()){
Intervals interval = intervals.get(i).Clone();
concatinatedIntervals.add(interval);
continue;
}
// 1
if(intervals.get(i).getMin() < intervals.get(j).getMin() && intervals.get(i).getMax()<intervals.get(j).getMax()){
Intervals interval = new Intervals(intervals.get(i).getMin(),intervals.get(j).getMax());
concatinatedIntervals.add(interval);
break;
}//2
if(intervals.get(i).getMin() < intervals.get(j).getMin() && intervals.get(i).getMax()>intervals.get(j).getMax()){
Intervals interval = intervals.get(i).Clone();
concatinatedIntervals.add(interval);
break;
}//3
if(intervals.get(i).getMin() < intervals.get(j).getMax() && intervals.get(i).getMax()>intervals.get(j).getMax()){
Intervals interval = new Intervals(intervals.get(j).getMin(),intervals.get(i).getMax());
concatinatedIntervals.add(interval);
break;
}//4
if(intervals.get(i).getMin() > intervals.get(j).getMin() && intervals.get(i).getMax()<intervals.get(j).getMax()){
Intervals interval = new Intervals(intervals.get(j).getMin(),intervals.get(j).getMax());
concatinatedIntervals.add(interval);
break;
}
}
}
//removes all duplicates
Object[] st = concatinatedIntervals.toArray();
for (Object s : st) {
if (concatinatedIntervals.indexOf(s) != concatinatedIntervals.lastIndexOf(s)) {
concatinatedIntervals.remove(concatinatedIntervals.lastIndexOf(s));
}
}
return concatinatedIntervals;
}
It should be returning a 3 intervals of 10, 100 200,300 and 400,500. but I seem to be getting null. Cant figure out where I'm going wrong. please help.
The idea is that for any input of intervals its going to return a list of intervals either 10-500 og 10-100, 200-300, 400-500 and if any are duplicates its supposed to strip that away and concatinate so they become one larger.
I assume that you mean the ArrayList returned is not null but contains null elements (Intervals), since the reference to concatinatedIntervals is only ever set equal to a constructor call and thus cannot be null. You implemented your own cloning method apparently, as you write Clone() instead of clone(). The only places where Intervals are added to the list add either references that were assigned the result of a constructor call in the previous line (and thus cannot be null) or add the result of a call to Clone(). Thus the Clone() method is the only obvious suspect.
Have you tried stepping through execution of your code line-by-line with a debugger, checking the values of all the Intervals added?

Updating the value of a variable from the outer scope within an if block

int i = 3;
int j = 2;
int k = 1;
Printer printer = new Printer();
if (printer.getTotalAmount() > 0) {
if (printer.getType().equals("canon")) {
if (i >= j) {
i = i-j; // i=3-2, so i will be 1 now
}
}
if (printer.getType().equals("epson")) {
if (i >= k) {
i = i - k; // it should be i = 1-1 and i will be 0 now
}
}
}
My problem is that the variable i's value is not updated after the previous if statement. Due to block scope, the variable i's value is still 3.
How can I solve this problem?
Your two if statements represent mutually-exclusive conditions. The printer's type can be "canon" OR it can be "epson". Never both. So only one of your two if conditions will be met, and only one of the two code blocks will be executed.
Say, for example, that your Printer's type is "epson". When the first condition is evaluated, it will check whether "epson" is equal to "canon". Since they are not equal, the condition evaluates to false and all of the code inside of your if () {/* code */} block is completely skipped.
Your theory behind the scope causing the issue isn't accurate: since the variable is declared outside of the if block, the updated value will be reflected in every location that has access to that variable.
You need to update your logic to account for the fact that only one of the scenarios will occur or, if this is just a code simplification, find a more appropriate scenario analogous to your real code.
It may be helpful to review Oracle's tutorial on the if statement if this still isn't clear.
I think you should add debug statements to know more about flow of your program
becuase you didn't mention the value of printer.getTotalAmount() and printer.getType()
on which value of i is depend.
e.g.
System.out.println("Total Amount:"+ printer.getTotalAmount());
if (printer.getTotalAmount() > 0) {
System.out.println("Type:"+ printer.getType());
if (printer.getType().equals("canon")) {
System.out.println("inside if canon");
if (i >= j) {
i = i-j; // i=3-2, so i will be 1 now
}
}
if (printer.getType().equals("epson")) {
System.out.println("inside if epson");
if (i >= k) {
i = i - k; // it should be i = 1-1 and i will be 0 now
}
}
}

Verify efficiently if all elements of one small arrayList are contained in another, several times

I have several small arrayLists (800~1500) and for each one of those I must verify if it contains all items from a evaluation arrayList in the best possible time. Both the target arrayList (let's say, tSet) and the evaluation arrayList (eSet) have 1 to 5 elements.
I have tried a sequence of simple loops (current implementation), with a execution time of ~10 seonds, and containsAll(), with an inconsistent execution time ranging from 8 seconds to 16 seconds (using the same tSet). Is there a reason for this inconsistency? Is there a better way to perform this action?
Array elements are from the following class:
public class ItemBD_Temp implements Comparable<ItemBD_Temp> {
private String sTabela;
private String sValor;
private String sNome;
...
}
which also has a compareTo() method:
public int compareTo(ItemBD_Temp o) {
String concatThis;
String concatOther;
if(this.sTabela.equals("*AnyTable*") || o.sTabela.equals("*AnyTable*")){
concatThis = "";
concatOther = "";
}
else if(this.sNome.equals("*AnyAtrib*") || o.sNome.equals("*AnyAtrib*")){
concatThis = this.sTabela;
concatOther = o.sTabela;
}
else if(this.sValor.equals("*AnyValue*") || o.sValor.equals("*AnyValue*")){
concatThis = this.sTabela + this.sNome;
concatOther = o.sTabela + o.sNome;
}
else{
concatThis = this.sTabela + this.sNome + this.sValor;
concatOther = o.sTabela + o.sNome + o.sValor;
}
return concatThis.compareTo(concatOther);
}
and this is a very simplified version of what I have so far:
for(int j = 0; j < eSet.itens.size() && tSetAllowed == true; j++){
itemFound = false;
//CURRENT ITEM TO BE SEARCHED
eItem = new ItemBD_Temp(eSet.itens.get(j));
//CHECK IF CURRENT ITEM IS ON THE CURRENT tSet. IF FOUND, STOPS AND CHECKS NEXT eItem
for(int k = 0; k < tSet.size() && itemFound == false; k++){
tItem = tSet.get(k);
if(tItem.compareTo(eItem) == 0){
itemFound = true;
}
else{
itemFound = false;
}
}
//IF tItem WASN'T FOUND, THEN tSet CAN BE DISCARTED
if(itemFound==false){
tSetAllowed = false;
}
}
EDIT 1:
In order to use arrayList.containsAll() I also had to override the Equals method, as follows:
#Override
public int hashCode() {
int hash = 3;
hash = 89 * hash + (this.sTabela != null ? this.sTabela.hashCode() : 0);
hash = 89 * hash + (this.sValor != null ? this.sValor.hashCode() : 0);
hash = 89 * hash + (this.sNome != null ? this.sNome.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object obj) {
System.out.println("OVERRIDED EQUALS");
if (getClass() == obj.getClass()) {
if(this.sTabela.equals("*AnyTable*") || ((ItemBD_Temp)obj).sTabela.equals("*AnyTable*")){
return true;
}
else if(this.sNome.equals("*AnyAtrib*") || ((ItemBD_Temp)obj).sNome.equals("*AnyAtrib*")){
if(this.sTabela.equals(((ItemBD_Temp)obj).sTabela))
return true;
else
return false;
}
else if(this.sValor.equals("*AnyValue*") || ((ItemBD_Temp)obj).sValor.equals("*AnyValue*")){
if((this.sTabela+this.sNome).equals( (((ItemBD_Temp)obj).sTabela+((ItemBD_Temp)obj).sNome) ))
return true;
else
return false;
}
else{
if((this.sTabela+this.sNome+this.sValor).equals( (((ItemBD_Temp)obj).sTabela+((ItemBD_Temp)obj).sNome+((ItemBD_Temp)obj).sValor) ))
return true;
else
return false;
}
}
else{
return (this == obj);
}
}
This is needed because different objects like obj1 = {sTabela = "1", sNome = "2", sValor="3"} and obj2 = {sTabela = "AnyTable", sNome = "AnyAtrib", sValor="AnyValue"} should be considered equivalent.
You are using ArrayList as a data structure. It is an unsynchronized data structure. In your question there are only read operations, so should not be a problem. However, overall in your program with so many unsynchronized lists, think about thread safety.
For ArrayList accessing element via iterator or via index is almost the same in terms of speed. However, that is not an official benchmark. You might consider trying your code with iterators also.
I have several small arrayLists (800~1500) and for each one of those I
must verify if it contains all items from a evaluation arrayList in
the best possible time. Both the target arrayList (let's say, tSet)
and the evaluation arrayList (eSet) have 1 to 5 elements.
You have between 800 and 1500 array lists. I suppose you "are obliged" to use that datastructure.
You have 1 evaluation arrayList. Here I would consider a change maybe. I would use a Hash table/map as a data structure.
In average the search is faster. This is proven to be correct. The average time complexity for inserting/deleting/searching an element in a hash table/map is O(1). This means constant time in average. (The worst case is O(n), but in general we are interested in the average).
"If a target list contains all items of an evaluation list" is equivalent to "all evaluation list items are in target list". In your example you loop through target list and compare, but you could as well loop through evaluation list and compare.
Now assuming that you always want to test whether evaluation
list is a sub set of target list. It is better to loop through
evaluation list and do the comparison as it is expected to have less
elements.
I will go through your code later. But there is one thing that I don't feel comfortable with:
The conditions in your loop! Are you sure your algorithm works as expected?

Java not recognizing elements in ArrayList?

I have a program where I make an arraylist to hold some cab objects. I keep getting an error that what I get from the message is that java does not recognize that the arraylist has objects in it. This is the error that I am getting.
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 20, Size: 20
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at edu.Tridenttech.MartiC.app.CabOrginazer.main(CabOrginazer.java:48)
This is the code that i am trying to get to work
public class CabOrginazer {
private static List<CabProperties> cabs = new ArrayList<CabProperties>();
private static int count = 0;
private static boolean found = false;
public void cabOrginazer()
{
}
public static void main(String[] args) {
// TODO Auto-generated method stub
CabRecordReaper reaper = new CabRecordReaper("C:/CabRecords/September.txt");
CabProperties cabNum;
for(int i = 0; i < 20; i++)
{
cabNum = new CabProperties();
cabs.add(cabNum);
}
while(reaper.hasMoreRecords())
{
CabRecord file = reaper.getNextRecord();
for(int j = 0; j < cabs.size(); j++)
{
if(cabs.get(j).getCabID() == file.getCabId())
{
found = true;
cabs.get(j).setTypeAndValue(file.getType(), file.getValue(), file.getPerGallonCost());
cabs.get(j).setDate(file.getDateString());
break;
}
}
if(found == false)
{
cabs.get(count).setCabId(file.getCabId());
count++;
}
/*for(CabProperties taxi : cabs)
{
if(taxi.getCabID() == file.getCabId())
{
found = true;
taxi.setTypeAndValue(file.getType(), file.getValue(), file.getPerGallonCost());
taxi.setDate(file.getDateString());
break;
}
}*/
}
for(CabProperties taxi : cabs)
{
System.out.print("cab ID: " + taxi.getCabID());
System.out.print("\tGross earning: " + taxi.getGrossEarn());
System.out.print("\tTotal Gas Cost: " + taxi.getGasCost());
System.out.print("\tTotal Service Cost: " + taxi.getServiceCost());
System.out.println();
}
}
}
line 48 is the inside of that if statement where it says cabs.get(count).setCabId(file.getCabId());
with the little knowledge I have of Java. Java should know that there are elements inside of cabs and I should be able to set that id of the cab. What can cause Java not to recognize that the arraylist is populated?
The list isn't populated with an element at item count. Look at the exception: you've got 20 elements in the list, so the valid indexes are 0 to 19 inclusive. You're asking for record 20 (i.e. the 21st record). That doesn't exist.
It sounds like your block should be something like:
if (!found)
{
CabProperties properties = new CabProperties();
properties.setCabId(file.getCabId());
// Probably set more stuff
cabs.add(properties);
}
You may well be able to get rid of the count variable entirely - and your initial population of the list with dummy properties. It's very odd to populate a list like that to start with - that's typically something you do with an array which has a fixed size. One of the main benefits of using a List such as ArrayList is that it's dynamically sized.
Java is recognizing the members just fine. You have 20 members in the array, indexed from index 0 through index 19.
You are asking for index 20, which does not exist.
The loop for:
while(reaper.hasMoreRecords())
must be running many more times than you expect, and your data is hitting the found == false if condition (which you can just say if (!found) { ... ) many times, and on the 21st time it fails with the index-out-of-bounds exception.
You should figure out how to use your debugger too.

Can I manipulate the way that variables change in Java?

If the die shows a 6, the player doesn't move at all on this turn and also forfeits the next turn.
To accomplish this, I have tried an integer type warning marker variable for the player and an integer type time counter variable.
If the die shows 6, I want to increment the warning marker variable by 1 during the first run(and have the while loop do nothing), then keep the value at 1 during the second run (while loop will not work), then lower it back down to 0 for the third run of the while loop (so the while loop will work). The marker will stay at zero unless the die shows a 6 again, after which the same process will repeat.
I have a while loop like this:
while the warning marker is equal to 0 {
Do Stuff
if the die shows a 6, the warning marker increases by 1.
the time counter also increases by 1.
}
How do I manipulate the variables to get the result that I need? Or is my partially complete method absolutely off in terms of logic?
Thanks.
Can u tell me if this works for you?
flag=true;
while condition{
if flag==true{
if die == 6
{
flag=false;
continue;}
}
else { Do STUFF }
} else
{
flag==true;
}
}
I think you want to reword this problem.
This is what I understood. You have a warning marker.
You have a loop that checks whether the marker is 0, if it is then you do something.
If the die is a six, you will increase the warning marker. If its new value is 3, then you will reset it to 0. Meanwhile, the time counter is always increasing.
If this is correct, I think you want something like:
int warningMarker = 0;
int timeMarker = 0;
while (true) {
if (die == 6) {
++warningMarker;
if (warningMarker == 3) {
warningMarker = 0;
}
}
if (warningMarker == 0) {
doSomething();
}
++timeMarker;
}
Java is Object-Oriented Pragramming language. Use this feature.
See following pseudocode and let me know if you have problem in undestanding it.
Create a class Player as following:
class Player
{
boolean skipChance = false;
... // Other fields
... //
}
Change your while as following:
while(isGameOn())
{
Player p = getCurrentPlayer();
if( ! p.skipChance)
{
int val = p.throwDice();
if(val == 6)
{
p.skipChance = true;
continue; // control moves to while.
}
// Do stuff
}
else
{
p.skipChance = false;
}
}

Categories

Resources