Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(#750): Compute Stack Map Frames #832

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from
Draft
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 @@ -27,11 +27,13 @@
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.eolang.jeo.representation.directives.DirectivesFrame;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.LabelNode;
import org.xembly.Directive;

Expand Down Expand Up @@ -176,14 +178,126 @@ public List<Label> jumps() {

@Override
public String view() {
final String name;
switch (this.type) {
case Opcodes.F_NEW:
name = "NEW";
break;
case Opcodes.F_FULL:
name = "FULL";
break;
case Opcodes.F_APPEND:
name = "APPEND";
break;
case Opcodes.F_CHOP:
name = "CHOP";
break;
case Opcodes.F_SAME:
name = "SAME";
break;
case Opcodes.F_SAME1:
name = "SAME1";
break;
default:
name = "UNKNOWN";
}
return String.format(
"Frame %d locals %d stack %d",
this.type,
"Frame %s locals %d stack %d",
name,
this.nlocal,
this.nstack
);
}

public int stackDiff(final BytecodeFrame other) {
return this.nstack - other.nstack;
}


public boolean stackOneElement() {
return this.nstack == 1;
}

public boolean stackEmpty() {
return this.nstack == 0;
}

public BytecodeFrame withType(final int type) {
return new BytecodeFrame(
type,
this.nlocal,
this.locals,
this.nstack,
this.stack
);
}

public BytecodeFrame substract(final BytecodeFrame other) {
List<Object> result = new ArrayList<>(0);
final Object[] tlocals = this.locals;
final Object[] olocals = other.locals;
int size = Math.max(tlocals.length, olocals.length);
for (int i = 0; i < size; ++i) {
final Object tlocal;
if (tlocals.length <= i) {
tlocal = Opcodes.TOP;
} else {
tlocal = tlocals[i];
}
final Object olocal;
if (olocals.length <= i) {
olocal = Opcodes.TOP;
} else {
olocal = olocals[i];
}
if (!tlocal.equals(olocal)) {
result.add(tlocal);
}
}
Object[] res = result.stream().filter(arg -> !arg.equals(Opcodes.TOP))
.toArray();
return new BytecodeFrame(
this.type,
res.length,
res,
this.nstack,
this.stack
);
}

public int localsDiff(final BytecodeFrame previous) {
return this.nlocal - previous.nlocal;
}

/**
* Check if the frame has the same locals.
* @param frame Frame to compare.
* @return True if the frame has the same locals.
*/
public boolean sameLocals(final BytecodeFrame frame) {
final int size = Math.max(this.nlocal, frame.nlocal);
final Object[] current = this.locals;
final Object[] other = frame.locals;
for (int index = 0; index < size; ++index) {
final Object curr;
if (current.length <= index) {
curr = Opcodes.TOP;
} else {
curr = current[index];
}
final Object oth;
if (other.length <= index) {
oth = Opcodes.TOP;
} else {
oth = other[index];
}
if (!curr.equals(oth)) {
return false;
}
}
return true;
}

/**
* Convert a list to array.
* @param list List of objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,57 @@ public boolean isOpcode() {
return true;
}


public int localIndex() {
return this.varIndex();
}

/**
* // Standard stack map frame element types.
*
* Integer TOP = Frame.ITEM_TOP;
* Integer INTEGER = Frame.ITEM_INTEGER;
* Integer FLOAT = Frame.ITEM_FLOAT;
* Integer DOUBLE = Frame.ITEM_DOUBLE;
* Integer LONG = Frame.ITEM_LONG;
* Integer NULL = Frame.ITEM_NULL;
* Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS;
* @return
*/
public Object elementType() {
final Object result;
switch (this.opcode) {
case Opcodes.ILOAD:
case Opcodes.ISTORE:
result = Opcodes.INTEGER;
break;
case Opcodes.LLOAD:
case Opcodes.LSTORE:
result = Opcodes.LONG;
break;
case Opcodes.FLOAD:
case Opcodes.FSTORE:
result = Opcodes.FLOAT;
break;
case Opcodes.DLOAD:
case Opcodes.DSTORE:
result = Opcodes.DOUBLE;
break;
case Opcodes.ALOAD:
case Opcodes.ASTORE:
result = Opcodes.TOP;
break;
default:
throw new IllegalStateException(
String.format(
"Unexpected opcode for local variable instruction: %s",
new OpcodeName(this.opcode).simplified()
)
);
}
return result;
}

/**
* Impact of each instruction on the stack.
* @return Stack impact.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import lombok.EqualsAndHashCode;
Expand Down Expand Up @@ -375,6 +376,32 @@ BytecodeMaxs currentMaxs() {
return this.maxs;
}

/**
* Compute frames.
* @return Frames.
*/
List<BytecodeFrame> computeFrames() {
return new StackMapFrames(
this.properties,
this.instructions,
this.tryblocks.stream()
.filter(BytecodeTryCatchBlock.class::isInstance)
.map(BytecodeTryCatchBlock.class::cast)
.collect(Collectors.toList())
).frames();
}

/**
* Current frames.
* @return Frames.
*/
List<BytecodeFrame> currentFrames() {
return this.instructions.stream()
.filter(BytecodeFrame.class::isInstance)
.map(BytecodeFrame.class::cast)
.collect(Collectors.toList());
}

/**
* Add instruction.
* @param opcode Opcode.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,18 @@ Label handlerLabel() {
return this.handler;
}

/**
* Exception type.
* @return Type.
*/
String descriptor() {
final String result;
if (this.type == null) {
result = "java/lang/Throwable";
} else {
result = this.type;
}
return result;
}

}
Loading
Loading