vf_Result vf_Context_x::dataflow_instruction()

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;
}