@@ -37,11 +40,6 @@
using namespace std;
/**
- * Set namespace Verifier.
- */
-namespace Verifier {
-
-/**
* Verifier defines.
*/
//===========================================================
@@ -72,6 +70,12 @@
stream << error_message; \
vf_set_error_message( stream, (context) ); \
}
+#define VERIFY_REPORT_METHOD(context, error_message ) \
+ VERIFY_REPORT(context, \
+ "(class: " << class_get_name( context->m_class ) \
+ << ", method: " << method_get_name( context->m_method ) \
+ << method_get_descriptor( context->m_method ) \
+ << ") " << error_message )
/**
* Define source code line and source file name parameters and arguments.
@@ -271,18 +275,14 @@
} vf_MapType_t;
/**
- * Code instruction flags enum.
+ * Each instruction has a descriptive bitmap.
*/
typedef enum {
- VF_FLAG_NONE = 0,
- VF_FLAG_BEGIN_BASIC_BLOCK = 1,
- VF_FLAG_START_ENTRY = 2,
- VF_FLAG_END_ENTRY = 4,
- VF_FLAG_HANDLER = 8,
- VF_FLAG_RETURN = 16,
- VF_FLAG_THROW = 32,
- VF_FLAG_SUBROUTINE = 64
-} vf_InstructionFlag_t;
+ VF_TYPE_INSTR_NONE = 0,
+ VF_TYPE_INSTR_RETURN = 1,
+ VF_TYPE_INSTR_THROW = 2,
+ VF_TYPE_INSTR_SUBROUTINE = 3
+} vf_CodeType;
/**
* Verifier structures.
@@ -291,20 +291,19 @@
/**
* Predefined structures
*/
+
+/**
+ * @ingroup Handles
+ * The handle of the verifier context.
+ */
+typedef const struct vf_Context* vf_ContextHandle;
+
/// Verifier context structure.
typedef struct vf_Context vf_Context_t;
/// Verifier code instruction structure.
typedef struct vf_Code_s vf_Code_t;
-/// Graph node container structure
-typedef struct vf_NodeContainer_s vf_NodeContainer_t;
-/// Graph edge container structure
-typedef struct vf_EdgeContainer_s vf_EdgeContainer_t;
/// Verifier graph structure.
-typedef struct vf_Graph vf_Graph_t;
-/// Verifier graph node structure.
-typedef struct vf_Node_s vf_Node_t;
-/// Verifier graph edge structure.
-typedef struct vf_Edge_s vf_Edge_t;
+class vf_Graph;
/// Verifier type constraint structure.
typedef struct vf_TypeConstraint_s vf_TypeConstraint_t;
/// Verifier hash table structure.
@@ -316,19 +315,19 @@
/// Verifier pool internal structure.
typedef struct vf_VerifyPoolInternal_s vf_VerifyPoolInternal_t;
+
/**
* Code instruction structures.
*/
-//===========================================================
+
/**
- * Initial struct of bytecode instruction.
+ * A byte of a bytecode.
*/
typedef struct {
- unsigned *m_off; ///< array of branches
- unsigned m_instr; ///< number of code instruction @see vf_Code_s
- unsigned m_offcount : 31; ///< number of branches
+ unsigned m_instr; ///< a number + 1 of code instruction at
+ ///< vf_Context.m_code
unsigned m_mark : 1; ///< control flow branch flag
-} vf_Instr_t;
+} vf_BCode_t;
/**
* Valid types structure.
@@ -362,16 +361,18 @@
*/
struct vf_Code_s {
unsigned char *m_addr; ///< address of bytecode instruction
+ unsigned m_offcount; ///< number of instruction branches
unsigned *m_off; ///< array of instruction branches
- unsigned char *m_handler; ///< array of instruction handlers
+ unsigned m_sum; ///< number of basic blocks before
+ ///< this instruction
vf_MapEntry_t *m_invector; ///< stack map IN instruction vector
vf_MapEntry_t *m_outvector; ///< stack map OUT instruction vector
- unsigned m_offcount; ///< number of instruction branches
unsigned short m_minstack; ///< minimal stack for instruction
unsigned short m_inlen; ///< stack map IN instruction vector length
unsigned short m_outlen; ///< stack map OUT instruction vector length
short m_stack; ///< stack change for instruction
- unsigned m_base : 7; ///< instruction flag @see vf_InstructionFlag_t
+ vf_CodeType m_type; ///< instruction flag @see vf_CodeType_t
+ bool m_basic_block_start : 1; ///< begin of a basic block
};
/**
@@ -392,522 +393,6 @@
} vf_Parse_t;
/**
- * Verifier control flow graph structures.
- */
-//===========================================================
-/**
- * Structure of stack map vector.
- */
-typedef struct {
- vf_MapEntry_t *m_stack; ///< stack map vector
- vf_MapEntry_t *m_local; ///< locals map vector
- unsigned short m_number; ///< number of locals
- unsigned short m_deep; ///< stack deep
- unsigned short m_maxstack; ///< max stack length
- unsigned short m_maxlocal; ///< max local number
-} vf_MapVector_t;
-
-/**
- * Graph node structure.
- */
-struct vf_Node_s
-{
- vf_MapVector_t m_invector; ///< stack map IN node vector
- vf_MapVector_t m_outvector; ///< stack map OUT node vector
- unsigned m_start; ///< beginning of the first instruction of the BB
- unsigned m_end; ///< beginning of the last instruction of the BB.
- unsigned m_inedge; ///< the first of incoming node edges
- unsigned m_outedge; ///< the first of outcoming node edges
- unsigned m_len; ///< length of the basic block
- unsigned m_innum; ///< number of incoming edges
- unsigned m_outnum; ///< number of outcoming edges
- unsigned m_nodecount; ///< node count in enumeration
- int m_stack; ///< stack deep of node
- int m_mark; ///< node mark
- bool m_initialized; ///< reference in local variable should be initialized
-};
-
-/**
- * Graph edge structure.
- */
-struct vf_Edge_s
-{
- unsigned m_start; ///< start edge node
- unsigned m_end; ///< end edge node
- unsigned m_innext; ///< next incoming edge
- unsigned m_outnext; ///< next outcoming edge
-};
-
-/**
- * Graph node container structure.
- */
-struct vf_NodeContainer_s
-{
- vf_NodeContainer_t* m_next; ///< next container
- unsigned m_max; ///< max number of nodes in container
- unsigned m_used; ///< number of nodes in container
- vf_Node_t m_node[1]; ///< array of container nodes
-};
-
-/**
- * Graph edge container structure.
- */
-struct vf_EdgeContainer_s
-{
- vf_EdgeContainer_t* m_next; ///< next container
- unsigned m_max; ///< max number of edges in container
- unsigned m_used; ///< number of edges in container
- vf_Edge_t m_edge[1]; ///< array of container edges
-};
-
-/**
- * Verifier control flow graph structure.
- */
-struct vf_Graph
-{
-public:
-
- /**
- * Control flow graph constructor.
- * @param node - number of graph nodes
- * @param edge - number of graph edges
- * @note Function allocates memory for graph structure, nodes and edges.
- */
- vf_Graph( unsigned node, unsigned edge );
-
- /**
- * Control flow graph constructor.
- * @param node - number of graph nodes
- * @param edge - number of graph edges
- * @param pool - external memory pool
- * @note Function allocates memory for graph structure, nodes and edges.
- */
- vf_Graph( unsigned node, unsigned edge, vf_VerifyPool_t *pool );
-
- /**
- * Control flow graph destructor.
- * @note Function release memory for graph structure, nodes and edges.
- */
- ~vf_Graph();
-
- /**
- * Function create graph nodes.
- * @param count - number of graph nodes
- * @note Function allocates memory for graph nodes.
- */
- void CreateNodes( unsigned count );
-
- /**
- * Gets graph node.
- * Parameter node_num must be in range.
- *
- * @param[in] node_num - node number
- *
- * @return The pointer to node structure.
- */
- vf_Node_t* GetNode( unsigned node_num );
-
- /**
- * Creates a new node and sets data to it.
- * Node array must have enough free space for a new element.
- *
- * @param[in] begin_instr - begin code instruction of node
- * @param[in] end_instr - end code instruction of code
- * @param[in] bytecode_len - bytecode length of node instructions
- */
- void NewNode( unsigned begin_instr,
- unsigned end_instr,
- unsigned bytecode_len);
-
- /**
- * Function set data to graph node.
- * @param node_num - number of graph node
- * @param begin_instr - begin code instruction of node
- * @param end_instr - end code instruction of code
- * @param bytecode_len - bytecode length of node instructions
- * @note Assertion is raised if node_num is out of range.
- */
- void SetNode( unsigned node_num,
- unsigned begin_instr,
- unsigned end_instr,
- unsigned bytecode_len );
-
- /**
- * Gets graph edge.
- * Parameter edge_num must be in range.
- *
- * @param[in] edge_num - edge number
- *
- * @return The pointer to edge structure.
- */
- vf_Edge_t* GetEdge( unsigned edge_num );
-
- /**
- * Creates a new edge for graph nodes.
- *
- * @param start_node - start edge node
- * @param end_node - end edge node
- * @note Edge is set as out edge for start_node and as in edge for end_node.
- */
- void NewEdge( unsigned start_node,
- unsigned end_node);
-
- /**
- * Function receive first code instruction of graph node.
- * @param node_num - graph node number
- * @return Number of first code instruction of graph node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeFirstInstr( unsigned node_num );
-
- /**
- * Function receive last code instruction of graph node.
- * @param node_num - graph node number
- * @return Number of last code instruction of graph node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeLastInstr( unsigned node_num );
-
- /**
- * Function receive bytecode length of graph node instructions.
- * @param node_num - graph node number
- * @return Bytecode length of graph node instructions.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeByteCodeLen( unsigned node_num );
-
- /**
- * Function receive stack modifier of graph.
- * @param node_num - graph node number
- * @return Stack modifier of graph node.
- * @note Assertion is raised if node_num is out of range.
- */
- int GetNodeStackModifier( unsigned node_num );
-
- /**
- * Function sets graph node stack modifier.
- * @param node_num - graph node number
- * @param stack - stack modifier (signed value)
- * @note Assertion is raised if node_num is out of range.
- */
- void SetNodeStackModifier( unsigned node_num, int stack );
-
- /**
- * Function returns number of graph nodes.
- * @return Number of graph nodes.
- */
- unsigned GetNodeNumber();
-
- /**
- * Function marks graph node.
- * @param node_num - graph node number
- * @param mark - node mark
- * @note Assertion is raised if node_num is out of range.
- */
- void SetNodeMark( unsigned node_num, int mark );
-
- /**
- * Function returns graph node mark.
- * @param node_num - graph node number
- * @return Function returns graph node mark.
- * @note Assertion is raised if node_num is out of range.
- */
- int GetNodeMark( unsigned node_num );
-
- /**
- * Function checks if node is marked.
- * @param node_num - graph node number
- * @return Returns true if node is marked, else returns false.
- * @note Assertion is raised if node_num is out of range.
- */
- bool IsNodeMarked( unsigned node_num );
-
- /**
- * Function removes node mark.
- */
- void CleanNodesMark();
-
- /**
- * Sets local variable reference initialization flag for node.
- * @param node_num - graph node number
- * @param flag - node flag
- */
- void SetNodeInitFlag( unsigned node_num, bool flag );
-
- /**
- * Gets local variable reference initialization flag for node.
- * @param node_num - graph node number
- * @return Returns true if local variable reference have
- * to be initialized else returns false.
- */
- bool GetNodeInitFlag( unsigned node_num );
-
- /**
- * Function creates IN data flow vector of node.
- * @param node_num - graph node number
- * @param example - current data flow vector
- * @param need_copy - copy flag
- * @note If copy flag true, incoming vector is copied to IN,
- * else if copy flag false, IN vector is created
- * with parameters of current vector.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_MapVector_t
- */
- void SetNodeInVector( unsigned node_num,
- vf_MapVector_t *example,
- bool need_copy);
-
- /**
- * Function creates OUT data flow vector of node.
- * @param node_num - graph node number
- * @param example - current data flow vector
- * @param need_copy - copy flag
- * @note If copy flag true, incoming vector is copied to OUT,
- * else if copy flag false, OUT vector is created
- * with parameters of current vector.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_MapVector_t
- */
- void SetNodeOutVector( unsigned node_num,
- vf_MapVector_t *example,
- bool need_copy );
-
- /**
- * Function receives IN data flow vector of node.
- * @param node_num - graph node number
- * @return IN data flow stack map vector of node.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_MapVector_t
- */
- vf_MapVector_t * GetNodeInVector( unsigned node_num );
-
- /**
- * Function receives OUT data flow vector of node.
- * @param node_num - graph node number
- * @return OUT data flow stack map vector of node.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_MapVector_t
- */
- vf_MapVector_t * GetNodeOutVector( unsigned node_num );
-
- /**
- * Function creates graph edges.
- * @param number - number of edges
- */
- void CreateEdges( unsigned number );
-
- /**
- * Function receives next IN edge of graph node.
- * @param edge_num - number of graph edge
- * @return Number of next IN edge of node.
- * @note Assertion is raised if edge_num is out of range.
- */
- unsigned GetEdgeNextInEdge( unsigned edge_num );
-
- /**
- * Function receives next OUT edge of graph node.
- * @param edge_num - number of graph edge
- * @return Number of next OUT edge of node.
- * @note Assertion is raised if edge_num is out of range.
- */
- unsigned GetEdgeNextOutEdge( unsigned edge_num );
-
- /**
- * Function receives start graph node of edge.
- * @param edge_num - number of graph edge
- * @return Number start graph node of edge.
- * @note Assertion is raised if edge_num is out of range.
- */
- unsigned GetEdgeStartNode( unsigned edge_num );
-
- /**
- * Function receives end graph node of edge.
- * @param edge_num - number of graph edge
- * @return Number end graph node of edge.
- * @note Assertion is raised if edge_num is out of range.
- */
- unsigned GetEdgeEndNode( unsigned edge_num );
-
- /**
- * Function receives number of IN edges of graph node.
- * @param node_num - number of graph node
- * @return Number of IN edges of graph node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeInEdgeNumber( unsigned node_num );
-
- /**
- * Function receives number of OUT edges of graph node.
- * @param node_num - number of graph node
- * @return Number of OUT edges of graph node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeOutEdgeNumber( unsigned node_num );
-
- /**
- * Function receives first IN edge of graph node.
- * @param node_num - number of graph node
- * @return First IN edges of node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeFirstInEdge( unsigned node_num );
-
- /**
- * Function receives first OUT edge of graph node.
- * @param node_num - number of graph node
- * @return First OUT edges of node.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeFirstOutEdge( unsigned node_num );
-
- /**
- * Function allocates memory in graph memory pool.
- * @param size - size of memory block
- * @return Allocated memory pointer
- * or NULLif memory allocation is failed.
- */
- void * AllocMemory( unsigned size );
-
- /**
- * Function cleans graph node enumeration, creates new graph
- * enumeration structure and sets first enumeration element.
- * @param node_num - first enumeration node
- * @note Assertion is raised if node_num is out of range.
- */
- void SetStartCountNode( unsigned node_num );
-
- /**
- * Function receives number of enumerated nodes.
- * @return Function returns number of enumerated nodes.
- */
- unsigned GetEnumCount();
-
- /**
- * Function sets next enumeration element in graph enumeration structure.
- * @param node_num - next enumeration node
- * @note Assertion is raised if node_num is out of range.
- */
- void SetNextCountNode( unsigned node_num );
-
- /**
- * Function receives first enumerated graph node.
- * @return First enumerated graph node in graph enumeration structure.
- */
- unsigned GetStartCountNode();
-
- /**
- * Function receives graph node relevant to enumeration element.
- * @param count - given enumeration element
- * @return Graph node relevant to enumeration element.
- * @note Assertion is raised if count is out of range.
- */
- unsigned GetCountElementNode( unsigned count );
-
- /**
- * Function receives graph node enumeration count.
- * @param node_num - given node
- * @return Graph node enumeration count.
- * @note Assertion is raised if node_num is out of range.
- */
- unsigned GetNodeCountElement( unsigned node_num );
-
- /**
- * Function prints graph structure in stderr.
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @see vf_Context_t
- */
- void DumpGraph( vf_Context_t *context );
-
- /**
- * Function dumps verifier graph in file in DOT format.
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @note File name is created from class and method names with .dot extension.
- * @see vf_Context_t
- */
- void DumpDotGraph( vf_Context_t *context );
-
-private:
- vf_NodeContainer_t *m_nodes; ///< array of nodes
- vf_EdgeContainer_t *m_edges; ///< array of edges
- vf_VerifyPool_t *m_pool; ///< graph memory pool
- unsigned *m_enum; ///< graph node enumeration structure
- unsigned m_nodenum; ///< number of nodes
- unsigned m_edgenum; ///< number of edges
- unsigned m_enummax; ///< max number of enumerated elements
- unsigned m_enumcount; ///< number of enumerated elements
- bool m_free; ///< need to free pool
-
- /**
- * Function prints graph node in stderr.
- * @param node_num - number of graph node
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_Context_t
- */
- void DumpNode( unsigned node_num, vf_Context_t *context );
-
- /**
- * Function prints graph node instruction in stream.
- * @param node_num - number of graph node
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_Context_t
- */
- void DumpNodeInternal( unsigned node_num,
- vf_Context_t *context);
-
-
- /**
- * Function dumps graph header in file in DOT format.
- * @param graph_name - graph name
- * @param fout - file stream
- * @note Function is valid in debug mode.
- * @note Graph name is created from class and method names.
- */
- void DumpDotHeader( char *graph_name, ofstream &fout );
-
- /**
- * Function dumps graph node in file in DOT format.
- * @param node_num - number of graph node
- * @param fout - file stream
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_Context_t
- */
- void DumpDotNode( unsigned node_num, ofstream &fout, vf_Context_t *context );
-
- /**
- * Function dumps graph node instruction in file stream in DOT format.
- * @param node_num - number of graph node
- * @param next_node - separator between nodes in stream
- * @param next_instr - separator between instructions in stream
- * @param fout - output file stream
- * @param context - current verifier context
- * @note Function is valid in debug mode.
- * @note Assertion is raised if node_num is out of range.
- * @see vf_Context_t
- */
- void DumpDotNodeInternal( unsigned node_num,
- char *next_node,
- char *next_instr,
- ofstream &fout,
- vf_Context_t *context);
-
- /**
- * Function dumps graph end in file in DOT format.
- * @param fout - output file stream
- * @note Function is valid in debug mode.
- */
- void DumpDotEnd( ofstream &fout );
-
-}; // struct vf_Graph
-
-/**
* Verifier hash table structures.
*/
//===========================================================
@@ -1182,9 +667,12 @@
vf_TypePool *m_type; ///< context type constraint collection
char *m_error; ///< context error message
method_handler m_method; ///< context method
- vf_Graph_t *m_graph; ///< context control flow graph
+ bool m_is_constructor; ///< true if the
+ ///< method is a constructor
+ vf_Graph *m_graph; ///< context control flow graph
vf_VerifyPool_t *m_pool; ///< context memory pool
vf_Code_t *m_code; ///< context code instruction of method
+ vf_BCode_t* m_bc; ///< bytecode to code mapping
unsigned m_codeNum; ///< code instruction number
unsigned m_nodeNum; ///< graph node number
unsigned m_edgeNum; ///< graph edge number
@@ -1217,6 +705,7 @@
unsigned m_code_vector : 1; ///< print data flow node code instruction vectors
unsigned m_merge_vector : 1; ///< print result of merge data flow vectors
} m_dump;
+
}; // struct vf_Context
/**
@@ -1393,16 +882,21 @@
vf_create_graph( vf_Context_t *context );
/**
- * Function provides some checks of control flow and data flow structures of graph.
- * @param context - verifier context
- * @return Checks result.
- * @see vf_Context_t
- * @see Verifier_Result
+ * Checks control flow and data flow of graph.
+ * @param context a verifier context
+ * @return a result of graph checks
*/
Verifier_Result
-vf_graph_checks( vf_Context_t *context );
+vf_check_graph( vf_Context_t *context );
/**
+ * Frees memory allocated for graph, if any.
+ * @param context a verifier context
+ */
+void
+vf_free_graph( vf_ContextHandle context );
+
+/**
* Function provides data flow checks of verifier graph structure.
* @param context - verifier context
* @return Check result.
@@ -1450,6 +944,22 @@
vf_Context_t *context);
/**
+ * Gets a class name from a constant pool.
+ * @param[in] klass a handle of the class
+ * @param[in] index the entry index
+ * @return a pointer to UTF8 constant pool entry
+ */
+static inline const char*
+vf_get_cp_class_name( class_handler klass,
+ unsigned short index )
+{
+ unsigned short class_name_index =
+ class_get_cp_class_name_index(klass, index);
+ const char* name = class_get_cp_utf8_bytes(klass, class_name_index);
+ return name;
+} // vf_get_cp_class_name
+
+/**
* Function creates valid type by given class name.
* @param class_name - class name
* @param context - verifier context
@@ -1512,8 +1022,10 @@
vf_Context::ClearContext()
{
m_method = NULL;
+ m_is_constructor = false;
m_graph = NULL;
m_code = NULL;
+ m_bc = NULL;
m_codeNum = 0;
m_nodeNum = 0;
m_edgeNum = 0;
@@ -1521,51 +1033,9 @@
} // vf_Context::vf_ClearContext
/**
- * Function checks basic block flag for given instruction.
- * @param code - bytecode instruction
- * @return If given instruction has basic block flag returns true,
- * else returns false.
- * @see vf_Code_t
- */
-static inline bool
-vf_is_begin_basic_block( vf_Code_t *code )
-{
- return (code->m_base & VF_FLAG_BEGIN_BASIC_BLOCK) != 0;
-} // vf_is_begin_basic_block
-
-/**
- * Function checks flags for given instruction.
- * @param code - bytecode instruction
- * @param flag - checked flags
- * @return If given instruction has checked flag returns true,
- * else returns false.
- * @see vf_Code_t
- */
-static inline bool
-vf_is_instruction_has_flags( vf_Code_t *code,
- unsigned flag)
-{
- return ((unsigned)code->m_base & flag) != 0;
-} // vf_is_instruction_has_flags
-
-/**
- * Function checks what given instruction has any flags.
- * @param code - bytecode instruction
- * @return If given instruction has any flags returns true,
- * else returns false.
- * @see vf_Code_t
- */
-static inline bool
-vf_is_instruction_has_any_flags( vf_Code_t *code )
-{
- return (code->m_base != 0);
-} // vf_is_instruction_has_flags
-
-
-/**
* Function sets error message of verifier.
- * @param stream - stringstream object with message
- * @param ctex - verifier context
+ * @param stream stringstream object with a message
+ * @param ctex a verifier context
* @see vf_Context_t
*/
static inline void
@@ -1589,8 +1059,9 @@
} // vf_set_error_message
/**
- * Checks version of class file
- * @param context - verifier context
+ * Checks a version of a class file.
+ * @param context a verifier context
+ * @return true if a class version is less than 1.4
*/
static inline bool
vf_is_class_version_14( vf_Context_t *context )
@@ -1598,8 +1069,68 @@
return (class_get_version(context->m_class) < 49) ? true : false;
} // vf_is_class_version_14
-} // namespace Verifier
+/**
+ * Function returns branch target for a given branch number.
+ * @param code a reference to instruction
+ * @param branch_num a branch number
+ * @return an absolute bytecode position to which the executuion
+ * branches
+ */
+static inline int
+vf_get_code_branch( vf_Code_t* code, unsigned branch_num )
+{
+ assert(branch_num < code->m_offcount);
+ return code->m_off[branch_num];
+} // vf_get_instruction_branch
-using namespace Verifier;
+/**
+ * Allocates memory for a new stack map vector.
+ * @param[out] vector a reference to vector
+ * @param[in] len vector length
+ * @param[in] pool memory pool
+ */
+static inline void
+vf_new_vector( vf_MapEntry_t** vector,
+ unsigned len,
+ vf_VerifyPool_t *pool)
+{
+ // create new vector
+ (*vector) = (vf_MapEntry_t*) vf_alloc_pool_memory(pool,
+ len * sizeof(vf_MapEntry_t));
+ return;
+} // vf_new_vector
+/**
+ * Sets a reference data type for a given stack map vector entry.
+ * @param[in, out] vector a reference to a stack map
+ * @param[in] num stack map index
+ * @param[in] type reference type
+ */
+static inline void
+vf_set_vector_stack_entry_ref( vf_MapEntry_t* vector,
+ unsigned num,
+ vf_ValidType_t* type)
+{
+ // set a stack map vector entry by ref
+ vector[num].m_type = SM_REF;
+ vector[num].m_vtype = type;
+} // vf_set_vector_stack_entry_ref
+
+
+/**
+ * Inline subroutines in the call graph.
+ *
+ * Here is the algorithm sketch: we define subroutine boundaries with
+ * simplified data flow analysis and duplicate subroutine nodes
+ * in the call graph. For more details check a
+ * wiki
+ * page.
+ *
+ * @param[in] context a verifier context
+ * @return VER_OK if subroutines were inlined successfully,
+ * an error code otherwise
+ */
+Verifier_Result
+vf_inline_subroutines(vf_ContextHandle context);
+
#endif // _VERIFIER_REAL_H_
Index: vm/vmcore/src/verifier/Verifier.cpp
===================================================================
--- vm/vmcore/src/verifier/Verifier.cpp (revision 507588)
+++ vm/vmcore/src/verifier/Verifier.cpp (working copy)
@@ -19,10 +19,8 @@
* @version $Revision: 1.1.2.3.4.4 $
*/
-#include
#include "ver_real.h"
-
/**
* Debug flag macros
*/
@@ -30,17 +28,8 @@
#define VERIFY_CLASS 0
// Macro sets verification only for defined method
#define VERIFY_METHOD 0
-// Macro dumps type constraints for class
-#define VERIFY_DUMP_CONSTRAINT 0
-// Macro prints code array in stream
-#define PRINT_CODE_ARRAY 0
/**
- * Set namespace Verifier
- */
-namespace Verifier {
-
-/**
* Function parse bytecode, determines code instructions, fills code array and
* provides checks of simple verifications.
*/
@@ -105,7 +94,7 @@
/**
* Getting bytecode array and its length
*/
- if( !(len = method_get_code_length( ctex->m_method) ) ) {
+ if( !( len = method_get_code_length( ctex->m_method ) ) ) {
return VER_OK;
}
@@ -115,46 +104,41 @@
ctex->m_type->SetMethod( ctex->m_method );
/**
- * Allocate memory for code array
- * (+2) for start-entry and end-entry instruction
+ * Allocate memory for code and bytecode annotations.
*/
- ctex->m_code = (vf_Code_t*)vf_alloc_pool_memory( ctex->m_pool, (len + 2
- + method_get_exc_handler_number( ctex->m_method )) * sizeof(vf_Code_t) );
+ ctex->m_code = (vf_Code_t*)vf_alloc_pool_memory( ctex->m_pool,
+ len * sizeof( vf_Code_t ) );
+ ctex->m_bc = (vf_BCode_t*)vf_alloc_pool_memory( ctex->m_pool,
+ len * sizeof( vf_BCode_t ) );
/**
- * Parse bytecode, fill instruction codeArray
+ * Parse bytecode, fill instruction code.
*/
result = vf_parse_bytecode( ctex );
if( result != VER_OK ) {
goto labelEnd_verifyClassBytecode;
- } else if( ctex->m_dump.m_with_subroutine ) {
- result = VER_NoSupportJSR;
- goto labelEnd_verifyClassBytecode;
}
-
/**
* Build bytecode graph
*/
result = vf_create_graph( ctex );
- if( result != VER_OK ) {
+ if( ctex->m_dump.m_with_subroutine ) {
+ result = VER_NoSupportJSR;
goto labelEnd_verifyClassBytecode;
+ result = vf_inline_subroutines( ctex );
+ if ( VER_OK != result ) {
+ goto labelEnd_verifyClassBytecode;
+ }
}
- /**
- * Handle graph
- */
- result = vf_graph_checks( ctex );
+ // check control and data flow
+ result = vf_check_graph( ctex );
if( result != VER_OK ) {
goto labelEnd_verifyClassBytecode;
}
labelEnd_verifyClassBytecode:
- /**
- * Free memory
- */
- if( ctex->m_graph ) {
- delete ctex->m_graph;
- }
+ vf_free_graph( ctex );
return result;
} // vf_verify_method_bytecode
@@ -167,39 +151,39 @@
* Function creates array of instruction branch offsets.
*/
static inline void
-vf_create_instruction_offset( vf_Instr_t *instr, // given instruction
- unsigned offcount, // number of offets
- vf_VerifyPool_t *pool) // memory pool
+vf_create_code_offset( vf_Code_t *code, // given instruction
+ unsigned offcount, // number of offets
+ vf_VerifyPool_t *pool) // memory pool
{
- assert( !instr->m_off );
- instr->m_off = (unsigned*)vf_alloc_pool_memory( pool, offcount * sizeof(unsigned) );
- instr->m_offcount = offcount;
+ assert( !code->m_off );
+ code->m_off = (unsigned*)vf_alloc_pool_memory( pool, offcount * sizeof( unsigned ) );
+ code->m_offcount = offcount;
return;
} // vf_create_instruction_offset
/**
- * Function sets instruction branch offset.
+ * Function sets code branch offset.
*/
static inline void
-vf_set_instruction_offset( vf_Instr_t *instr, // given instruction
- unsigned offnum, // offset index in array
- unsigned value) // offset value
+vf_set_code_offset( vf_Code_t *code, // given instruction
+ unsigned offnum, // offset index in array
+ unsigned value) // offset value
{
- assert( instr->m_off && offnum < instr->m_offcount );
- instr->m_off[offnum] = value;
+ assert( code->m_off && offnum < code->m_offcount );
+ code->m_off[offnum] = value;
return;
} // vf_set_instruction_offset
/**
- * Function creates branch offset array on 1 element and sets given value.
+ * Function creates a single branch.
*/
static inline void
-vf_set_single_instruction_offset( vf_Instr_t *instr, // given instruction
+vf_set_single_branch_offset( vf_Code_t *code, // given instruction
unsigned value, // offset value
vf_VerifyPool_t *pool) // memory pool
{
- vf_create_instruction_offset( instr, 1, pool );
- vf_set_instruction_offset( instr, 0, value );
+ vf_create_code_offset( code, 1, pool );
+ vf_set_code_offset( code, 0, value );
return;
} // vf_set_single_instruction_offset
@@ -235,7 +219,7 @@
* Function sets basic block attribute for instruction.
*/
static inline void
-vf_set_basic_block_flag( vf_Instr_t *code ) // instruction
+vf_set_basic_block_flag( vf_BCode_t *code ) // instruction
{
// set begin of basic block for instruction
code->m_mark = 1;
@@ -243,16 +227,16 @@
} // vf_set_basic_block_flag
/**
- * Function sets flags for code instruction.
+ * Sets flags for the instruction.
*/
static inline void
-vf_set_instruction_flag( vf_Code_t *code, // code instruction
- unsigned flag) // given flags
+vf_set_code_type( vf_Code_t *code, // instruction
+ vf_CodeType type) // given flags
{
// set flag for instruction
- code->m_base |= flag;
+ code->m_type = type;
return;
-} // vf_set_instruction_flag
+} // vf_set_code_type
/**
* Function checks local number.
@@ -264,10 +248,8 @@
{
// check local variable number
if( local >= maxlocal ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Incorrect usage of local variable" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incorrect usage of local variable" );
return VER_ErrorLocals;
}
return VER_OK;
@@ -283,10 +265,8 @@
{
if( offset < 0 || (unsigned)offset >= maxlen ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Instruction branch offset is out of range" );
+ VERIFY_REPORT( ctex,
+ "Instruction branch offset is out of range" );
return VER_ErrorBranch;
}
return VER_OK;
@@ -298,11 +278,12 @@
static inline unsigned
vf_get_local_var_number( vf_Code_t *code, // code instruction
unsigned char *bytecode, // method bytecode
- unsigned *index_p) // index in bytecode array
+ unsigned *index_p, // index in bytecode array
+ bool wide_flag) // if this is a wide instruction
{
unsigned local;
- if( (*index_p) != 1 && *((code - 1)->m_addr) == OPCODE_WIDE ) {
+ if( (wide_flag) ) {
// get number of local variable
local = (unsigned)( (bytecode[(*index_p)] << 8)|(bytecode[(*index_p)+ 1]) );
// skip parameter (u2)
@@ -317,17 +298,6 @@
} // vf_get_local_var_number
/**
- * Function returns instruction branch offset for given branch number.
- */
-static inline int
-vf_get_instruction_branch( vf_Instr_t *code, // instruction
- unsigned branch_num) // branch number
-{
- assert( branch_num < code->m_offcount );
- return code->m_off[branch_num];
-} // vf_get_instruction_branch
-
-/**
* Function receives half word (2 bytes) instruction branch offset
* value from bytecode array.
*/
@@ -366,7 +336,7 @@
* sets into instruction and returns it.
*/
static inline int
-vf_get_single_hword_branch_offset( vf_Instr_t *code, // instruction
+vf_get_single_hword_branch_offset( vf_Code_t *code, // instruction
unsigned code_pc, // offset in bytecode array
unsigned char *bytecode, // bytecode array
unsigned *index_p, // offset index in bytecode array
@@ -375,7 +345,7 @@
// get first branch offset
int offset = vf_get_hword_offset( code_pc, bytecode, index_p );
// create and set edge branch for instruction
- vf_set_single_instruction_offset( code, offset, pool );
+ vf_set_single_branch_offset( code, offset, pool );
return offset;
} // vf_get_single_hword_branch_offset
@@ -384,7 +354,7 @@
* sets into instruction and returns it.
*/
static inline int
-vf_get_single_word_branch_offset( vf_Instr_t *code, // instruction
+vf_get_single_word_branch_offset( vf_Code_t *code, // instruction
unsigned code_pc, // offset in bytecode array
unsigned char *bytecode, // bytecode array
unsigned *index_p, // offset index in bytecode array
@@ -393,7 +363,7 @@
// get first branch offset
int offset = vf_get_word_offset( code_pc, bytecode, index_p );
// create and set edge branch for instruction
- vf_set_single_instruction_offset( code, offset, pool );
+ vf_set_single_branch_offset( code, offset, pool );
return offset;
} // vf_get_single_word_branch_offset
@@ -403,7 +373,7 @@
* Function returns received offset.
*/
static inline int
-vf_get_double_hword_branch_offset( vf_Instr_t *code, // instruction
+vf_get_double_hword_branch_offset( vf_Code_t *code, // instruction
unsigned code_pc, // instruction offset in bytcode array
unsigned char *bytecode, // bytecode array
unsigned *index_p, // offset index in bytecode array
@@ -412,11 +382,11 @@
// get first branch offset
int offset = vf_get_hword_offset( code_pc, bytecode, index_p );
// create and set edge branches for instruction
- vf_create_instruction_offset( code, 2, pool );
+ vf_create_code_offset( code, 2, pool );
// set first edge branch for instruction
- vf_set_instruction_offset( code, 0, offset );
+ vf_set_code_offset( code, 0, offset );
// set second edge branch for instruction
- vf_set_instruction_offset( code, 1, (*index_p) );
+ vf_set_code_offset( code, 1, (*index_p) );
return offset;
} // vf_get_double_hword_branch_offset
@@ -426,7 +396,7 @@
* Function returns received offset.
*/
static inline int
-vf_get_double_word_branch_offset( vf_Instr_t *code, // instruction
+vf_get_double_word_branch_offset( vf_Code_t *code, // instruction
unsigned code_pc, // instruction offset in bytcode array
unsigned char *bytecode, // bytecode array
unsigned *index_p, // offset index in bytecode array
@@ -435,11 +405,11 @@
// get first branch offset
int offset = vf_get_word_offset( code_pc, bytecode, index_p );
// create and set edge branches for instruction
- vf_create_instruction_offset( code, 2, pool );
+ vf_create_code_offset( code, 2, pool );
// set first edge branch for instruction
- vf_set_instruction_offset( code, 0, offset );
+ vf_set_code_offset( code, 0, offset );
// set second edge branch for instruction
- vf_set_instruction_offset( code, 1, (*index_p) );
+ vf_set_code_offset( code, 1, (*index_p) );
return offset;
} // vf_get_double_word_branch_offset
@@ -449,7 +419,7 @@
* Function returns received branch.
*/
static inline int
-vf_get_tableswitch_alternative( vf_Instr_t *code, // instruction
+vf_get_tableswitch_alternative( vf_Code_t *code, // instruction
unsigned code_pc, // offset in bytcode array
unsigned alternative, // number of tableswitch branch
unsigned char *bytecode, // bytecode array
@@ -458,7 +428,7 @@
// get first branch offset
int offset = vf_get_word_offset( code_pc, bytecode, index_p );
// set first edge branch for instruction
- vf_set_instruction_offset( code, alternative, offset );
+ vf_set_code_offset( code, alternative, offset );
return offset;
} // vf_get_tableswitch_alternative
@@ -468,7 +438,7 @@
* Function returns number of alternatives.
*/
static inline int
-vf_set_tableswitch_offsets( vf_Instr_t *code, // instruction
+vf_set_tableswitch_offsets( vf_Code_t *code, // instruction
unsigned code_pc, // instruction offset in bytecode array
unsigned *index_p, // offset index in bytecode array
unsigned char *bytecode, // bytecode array
@@ -484,7 +454,7 @@
int high = vf_get_word_offset( code_pc, bytecode, &index );
int number = high - low + 2;
// create tableswitch branches
- vf_create_instruction_offset( code, number, pool );
+ vf_create_code_offset( code, number, pool );
// set default offset
vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off );
// set another instruction offsets
@@ -503,7 +473,7 @@
* Function returns number of alternatives.
*/
static inline Verifier_Result
-vf_set_lookupswitch_offsets( vf_Instr_t *code, // instruction
+vf_set_lookupswitch_offsets( vf_Code_t *code, // instruction
unsigned code_pc, // instruction offset in bytecode
unsigned *index_p, // offset index in bytecode array
unsigned char *bytecode, // array of bytecode
@@ -519,7 +489,7 @@
int number = vf_get_word_offset( 0, bytecode, &index ) + 1;
*branch_p = number;
// create and tableswitch branches
- vf_create_instruction_offset( code, number, ctex->m_pool );
+ vf_create_code_offset( code, number, ctex->m_pool );
// set default offset
vf_get_tableswitch_alternative( code, code_pc, 0, bytecode, &default_off );
// set another instruction offsets
@@ -530,10 +500,8 @@
if( old_key < key ) {
old_key = key;
} else if( key != INT_MIN ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Instruction lookupswitch has unsorted key values" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Instruction lookupswitch has unsorted key values" );
return VER_ErrorInstruction;
}
// get lookupswitch alternative and set offset to instruction
@@ -550,20 +518,6 @@
************************************************************/
/**
- * Function allocates memory for new stack map vector.
- */
-static inline void
-vf_new_vector( vf_MapEntry_t **vector, // pointer to vector
- unsigned len, // vector length
- vf_VerifyPool_t *pool) // memory pool
-{
- // create new vector
- (*vector) = (vf_MapEntry_t*)vf_alloc_pool_memory( pool,
- len * sizeof(vf_MapEntry_t) );
- return;
-} // vf_new_vector
-
-/**
* Function sets check type for a given stack map vector entry.
*/
static inline void
@@ -665,19 +619,6 @@
} // vf_set_vector_stack_entry_double
/**
- * Function sets reference data type for given stack map vector entry.
- */
-static inline void
-vf_set_vector_stack_entry_ref( vf_MapEntry_t *vector, // stack map vector
- unsigned num, // vector entry number
- vf_ValidType_t *type) // reference type
-{
- // set stack map vector entry by ref
- vector[num].m_type = SM_REF;
- vector[num].m_vtype = type;
-} // vf_set_vector_stack_entry_ref
-
-/**
* Function sets return address data type for given stack map vector entry.
*/
static inline void
@@ -835,7 +776,7 @@
************************************************************/
/**
- * Function allocates memory for new code instruction IN stack map vector.
+ * Allocates memory for new code instruction in the IN stack map vector.
*/
static inline void
vf_new_in_vector( vf_Code_t *code, // code instruction
@@ -846,12 +787,12 @@
code->m_inlen = (unsigned short)len;
code->m_invector =
(vf_MapEntry_t*)vf_alloc_pool_memory( pool,
- len * sizeof(vf_MapEntry_t) );
+ len * sizeof( vf_MapEntry_t) );
return;
} // vf_new_in_vector
/**
- * Function sets check attribute for a code instruction IN stack map vector entry.
+ * Sets check attribute for a code instruction in the IN stack map vector entry.
*/
static inline void
vf_set_in_vector_check( vf_Code_t *code, // code instruction
@@ -1078,7 +1019,7 @@
code->m_outlen = (unsigned short)len;
code->m_outvector =
(vf_MapEntry_t*)vf_alloc_pool_memory( pool,
- len * sizeof(vf_MapEntry_t) );
+ len * sizeof( vf_MapEntry_t ) );
return;
} // vf_new_out_vector
@@ -1590,20 +1531,6 @@
} // vf_get_cp_nameandtype
/**
- * Function receives class name string.
- * Function returns result of constant pool UTF8 entry check and class name string.
- */
-static inline const char *
-vf_get_cp_class_name( unsigned short index, // constant pool entry index
- vf_Context_t *ctex) // verifier context
-{
- unsigned short class_name_index =
- class_get_cp_class_name_index( ctex->m_class, index );
- const char* name = class_get_cp_utf8_bytes( ctex->m_class, class_name_index );
- return name;
-} // vf_get_cp_class_name
-
-/**
* Function returns valid type string by given class name.
*/
static inline const char *
@@ -1680,14 +1607,14 @@
const char **class_name, // pointer to class name
vf_Context_t *ctex) // verifier context
{
- assert(name);
- assert(descr);
+ assert( name );
+ assert( descr );
// get class name if it's needed
if( class_name ) {
unsigned short class_cp_index =
class_get_cp_ref_class_index( ctex->m_class, index );
- *class_name = vf_get_cp_class_name( class_cp_index, ctex );
+ *class_name = vf_get_cp_class_name( ctex->m_class, class_cp_index );
}
// get name and descriptor from NameAndType constant pool entry
@@ -1741,7 +1668,7 @@
if( stack_with_ref ) {
vf_set_description_vector( descr, cp_parse->method.m_inlen, 1 /* ref + vector */,
cp_parse->method.m_outlen, &cp_parse->method.m_invector,
- &cp_parse->method.m_outvector, ctex);
+ &cp_parse->method.m_outvector, ctex );
// set first ref
cp_parse->method.m_inlen += 1;
vf_ValidType_t *type = vf_create_class_valid_type( class_name, ctex );
@@ -1749,7 +1676,7 @@
} else {
vf_set_description_vector( descr, cp_parse->method.m_inlen, 0 /* only vector */,
cp_parse->method.m_outlen, &cp_parse->method.m_invector,
- &cp_parse->method.m_outvector, ctex);
+ &cp_parse->method.m_outvector, ctex );
}
return VER_OK;
} // vf_check_cp_method
@@ -1785,14 +1712,14 @@
// create instruction vectors
if( stack_with_ref ) {
vf_set_description_vector( descr, cp_parse->field.f_vlen, 1 /* ref + vector */,
- 0, &cp_parse->field.f_vector, NULL, ctex);
+ 0, &cp_parse->field.f_vector, NULL, ctex );
// set first ref
cp_parse->field.f_vlen += 1;
vf_ValidType_t *type = vf_create_class_valid_type( class_name, ctex );
vf_set_vector_stack_entry_ref( cp_parse->field.f_vector, 0, type );
} else {
vf_set_description_vector( descr, cp_parse->field.f_vlen, 0 /* only vector */,
- 0, &cp_parse->field.f_vector, NULL, ctex);
+ 0, &cp_parse->field.f_vector, NULL, ctex );
}
return VER_OK;
} // vf_check_cp_field
@@ -1829,22 +1756,20 @@
vf_set_vector_stack_entry_ref( cp_parse->field.f_vector, 0, type );
break;
case _CONSTANT_Class:
- if( !vf_is_class_version_14(ctex) ) {
+ if( !vf_is_class_version_14( ctex ) ) {
type = ctex->m_type->NewType( "Ljava/lang/Class", 16 );
vf_set_vector_stack_entry_ref( cp_parse->field.f_vector, 0, type );
break;
}
// if class version is 1.4 verifier fails in default
default:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Illegal type for constant pool entry #"
+ VERIFY_REPORT_METHOD( ctex,
+ "Illegal type for constant pool entry #"
<< index
- << (vf_is_class_version_14(ctex)
+ << (vf_is_class_version_14( ctex )
? ": CONSTANT_Integer, CONSTANT_Float or CONSTANT_String"
: ": CONSTANT_Integer, CONSTANT_Float, CONSTANT_String "
- "or CONSTANT_Class")
+ "or CONSTANT_Class" )
<< " are expected for ldc/ldc_w instruction" );
return VER_ErrorConstantPool;
}
@@ -1878,10 +1803,8 @@
vf_set_vector_stack_entry_long( cp_parse->field.f_vector, 0 );
break;
default:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Illegal type in constant pool,"
+ VERIFY_REPORT_METHOD( ctex,
+ "Illegal type in constant pool, "
<< index << ": CONSTANT_Double or CONSTANT_Long are expected" );
return VER_ErrorConstantPool;
}
@@ -1904,7 +1827,7 @@
CHECK_CONST_POOL_CLASS( ctex, index );
if( cp_parse ) {
// create valid type
- const char *name = vf_get_cp_class_name( index, ctex );
+ const char* name = vf_get_cp_class_name( ctex->m_class, index );
// check result
assert( name );
@@ -2646,7 +2569,7 @@
vf_set_in_vector_stack_entry_ref( code, 0, NULL );
vf_set_in_vector_check( code, 0, VF_CHECK_REF_ARRAY );
vf_set_in_vector_stack_entry_int( code, 1 );
- if( vf_is_class_version_14(ctex) ) {
+ if( vf_is_class_version_14( ctex ) ) {
vf_set_in_vector_type( code, 2, SM_UP_ARRAY );
} else {
vf_set_in_vector_stack_entry_ref( code, 2, NULL );
@@ -3401,8 +3324,8 @@
*/
static inline void
vf_opcode_ifeq( vf_Code_t *code, // code instruction
- vf_Instr_t *icode1, // first branch instruction
- vf_Instr_t *icode2, // second branch instruction
+ vf_BCode_t *icode1, // first branch instruction
+ vf_BCode_t *icode2, // second branch instruction
vf_VerifyPool_t * pool) // memory pool
{
// set stack modifier for instruction
@@ -3424,8 +3347,8 @@
*/
static inline void
vf_opcode_if_icmpeq( vf_Code_t *code, // code instruction
- vf_Instr_t *icode1, // first branch instruction
- vf_Instr_t *icode2, // second branch instruction
+ vf_BCode_t *icode1, // first branch instruction
+ vf_BCode_t *icode2, // second branch instruction
vf_VerifyPool_t * pool) // memory pool
{
// set stack modifier for instruction
@@ -3448,8 +3371,8 @@
*/
static inline void
vf_opcode_if_acmpeq( vf_Code_t *code, // code instruction
- vf_Instr_t *icode1, // first branch instruction
- vf_Instr_t *icode2, // second branch instruction
+ vf_BCode_t *icode1, // first branch instruction
+ vf_BCode_t *icode2, // second branch instruction
vf_VerifyPool_t * pool) // memory pool
{
// set stack modifier for instruction
@@ -3492,7 +3415,7 @@
vf_VerifyPool_t * pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// set minimal stack for instruction
vf_set_min_stack( code, 1 );
// create in vector
@@ -3509,7 +3432,7 @@
vf_VerifyPool_t * pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// set minimal stack for instruction
vf_set_min_stack( code, 2 );
// create in vector
@@ -3526,7 +3449,7 @@
vf_VerifyPool_t * pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// set minimal stack for instruction
vf_set_min_stack( code, 1 );
// create in vector
@@ -3543,7 +3466,7 @@
vf_VerifyPool_t * pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// set minimal stack for instruction
vf_set_min_stack( code, 2 );
// create in vector
@@ -3560,7 +3483,7 @@
vf_VerifyPool_t * pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// set minimal stack for instruction
vf_set_min_stack( code, 1 );
// create in vector
@@ -3703,18 +3626,14 @@
}
// check method name
if( cp_parse.method.m_name[0] == '<' ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Must call initializers using invokespecial" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Must call initializers using invokespecial" );
return VER_ErrorConstantPool;
}
// check number of arguments
if( cp_parse.method.m_inlen > 255 ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") The number of method parameters is limited to 255" );
+ VERIFY_REPORT_METHOD( ctex,
+ "The number of method parameters is limited to 255" );
return VER_ErrorInstruction;
}
// set stack modifier for instruction
@@ -3754,10 +3673,8 @@
}
// check number of arguments
if( cp_parse.method.m_inlen > 255 ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") The number of method parameters is limited to 255" );
+ VERIFY_REPORT_METHOD( ctex,
+ "The number of method parameters is limited to 255" );
return VER_ErrorInstruction;
}
// set stack modifier for instruction
@@ -3805,10 +3722,8 @@
// check created reference
assert( cp_parse.field.f_vector->m_vtype->number == 1 );
if( cp_parse.field.f_vector->m_vtype->string[0][0] != 'L' ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Illegal creation of array" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Illegal creation of array" );
return VER_ErrorInstruction;
}
// set stack out vector
@@ -3856,10 +3771,8 @@
vtype = ctex->m_type->NewType( "[J", 2 );
break;
default:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Incorrect type in instruction newarray" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incorrect type in instruction newarray" );
return VER_ErrorInstruction;
}
// set minimal stack for instruction
@@ -3949,7 +3862,7 @@
}
// get array element type name
- const char *name = vf_get_cp_class_name( cp_index, ctex );
+ const char* name = vf_get_cp_class_name( ctex->m_class, cp_index);
assert( name );
// create valid type string
@@ -3964,10 +3877,8 @@
continue;
}
if( index > 255 ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Array with too many dimensions" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Array with too many dimensions" );
return VER_ErrorInstruction;
}
@@ -4014,7 +3925,7 @@
vf_Context_t *ctex) // verifier context
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_THROW );
+ vf_set_code_type( code, VF_TYPE_INSTR_THROW );
// set minimal stack for instruction
vf_set_min_stack( code, 1 );
// create in vector
@@ -4099,7 +4010,7 @@
static inline Verifier_Result
vf_opcode_multianewarray( vf_Code_t *code, // code instruction
unsigned short cp_index, // constant pool entry index
- unsigned short dimension, // dimension of array
+ unsigned char dimensions, // dimension of array
vf_Context_t *ctex) // verifier context
{
// check constant pool for instruction
@@ -4109,7 +4020,7 @@
}
// get array element type name
- const char *name = vf_get_cp_class_name( cp_index, ctex );
+ const char *name = vf_get_cp_class_name( ctex->m_class, cp_index);
assert( name );
// get valid type string
@@ -4123,17 +4034,13 @@
continue;
}
if( index > 255 ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Array with too many dimensions" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Array with too many dimensions" );
return VER_ErrorInstruction;
}
- if( dimension == 0 || index < dimension ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Illegal dimension argument" );
+ if( dimensions == 0 || index < dimensions ) {
+ VERIFY_REPORT_METHOD( ctex,
+ "Illegal dimension argument" );
return VER_ErrorInstruction;
}
@@ -4141,12 +4048,12 @@
vf_ValidType_t *type = ctex->m_type->NewType( array, len );
// set stack modifier for instruction
- vf_set_stack_modifier( code, 1 - dimension );
+ vf_set_stack_modifier( code, 1 - dimensions );
// set minimal stack for instruction
- vf_set_min_stack( code, dimension );
+ vf_set_min_stack( code, dimensions );
// create in vector
- vf_new_in_vector( code, dimension, ctex->m_pool );
- for( index = 0; index < dimension; index++ ) {
+ vf_new_in_vector( code, dimensions, ctex->m_pool );
+ for( index = 0; index < dimensions; index++ ) {
vf_set_in_vector_stack_entry_int( code, index );
}
// create out vector
@@ -4160,8 +4067,8 @@
*/
static inline void
vf_opcode_ifxnull( vf_Code_t *code, // code instruction
- vf_Instr_t *icode1, // first branch instruction
- vf_Instr_t *icode2, // second branch instruction
+ vf_BCode_t *icode1, // first branch instruction
+ vf_BCode_t *icode2, // second branch instruction
vf_VerifyPool_t * pool) // memory pool
{
// set stack modifier for instruction
@@ -4187,7 +4094,7 @@
vf_VerifyPool_t *pool) // memory pool
{
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_SUBROUTINE );
+ vf_set_code_type( code, VF_TYPE_INSTR_SUBROUTINE );
// set stack modifier for instruction
vf_set_stack_modifier( code, 1 );
// create out vector
@@ -4211,48 +4118,17 @@
} // vf_opcode_ret
/**
- * Function sets code instruction structure for end-entry.
+ * Parses bytecode, determines code instructions, fills code array and
+ * provides simple verifications.
*/
-static inline void
-vf_create_end_entry( vf_Code_t *code, // code instruction
- vf_Context_t *ctex) // verifier context
-{
- int inlen,
- outlen;
- vf_MapEntry_t *invector,
- *outvector;
-
- // set end-entry flag
- vf_set_instruction_flag( code, VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_END_ENTRY);
- // get method description
- char *descr = (char*)method_get_descriptor( ctex->m_method );
- // parse description
- vf_parse_description( descr, &inlen, &outlen );
- // set minimal stack for instruction
- vf_set_min_stack( code, outlen );
- // create method vectors
- vf_set_description_vector( descr, inlen, 0, outlen, &invector, &outvector, ctex );
- // set stack in vector
- code->m_invector = outvector;
- code->m_inlen = (unsigned short)outlen;
- return;
-} // vf_create_end_entry
-
-/**
- * Function parse bytecode, determines code instructions, fills code array and
- * provides checks of simple verifications.
- */
static Verifier_Result
-vf_parse_bytecode( vf_Context_t *ctex ) // verifier context
+vf_parse_bytecode( vf_Context_t *ctex )
{
- int offset,
- number;
- unsigned edges = 0,
- index,
- count,
- bbCount = 0;
- unsigned short local,
- constIndex;
+ int offset;
+ unsigned index, count;
+ unsigned short local, const_index;
+ unsigned char u1;
+
Verifier_Result result = VER_OK;
/**
@@ -4261,52 +4137,62 @@
unsigned len = method_get_code_length( ctex->m_method );
unsigned char *bytecode = method_get_bytecode( ctex->m_method );
unsigned short locals = method_get_max_local( ctex->m_method );
- unsigned short handlcount = method_get_exc_handler_number( ctex->m_method );
- unsigned short constlen = class_get_cp_size( ctex->m_class );
- /**
- * Allocate memory for codeInstr
- * +1 more instruction is the end of exception handler
- */
- vf_Instr_t *codeInstr = (vf_Instr_t*)vf_alloc_pool_memory( ctex->m_pool,
- (len + 1) * sizeof(vf_Instr_t) );
- /**
- * Create start-entry instruction
- */
- unsigned codeNum = 0;
- vf_set_instruction_flag( &ctex->m_code[codeNum],
- VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_START_ENTRY);
- codeNum++;
+ // first instruction is always begin of basic block
+ vf_BCode_t* bc = ctex->m_bc;
+ bc[0].m_mark = 1;
- /**
- * Create handler instructions
- */
- vf_Code_t *code;
- for( index = 0, code = &ctex->m_code[codeNum];
- index < handlcount;
- index++, codeNum++, code = &ctex->m_code[codeNum] )
- {
- vf_set_instruction_flag( code, VF_FLAG_BEGIN_BASIC_BLOCK | VF_FLAG_HANDLER );
- }
-
/**
- * Define bytecode instructions and fill code array
+ * Parse bytecode instructions and fill a code array
*/
unsigned instr;
unsigned branches;
+ unsigned codeNum = 0;
+
+ vf_Code_t *code;
vf_VerifyPool_t *pool = ctex->m_pool;
- for( index = 0, code = &ctex->m_code[codeNum];
- index < len;
- codeNum++, code = &ctex->m_code[codeNum] )
+ for( index = 0; index < len; codeNum++ )
{
+ code = &ctex->m_code[codeNum];
code->m_addr = &bytecode[index];
- codeInstr[index].m_instr = codeNum;
+ // Note:
+ // bc[ index ].m_instr is assigned to a positive
+ // value to differentiate with non-assignd values:
+ // the correspondent index in vf_Context.m_code array
+ // is increased by one.
+ bc[ index ].m_instr = codeNum + 1;
+
+ bool wide = ( OPCODE_WIDE == bytecode[index] ); /* 0xc4 */
+ if( wide )
+ {
+ switch( bytecode[++index] ) // check the next instruction
+ {
+ case OPCODE_ILOAD:
+ case OPCODE_FLOAD:
+ case OPCODE_ALOAD:
+ case OPCODE_LLOAD:
+ case OPCODE_DLOAD:
+ case OPCODE_ISTORE:
+ case OPCODE_FSTORE:
+ case OPCODE_ASTORE:
+ case OPCODE_LSTORE:
+ case OPCODE_DSTORE:
+ case OPCODE_RET:
+ case OPCODE_IINC:
+ break;
+ default:
+ VERIFY_REPORT_METHOD( ctex,
+ "wide should be followed by iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, ret or iinc" );
+ result = VER_ErrorInstruction;
+ goto labelEnd_vf_parse_bytecode;
+ }
+ }
instr = index; // remember offset of instruction
index++; // skip bytecode
+
switch( bytecode[instr] )
{
case OPCODE_NOP: /* 0x00 */
- case OPCODE_WIDE: /* 0xc4 */
break;
case OPCODE_ACONST_NULL: /* 0x01 */
vf_opcode_aconst_null( code, pool );
@@ -4339,10 +4225,10 @@
break;
case OPCODE_LDC: /* 0x12 + u1 */
// get constant pool index
- constIndex = (unsigned short)bytecode[index];
+ const_index = (unsigned short)bytecode[index];
// skip constant pool index (u1)
index++;
- result = vf_opcode_ldcx( code, 1, constIndex, ctex );
+ result = vf_opcode_ldcx( code, 1, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
@@ -4350,16 +4236,16 @@
case OPCODE_LDC_W: /* 0x13 + u2 */
case OPCODE_LDC2_W: /* 0x14 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_ldcx( code, bytecode[instr] - OPCODE_LDC, constIndex, ctex );
+ result = vf_opcode_ldcx( code, bytecode[instr] - OPCODE_LDC, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_ILOAD: /* 0x15 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4367,7 +4253,7 @@
vf_opcode_iloadx( code, local, pool );
break;
case OPCODE_LLOAD: /* 0x16 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local + 1, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4375,7 +4261,7 @@
vf_opcode_lloadx( code, local, pool );
break;
case OPCODE_FLOAD: /* 0x17 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4383,7 +4269,7 @@
vf_opcode_floadx( code, local, pool );
break;
case OPCODE_DLOAD: /* 0x18 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local + 1, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4391,7 +4277,7 @@
vf_opcode_dloadx( code, local, pool );
break;
case OPCODE_ALOAD: /* 0x19 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4483,7 +4369,7 @@
vf_opcode_aaload( code, ctex );
break;
case OPCODE_ISTORE: /* 0x36 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4491,7 +4377,7 @@
vf_opcode_istorex( code, local, pool );
break;
case OPCODE_LSTORE: /* 0x37 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local + 1, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4499,7 +4385,7 @@
vf_opcode_lstorex( code, local, pool );
break;
case OPCODE_FSTORE: /* 0x38 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4507,7 +4393,7 @@
vf_opcode_fstorex( code, local, pool );
break;
case OPCODE_DSTORE: /* 0x39 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local + 1, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4515,7 +4401,7 @@
vf_opcode_dstorex( code, local, pool );
break;
case OPCODE_ASTORE: /* 0x3a + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4693,7 +4579,7 @@
break;
case OPCODE_IINC: /* 0x84 + u1|u2 + s1|s2 */
count = index;
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
count = index - count;
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
@@ -4761,7 +4647,7 @@
case OPCODE_IFGE: /* 0x9c + s2 */
case OPCODE_IFGT: /* 0x9d + s2 */
case OPCODE_IFLE: /* 0x9e + s2 */
- offset = vf_get_double_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_double_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -4771,8 +4657,8 @@
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_opcode_ifeq( code, &codeInstr[offset],
- &codeInstr[index], pool );
+ vf_opcode_ifeq( code, &bc[offset],
+ &bc[index], pool );
break;
case OPCODE_IF_ICMPEQ: /* 0x9f + s2 */
case OPCODE_IF_ICMPNE: /* 0xa0 + s2 */
@@ -4780,7 +4666,7 @@
case OPCODE_IF_ICMPGE: /* 0xa2 + s2 */
case OPCODE_IF_ICMPGT: /* 0xa3 + s2 */
case OPCODE_IF_ICMPLE: /* 0xa4 + s2 */
- offset = vf_get_double_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_double_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -4790,12 +4676,12 @@
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_opcode_if_icmpeq( code, &codeInstr[offset],
- &codeInstr[index], pool );
+ vf_opcode_if_icmpeq( code, &bc[offset],
+ &bc[index], pool );
break;
case OPCODE_IF_ACMPEQ: /* 0xa5 + s2 */
case OPCODE_IF_ACMPNE: /* 0xa6 + s2 */
- offset = vf_get_double_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_double_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -4805,23 +4691,23 @@
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_opcode_if_acmpeq( code, &codeInstr[offset],
- &codeInstr[index], pool );
+ vf_opcode_if_acmpeq( code, &bc[offset],
+ &bc[index], pool );
break;
case OPCODE_GOTO: /* 0xa7 + s2 */
- offset = vf_get_single_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_single_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_set_basic_block_flag( &codeInstr[offset] );
+ vf_set_basic_block_flag( &bc[offset] );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_JSR: /* 0xa8 + s2 */
- offset = vf_get_double_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_single_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -4833,43 +4719,42 @@
}
vf_opcode_jsr( code, codeNum, pool );
ctex->m_dump.m_with_subroutine = 1;
- vf_set_basic_block_flag( &codeInstr[offset] );
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[offset] );
+ vf_set_basic_block_flag( &bc[index] );
break;
case OPCODE_RET: /* 0xa9 + u1|u2 */
- local = (unsigned short)vf_get_local_var_number( code, bytecode, &index );
+ local = (unsigned short)vf_get_local_var_number( code, bytecode, &index, wide );
result = vf_check_local_var_number( local, locals, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
vf_opcode_ret( code, local, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_TABLESWITCH: /* 0xaa + pad + s4 * (3 + N) */
vf_opcode_switch( code, pool );
- branches = vf_set_tableswitch_offsets( &codeInstr[instr],
+ branches = vf_set_tableswitch_offsets( code,
instr, &index, bytecode, pool);
// check tableswitch branches and set begin of basic blocks
for( count = 0; count < branches; count++ )
{
- offset = vf_get_instruction_branch( &codeInstr[instr], count );
+ offset = vf_get_code_branch( code, count );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_set_basic_block_flag( &codeInstr[offset] );
+ vf_set_basic_block_flag( &bc[offset] );
}
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_LOOKUPSWITCH: /* 0xab + pad + s4 * 2 * (N + 1) */
vf_opcode_switch( code, pool );
- result = vf_set_lookupswitch_offsets( &codeInstr[instr],
+ result = vf_set_lookupswitch_offsets( code,
instr, &index, bytecode, &branches, ctex);
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
@@ -4877,142 +4762,136 @@
// check tableswitch branches and set begin of basic blocks
for( count = 0; count < branches; count++ )
{
- offset = vf_get_instruction_branch( &codeInstr[instr], count );
+ offset = vf_get_code_branch( code, count );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_set_basic_block_flag( &codeInstr[offset] );
+ vf_set_basic_block_flag( &bc[offset] );
}
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_IRETURN: /* 0xac */
vf_opcode_ireturn( code, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_LRETURN: /* 0xad */
vf_opcode_lreturn( code, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_FRETURN: /* 0xae */
vf_opcode_freturn( code, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_DRETURN: /* 0xaf */
vf_opcode_dreturn( code, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_ARETURN: /* 0xb0 */
vf_opcode_areturn( code, pool );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_RETURN: /* 0xb1 */
// set instruction flag
- vf_set_instruction_flag( code, VF_FLAG_RETURN );
+ vf_set_code_type( code, VF_TYPE_INSTR_RETURN );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_GETSTATIC: /* 0xb2 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_getstatic( code, constIndex, ctex );
+ result = vf_opcode_getstatic( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_PUTSTATIC: /* 0xb3 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_putstatic( code, constIndex, ctex );
+ result = vf_opcode_putstatic( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_GETFIELD: /* 0xb4 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_getfield( code, constIndex, ctex );
+ result = vf_opcode_getfield( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_PUTFIELD: /* 0xb5 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_putfield( code, constIndex, ctex );
+ result = vf_opcode_putfield( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_INVOKEVIRTUAL: /* 0xb6 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_invoke( code, constIndex, ctex );
+ result = vf_opcode_invoke( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_INVOKESPECIAL: /* 0xb7 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_invokespecial( code, constIndex, ctex );
+ result = vf_opcode_invokespecial( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_INVOKESTATIC: /* 0xb8 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_invoke( code, constIndex, ctex );
+ result = vf_opcode_invoke( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_INVOKEINTERFACE:/* 0xb9 + u2 + u1 + u1 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_invoke( code, constIndex, ctex );
+ result = vf_opcode_invoke( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
@@ -5020,10 +4899,8 @@
if( ctex->m_code[codeNum].m_inlen != (unsigned short)bytecode[index]
|| bytecode[index + 1] != 0 )
{
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Incorrect operand byte of invokeinterface");
+ VERIFY_REPORT_METHOD( ctex,
+ "Incorrect operand byte of invokeinterface");
result = VER_ErrorInstruction;
goto labelEnd_vf_parse_bytecode;
}
@@ -5032,30 +4909,30 @@
break;
case OPCODE_NEW: /* 0xbb + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_new( code, constIndex, codeNum, ctex );
+ result = vf_opcode_new( code, const_index, codeNum, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_NEWARRAY: /* 0xbc + u1 */
// get array type
- number = (int)bytecode[index];
+ u1 = (unsigned char)bytecode[index];
// skip parameter (u1)
index++;
- result = vf_opcode_newarray( code, (unsigned char)number, ctex );
+ result = vf_opcode_newarray( code, u1, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_ANEWARRAY: /* 0xbd + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_anewarray( code, constIndex, ctex );
+ result = vf_opcode_anewarray( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
@@ -5066,27 +4943,26 @@
case OPCODE_ATHROW: /* 0xbf */
vf_opcode_athrow( code, ctex );
// create and set edge branch to exit
- vf_set_single_instruction_offset( &codeInstr[instr], ~0U, pool );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_CHECKCAST: /* 0xc0 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_checkcast( code, constIndex, ctex );
+ result = vf_opcode_checkcast( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_INSTANCEOF: /* 0xc1 + u2 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
- result = vf_opcode_instanceof( code, constIndex, ctex );
+ result = vf_opcode_instanceof( code, const_index, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
@@ -5097,21 +4973,21 @@
break;
case OPCODE_MULTIANEWARRAY: /* 0xc5 + u2 + u1 */
// get constant pool index
- constIndex = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
+ const_index = (unsigned short)( (bytecode[index] << 8)|(bytecode[index + 1]) );
// skip constant pool index (u2)
index += 2;
// get dimensions of array
- number = (int)bytecode[index];
+ u1 = (int)bytecode[index];
// skip dimensions of array (u1)
index++;
- result = vf_opcode_multianewarray( code, constIndex, (unsigned short)number, ctex );
+ result = vf_opcode_multianewarray( code, const_index, u1, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
break;
case OPCODE_IFNULL: /* 0xc6 + s2 */
case OPCODE_IFNONNULL: /* 0xc7 + s2 */
- offset = vf_get_double_hword_branch_offset( &codeInstr[instr],
+ offset = vf_get_double_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -5121,23 +4997,23 @@
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_opcode_ifxnull( &ctex->m_code[codeNum], &codeInstr[offset],
- &codeInstr[index], pool );
+ vf_opcode_ifxnull( &ctex->m_code[codeNum], &bc[offset],
+ &bc[index], pool );
break;
case OPCODE_GOTO_W: /* 0xc8 + s4 */
- offset = vf_get_single_word_branch_offset( &codeInstr[instr],
+ offset = vf_get_single_word_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
goto labelEnd_vf_parse_bytecode;
}
- vf_set_basic_block_flag( &codeInstr[offset] );
+ vf_set_basic_block_flag( &bc[offset] );
if( index < len ) {
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[index] );
}
break;
case OPCODE_JSR_W: /* 0xc9 + s4 */
- offset = vf_get_double_word_branch_offset( &codeInstr[instr],
+ offset = vf_get_single_word_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -5149,174 +5025,154 @@
}
vf_opcode_jsr( code, codeNum, pool );
ctex->m_dump.m_with_subroutine = 1;
- vf_set_basic_block_flag( &codeInstr[offset] );
- vf_set_basic_block_flag( &codeInstr[index] );
+ vf_set_basic_block_flag( &bc[offset] );
+ vf_set_basic_block_flag( &bc[index] );
break;
case _OPCODE_UNDEFINED: /* 0xba */
default:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Unknown instruction bytecode" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Unknown instruction bytecode" );
result = VER_ErrorInstruction;
goto labelEnd_vf_parse_bytecode;
}
}
- /**
- * Create end-entry instruction
- */
- code = ctex->m_code;
- vf_create_end_entry( &code[codeNum], ctex );
- codeInstr[index].m_instr = codeNum;
- codeNum++;
+ if (index > len) {
+ VERIFY_REPORT_METHOD( ctex,
+ "The last instruction doesn't fit bytecode array" );
+ result = VER_ErrorCodeEnd;
+ goto labelEnd_vf_parse_bytecode;
+ }
/**
- * Set handler basic blocks
+ * Set handler basic blocks.
*/
- edges = 0;
- for( index = 0; index < handlcount; index++ ) {
- // check instruction range
- unsigned short start_pc;
- unsigned short end_pc;
- unsigned short handler_pc;
+ unsigned short handler_count = method_get_exc_handler_number( ctex->m_method );
+ unsigned short handler_index;
+ unsigned short constLen = class_get_cp_size( ctex->m_class );
+ for( handler_index = 0;
+ handler_index < handler_count; handler_index++ )
+ {
+ unsigned short start_pc, end_pc, handler_pc;
unsigned short handler_cp_index;
- method_get_exc_handler_info( ctex->m_method, (unsigned short)index, &start_pc, &end_pc,
- &handler_pc, &handler_cp_index );
- if( ( start_pc >= len ) || ( end_pc > len ) || ( handler_pc >= len ) )
+ method_get_exc_handler_info( ctex->m_method,
+ handler_index, &start_pc, &end_pc, &handler_pc,
+ &handler_cp_index );
+ // check instruction range
+ if( ( start_pc >= len )
+ || ( end_pc > len )
+ || ( handler_pc >= len ) )
{
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Handler pc is out of range" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception handler pc is out of range" );
result = VER_ErrorHandler;
goto labelEnd_vf_parse_bytecode;
}
- // check constant pool index
- CHECK_HANDLER_CONST_POOL_ID( handler_cp_index, constlen, ctex );
- CHECK_HANDLER_CONST_POOL_CLASS( ctex, handler_cp_index );
- // check instruction relations
- if( (codeInstr[ start_pc ].m_instr == 0)
- || (codeInstr[ end_pc ].m_instr == 0)
- || (codeInstr[ handler_pc ].m_instr == 0) )
+ if( start_pc >= end_pc )
{
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Handler pc is out of instruction set" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception handler range starting point should be before ending point" );
result = VER_ErrorHandler;
goto labelEnd_vf_parse_bytecode;
}
- // set handler basic blocks
- codeInstr[ start_pc ].m_mark = 1;
- codeInstr[ end_pc ].m_mark = 1;
- codeInstr[ handler_pc ].m_mark = 1;
- /**
- * Set handler branch offset
- */
- edges++;
- code[index + 1].m_offcount = 1;
- code[index + 1].m_off = (unsigned*)vf_alloc_pool_memory( pool,
- sizeof(unsigned) );
- // fill offset array for code instruction
- code[index + 1].m_off[0] = codeInstr[ handler_pc ].m_instr;
- // create handler valid type
- vf_ValidType_t *type = NULL;
- if( handler_cp_index ) {
- const char* name = vf_get_cp_class_name( handler_cp_index, ctex );
- assert(name);
+ // check that handlers point to instruction
+ // boundaries
+ if( bc[ start_pc ].m_instr == 0 )
+ {
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception start_pc (" << start_pc << ") is out of instruction set" );
+ result = VER_ErrorHandler;
+ goto labelEnd_vf_parse_bytecode;
+ }
+ if( bc[ handler_pc ].m_instr == 0 )
+ {
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception handler_pc (" << handler_pc << ") is out of instruction set" );
+ result = VER_ErrorHandler;
+ goto labelEnd_vf_parse_bytecode;
+ }
- type = vf_create_class_valid_type( name, ctex );
- // set restriction for handler class
- if( ctex->m_vtype.m_throwable->string[0] != type->string[0] ) {
- ctex->m_type->SetRestriction( ctex->m_vtype.m_throwable->string[0],
- type->string[0], 0, VF_CHECK_SUPER );
+ if( end_pc < len )
+ {
+ if( bc[ end_pc ].m_instr == 0 )
+ {
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception end_pc (" << end_pc << ") is out of instruction set" );
+ result = VER_ErrorHandler;
+ goto labelEnd_vf_parse_bytecode;
}
+ bc[ end_pc ].m_mark = 1;
}
- // create out vector for handler
- vf_new_out_vector( &code[index + 1], 1, pool );
- vf_set_out_vector_stack_entry_ref( &code[index + 1], 0, type );
+ bc[ start_pc ].m_mark = 1;
+ bc[ handler_pc ].m_mark = 1;
+ }
- /**
- * Set handler branches
- * Set handler branches to last instructions of basic blocks
- */
- for( count = start_pc + 1; count <= end_pc; count++ ) {
- if( count < len && codeInstr[count].m_mark ) {
- // calculate code instruction number
- instr = codeInstr[count].m_instr - 1;
- // check existence of handler array
- if( code[instr].m_handler == NULL ) {
- // create handler array for code instruction
- code[instr].m_handler =
- (unsigned char*)vf_alloc_pool_memory( pool,
- handlcount * sizeof(unsigned char) );
- }
- // count handler edges
- edges++;
- // set handler branch
- code[instr].m_handler[index] = 1;
- }
+ /**
+ * Count edges from basic blocks from exception range to the
+ * corresponding exception handlers.
+ */
+ unsigned edges = 0;
+ for( handler_index = 0;
+ handler_index < handler_count; handler_index++ ) {
+ unsigned short start_pc, end_pc, handler_pc;
+ unsigned short handler_cp_index;
+ method_get_exc_handler_info( ctex->m_method, handler_index,
+ &start_pc, &end_pc, &handler_pc, &handler_cp_index );
+
+ // number of basic blocks in the exception range
+ unsigned handler_edges = 0;
+ for( count = start_pc; count < end_pc; count++ ) {
+ handler_edges += bc[ count ].m_mark;
}
+
+ edges += handler_edges;
}
/**
- * Initialize basic block count
- * Include start-entry basic block, handler basic blocks,
- * end-entry basic block.
+ * Initialize a node counter with handler nodes and
+ * terminator nodes.
*/
- bbCount = 1 + handlcount + 1;
+ unsigned nodes = handler_count + 2;
/**
- * Set code offsets
- * Check code instructions
+ * Check code offsets, count basic blocks and edges.
*/
for( index = 0; index < len; index++ ) {
- if( !index || codeInstr[index].m_mark ) {
- // first instruction is always begin of basic block
- if( (count = codeInstr[index].m_instr) == 0 ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Illegal target of jump or branch" );
+ instr = bc[ index ].m_instr;
+ if (instr == 0) {
+ if( bc[ index ].m_mark ) {
+ VERIFY_REPORT_METHOD( ctex,
+ "Illegal target of jump or branch" );
result = VER_ErrorBranch;
goto labelEnd_vf_parse_bytecode;
- }
- vf_set_instruction_flag( &code[count], VF_FLAG_BEGIN_BASIC_BLOCK );
- bbCount++;
- if( !index || code[count - 1].m_offcount == 0 ) {
- // considering first edge from start-entry to first instruction
- // count only edges that catenate 2 nearby instructions
- edges++;
- }
- }
- if( codeInstr[index].m_offcount ) {
- // calculate code instruction number
- instr = codeInstr[index].m_instr;
- // create offset array for code instruction
- edges += codeInstr[index].m_offcount;
- code[instr].m_offcount = codeInstr[index].m_offcount;
- code[instr].m_off = codeInstr[index].m_off;
- // fill offset array for code instruction
- for( count = 0; count < codeInstr[index].m_offcount; count++ ) {
- offset = codeInstr[index].m_off[count];
- if( offset == -1 ) {
- code[instr].m_off[count] = codeNum - 1;
} else {
- code[instr].m_off[count] = codeInstr[offset].m_instr;
- }
+ continue;
}
}
+
+ code = &ctex->m_code[instr - 1];
+ if( bc[ index ].m_mark ) {
+ code->m_basic_block_start = true;
+ nodes++;
}
-labelEnd_vf_parse_bytecode:
+ if( code->m_offcount ) {
+ // basic block should start next, so we will
+ // count one branch anyway
+ edges += code->m_offcount - 1;
+ }
+ }
/**
- * Free allocated memory
+ * Each node except the ending node emits at least one branch.
*/
+ edges += nodes - 1;
+
+labelEnd_vf_parse_bytecode:
+
ctex->m_codeNum = codeNum;
- ctex->m_nodeNum = bbCount;
+ ctex->m_nodeNum = nodes;
ctex->m_edgeNum = edges;
#if _VERIFY_DEBUG
@@ -5336,60 +5192,58 @@
void
vf_dump_bytecode( vf_Context_t *ctex ) // verifier context
{
- unsigned char* bytecode;
- unsigned index,
- count,
- handlcount;
- vf_Code_t *code = ctex->m_code;
-
- bytecode = method_get_bytecode( ctex->m_method );
- handlcount = method_get_exc_handler_number( ctex->m_method );
VERIFY_DEBUG( "======================== VERIFIER METHOD DUMP ========================" );
VERIFY_DEBUG( "Method: " << class_get_name( ctex->m_class )
<< "." << method_get_name( ctex->m_method )
<< method_get_descriptor( ctex->m_method ) << endl );
VERIFY_DEBUG( "0 [-]: -> START-ENTRY" );
- for( index = 0; index < handlcount; index++ ) {
- VERIFY_DEBUG( index + 1 << " [-]: -> HANDLER #" << index + 1 );
- if( code[index + 1].m_offcount ) {
- for( count = 0; count < code[index + 1].m_offcount; count++ )
- if( code[index + 1].m_off[count] == ctex->m_codeNum - 1 ) {
- VERIFY_DEBUG( " --> " << code[index + 1].m_off[count] << " [-]" );
- } else {
- VERIFY_DEBUG( " --> " << code[index + 1].m_off[count]
- << " ["
- << code[ code[index + 1].m_off[count] ].m_addr
- - bytecode << "]" );
+
+ unsigned short handler_count =
+ method_get_exc_handler_number( ctex->m_method );
+ for( unsigned short handler_index = 0;
+ handler_index < handler_count; handler_index++ ) {
+ VERIFY_DEBUG( handler_index + 1 << " [-]: -> HANDLER #" << handler_index + 1 );
+ unsigned short start_pc, end_pc, handler_pc;
+ unsigned short handler_cp_index;
+ method_get_exc_handler_info( ctex->m_method,
+ handler_index, &start_pc, &end_pc,
+ &handler_pc, &handler_cp_index );
+
+ VERIFY_DEBUG(
+ " from " << ctex->m_bc[start_pc].m_instr + handler_count
+ << " [" << start_pc << "]"
+ " to " << ctex->m_bc[end_pc].m_instr + handler_count
+ << " [" << end_pc << "]"
+ " --> " << ctex->m_bc[handler_pc].m_instr + handler_count
+ << " [" << handler_pc << "]"
+ ", CP type " << handler_cp_index );
}
+
+ unsigned char* bytecode =
+ method_get_bytecode( ctex->m_method );
+ unsigned index = handler_count + 1;
+ vf_Code_t* code = ctex->m_code;
+ for( ; index < ctex->m_codeNum + handler_count + 1; index++, code++) {
+ VERIFY_DEBUG( index
+ << " [" << code->m_addr - bytecode << "]:"
+ << ((code->m_basic_block_start) ? " -> " : " ")
+ << ((code->m_stack < 0) ? "" : " " )
+ << code->m_stack
+ << "|" << code->m_minstack << " "
+ << vf_opcode_names[*(code->m_addr)] );
+ for( unsigned count = 0; count < code->m_offcount; count++ ) {
+ unsigned offset = code->m_off[count];
+ VERIFY_DEBUG( " --> "
+ << ctex->m_bc[offset].m_instr + handler_count
+ << " [" << offset << "]" );
}
}
- for( index = handlcount + 1; index < ctex->m_codeNum - 1; index++ ) {
- VERIFY_DEBUG( index << " [" << code[index].m_addr - bytecode << "]:"
- << (vf_is_begin_basic_block( &code[index] ) ? " -> " : " ")
- << ((code[index].m_stack < 0) ? "" : " " )
- << code[index].m_stack
- << "|" << code[index].m_minstack << " "
- << vf_opcode_names[*(code[index].m_addr)] );
- if( code[index].m_offcount ) {
- for( count = 0; count < code[index].m_offcount; count++ )
- if( code[index].m_off[count] == ctex->m_codeNum - 1 ) {
- VERIFY_DEBUG( " --> " << code[index].m_off[count] << " [-]" );
- } else {
- VERIFY_DEBUG( " --> " << code[index].m_off[count]
- << " ["
- << code[ code[index].m_off[count] ].m_addr
- - bytecode << "]" );
- }
- }
- }
VERIFY_DEBUG( index << " [-]: -> END-ENTRY" << endl );
VERIFY_DEBUG( "======================================================================" );
return;
} // vf_dump_bytecode
#endif //_VERIFY_DEBUG
-} // namespace Verifier
-
/**
* Function provides initial verification of class.
*/
@@ -5398,8 +5252,8 @@
unsigned verifyAll, // verification level flag
char **message) // verifier error message
{
- assert(klass);
- assert(message);
+ assert( klass);
+ assert( message);
#if VERIFY_CLASS
if( strcmp( class_get_name( klass ), "" ) ) {
return VER_OK;
@@ -5467,6 +5321,7 @@
//context.m_dump.m_node_vector = 1;
//context.m_dump.m_code_vector = 1;
//context.m_dump.m_merge_vector = 1;
+ //context.m_dump.m_dot_graph = 1;
result = vf_verify_method_bytecode( &context );
context.ClearContext();
}
@@ -5496,7 +5351,7 @@
*message = context.m_error;
#if _VERIFY_DEBUG
if( result != VER_OK ) {
- TRACE2("verifier", "VerifyError: " << (context.m_error ? context.m_error : "NULL") );
+ TRACE2( "verifier", "VerifyError: " << (context.m_error ? context.m_error : "NULL") );
}
#endif // _VERIFY_DEBUG
Index: vm/vmcore/src/verifier/ver_subroutine.cpp
===================================================================
--- vm/vmcore/src/verifier/ver_subroutine.cpp (revision 0)
+++ vm/vmcore/src/verifier/ver_subroutine.cpp (revision 0)
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "ver_subroutine.h"
+
+static vf_Result
+MarkTopcode(vf_ContextHandle context, vf_NodeHandle nh) {
+ return VER_OK;
+} // MarkTopcode
+
+static vf_Result
+InlineMarkedSubNodes(vf_ContextHandle context) {
+ return VER_OK;
+} // InlineMarkedSubNodes
+
+vf_Result
+vf_inline_subroutines(vf_ContextHandle context) {
+
+ vf_Result r = MarkTopcode(context, context->m_graph->GetFirstNode());
+ if (VER_OK != r) {
+ return r;
+ }
+
+ r = InlineMarkedSubNodes(context);
+ return r;
+} // InlineSubroutines
Index: vm/vmcore/src/verifier/ver_utils.cpp
===================================================================
--- vm/vmcore/src/verifier/ver_utils.cpp (revision 507588)
+++ vm/vmcore/src/verifier/ver_utils.cpp (working copy)
@@ -28,11 +28,6 @@
// Macro enable verifier memory trace
#define VERIFY_TRACE_MEMORY 0
-/**
- * Set namespace Verifier
- */
-namespace Verifier {
-
/************************************************************
*********************** Hash class *************************
************************************************************/
@@ -1031,52 +1026,36 @@
switch( check )
{
case VF_CHECK_PARAM:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Incompatible argument for function" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incompatible argument for function" );
break;
case VF_CHECK_ASSIGN:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Incompatible types for field assignment" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incompatible types for field assignment" );
break;
case VF_CHECK_ASSIGN_WEAK:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Incompatible types for array assignment" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incompatible types for array assignment" );
break;
case VF_CHECK_SUPER:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Exception class not a subclass of Throwable" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Exception class not a subclass of Throwable" );
break;
case VF_CHECK_ACCESS_FIELD:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Bad access to protected field" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Bad access to protected field" );
break;
case VF_CHECK_ACCESS_METHOD:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Bad access to protected method" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Bad access to protected method" );
break;
case VF_CHECK_DIRECT_SUPER:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Call to wrong initialization method" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Call to wrong initialization method" );
break;
case VF_CHECK_INVOKESPECIAL:
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( method )
- << method_get_descriptor( method )
- << ") Incompatible object argument for invokespecial" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incompatible object argument for invokespecial" );
break;
default:
LDIE(41, "Verifier: vf_set_error: unknown check type" );
@@ -1815,8 +1794,6 @@
return;
} // vf_delete_pool_func
-} // namespace Verifier
-
/**
* Function provides final constraint checks for a given class.
*/
@@ -1834,7 +1811,7 @@
context.m_dump.m_verify = verifyAll ? 1 : 0;
// verified constraint for a given method
- Verifier_Result result = Verifier::vf_verify_class_constraints( &context );
+ Verifier_Result result = vf_verify_class_constraints( &context );
*message = context.m_error;
#if _VERIFY_DEBUG
Index: vm/vmcore/src/verifier/ver_dataflow.cpp
===================================================================
--- vm/vmcore/src/verifier/ver_dataflow.cpp (revision 507588)
+++ vm/vmcore/src/verifier/ver_dataflow.cpp (working copy)
@@ -20,6 +20,7 @@
*/
#include "ver_real.h"
+#include "ver_graph.h"
/**
* Debug flag macros
@@ -29,11 +30,6 @@
// Macro prints data flow node instruction vectors
#define DUMP_NODE_INSTR_VECTOR 0
-/**
- * Set namespace Verifier
- */
-namespace Verifier {
-
/************************************************************
**************** Graph Data Flow Analysis ******************
************************************************************/
@@ -96,7 +92,7 @@
* Function prints data flow vector into output stream.
*/
void
-vf_dump_vector( vf_MapVector_t *vector, // data flow vector
+vf_dump_vector( vf_MapVectorHandle vector, // data flow vector
vf_Code_t *code, // code instruction
ostream *stream) // output stream (can be NULL)
{
@@ -152,7 +148,7 @@
}
// dump stack vector
*stream << "S:";
- for( index = 0; index < vector->m_deep; index++ ) {
+ for( index = 0; index < vector->m_depth; index++ ) {
vf_dump_vector_entry( &vector->m_stack[index], stream );
if( vector->m_stack[index].m_is_local ) {
*stream << "!";
@@ -162,7 +158,7 @@
}
*stream << endl;
// dump stack references
- for( index = 0; index < vector->m_deep; index++ ) {
+ for( index = 0; index < vector->m_depth; index++ ) {
if( vector->m_stack[index].m_type == SM_REF ) {
*stream << " REF #" << index << ": ";
} else if( vector->m_stack[index].m_type == SM_UNINITIALIZED ) {
@@ -216,8 +212,8 @@
* If first vector was changed, returns true, else - false.
*/
static inline bool
-vf_merge_vectors( vf_MapVector_t *first, // first vector
- vf_MapVector_t *second, // second vector
+vf_merge_vectors( struct vf_MapVector* first, // first vector
+ vf_MapVectorHandle second, // second vector
bool handler_flag, // if merged node is handler
vf_Context_t *ctex) // verifier context
{
@@ -288,8 +284,8 @@
}
// merge stack map vector
- assert( first->m_deep == second->m_deep );
- for( index = 0; index < second->m_deep; index++ ) {
+ assert( first->m_depth == second->m_depth );
+ for( index = 0; index < second->m_depth; index++ ) {
// merge entries type
if( first->m_stack[index].m_type == SM_TOP ) {
// no need to merge
@@ -327,8 +323,8 @@
* Function copies source vector to data vector.
*/
static inline void
-vf_copy_vector( vf_MapVector_t *source, // copied vector
- vf_MapVector_t *data) // data vector
+vf_copy_vector( vf_MapVectorHandle source, // copied vector
+ struct vf_MapVector* data) // data vector
{
unsigned index;
vf_MapEntry_t zero = {0};
@@ -344,8 +340,8 @@
data->m_local[index] = zero;
}
// copy stack
- data->m_deep = source->m_deep;
- for( index = 0; index < source->m_deep; index++ ) {
+ data->m_depth = source->m_depth;
+ for( index = 0; index < source->m_depth; index++ ) {
data->m_stack[index] = source->m_stack[index];
}
for( ; index < data->m_maxstack; index++ ) {
@@ -358,14 +354,14 @@
* Function compares two vectors.
*/
static inline bool
-vf_compare_vectors( vf_MapVector_t *first, // first vector
- vf_MapVector_t *second) // second vector
+vf_compare_vectors( vf_MapVectorHandle first, // first vector
+ vf_MapVectorHandle second) // second vector
{
// compare vector parameters
if( first->m_maxlocal != second->m_maxlocal
|| first->m_maxstack != second->m_maxstack
|| first->m_number != second->m_number
- || first->m_deep != second->m_deep )
+ || first->m_depth != second->m_depth )
{
return false;
}
@@ -383,7 +379,7 @@
}
}
// compare stack
- for( index = 0; index < first->m_deep; index++ ) {
+ for( index = 0; index < first->m_depth; index++ ) {
if( first->m_stack[index].m_type != second->m_stack[index].m_type
|| first->m_stack[index].m_vtype != second->m_stack[index].m_vtype )
{
@@ -397,9 +393,9 @@
* Function check access constraint for two stack map references.
*/
static inline Verifier_Result
-vf_check_access(vf_MapEntry_t *source, // stack map entry
- vf_MapEntry_t *target, // required map entry
- vf_Context_t *ctex) // verifier context
+vf_check_access( vf_MapEntry_t *source, // stack map entry
+ vf_MapEntry_t *target, // required map entry
+ vf_Context_t *ctex) // verifier context
{
// compare types
assert( target->m_vtype->number == 1 );
@@ -475,10 +471,8 @@
// can be stored in a local variable if backward branch is
// taken or the code is protected by exception handler.
} else {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Uninitialized reference usage" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Uninitialized reference usage" );
return VER_ErrorDataFlow;
}
}
@@ -721,15 +715,15 @@
* Function clears stack map vector.
*/
static inline void
-vf_clear_stack( vf_MapVector_t *vector ) // map vector
+vf_clear_stack( struct vf_MapVector* vector ) // map vector
{
vf_MapEntry_t zero_entry = {0};
// zero stack vector
- for( unsigned index = 0; index < vector->m_deep; index++ ) {
+ for( unsigned index = 0; index < vector->m_depth; index++ ) {
vector->m_stack[index] = zero_entry;
}
- vector->m_deep = 0;
+ vector->m_depth = 0;
return;
} // vf_clear_stack
@@ -810,10 +804,8 @@
// check entry types
result = vf_check_entry_refs( entry, newvector, local_init, ctex );
if( result != VER_OK ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Incompatible types for array assignment" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Incompatible types for array assignment" );
return result;
}
break;
@@ -822,10 +814,8 @@
result = vf_check_entry_refs( entry, vector, local_init, ctex );
if( result != VER_OK ) {
if( !ctex->m_error ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Data flow analysis error" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Data flow analysis error" );
}
return result;
}
@@ -835,18 +825,14 @@
// check entry references
if( entry->m_type == SM_REF ) {
// double initialization
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Double initialization of object reference" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Double initialization of object reference" );
return VER_ErrorDataFlow;
}
result = vf_check_entry_refs( entry, vector, local_init, ctex );
if( result != VER_OK ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Data flow analysis error (uninitialized)" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Data flow analysis error (uninitialized)" );
return result;
}
// check initialization class in constructor
@@ -865,10 +851,8 @@
// check entry types
result = vf_check_entry_types( entry, vector, local_init, ©, ctex );
if( result != VER_OK ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Data flow analysis error" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Data flow analysis error" );
return result;
}
}
@@ -888,7 +872,7 @@
static Verifier_Result
vf_get_instruction_out_vector( unsigned node_num, // graph node
vf_Code_t *instr, // code instruction
- vf_MapVector_t *invector, // incoming data flow vector
+ struct vf_MapVector* invector, // incoming data flow vector
vf_MapEntry_t *buf, // buf storage vector
vf_Context_t *ctex) // verifier context
{
@@ -897,31 +881,30 @@
vf_MapEntry_t zero_entry = {0};
// set stack vector
- assert( invector->m_deep - instr->m_minstack >= 0 );
- vf_MapEntry_t *stack = invector->m_stack + invector->m_deep - instr->m_minstack;
+ assert( invector->m_depth - instr->m_minstack >= 0 );
+ vf_MapEntry_t *stack = invector->m_stack + invector->m_depth - instr->m_minstack;
// set locals vector
vf_MapEntry_t *locals = invector->m_local;
// check instruction in vector
Verifier_Result result = vf_check_instruction_in_vector( stack, locals, buf,
- instr->m_invector, instr->m_inlen, ctex->m_graph->GetNodeInitFlag(node_num),
+ instr->m_invector, instr->m_inlen, ctex->m_graph->GetNodeInitFlag( node_num ),
&need_init, ctex );
if( result != VER_OK ) {
return result;
}
// create out vector for return instructions
- if( vf_is_instruction_has_flags( instr, VF_FLAG_RETURN ) ) {
+ if( VF_TYPE_INSTR_RETURN == instr->m_type ) {
// clear stack
- unsigned deep = invector->m_deep;
+ unsigned deep = invector->m_depth;
vf_clear_stack( invector );
// set result vector stack deep
- invector->m_deep = (unsigned short)(deep + instr->m_stack);
+ invector->m_depth = (unsigned short)(deep + instr->m_stack);
// set out vector
vf_set_return_out_vector( invector->m_stack, buf, instr->m_invector,
instr->m_inlen, ctex );
return VER_OK;
- } else if( vf_is_instruction_has_flags( instr, VF_FLAG_THROW ) ) {
- // set result vector stack deep
+ } else if( VF_TYPE_INSTR_THROW == instr->m_type ) {
invector->m_stack->m_type = SM_TERMINATE;
return VER_OK;
}
@@ -944,7 +927,7 @@
}
}
// init stack reference
- for( index = 0; index < (unsigned)invector->m_deep - instr->m_minstack; index++ ) {
+ for( index = 0; index < (unsigned)invector->m_depth - instr->m_minstack; index++ ) {
if( invector->m_stack[index].m_type == SM_UNINITIALIZED
&& invector->m_stack[index].m_new == buf[0].m_new )
{
@@ -955,8 +938,8 @@
}
// set instruction OUT vector
- invector->m_deep = (unsigned short )(invector->m_deep + instr->m_stack);
- assert( invector->m_deep <= invector->m_maxstack );
+ invector->m_depth = (unsigned short )(invector->m_depth + instr->m_stack);
+ assert( invector->m_depth <= invector->m_maxstack );
index = invector->m_number;
vf_set_instruction_out_vector( instr, stack, locals, &invector->m_number, buf, ctex );
assert( invector->m_number <= invector->m_maxlocal );
@@ -972,19 +955,22 @@
} // vf_get_instruction_out_vector
/**
- * Function receives handler OUT data flow vector.
+ * Copies a stored handler vector to the out vector.
*/
static inline Verifier_Result
-vf_get_handler_out_vector( vf_Code_t *instr, // handler code instruction
- vf_MapVector_t *invector) // incoming data flow vector
+vf_get_handler_out_vector( struct vf_MapVector* invector, // IN handler vector
+ vf_MapVectorHandle handler_vector) // stored handler vector
{
+ assert( 0 == invector->m_depth );
+ assert( 1 == handler_vector->m_depth );
+ assert( SM_REF == handler_vector->m_stack->m_type );
+
// set handler out vector
- assert( invector->m_deep == 0 );
- assert( instr->m_outlen == 1 );
- invector->m_stack->m_type = instr->m_outvector->m_type;
- invector->m_stack->m_vtype = instr->m_outvector->m_vtype;
+ invector->m_stack->m_type = handler_vector->m_stack->m_type;
+ invector->m_stack->m_vtype = handler_vector->m_stack->m_vtype;
+
// set modify vector value
- invector->m_deep++;
+ invector->m_depth = 1;
return VER_OK;
} // vf_get_handler_out_vector
@@ -993,59 +979,56 @@
*/
static Verifier_Result
vf_set_node_out_vector( unsigned node_num, // graph node number
- vf_MapVector_t *invector, // incoming data flow vector
+ struct vf_MapVector* invector, // incoming data flow vector
vf_MapEntry_t *buf, // buf stack map vector
vf_Context_t *ctex) // verifier context
{
- unsigned index,
- instruction;
- vf_Code_t *instr;
Verifier_Result result;
// get node instruction number
- vf_Graph_t *graph = ctex->m_graph;
- instruction = graph->GetNodeLastInstr( node_num )
- - graph->GetNodeFirstInstr( node_num ) + 1;
- // get first instruction
- instr = &ctex->m_code[graph->GetNodeFirstInstr( node_num )];
+ vf_Graph* graph = ctex->m_graph;
+ vf_NodeHandle node = graph->GetNode( node_num );
/**
* For start-entry node doesn't need to check data flow
*/
- if( vf_is_instruction_has_flags( instr, VF_FLAG_START_ENTRY ) ) {
- assert( instruction == 1 );
+ if (VF_TYPE_NODE_START_ENTRY == node->m_type) {
return VER_OK;
- } else if( vf_is_instruction_has_flags( instr, VF_FLAG_HANDLER ) ) {
- assert( instruction == 1 );
- // set out vector for handler node
- result = vf_get_handler_out_vector( instr, invector );
+ }
+
+ if (VF_TYPE_NODE_HANDLER == node->m_type) {
+ // set OUT vector for a handler node
+ return vf_get_handler_out_vector( invector, &node->m_outMapVector );
+ }
+
+ // get first instruction
+ vf_Code_t* instr = &ctex->m_code[graph->GetNodeFirstInstr( node_num )];
+ unsigned instruction = graph->GetNodeLastInstr( node_num )
+ - graph->GetNodeFirstInstr( node_num ) + 1;
+
+ // set out vector for each instruction
+ for( unsigned index = 0; index < instruction; index++ )
+ {
+ if( ( 0 == instr[index].m_inlen + instr[index].m_outlen )
+ && ( VF_TYPE_INSTR_NONE == instr->m_type ) )
+ {
+ continue;
+ } else {
+ result = vf_get_instruction_out_vector( node_num, &instr[index],
+ invector, buf, ctex );
+ }
if( result != VER_OK ) {
return result;
}
- } else {
- // set out vector for each instruction
- for( index = 0; index < instruction; index++ ) {
- if( instr[index].m_inlen + instr[index].m_outlen == 0
- && !vf_is_instruction_has_any_flags( instr ) )
- {
- continue;
- } else {
- result = vf_get_instruction_out_vector( node_num, &instr[index], invector,
- buf, ctex );
- }
- if( result != VER_OK ) {
- return result;
- }
#if _VERIFY_DEBUG
- if( ctex->m_dump.m_code_vector ) {
- // dump instruction OUT vector
- cerr << "-------------- instruction #" << index << " out: " << endl;
- vf_dump_vector( invector, &instr[index], &cerr );
- }
-#endif // _VERIFY_DEBUG
+ if( ctex->m_dump.m_code_vector )
+ {
+ // dump instruction OUT vector
+ cerr << "-------------- instruction #" << index << " out: " << endl;
+ vf_dump_vector( invector, &instr[index], &cerr );
}
+#endif // _VERIFY_DEBUG
}
-
return VER_OK;
} // vf_set_node_out_vector
@@ -1054,13 +1037,13 @@
*/
static Verifier_Result
vf_create_node_vectors( unsigned node_num, // graph node number
- vf_MapVector_t *incoming, // vector for instruction data flow change
+ struct vf_MapVector* incoming, // vector for instruction data flow change
vf_MapEntry_t *buf, // buf stack map vector
bool *is_out_changed, // pointer to OUT vector change flag
vf_Context_t *ctex) // verifier context
{
// copy IN vector to buf
- vf_Graph_t *graph = ctex->m_graph;
+ vf_Graph* graph = ctex->m_graph;
vf_copy_vector( graph->GetNodeInVector( node_num ), incoming );
#if _VERIFY_DEBUG
@@ -1082,12 +1065,12 @@
}
// set node OUT vector
- vf_MapVector_t *outcoming = graph->GetNodeOutVector( node_num );
+ struct vf_MapVector* outcoming = (struct vf_MapVector*) graph->GetNodeOutVector( node_num );
if( !outcoming->m_maxlocal || !outcoming->m_maxstack )
{
// create node OUT vector
graph->SetNodeOutVector( node_num, incoming, true );
- outcoming = graph->GetNodeOutVector( node_num );
+ outcoming = (struct vf_MapVector*) graph->GetNodeOutVector( node_num );
*is_out_changed = true;
} else if( !vf_compare_vectors( outcoming, incoming ) ) {
// vectors are differ
@@ -1104,19 +1087,18 @@
#endif // _VERIFY_DEBUG
// check stack modifier
- assert( (int)((graph->GetNodeOutVector( node_num )->m_deep
- - graph->GetNodeInVector( node_num )->m_deep))
+ assert( (int)((graph->GetNodeOutVector( node_num )->m_depth
+ - graph->GetNodeInVector( node_num )->m_depth))
== graph->GetNodeStackModifier( node_num ) );
return VER_OK;
} // vf_create_node_vectors
/**
- * Function checks data flow for end graph node.
+ * Checks data flow for an end graph node.
*/
static Verifier_Result
-vf_check_end_node_data_flow( unsigned node_num, // graph node number
- vf_MapVector_t *invector, // end node incoming data flow vector
+vf_check_end_node_data_flow( vf_MapVectorHandle invector, // end node incoming data flow vector
vf_Context_t *ctex) // verifier context
{
bool copy;
@@ -1129,7 +1111,7 @@
}
// check method
- if( !memcmp( method_get_name( ctex->m_method ), "", 7 )
+ if( ctex->m_is_constructor
&& ctex->m_vtype.m_class != ctex->m_vtype.m_object )
{
if( invector->m_local->m_type != SM_UNINITIALIZED
@@ -1137,19 +1119,17 @@
{
// constructor returns initialized reference of a given class
} else {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Constructor must be invoked" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Constructor must be invoked" );
return VER_ErrorDataFlow;
}
}
- // get first instruction
- vf_Code_t *instr = &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( node_num )];
+ // get the end entry
+ vf_NodeHandle node = ctex->m_graph->GetNode( ctex->m_nodeNum - 1 );
// check void return
- if( !instr->m_inlen ) {
+ if( 0 == node->m_inMapVector.m_depth ) {
if( invector->m_stack ) {
if( invector->m_stack->m_type == SM_TOP ) {
// no return value, empty stack - all is ok
@@ -1159,32 +1139,33 @@
// no stack, no return value - all is ok
return VER_OK;
}
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Wrong return type in function" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Wrong return type in function" );
return VER_ErrorDataFlow;
}
- assert( invector->m_deep - instr->m_minstack >= 0 );
+ // stack size should be greater or equal than a minimal
+ // stack size which is a number of words to return (0, 1 or 2)
+ assert( invector->m_depth - node->m_inMapVector.m_depth >= 0 );
/**
* Check end-entry IN vector
*/
- for( index = 0, vector = &instr->m_invector[0];
- index < instr->m_inlen;
- index++, vector = &instr->m_invector[index] )
+ for( index = 0;
+ index < node->m_inMapVector.m_depth;
+ index++ )
{
// get check entry
+ vector = node->m_inMapVector.m_stack + index;
assert( vector->m_is_local == 0 );
+
// check stack type
vf_MapEntry_t *entry = invector->m_stack + index;
+
// check entry types
Verifier_Result result = vf_check_entry_types( entry, vector, true, ©, ctex );
if( result != VER_OK ) {
- VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class )
- << ", method: " << method_get_name( ctex->m_method )
- << method_get_descriptor( ctex->m_method )
- << ") Wrong return type in function" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Wrong return type in function" );
return result;
}
}
@@ -1196,18 +1177,18 @@
*/
static Verifier_Result
vf_check_node_data_flow( unsigned node_num, // graph node number
- vf_MapVector_t *incoming, // incoming data flow vector
+ struct vf_MapVector* incoming, // incoming data flow vector
vf_MapEntry_t *buf, // buf stack map vector
unsigned *node_count, // last graph node in recursion
bool *need_recheck, // set to true if need to recheck previous nodes
vf_Context_t *ctex) // verifier context
{
// get graph
- vf_Graph_t *graph = ctex->m_graph;
+ vf_Graph* graph = ctex->m_graph;
// skip end-entry node
- if( vf_is_instruction_has_flags( &ctex->m_code[graph->GetNodeFirstInstr( node_num )],
- VF_FLAG_END_ENTRY) )
+ vf_NodeHandle node = graph->GetNode( node_num );
+ if( VF_TYPE_NODE_END_ENTRY == node->m_type )
{
return VER_OK;
}
@@ -1233,7 +1214,7 @@
}
// set incoming vector for following nodes
- vf_MapVector_t *in_node_vector = graph->GetNodeOutVector( node_num );
+ vf_MapVectorHandle in_node_vector = graph->GetNodeOutVector( node_num );
for( unsigned out_edge = graph->GetNodeFirstOutEdge( node_num );
out_edge;
out_edge = graph->GetEdgeNextOutEdge( out_edge ) )
@@ -1242,11 +1223,9 @@
unsigned out_node = graph->GetEdgeEndNode( out_edge );
// check vectors for end-entry
- if( vf_is_instruction_has_flags(
- &ctex->m_code[graph->GetNodeFirstInstr( out_node )],
- VF_FLAG_END_ENTRY) )
+ if( VF_TYPE_NODE_END_ENTRY == graph->GetNode( out_node )->m_type )
{
- Verifier_Result result = vf_check_end_node_data_flow( out_node,
+ Verifier_Result result = vf_check_end_node_data_flow(
in_node_vector, ctex );
if( result != VER_OK ) {
return result;
@@ -1255,13 +1234,12 @@
}
// get out node IN vector
- vf_MapVector_t *out_node_vector = graph->GetNodeInVector( out_node );
+ struct vf_MapVector* out_node_vector = (struct vf_MapVector*)
+ graph->GetNodeInVector( out_node );
if( !out_node_vector->m_maxlocal || !out_node_vector->m_maxstack )
{
// node's IN vector is invalid, set it
- if( vf_is_instruction_has_flags(
- &ctex->m_code[graph->GetNodeFirstInstr( out_node )],
- VF_FLAG_HANDLER) )
+ if( VF_TYPE_NODE_HANDLER == graph->GetNode( out_node )->m_type )
{
// it's exception node, create IN vector for it
vf_copy_vector( in_node_vector, incoming );
@@ -1279,9 +1257,7 @@
}
#endif // _VERIFY_DEBUG
// node's IN vector is valid, merge them
- bool is_handler = vf_is_instruction_has_flags(
- &ctex->m_code[graph->GetNodeFirstInstr( out_node )],
- VF_FLAG_HANDLER);
+ bool is_handler = VF_TYPE_NODE_HANDLER == graph->GetNode( out_node )->m_type;
is_changed = vf_merge_vectors( out_node_vector, in_node_vector, is_handler, ctex );
if( is_changed ) {
// node IN vector is changed, reset node OUT vector results
@@ -1316,57 +1292,69 @@
} // vf_check_node_data_flow
/**
- * Function creates initial data flow vector for method.
+ * Creates input and output stack maps.
*/
-static vf_MapVector_t*
-vf_create_method_begin_vector( vf_Context_t *ctex ) // verifier context
+static vf_MapVectorHandle
+vf_create_terminal_maps( vf_Context_t *ctex ) // verifier context
{
int index,
count,
inlen,
- begin,
+ start,
outlen;
unsigned locals,
maxstack;
- vf_MapEntry_t *invector,
- *outvector;
- vf_MapVector_t *vector;
+ vf_MapEntry_t *invector;
+ struct vf_MapVector* vector;
// get method values
locals = method_get_max_local( ctex->m_method );
maxstack = method_get_max_stack( ctex->m_method );
// alloc memory for vector structure
- vector = (vf_MapVector_t*)ctex->m_graph->AllocMemory( sizeof(vf_MapVector_t) );
+ vector = (struct vf_MapVector*) ctex->m_graph->AllocMemory( sizeof( vf_MapVector ) );
+
// alloc memory for stack vector
if( maxstack ) {
vector->m_maxstack = (unsigned short)maxstack;
vector->m_stack = (vf_MapEntry_t*)ctex->m_graph->
- AllocMemory( maxstack * sizeof(vf_MapEntry_t) );
+ AllocMemory( maxstack * sizeof( vf_MapEntry_t ) );
}
// alloc memory for locals vector
if( locals ) {
vector->m_maxlocal = (unsigned short)locals;
vector->m_local = (vf_MapEntry_t*)ctex->m_graph->
- AllocMemory( locals * sizeof(vf_MapEntry_t) );
+ AllocMemory( locals * sizeof( vf_MapEntry_t ) );
}
// get method signature
const char *descr = method_get_descriptor( ctex->m_method );
- // get method vectors
+ // get the end node IN vector
+ struct vf_MapVector* p_outvector = (struct vf_MapVector*)
+ ctex->m_graph->GetNodeInVector( ctex->m_nodeNum - 1 );
+
+ // get vectors sizes
vf_parse_description( descr, &inlen, &outlen );
- vf_set_description_vector( descr, inlen, 0, outlen, &invector, &outvector, ctex );
+ p_outvector->m_depth = outlen;
+ // get method vectors
+ vf_set_description_vector( descr, inlen, 0, outlen, &invector,
+ &p_outvector->m_stack, ctex );
+
+ // cache in the context if the method is a constructor
+ ctex->m_is_constructor =
+ memcmp( method_get_name( ctex->m_method ), "", 7 ) == 0;
+
// set "this" reference in local variable
if( method_is_static( ctex->m_method ) ) {
- begin = 0;
+ start = 0;
} else {
- begin = 1;
+ start = 1;
// fill "this" entry
const char *name = class_get_name( ctex->m_class );
vf_ValidType_t *type = vf_create_class_valid_type( name, ctex );
- if( !memcmp( method_get_name( ctex->m_method ), "", 7 ) ) {
+ if( ctex->m_is_constructor ) {
vector->m_local->m_type = SM_UNINITIALIZED;
} else {
vector->m_local->m_type = SM_REF;
@@ -1377,7 +1365,7 @@
}
// set start vector
- for( index = begin, count = 0; count < inlen; index++, count++ ) {
+ for( index = start, count = 0; count < inlen; index++, count++ ) {
vector->m_local[index].m_type = invector[count].m_type;
vector->m_local[index].m_vtype = invector[count].m_vtype;
vector->m_local[index].m_is_local = 1;
@@ -1385,7 +1373,6 @@
}
vector->m_number = (unsigned short)index;
- // FIXME - need set end entry vector
return vector;
} // vf_create_method_begin_vector
@@ -1396,15 +1383,15 @@
vf_enumerate_graph_node( vf_Context_t *ctex )
{
// clear graph node marks
- vf_Graph_t *graph = ctex->m_graph;
+ vf_Graph* graph = ctex->m_graph;
graph->CleanNodesMark();
// set first enumeration node
- graph->SetStartCountNode(0);
+ graph->SetStartCountNode( 0 );
graph->SetNodeMark( 0, VERIFY_START_MARK );
// enumerate graph nodes
- for( unsigned index = 0; index < graph->GetNodeNumber(); index++ ) {
+ for( unsigned index = 0; index < graph->GetNodeCount(); index++ ) {
// get node by count element
unsigned node_num = graph->GetCountElementNode( index );
if( node_num == ~0U ) {
@@ -1447,26 +1434,26 @@
// enumerate graph
vf_enumerate_graph_node( ctex );
- // get begin vector
- vf_MapVector_t *begin = vf_create_method_begin_vector( ctex );
+ // get a start vector
+ struct vf_MapVector* start = (struct vf_MapVector*) vf_create_terminal_maps( ctex );
// create buf stack map vector (max 4 entry)
vf_MapEntry_t *buf = (vf_MapEntry_t*)vf_alloc_pool_memory( ctex->m_pool,
- sizeof(vf_MapEntry_t) * method_get_max_stack( ctex->m_method ) );
+ sizeof( vf_MapEntry_t ) * method_get_max_stack( ctex->m_method ) );
// clean graph mark
- vf_Graph_t *graph = ctex->m_graph;
+ vf_Graph* graph = ctex->m_graph;
graph->CleanNodesMark();
// set start node IN vector
- graph->SetNodeInVector( 0, begin, true );
+ graph->SetNodeInVector( 0, start, true );
// check graph data flow
bool need_recheck = false;
unsigned count = 0;
do {
unsigned node = graph->GetCountElementNode( count );
- Verifier_Result result = vf_check_node_data_flow( node, begin, buf, &count, &need_recheck, ctex );
+ Verifier_Result result = vf_check_node_data_flow( node, start, buf, &count, &need_recheck, ctex );
if( result != VER_OK ) {
return result;
}
@@ -1480,5 +1467,3 @@
return VER_OK;
} // vf_check_graph_data_flow
-
-} // namespace Verifier