in src/org/jetbrains/java/decompiler/modules/decompiler/ExprProcessor.java [265:612]
public void processBlock(BasicBlockStatement stat, PrimitiveExpressionList data, StructClass cl) {
ConstantPool pool = cl.getPool();
StructBootstrapMethodsAttribute bootstrap = cl.getAttribute(StructGeneralAttribute.ATTRIBUTE_BOOTSTRAP_METHODS);
BasicBlock block = stat.getBlock();
ExpressionStack stack = data.getStack();
List<Exprent> exprList = data.getExpressions();
InstructionSequence seq = block.getSeq();
for (int i = 0; i < seq.length(); i++) {
Instruction instr = seq.getInstr(i);
Integer offset = block.getOriginalOffset(i);
BitSet offsets = null;
if (offset >= 0) {
offsets = new BitSet();
offsets.set(offset);
int end_offset = block.getOriginalOffset(i + 1);
if (end_offset > offset && seq.length() > i + 1) {
offsets.set(offset, end_offset);
}
}
switch (instr.opcode) {
case CodeConstants.opc_aconst_null:
pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_NULL, null, offsets));
break;
case CodeConstants.opc_bipush:
case CodeConstants.opc_sipush:
pushEx(stack, exprList, new ConstExprent(instr.operand(0), true, offsets));
break;
case CodeConstants.opc_lconst_0:
case CodeConstants.opc_lconst_1:
pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_LONG, (long)(instr.opcode - CodeConstants.opc_lconst_0), offsets));
break;
case CodeConstants.opc_fconst_0:
case CodeConstants.opc_fconst_1:
case CodeConstants.opc_fconst_2:
pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_FLOAT, (float)(instr.opcode - CodeConstants.opc_fconst_0), offsets));
break;
case CodeConstants.opc_dconst_0:
case CodeConstants.opc_dconst_1:
pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_DOUBLE, (double)(instr.opcode - CodeConstants.opc_dconst_0), offsets));
break;
case CodeConstants.opc_ldc:
case CodeConstants.opc_ldc_w:
case CodeConstants.opc_ldc2_w: {
PooledConstant cn = pool.getConstant(instr.operand(0));
if (cn instanceof PrimitiveConstant) {
pushEx(stack, exprList, new ConstExprent(constants[cn.type - CodeConstants.CONSTANT_Integer], ((PrimitiveConstant)cn).value, offsets));
}
else if (cn instanceof LinkConstant) {
//TODO: for now treat Links as Strings
pushEx(stack, exprList, new ConstExprent(VarType.VARTYPE_STRING, ((LinkConstant)cn).elementName, offsets));
}
break;
}
case CodeConstants.opc_iload:
case CodeConstants.opc_lload:
case CodeConstants.opc_fload:
case CodeConstants.opc_dload:
case CodeConstants.opc_aload:
VarExprent varExprent = new VarExprent(instr.operand(0), varTypes[instr.opcode - CodeConstants.opc_iload], varProcessor, offsets);
varProcessor.findLVT(varExprent, offset + instr.length);
pushEx(stack, exprList, varExprent);
break;
case CodeConstants.opc_iaload:
case CodeConstants.opc_laload:
case CodeConstants.opc_faload:
case CodeConstants.opc_daload:
case CodeConstants.opc_aaload:
case CodeConstants.opc_baload:
case CodeConstants.opc_caload:
case CodeConstants.opc_saload: {
Exprent index = stack.pop();
Exprent arr = stack.pop();
VarType type = instr.opcode == CodeConstants.opc_laload ? VarType.VARTYPE_LONG : instr.opcode == CodeConstants.opc_daload ? VarType.VARTYPE_DOUBLE : null;
pushEx(stack, exprList, new ArrayExprent(arr, index, arrTypes[instr.opcode - CodeConstants.opc_iaload], offsets), type);
break;
}
case CodeConstants.opc_istore:
case CodeConstants.opc_lstore:
case CodeConstants.opc_fstore:
case CodeConstants.opc_dstore:
case CodeConstants.opc_astore: {
Exprent value = stack.pop();
int varIndex = instr.operand(0);
if (offsets != null) { //TODO: Figure out why this nulls in some cases
offsets.set(offset, offset + instr.length);
}
VarExprent left = new VarExprent(varIndex, varTypes[instr.opcode - CodeConstants.opc_istore], varProcessor, offsets);
varProcessor.findLVT(left, offset + instr.length);
exprList.add(new AssignmentExprent(left, value, offsets));
break;
}
case CodeConstants.opc_iastore:
case CodeConstants.opc_lastore:
case CodeConstants.opc_fastore:
case CodeConstants.opc_dastore:
case CodeConstants.opc_aastore:
case CodeConstants.opc_bastore:
case CodeConstants.opc_castore:
case CodeConstants.opc_sastore: {
Exprent value = stack.pop();
Exprent index = stack.pop();
Exprent array = stack.pop();
ArrayExprent left = new ArrayExprent(array, index, arrTypes[instr.opcode - CodeConstants.opc_iastore], offsets);
exprList.add(new AssignmentExprent(left, value, offsets));
break;
}
case CodeConstants.opc_iadd:
case CodeConstants.opc_ladd:
case CodeConstants.opc_fadd:
case CodeConstants.opc_dadd:
case CodeConstants.opc_isub:
case CodeConstants.opc_lsub:
case CodeConstants.opc_fsub:
case CodeConstants.opc_dsub:
case CodeConstants.opc_imul:
case CodeConstants.opc_lmul:
case CodeConstants.opc_fmul:
case CodeConstants.opc_dmul:
case CodeConstants.opc_idiv:
case CodeConstants.opc_ldiv:
case CodeConstants.opc_fdiv:
case CodeConstants.opc_ddiv:
case CodeConstants.opc_irem:
case CodeConstants.opc_lrem:
case CodeConstants.opc_frem:
case CodeConstants.opc_drem:
pushEx(stack, exprList, new FunctionExprent(func1[(instr.opcode - CodeConstants.opc_iadd) / 4], stack, offsets));
break;
case CodeConstants.opc_ishl:
case CodeConstants.opc_lshl:
case CodeConstants.opc_ishr:
case CodeConstants.opc_lshr:
case CodeConstants.opc_iushr:
case CodeConstants.opc_lushr:
case CodeConstants.opc_iand:
case CodeConstants.opc_land:
case CodeConstants.opc_ior:
case CodeConstants.opc_lor:
case CodeConstants.opc_ixor:
case CodeConstants.opc_lxor:
pushEx(stack, exprList, new FunctionExprent(func2[(instr.opcode - CodeConstants.opc_ishl) / 2], stack, offsets));
break;
case CodeConstants.opc_ineg:
case CodeConstants.opc_lneg:
case CodeConstants.opc_fneg:
case CodeConstants.opc_dneg:
pushEx(stack, exprList, new FunctionExprent(FunctionExprent.FUNCTION_NEG, stack, offsets));
break;
case CodeConstants.opc_iinc: {
VarExprent varExpr = new VarExprent(instr.operand(0), VarType.VARTYPE_INT, varProcessor, offsets);
varProcessor.findLVT(varExpr, offset + instr.length);
int type = instr.operand(1) < 0 ? FunctionExprent.FUNCTION_SUB : FunctionExprent.FUNCTION_ADD;
List<Exprent> operands = Arrays.asList(varExpr.copy(), new ConstExprent(VarType.VARTYPE_INT, Math.abs(instr.operand(1)), null));
exprList.add(new AssignmentExprent(varExpr, new FunctionExprent(type, operands, offsets), offsets));
break;
}
case CodeConstants.opc_i2l:
case CodeConstants.opc_i2f:
case CodeConstants.opc_i2d:
case CodeConstants.opc_l2i:
case CodeConstants.opc_l2f:
case CodeConstants.opc_l2d:
case CodeConstants.opc_f2i:
case CodeConstants.opc_f2l:
case CodeConstants.opc_f2d:
case CodeConstants.opc_d2i:
case CodeConstants.opc_d2l:
case CodeConstants.opc_d2f:
case CodeConstants.opc_i2b:
case CodeConstants.opc_i2c:
case CodeConstants.opc_i2s:
pushEx(stack, exprList, new FunctionExprent(func3[instr.opcode - CodeConstants.opc_i2l], stack, offsets));
break;
case CodeConstants.opc_lcmp:
case CodeConstants.opc_fcmpl:
case CodeConstants.opc_fcmpg:
case CodeConstants.opc_dcmpl:
case CodeConstants.opc_dcmpg:
pushEx(stack, exprList, new FunctionExprent(func4[instr.opcode - CodeConstants.opc_lcmp], stack, offsets));
break;
case CodeConstants.opc_ifeq:
case CodeConstants.opc_ifne:
case CodeConstants.opc_iflt:
case CodeConstants.opc_ifge:
case CodeConstants.opc_ifgt:
case CodeConstants.opc_ifle:
exprList.add(new IfExprent(negIfs[func5[instr.opcode - CodeConstants.opc_ifeq]], stack, offsets));
break;
case CodeConstants.opc_if_icmpeq:
case CodeConstants.opc_if_icmpne:
case CodeConstants.opc_if_icmplt:
case CodeConstants.opc_if_icmpge:
case CodeConstants.opc_if_icmpgt:
case CodeConstants.opc_if_icmple:
case CodeConstants.opc_if_acmpeq:
case CodeConstants.opc_if_acmpne:
exprList.add(new IfExprent(negIfs[func6[instr.opcode - CodeConstants.opc_if_icmpeq]], stack, offsets));
break;
case CodeConstants.opc_ifnull:
case CodeConstants.opc_ifnonnull:
exprList.add(new IfExprent(negIfs[func7[instr.opcode - CodeConstants.opc_ifnull]], stack, offsets));
break;
case CodeConstants.opc_tableswitch:
case CodeConstants.opc_lookupswitch:
exprList.add(new SwitchExprent(stack.pop(), offsets));
break;
case CodeConstants.opc_ireturn:
case CodeConstants.opc_lreturn:
case CodeConstants.opc_freturn:
case CodeConstants.opc_dreturn:
case CodeConstants.opc_areturn:
case CodeConstants.opc_return:
case CodeConstants.opc_athrow:
exprList.add(new ExitExprent(instr.opcode == CodeConstants.opc_athrow ? ExitExprent.EXIT_THROW : ExitExprent.EXIT_RETURN,
instr.opcode == CodeConstants.opc_return ? null : stack.pop(),
instr.opcode == CodeConstants.opc_athrow ? null : methodDescriptor.ret,
offsets, methodDescriptor));
break;
case CodeConstants.opc_monitorenter:
case CodeConstants.opc_monitorexit:
exprList.add(new MonitorExprent(func8[instr.opcode - CodeConstants.opc_monitorenter], stack.pop(), offsets));
break;
case CodeConstants.opc_checkcast:
case CodeConstants.opc_instanceof:
stack.push(new ConstExprent(new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true), null, null));
case CodeConstants.opc_arraylength:
pushEx(stack, exprList, new FunctionExprent(functionMap.get(instr.opcode), stack, offsets));
break;
case CodeConstants.opc_getstatic:
case CodeConstants.opc_getfield:
pushEx(stack, exprList,
new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == CodeConstants.opc_getstatic ? null : stack.pop(), offsets));
break;
case CodeConstants.opc_putstatic:
case CodeConstants.opc_putfield:
Exprent valField = stack.pop();
Exprent exprField =
new FieldExprent(pool.getLinkConstant(instr.operand(0)), instr.opcode == CodeConstants.opc_putstatic ? null : stack.pop(), offsets);
exprList.add(new AssignmentExprent(exprField, valField, offsets));
break;
case CodeConstants.opc_invokevirtual:
case CodeConstants.opc_invokespecial:
case CodeConstants.opc_invokestatic:
case CodeConstants.opc_invokeinterface:
case CodeConstants.opc_invokedynamic:
if (instr.opcode != CodeConstants.opc_invokedynamic || instr.bytecodeVersion >= CodeConstants.BYTECODE_JAVA_7) {
LinkConstant invoke_constant = pool.getLinkConstant(instr.operand(0));
List<PooledConstant> bootstrap_arguments = null;
if (instr.opcode == CodeConstants.opc_invokedynamic && bootstrap != null) {
bootstrap_arguments = bootstrap.getMethodArguments(invoke_constant.index1);
}
InvocationExprent exprInv = new InvocationExprent(instr.opcode, invoke_constant, bootstrap_arguments, stack, offsets);
if (exprInv.getDescriptor().ret.getType() == CodeConstants.TYPE_VOID) {
exprList.add(exprInv);
}
else {
pushEx(stack, exprList, exprInv);
}
}
break;
case CodeConstants.opc_new:
case CodeConstants.opc_anewarray:
case CodeConstants.opc_multianewarray:
int dimensions = (instr.opcode == CodeConstants.opc_new) ? 0 : (instr.opcode == CodeConstants.opc_anewarray) ? 1 : instr.operand(1);
VarType arrType = new VarType(pool.getPrimitiveConstant(instr.operand(0)).getString(), true);
if (instr.opcode != CodeConstants.opc_multianewarray) {
arrType = arrType.resizeArrayDim(arrType.getArrayDim() + dimensions);
}
pushEx(stack, exprList, new NewExprent(arrType, stack, dimensions, offsets));
break;
case CodeConstants.opc_newarray:
pushEx(stack, exprList, new NewExprent(new VarType(arrTypeIds[instr.operand(0) - 4], 1), stack, 1, offsets));
break;
case CodeConstants.opc_dup:
pushEx(stack, exprList, stack.getByOffset(-1).copy());
break;
case CodeConstants.opc_dup_x1:
insertByOffsetEx(-2, stack, exprList, -1);
break;
case CodeConstants.opc_dup_x2:
if (stack.getByOffset(-2).getExprType().getStackSize() == 2) {
insertByOffsetEx(-2, stack, exprList, -1);
}
else {
insertByOffsetEx(-3, stack, exprList, -1);
}
break;
case CodeConstants.opc_dup2:
if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
pushEx(stack, exprList, stack.getByOffset(-1).copy());
}
else {
pushEx(stack, exprList, stack.getByOffset(-2).copy());
pushEx(stack, exprList, stack.getByOffset(-2).copy());
}
break;
case CodeConstants.opc_dup2_x1:
if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
insertByOffsetEx(-2, stack, exprList, -1);
}
else {
insertByOffsetEx(-3, stack, exprList, -2);
insertByOffsetEx(-3, stack, exprList, -1);
}
break;
case CodeConstants.opc_dup2_x2:
if (stack.getByOffset(-1).getExprType().getStackSize() == 2) {
if (stack.getByOffset(-2).getExprType().getStackSize() == 2) {
insertByOffsetEx(-2, stack, exprList, -1);
}
else {
insertByOffsetEx(-3, stack, exprList, -1);
}
}
else {
if (stack.getByOffset(-3).getExprType().getStackSize() == 2) {
insertByOffsetEx(-3, stack, exprList, -2);
insertByOffsetEx(-3, stack, exprList, -1);
}
else {
insertByOffsetEx(-4, stack, exprList, -2);
insertByOffsetEx(-4, stack, exprList, -1);
}
}
break;
case CodeConstants.opc_swap:
insertByOffsetEx(-2, stack, exprList, -1);
stack.pop();
break;
case CodeConstants.opc_pop:
stack.pop();
break;
case CodeConstants.opc_pop2:
if (stack.getByOffset(-1).getExprType().getStackSize() == 1) {
// Since the value at the top of the stack is a value of category 1 (JVMS9 2.11.1),
// we should remove one more item from the stack.
// See JVMS9 pop2 chapter.
stack.pop();
}
stack.pop();
break;
}
}
}