in vm/vmcore/src/verifier-3363/base/context_x.cpp [347:1802]
vf_Result vf_Context_x<ActualClass, WorkmapElement, _WorkmapElement, StackmapElement>::dataflow_instruction(Address instr) {
vf_Result tcr;
OpCode opcode = (OpCode)m_bytecode[instr];
processed_instruction = instr;
bool wide = false;
if( opcode == OP_WIDE ) {
wide = true;
opcode = (OpCode)m_bytecode[instr+1];
}
switch( opcode ) {
case OP_AALOAD: {
// check stack
if( !workmap_can_pop(2) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement index = workmap_pop();
WorkmapElement arrayref = workmap_pop();
//check INs
if( !workmap_expect_strict(index, SM_INTEGER) ||
!workmap_expect(arrayref, tpool.sm_get_const_arrayref_of_object()) )
{
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//create OUTs
WorkmapElement wme;
if( (tcr = new_scalar_array2ref_constraint(&arrayref, &wme)) != VF_OK ) {
return tcr;
}
//pop OUTs
workmap_push(wme);
break;
}
case OP_AASTORE: {
// check stack
if( !workmap_can_pop(3) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement value = workmap_pop();
WorkmapElement index = workmap_pop();
WorkmapElement arrayref = workmap_pop();
//check & bind INs
if( !workmap_expect_strict(index, SM_INTEGER) ||
!workmap_expect(value, tpool.sm_get_const_object()) ||
!workmap_expect(arrayref, tpool.sm_get_const_arrayref_of_object()) )
{
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
break;
}
case OP_ACONST_NULL: {
// check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//create & pop OUTs
workmap_push_const(SM_NULL);
break;
}
case OP_ALOAD: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call macro
CHECK_ALOAD( local_idx );
break;
}
case OP_ALOAD_0: case OP_ALOAD_1:
case OP_ALOAD_2: case OP_ALOAD_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_ALOAD_0;
//call macro
CHECK_ALOAD( local_idx );
break;
}
case OP_ANEWARRAY: {
//check stack
if( !workmap_can_pop(1) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement count = workmap_pop();
//check INs
if( !workmap_expect_strict(count, SM_INTEGER) ) return error(VF_ErrorIncompatibleArgument, "incompartible argument");
//get OUT type
SmConstant arrayref;
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
if( !tpool.cpool_get_array(cp_idx, &arrayref) ) return error(VF_ErrorConstantPool, "incorrect type for anewarray");
//push OUTs
workmap_push_const( arrayref );
break;
}
case OP_ARETURN: {
if( return_type == SM_BOGUS ) return error(VF_ErrorDataFlow, "returned a value from a void method");
POP_ref( return_type );
break;
}
case OP_ARRAYLENGTH: {
//check stack
if( !workmap_can_pop(1) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement arrayref = workmap_pop();
//check INs
if( !workmap_expect(arrayref, SM_ANYARRAY) ) return error(VF_ErrorIncompatibleArgument, "incompartible argument");
//push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_ASTORE: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call MACRO
CHECK_ASTORE( local_idx );
break;
}
case OP_ASTORE_0: case OP_ASTORE_1:
case OP_ASTORE_2: case OP_ASTORE_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_ASTORE_0;
//call MACRO
CHECK_ASTORE( local_idx );
break;
}
case OP_ATHROW: {
POP_ref( tpool.sm_get_const_throwable() );
break;
}
case OP_BALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_bb();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_BASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_bb();
//call MACRO that loads inegral types
CHECK_xASTORE( workmap_expect( arrayref, type ), SM_INTEGER );
break;
}
case OP_BIPUSH:
case OP_SIPUSH: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//create and push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_CALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_char();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_CASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_char();
//call MACRO that loads inegral types
CHECK_xASTORE( workmap_expect( arrayref, type ), SM_INTEGER );
break;
}
case OP_CHECKCAST: {
//check stack
if( !workmap_can_pop(1) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement inref = workmap_pop();
//check INs
if( !workmap_expect(inref, tpool.sm_get_const_object()) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//check instruction & create OUTs
SmConstant outref;
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
if( !tpool.cpool_get_class(cp_idx, &outref) ) return error(VF_ErrorConstantPool, "incorrect constantpool entry");
//push OUTs
workmap_push_const(outref);
break;
}
case OP_D2F: {
POP_xx ( SM_DOUBLE );
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_D2I: {
POP_xx ( SM_DOUBLE );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_D2L: {
POP_xx ( SM_DOUBLE );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_DADD: case OP_DDIV:
case OP_DMUL: case OP_DREM: case OP_DSUB: {
POP_xx_xx( SM_DOUBLE );
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_DALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_double();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_2w_push_const( SM_DOUBLE );
break;
}
case OP_DASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_double();
//call MACRO that loads inegral types
CHECK_xxASTORE( workmap_expect( arrayref, type ), SM_DOUBLE );
break;
}
case OP_DCMPL: case OP_DCMPG: {
POP_xx_xx( SM_DOUBLE );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_DCONST_0:
case OP_DCONST_1: {
//check stack
if( !workmap_can_push(2) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_DLOAD: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call macro
CHECK_xxLOAD( local_idx, SM_DOUBLE );
break;
}
case OP_DLOAD_0: case OP_DLOAD_1:
case OP_DLOAD_2: case OP_DLOAD_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_DLOAD_0;
//call macro
CHECK_xxLOAD( local_idx, SM_DOUBLE );
break;
}
case OP_DNEG: {
POP_xx( SM_DOUBLE );
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_DRETURN: {
if( return_type != SM_DOUBLE ) return error(VF_ErrorDataFlow, "incorrect type returned");
POP_xx( SM_DOUBLE );
break;
}
case OP_DSTORE: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
CHECK_xxSTORE( local_idx, SM_DOUBLE );
break;
}
case OP_DSTORE_0: case OP_DSTORE_1:
case OP_DSTORE_2: case OP_DSTORE_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_DSTORE_0;
CHECK_xxSTORE( local_idx, SM_DOUBLE );
break;
}
case OP_DUP: {
//check stack
if( !workmap_can_pop(1) || !workmap_can_push(1) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value = workmap_pop();
//check INs
if( !workmap_expect(value, SM_LOW_WORD) ) return error(VF_ErrorIncompatibleArgument, "incompartible argument");
//push OUTs
workmap_push( value );
workmap_push( value );
break;
}
case OP_DUP_X1: {
//check stack
if( !workmap_can_pop(2) || !workmap_can_push(1) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
//check INs
if( !workmap_expect(value1, SM_LOW_WORD) || !workmap_expect(value2, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value1 );
workmap_push( value2 );
workmap_push( value1 );
break;
}
case OP_DUP_X2: {
//check stack
if( !workmap_can_pop(3) || !workmap_can_push(1) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
WorkmapElement value3 = workmap_pop();
//check INs !!! SM_HIGH_WORD is a two-word element: Long and Double are not !!!
if( !workmap_expect(value1, SM_LOW_WORD) || !workmap_expect(value3, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value1 );
workmap_push( value3 );
workmap_push( value2 );
workmap_push( value1 );
break;
}
case OP_DUP2: {
//check stack
if( !workmap_can_pop(2) || !workmap_can_push(2) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
//check INs
if( !workmap_expect(value2, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value2 );
workmap_push( value1 );
workmap_push( value2 );
workmap_push( value1 );
break;
}
case OP_DUP2_X1: {
//check stack
if( !workmap_can_pop(3) || !workmap_can_push(2) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
WorkmapElement value3 = workmap_pop();
//check INs
if( !workmap_expect(value2, SM_LOW_WORD) || !workmap_expect(value3, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value2 );
workmap_push( value1 );
workmap_push( value3 );
workmap_push( value2 );
workmap_push( value1 );
break;
}
case OP_DUP2_X2: {
//check stack
if( !workmap_can_pop(4) || !workmap_can_push(2) ) {
return error(VF_ErrorDataFlow, "unable to pop/push");
}
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
WorkmapElement value3 = workmap_pop();
WorkmapElement value4 = workmap_pop();
//check INs
if( !workmap_expect(value2, SM_LOW_WORD) || !workmap_expect(value4, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value2 );
workmap_push( value1 );
workmap_push( value4 );
workmap_push( value3 );
workmap_push( value2 );
workmap_push( value1 );
break;
}
case OP_F2D: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
POP_x ( SM_FLOAT );
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_F2I: {
POP_x ( SM_FLOAT );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_F2L: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
POP_x ( SM_FLOAT );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_FADD: case OP_FDIV:
case OP_FMUL: case OP_FREM:
case OP_FSUB: {
POP_x_x( SM_FLOAT );
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_FALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_float();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_push_const( SM_FLOAT );
break;
}
case OP_FASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_float();
//call MACRO that loads inegral types
CHECK_xASTORE( workmap_expect( arrayref, type ), SM_FLOAT );
break;
}
case OP_FCMPL: case OP_FCMPG: {
POP_x_x( SM_FLOAT );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_FCONST_0:
case OP_FCONST_1:
case OP_FCONST_2: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_FLOAD: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call macro
CHECK_xLOAD( local_idx, SM_FLOAT );
break;
}
case OP_FLOAD_0: case OP_FLOAD_1:
case OP_FLOAD_2: case OP_FLOAD_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_FLOAD_0;
//call macro
CHECK_xLOAD( local_idx, SM_FLOAT );
break;
}
case OP_FNEG: {
POP_x( SM_FLOAT );
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_FRETURN: {
if( return_type != SM_FLOAT ) return error(VF_ErrorDataFlow, "incorrect type returned");
POP_x( SM_FLOAT );
break;
}
case OP_FSTORE: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
CHECK_xSTORE( local_idx, SM_FLOAT );
break;
}
case OP_FSTORE_0: case OP_FSTORE_1:
case OP_FSTORE_2: case OP_FSTORE_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_FSTORE_0;
CHECK_xSTORE( local_idx, SM_FLOAT );
break;
}
case OP_GOTO: case OP_GOTO_W: case OP_NOP:
break;
case OP_I2B: case OP_I2C: case OP_I2S: {
POP_x ( SM_INTEGER );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_I2D: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
POP_x ( SM_INTEGER );
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_I2F: {
POP_x ( SM_INTEGER );
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_I2L: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
POP_x ( SM_INTEGER );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_IADD: case OP_IAND:
case OP_IDIV: case OP_IMUL:
case OP_IOR: case OP_IREM:
case OP_ISHL: case OP_ISHR:
case OP_ISUB: case OP_IUSHR:
case OP_IXOR: {
POP_x_x ( SM_INTEGER );
//push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_IALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_integer();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_IASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_integer();
//call MACRO that loads inegral types
CHECK_xASTORE( workmap_expect( arrayref, type ), SM_INTEGER );
break;
}
case OP_ICONST_M1: case OP_ICONST_0:
case OP_ICONST_1: case OP_ICONST_2:
case OP_ICONST_3: case OP_ICONST_4:
case OP_ICONST_5: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_IF_ACMPEQ:
case OP_IF_ACMPNE: {
POP_ref( tpool.sm_get_const_object() );
POP_ref( tpool.sm_get_const_object() );
break;
}
case OP_IF_ICMPEQ: case OP_IF_ICMPNE:
case OP_IF_ICMPLT: case OP_IF_ICMPGE:
case OP_IF_ICMPGT: case OP_IF_ICMPLE: {
POP_x_x( SM_INTEGER );
break;
}
case OP_IFEQ: case OP_IFNE:
case OP_IFLT: case OP_IFGE:
case OP_IFGT: case OP_IFLE:
case OP_LOOKUPSWITCH:
case OP_TABLESWITCH: {
POP_x( SM_INTEGER );
break;
}
case OP_IFNONNULL:
case OP_IFNULL:
case OP_MONITORENTER:
case OP_MONITOREXIT: {
POP_ref( tpool.sm_get_const_object() );
break;
}
case OP_IINC: {
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
if( !workmap_valid_local(local_idx) ) {
return error(VF_ErrorLocals, "invalid local index");
}
WorkmapElement value = workmap_get_local(local_idx);
if( !workmap_expect_strict(value, SM_INTEGER) ) return error(VF_ErrorIncompatibleArgument, "incompartible argument");
break;
}
case OP_ILOAD: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call macro
CHECK_xLOAD( local_idx, SM_INTEGER );
break;
}
case OP_ILOAD_0: case OP_ILOAD_1:
case OP_ILOAD_2: case OP_ILOAD_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_ILOAD_0;
//call macro
CHECK_xLOAD( local_idx, SM_INTEGER );
break;
}
case OP_INEG: {
POP_x( SM_INTEGER );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_INSTANCEOF: {
//check instruction
unsigned cp_idx = read_uint16(m_bytecode + instr + 1);
if( !tpool.cpool_is_reftype(cp_idx) ) return error(VF_ErrorConstantPool, "incorrect constantpool entry");
POP_ref( tpool.sm_get_const_object() );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_IRETURN: {
if( return_type != SM_INTEGER ) return error(VF_ErrorDataFlow, "incorrect type returned");
POP_x( SM_INTEGER );
break;
}
case OP_ISTORE: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
CHECK_xSTORE( local_idx, SM_INTEGER );
break;
}
case OP_ISTORE_0: case OP_ISTORE_1:
case OP_ISTORE_2: case OP_ISTORE_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_ISTORE_0;
CHECK_xSTORE( local_idx, SM_INTEGER );
break;
}
case OP_L2D: {
POP_xx ( SM_LONG );
//push OUTs
workmap_2w_push_const(SM_DOUBLE);
break;
}
case OP_L2F: {
POP_xx ( SM_LONG );
//push OUTs
workmap_push_const(SM_FLOAT);
break;
}
case OP_L2I: {
POP_xx ( SM_LONG );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_LADD: case OP_LAND: case OP_LDIV:
case OP_LMUL: case OP_LOR: case OP_LREM:
case OP_LSUB: case OP_LXOR: {
POP_xx_xx( SM_LONG );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_LALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_long();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_2w_push_const( SM_LONG );
break;
}
case OP_LASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_long();
//call MACRO that loads inegral types
CHECK_xxASTORE( workmap_expect( arrayref, type ), SM_LONG );
break;
}
case OP_LCMP: {
POP_xx_xx( SM_LONG );
//push OUTs
workmap_push_const(SM_INTEGER);
break;
}
case OP_LCONST_0:
case OP_LCONST_1: {
//check stack
if( !workmap_can_push(2) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_LDC: {
//check instruction and create OUTs
unsigned cp_idx = m_bytecode[instr + 1];
SmConstant el = tpool.cpool_get_ldcarg(cp_idx);
if( el == SM_BOGUS ) return error(VF_ErrorConstantPool, "incorrect constantpool entry");
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_push_const(el);
break;
}
case OP_LDC_W: {
//check instruction and create OUTs
unsigned cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant el = tpool.cpool_get_ldcarg(cp_idx);
if( el == SM_BOGUS ) return error(VF_ErrorConstantPool, "incorrect constantpool entry");
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_push_const(el);
break;
}
case OP_LDC2_W: {
//check instruction and create OUTs
unsigned cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant el = tpool.cpool_get_ldc2arg(cp_idx);
if( el == SM_BOGUS ) return error(VF_ErrorConstantPool, "incorrect constantpool entry");
//check stack
if( !workmap_can_push(2) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//push OUTs
workmap_2w_push_const(el);
break;
}
case OP_LLOAD: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//call macro
CHECK_xxLOAD( local_idx, SM_LONG );
break;
}
case OP_LLOAD_0: case OP_LLOAD_1:
case OP_LLOAD_2: case OP_LLOAD_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_LLOAD_0;
//call macro
CHECK_xxLOAD( local_idx, SM_LONG );
break;
}
case OP_LNEG: {
POP_xx( SM_LONG );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_LRETURN: {
if( return_type != SM_LONG ) return error(VF_ErrorDataFlow, "incorrect type returned");
POP_xx( SM_LONG );
break;
}
case OP_LSTORE: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
CHECK_xxSTORE( local_idx, SM_LONG );
break;
}
case OP_LSTORE_0: case OP_LSTORE_1:
case OP_LSTORE_2: case OP_LSTORE_3: {
//get local index from opcode
U_8 local_idx = opcode - OP_LSTORE_0;
CHECK_xxSTORE( local_idx, SM_LONG );
break;
}
case OP_LSHL: case OP_LSHR: case OP_LUSHR: {
POP_x( SM_INTEGER );
POP_xx( SM_LONG );
//push OUTs
workmap_2w_push_const(SM_LONG);
break;
}
case OP_MULTIANEWARRAY: {
unsigned dims = m_bytecode[instr + 3];
if( !dims ) {
return error(VF_ErrorConstantPool, "incorrect format of multianewarray");
}
//check stack
if( !workmap_can_pop(dims) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
for( unsigned i = 0; i < dims; i++ ) {
WorkmapElement count = workmap_pop();
//check INs
if( !workmap_expect_strict(count, SM_INTEGER) ) return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//get OUT type
SmConstant arrayref;
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
if( !tpool.cpool_get_class(cp_idx, &arrayref, (int)dims) ) {
return error(VF_ErrorConstantPool, "incorrect type for multianewarray");
}
//push OUTs
workmap_push_const( arrayref );
break;
}
case OP_NEW: {
//check instruction
unsigned cp_idx = read_uint16(m_bytecode + instr + 1);
//TODO: unused variable?
SmConstant new_type = SM_BOGUS;
//TODO: CONSTANTPOOL validation
//if( !tpool.cpool_get_class(cp_idx, &new_type, 0xFFFFFFFF) ) return VF_ErrorConstantPool;
if( !tpool.cpool_get_class(cp_idx, 0, -1) ) {
return error(VF_ErrorConstantPool, "incorrect constantpool entry for new");
}
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//create OUTs
SmConstant newobj = SmConstant::getNewObject(instr);
//push OUTs
workmap_push_const( newobj );
break;
}
case OP_NEWARRAY: {
POP_x( SM_INTEGER );
U_8 array_type = m_bytecode[instr + 1];
if( array_type < 4 || array_type > 11 ) return error(VF_ErrorInstruction, "bad array type");
SmConstant ref = tpool.sm_get_const_arrayref(array_type);
workmap_push_const( ref);
break;
}
case OP_POP: {
//check stack
if( !workmap_can_pop(1) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement value = workmap_pop();
//check INs
if( !workmap_expect(value, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
break;
}
case OP_POP2: {
//check stack
if( !workmap_can_pop(2) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
workmap_pop();
WorkmapElement lo_val = workmap_pop();
//check INs
if( !workmap_expect(lo_val, SM_LOW_WORD) ) {
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
break;
}
case OP_RETURN: {
//check instruction
if( return_type != SM_BOGUS ) return error(VF_ErrorDataFlow, "incorrect type returned");
if( m_is_constructor && !workmap_expect_strict(workmap->elements[m_max_locals], tpool.sm_get_const_this()) ) {
return error(VF_ErrorIncompatibleArgument, "has not called constructor of super class");
}
break;
}
case OP_SALOAD: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_short();
//call MACRO that loads inegral types
CHECK_zALOAD( workmap_expect( arrayref, type ) );
//create and push OUTs
workmap_push_const( SM_INTEGER );
break;
}
case OP_SASTORE: {
//get required array type
SmConstant type = tpool.sm_get_const_arrayref_of_short();
//call MACRO that loads inegral types
CHECK_xASTORE( workmap_expect( arrayref, type ), SM_INTEGER );
break;
}
case OP_SWAP: {
//check stack
if( !workmap_can_pop(2) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop INs
WorkmapElement value1 = workmap_pop();
WorkmapElement value2 = workmap_pop();
//check INs
if( !workmap_expect(value1, SM_LOW_WORD) ||
!workmap_expect(value2, SM_LOW_WORD) )
{
return error(VF_ErrorIncompatibleArgument, "incompartible argument");
}
//push OUTs
workmap_push( value1 );
workmap_push( value2 );
break;
}
case OP_GETFIELD: {
//check and resolve instruction
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant ref, value;
if( !tpool.cpool_get_field(cp_idx, &ref, &value) ) return error(VF_ErrorUnknown, "incorrect constantpool entry");
//pop INs
vf_Result result;
if( (result = popFieldRef(ref, cp_idx)) != VF_OK ) {
return result;
}
//push OUTs
PUSH_z(value);
break;
}
case OP_GETSTATIC: {
//check and resolve instruction
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant value;
if( !tpool.cpool_get_field(cp_idx, 0, &value) ) return error(VF_ErrorUnknown, "incorrect constantpool entry");
//push OUTs
PUSH_z(value);
break;
}
case OP_PUTFIELD: {
//check and resolve instruction
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant expected_ref, expected_val;
if( !tpool.cpool_get_field(cp_idx, &expected_ref, &expected_val) ) {
return error(VF_ErrorUnknown, "incorrect constantpool entry");
}
//pop INs
POP_z( expected_val );
if (!workmap_can_pop(1)) {
return error(VF_ErrorUnknown, "unable to pop from the empty stack");
}
WorkmapElement &w0 = workmap_stackview(0);
if( w0.getAnyPossibleValue() != SM_THISUNINIT ) {
vf_Result result;
if( (result = popFieldRef(expected_ref, cp_idx)) != VF_OK ) {
return result;
}
} else if( expected_ref == tpool.sm_get_const_this() ) {
if( !workmap_expect_strict(w0, SM_THISUNINIT) ) {
return error(VF_ErrorUnknown, "Incompatible argument");
}
workmap_pop();
} else {
return error(VF_ErrorUnknown, "incorrect uninitialized type");
}
break;
}
case OP_PUTSTATIC: {
//check and resolve instruction
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
SmConstant expected_val;
if( !tpool.cpool_get_field(cp_idx, 0, &expected_val) ) return error(VF_ErrorUnknown, "incorrect constantpool entry");
//pop INs
POP_z( expected_val );
break;
}
case OP_INVOKEINTERFACE:
case OP_INVOKESPECIAL:
case OP_INVOKESTATIC:
case OP_INVOKEVIRTUAL: {
//check instruction
unsigned short cp_idx = read_uint16(m_bytecode + instr + 1);
//parse constant pool entrance
const char *state;
SmConstant expected_ref, expected_rettype;
unsigned short name_idx;
int args_sz;
//get method's class
if( !tpool.cpool_method_start(cp_idx, &state, &expected_ref, &name_idx, opcode) ||
!tpool.cpool_method_get_rettype(&state, &expected_rettype, &args_sz) )
{
return error(VF_ErrorUnknown, "incorrect constantpool entry");
}
assert( args_sz && state || !args_sz && !state);
if( opcode == OP_INVOKEINTERFACE ) {
//TODO: is verifier the right place for this check?
//check 'count' value for invokeinterface instruction
U_8 count = m_bytecode[instr + 3];
U_8 fourth = m_bytecode[instr + 4];
if( count != args_sz + 1 || fourth ) {
return error(VF_ErrorUnknown, "incorrect invokeinterface instruction");
}
}
if( args_sz > 255 || args_sz > 254 && opcode != OP_INVOKESTATIC ) {
//TODO: is verifier the right place for this check?
return error(VF_ErrorUnknown, "too many arguments for the method");
}
if( args_sz ) {
if( !workmap_can_pop(args_sz) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
//pop args
SmConstant expected_arg;
int arg_depth = args_sz;
while( state ) {
if( !tpool.cpool_method_next_arg(&state, &expected_arg) ) {
return error(VF_ErrorUnknown, "incorrect constantpool entry");
}
/* pop INs */
VIEW_z( expected_arg, arg_depth );
}
workmap->depth -= args_sz;
}
if( tpool.cpool_method_is_constructor_call(name_idx) ) {
if( opcode != OP_INVOKESPECIAL ) {
//TODO: is verifier the right place for this check?
return error(VF_ErrorUnknown, "constructor must be called by invokespecial");
}
//constructor must return void - if it is not checked somewhere else, add check here
assert(expected_rettype == SM_BOGUS);
//translate expected ref
// check stack
if( !workmap_can_pop(1) ) return error(VF_ErrorDataFlow, "unable to pop from empty operand stack");
// pop INs
WorkmapElement uninit_object = workmap_pop();
/* check INs */
SmConstant uninit_value = uninit_object.getAnyPossibleValue();
if( uninit_value != SM_THISUNINIT && !uninit_value.isNewObject() ||
!workmap_expect_strict(uninit_object, uninit_value) )
{
return error(VF_ErrorIncompatibleArgument, "incompartible argument: new object expected");
}
assert( uninit_value != SM_NONE );
SmConstant init_val = sm_convert_to_initialized( uninit_value );
//exception might be thrown from the constructor, all uninit values will be invalid
//BUT if try block contains both this and the next instruction then no extra actions is necessary:
//SM_BOGUS will appear when the values are merged
propagate_bogus_to_handlers(instr, uninit_value);
//replace all uninit values on stack & locals & possibly "constructor called flag" with init value
for( unsigned i = 0; i < + m_stack_start + workmap->depth; i++ ) {
WorkmapElement &wm_el = workmap->elements[i];
if( wm_el.getAnyPossibleValue() == uninit_value ) {
new_bogus_propagation_constraint(wm_el, init_val);
//respect changed_locals
if( i < m_stack_start ) {
changed_locals[ i ] = 1;
wm_el.setJsrModified();
//will be set later
//locals_changed = true;
}
}
}
//flags need to be checked
locals_changed = true;
//check that objectref is exactly necessary class
if( uninit_value == SM_THISUNINIT ) {
assert(m_is_constructor);
assert(tpool.sm_get_const_this() != tpool.sm_get_const_object());
if( expected_ref != tpool.sm_get_const_this() &&
expected_ref != tpool.sm_get_const_super() )
{
return error(VF_ErrorUnknown, "incorrect uninitialized type");
}
} else {
if( expected_ref != init_val ) return error(VF_ErrorUnknown, "incorrect uninitialized type");
}
} else if( opcode == OP_INVOKESPECIAL ) {
//pop object ref (it must extend be either 'this' or a sub class of 'this')
POP_ref( tpool.sm_get_const_this() );
//check that 'expected_ref' is a super class of 'this'
if( !tpool.mustbe_assignable(tpool.sm_get_const_this(), expected_ref) ) {
return error(VF_ErrorUnknown, "incorrect use of invokespecial");
}
} else if( opcode == OP_INVOKEVIRTUAL ) {
vf_Result result;
if( (result = popVirtualRef(expected_ref, cp_idx)) != VF_OK ) {
return result;
}
} else if( opcode != OP_INVOKESTATIC ) {
//pop object ref
POP_ref( expected_ref );
}
//push OUTs
if( expected_rettype != SM_BOGUS ) {
//is not void
PUSH_z( expected_rettype );
}
break;
}
case OP_JSR: case OP_JSR_W: {
//check stack
if( !workmap_can_push(1) ) return error(VF_ErrorDataFlow, "operand stack overflow");
//extract JSR target. would be better to do it in dataflow_liner, but it's also not very good
Address target = opcode == OP_JSR_W ? instr_get_int32_target(instr, m_bytecode + instr + 1) :
instr_get_int16_target(instr, m_bytecode + instr + 1);
//create OUTs
SmConstant retaddr = SmConstant::getRetAddr(target);
//push OUTs
workmap_push_const(retaddr);
break;
}
case OP_RET: {
//get local index from bytecode
unsigned local_idx = wide ? read_uint16(m_bytecode + instr + 2) : m_bytecode[instr + 1];
//check whether it is a valid local
if( !workmap_valid_local(local_idx) ) {
return error(VF_ErrorLocals, "invalid local index");
}
//get local type from there
WorkmapElement value = workmap_get_local(local_idx);
SmConstant retaddr = value.getAnyPossibleValue();
assert(retaddr != SM_NONE);
//expect ret address
if( !retaddr.isRetAddr() || !workmap_expect_strict(value, retaddr) ) {
return error(VF_ErrorIncompatibleArgument, "ret address expected");
}
//replace all copies of retaddr with SM_BOGUS to avoid recursion
for( unsigned i = 0; i < m_stack_start + workmap->depth; i++ ) {
WorkmapElement &wm_el = workmap->elements[i];
if( wm_el.getAnyPossibleValue() == retaddr ) {
wm_el = _WorkmapElement(SM_BOGUS);
//don't need to track changed locals
}
}
//actually is not a ret address: it's an address of subroutine's start
return new_ret_vector_constraint(retaddr.getRetInstr());
}
default:
assert(0);
return error(VF_ErrorInternal, "unreachable statement");
}
if( (tcr=dataflow_handlers(instr)) != VF_OK ) {
return tcr;
}
return VF_OK;
}