Index: build/custom/msvc_2003/vmcore/vmcore.vcproj =================================================================== --- build/custom/msvc_2003/vmcore/vmcore.vcproj (revision 507588) +++ build/custom/msvc_2003/vmcore/vmcore.vcproj (working copy) @@ -1060,9 +1060,18 @@ RelativePath="..\..\..\..\vm\vmcore\src\verifier\ver_dataflow.cpp"> + + + + + + 0); - vf_NodeContainer_t* nodes; - nodes = (vf_NodeContainer_t*)AllocMemory( sizeof(vf_NodeContainer_t) - + (number - 1) * sizeof(vf_Node_t) ); + assert( number > 0 ); + struct vf_NodeContainer* nodes = + (struct vf_NodeContainer*) AllocMemory( sizeof( struct vf_NodeContainer ) + + (number - 1) * sizeof( vf_Node ) ); nodes->m_max = number; + nodes->m_next = m_nodes; + nodes->m_max = number; if( m_nodes == NULL ) { m_nodes = nodes; } else { - vf_NodeContainer_t *index = m_nodes->m_next; + struct vf_NodeContainer* index = m_nodes->m_next; while( index->m_next ) { index = index->m_next; } index->m_next = nodes; } - return; } // vf_Graph::CreateNodes /** * Gets graph node. */ -vf_Node_t* +vf_NodeHandle vf_Graph::GetNode( unsigned node_num ) // graph node number { // get node assert( m_nodes ); assert( node_num < m_nodenum ); unsigned count = node_num; - vf_NodeContainer_t* nodes = m_nodes; + struct vf_NodeContainer* nodes = m_nodes; while( count > nodes->m_max ) { count -= nodes->m_max; nodes = nodes->m_next; - assert(nodes); + assert( nodes ); } return &nodes->m_node[count]; } // vf_Graph::GetNode -/** - * Creates a new node and sets data to it. - */ -void -vf_Graph::NewNode( unsigned begin, // begin code instruction of node - unsigned end, // end code instruction of node - unsigned len) // bytecode length of node +vf_NodeHandle +vf_Graph::NewNode( vf_NodeType type ) { // get node assert( m_nodes ); unsigned count = m_nodenum; - vf_NodeContainer_t* nodes = m_nodes; + struct vf_NodeContainer* nodes = m_nodes; while( count > nodes->m_max ) { count -= nodes->m_max; nodes = nodes->m_next; - assert(nodes); + assert( nodes ); } - // set node - vf_Node_t* node = &nodes->m_node[count]; - node->m_start = begin; - node->m_end = end; - node->m_len = len; - // increment nodes count m_nodenum++; nodes->m_used++; assert( nodes->m_used <= nodes->m_max ); - return; + // set node + struct vf_Node* node = &nodes->m_node[count]; + node->m_type = type; + return node; } // vf_Graph::NewNode /** - * Function set data to graph node. + * Gets a bytecode length for this code range node. */ -void -vf_Graph::SetNode( unsigned num, // graph node number - unsigned begin, // begin code instruction of node - unsigned end, // end code instruction of node - unsigned len) // bytecode length of node +unsigned vf_Graph::GetNodeBytecodeLen( vf_ContextHandle context, + vf_NodeHandle node) { - vf_Node_t* node = GetNode( num ); - node->m_start = begin; - node->m_end = end; - node->m_len = len; - return; -} // vf_Graph::SetNode + assert( VF_TYPE_NODE_CODE_RANGE == node->m_type ); + unsigned char* code_end = (node->m_end + 1 == context->m_codeNum) ? + method_get_bytecode( context->m_method ) + + method_get_code_length( context->m_method ) : + context->m_code[node->m_end + 1].m_addr; + unsigned len = code_end - context->m_code[node->m_start].m_addr; + return len; +} // vf_Graph::GetNodeBytecodeLen + /** * Gets graph edge. */ -vf_Edge_t* +vf_EdgeHandle vf_Graph::GetEdge( unsigned edge_num ) // graph edge number { // get edge @@ -202,11 +164,11 @@ assert( edge_num < m_edgenum ); assert( edge_num ); // zero edge is reserved unsigned count = edge_num; - vf_EdgeContainer_t* edges = m_edges; + struct vf_EdgeContainer* edges = m_edges; while( count > edges->m_max ) { count -= edges->m_max; edges = edges->m_next; - assert(edges); + assert( edges ); } return &edges->m_edge[count]; } // vf_Graph::GetEdge @@ -225,17 +187,17 @@ // get edge assert( m_edges ); unsigned count = m_edgenum; - vf_EdgeContainer_t* edges = m_edges; + struct vf_EdgeContainer* edges = m_edges; while( count > edges->m_max ) { count -= edges->m_max; edges = edges->m_next; - assert(edges); + assert( edges ); } // get a new edge and edge's nodes - vf_Edge_t *edge = &edges->m_edge[count]; - vf_Node_t *node_start = GetNode( start ); - vf_Node_t *node_end = GetNode( end ); + struct vf_Edge* edge = &edges->m_edge[count]; + struct vf_Node* node_start = (struct vf_Node*) GetNode( start ); + struct vf_Node* node_end = (struct vf_Node*) GetNode( end ); // set a new edge edge->m_start = start; @@ -256,107 +218,6 @@ } // vf_Graph::NewEdge /** - * Function receive first code instruction of graph node. - */ -unsigned -vf_Graph::GetNodeFirstInstr( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_start; -} // vf_Graph::GetNodeFirstInstr - -/** - * Function receive last code instruction of graph node. - */ -unsigned -vf_Graph::GetNodeLastInstr( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_end; -} // vf_Graph::GetNodeLastInstr - -/** - * Function receive bytecode length of graph node instructions. - */ -inline unsigned -vf_Graph::GetNodeByteCodeLen( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_len; -} // vf_Graph::GetNodeByteCodeLen - -/** - * Function receive stack modifier of graph. - */ -int -vf_Graph::GetNodeStackModifier( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_stack; -} // vf_Graph::GetNodeStackModifier - -/** - * Function sets graph node stack modifier. - */ -inline void -vf_Graph::SetNodeStackModifier( unsigned num, // graph node number - int stack) // stack deep modifier -{ - // check node number is in range. - assert( num < m_nodenum ); - GetNode( num )->m_stack = stack; - return; -} // vf_Graph::SetNodeStackModifier - -/** - * Function returns number of graph nodes. - */ -unsigned -vf_Graph::GetNodeNumber() -{ - return m_nodenum; -} // vf_Graph::GetNodeNumber - -/** - * Function marks graph node. - */ -void -vf_Graph::SetNodeMark( unsigned num, // graph node number - int mark) // node mark value -{ - // check node number is in range. - assert( num < m_nodenum ); - GetNode( num )->m_mark = mark; - return; -} // vf_Graph::SetNodeMark - -/** - * Function returns graph node mark. - */ -int -vf_Graph::GetNodeMark( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_mark; -} // vf_Graph::GetNodeMark - -/** - * Function checks if node is marked. - */ -inline bool -vf_Graph::IsNodeMarked( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return (GetNode( num )->m_mark != 0); -} // vf_Graph::IsNodeMarked - -/** * Function removes node mark. */ void @@ -364,7 +225,7 @@ { // clean node's mark assert( m_nodes ); - vf_NodeContainer_t* nodes = m_nodes; + struct vf_NodeContainer* nodes = m_nodes; while( nodes != NULL ) { for( unsigned index = 0; index < nodes->m_used; index++ ) { nodes->m_node[index].m_mark = 0; @@ -375,110 +236,29 @@ } // vf_Graph::CleanNodesMark /** - * Sets local variable reference initialization flag for node. + * Creates a data flow vector from the given example. */ void -vf_Graph::SetNodeInitFlag( unsigned num, // graph node number - bool flag) // node flag +vf_Graph::SetVector( vf_MapVectorHandle vector_handle, // vector to set + vf_MapVectorHandle example, // current data flow vector + bool need_copy) // copy flag { - // check node number is in range. - assert( num < m_nodenum ); - GetNode( num )->m_initialized = flag; - return; -} // vf_Graph::SetNodeInitFlag - -/** - * Gets local variable reference initialization flag for node. - */ -bool -vf_Graph::GetNodeInitFlag( unsigned num ) // graph node number -{ - // check node number is in range. - assert( num < m_nodenum ); - return GetNode( num )->m_initialized; -} // vf_Graph::GetNodeInitFlag - -/** - * Function receives IN data flow vector of node. - */ -vf_MapVector_t * -vf_Graph::GetNodeInVector( unsigned node_num ) // graph node number -{ - assert( node_num < m_nodenum ); - return &(GetNode( node_num )->m_invector); -} // vf_Graph::GetNodeInVector - -/** - * Function receives OUT data flow vector of node. - */ -vf_MapVector_t * -vf_Graph::GetNodeOutVector( unsigned node_num ) // graph node number -{ - assert( node_num <= m_nodenum ); - return &(GetNode( node_num )->m_outvector); -} // vf_Graph::GetNodeOutVector - - -/** - * Function creates IN data flow vector of node. - */ -void -vf_Graph::SetNodeInVector( unsigned node_num, // graph node number - vf_MapVector_t *example, // current data flow vector - bool need_copy) // copy flag -{ assert( example ); - assert( node_num < m_nodenum ); - vf_MapVector_t *vector = GetNodeInVector( node_num ); - // create and set local vector - if( example->m_maxlocal ) { - vector->m_local = (vf_MapEntry_t*)AllocMemory(example->m_maxlocal - * sizeof(vf_MapEntry_t) ); - vector->m_number = example->m_number; - vector->m_maxlocal = example->m_maxlocal; - } - // create and set stack vector - if( example->m_maxstack ) { - vector->m_stack = (vf_MapEntry_t*)AllocMemory( example->m_maxstack - * sizeof(vf_MapEntry_t) ); - vector->m_deep = example->m_deep; - vector->m_maxstack = example->m_maxstack; - } - if( need_copy ) { - unsigned index; - for( index = 0; index < example->m_number; index++ ) { - vector->m_local[index] = example->m_local[index]; - } - for( index = 0; index < example->m_deep; index++ ) { - vector->m_stack[index] = example->m_stack[index]; - } - } - return; -} // vf_Graph::SetNodeInVector + struct vf_MapVector* vector = (struct vf_MapVector*) vector_handle; -/** - * Function creates OUT data flow vector of node. - */ -void -vf_Graph::SetNodeOutVector( unsigned node_num, // graph node number - vf_MapVector_t *example, // current data flow vector - bool need_copy) // copy flag -{ - assert( example ); - assert( node_num < m_nodenum ); - vf_MapVector_t *vector = GetNodeOutVector( node_num ); // create and set local vector if( example->m_maxlocal ) { - vector->m_local = (vf_MapEntry_t*)AllocMemory( example->m_maxlocal - * sizeof(vf_MapEntry_t) ); + vector->m_local = (vf_MapEntry_t*) AllocMemory( example->m_maxlocal + * sizeof( vf_MapEntry_t ) ); + assert( vector->m_local ); vector->m_number = example->m_number; vector->m_maxlocal = example->m_maxlocal; } // create and set stack vector if( example->m_maxstack ) { - vector->m_stack = (vf_MapEntry_t*)AllocMemory( example->m_maxstack - * sizeof(vf_MapEntry_t) ); - vector->m_deep = example->m_deep; + vector->m_stack = (vf_MapEntry_t*) AllocMemory( example->m_maxstack + * sizeof( vf_MapEntry_t ) ); + vector->m_depth = example->m_depth; vector->m_maxstack = example->m_maxstack; } if( need_copy ) { @@ -486,12 +266,11 @@ for( index = 0; index < example->m_number; index++ ) { vector->m_local[index] = example->m_local[index]; } - for( index = 0; index < example->m_deep; index++ ) { + for( index = 0; index < example->m_depth; index++ ) { vector->m_stack[index] = example->m_stack[index]; } } - return; -} // vf_Graph::SetNodeOutVector +} // vf_Graph::SetVector /** * Function creates graph edges. @@ -499,15 +278,15 @@ void vf_Graph::CreateEdges( unsigned number ) // number of edges { - assert(number > 0); - vf_EdgeContainer_t* edges; - edges = (vf_EdgeContainer_t*)AllocMemory( sizeof(vf_EdgeContainer_t) - + number * sizeof(vf_Edge_t) ); + assert( number > 0 ); + struct vf_EdgeContainer* edges; + edges = (struct vf_EdgeContainer*) AllocMemory( sizeof( vf_EdgeContainer ) + + number * sizeof( vf_Edge ) ); edges->m_max = number + 1; // zero edge is reserved if( m_edges == NULL ) { m_edges = edges; } else { - vf_EdgeContainer_t *index = m_edges->m_next; + struct vf_EdgeContainer* index = m_edges->m_next; while( index->m_next ) { index = index->m_next; } @@ -601,17 +380,6 @@ } // vf_Graph::GetNodeFirstOutEdge /** - * Function allocates memory in graph memory pool. - */ -void * -vf_Graph::AllocMemory( unsigned size ) // memory block size -{ - assert(size); - void *result = vf_alloc_pool_memory( m_pool, size ); - return result; -} // vf_Graph::AllocMemory - -/** * Function cleans graph node enumeration, creates new graph * enumeration structure and sets first enumeration node. */ @@ -624,11 +392,11 @@ // create memory if( m_enummax < m_nodenum ) { - m_enum = (unsigned*)AllocMemory( sizeof(unsigned) * m_nodenum ); + m_enum = (unsigned*)AllocMemory( sizeof( unsigned ) * m_nodenum ); } // clean node enumeration - vf_NodeContainer_t* nodes = m_nodes; + struct vf_NodeContainer* nodes = m_nodes; unsigned count = 0; while( nodes != NULL ) { for( unsigned index = 0; index < nodes->m_used; index++, count++ ) { @@ -644,7 +412,8 @@ m_enumcount = 1; // set node enumeration number - GetNode( node_num )->m_nodecount = 0; + struct vf_Node* node = (struct vf_Node*) GetNode( node_num ); + node->m_nodecount = 0; return; } // vf_Graph::SetStartCountNode @@ -671,7 +440,8 @@ m_enum[m_enumcount] = node_num; // set node enumeration number and increase number of enumerated nodes - GetNode( node_num )->m_nodecount = m_enumcount++; + struct vf_Node* node = (struct vf_Node*) GetNode( node_num ); + node->m_nodecount = m_enumcount++; return; } // vf_Graph::SetNextCountNode @@ -722,7 +492,7 @@ << method_get_name( ctex->m_method ) << method_get_descriptor( ctex->m_method ) << endl ); VERIFY_DEBUG( "-- start --" ); - for( unsigned index = 0; index < GetNodeNumber(); index++ ) { + for( unsigned index = 0; index < GetNodeCount(); index++ ) { DumpNode( index, ctex ); } #endif // _VERIFY_DEBUG @@ -744,23 +514,21 @@ index < GetNode( num )->m_innum; index++ ) { - vf_Edge_t *edge = GetEdge( edge_num ); + vf_EdgeHandle edge = GetEdge( edge_num ); VERIFY_DEBUG( " [" << edge->m_start << "] -->" ); edge_num = edge->m_innext; } + vf_NodeHandle node = GetNode( num ); // print node - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_START_ENTRY ) ) + if( VF_TYPE_NODE_START_ENTRY == node->m_type) { // start node - VERIFY_DEBUG( "node[" << num << "]: " << GetNode( num )->m_start << "[-] start" ); - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_END_ENTRY ) ) + VERIFY_DEBUG( "node[" << num << "]: " << node->m_start << "[-] start" ); + } else if( VF_TYPE_NODE_END_ENTRY == node->m_type) { // end node - VERIFY_DEBUG( "node[" << num << "]: " << GetNode( num )->m_start << "[-] end" ); + VERIFY_DEBUG( "node[" << num << "]: " << node->m_start << "[-] end" ); VERIFY_DEBUG( "-- end --" ); - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_HANDLER ) ) + } else if( VF_TYPE_NODE_HANDLER == node->m_type ) { // handler node VERIFY_DEBUG( "node[" << num << "]: " << num << "handler entry" ); } else { // another nodes @@ -772,7 +540,7 @@ index < GetNode( num )->m_outnum; index++ ) { - vf_Edge_t *edge = GetEdge( edge_num ); + vf_EdgeHandle edge = GetEdge( edge_num ); VERIFY_DEBUG( " --> [" << edge->m_end << "]" ); edge_num = edge->m_outnext; } @@ -822,13 +590,13 @@ const char *method_desc = method_get_descriptor( ctex->m_method ); // create file name - unsigned len = strlen(class_name) + strlen(method_name) - + strlen(method_desc) + 6; - char *fname = (char*)STD_ALLOCA(len); + unsigned len = strlen( class_name ) + strlen( method_name ) + + strlen( method_desc ) + 6; + char *fname = (char*)STD_ALLOCA( len ); sprintf( fname, "%s_%s%s.dot", class_name, method_name, method_desc ); char* pointer = fname; while( pointer != NULL ) { - switch(*pointer) + switch( *pointer ) { case '/': case '*': @@ -903,22 +671,20 @@ vf_Context_t *ctex) // verifier contex { #if _VERIFY_DEBUG + vf_NodeHandle node = GetNode( num ); + // print node to dot file - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_START_ENTRY ) ) + if( VF_TYPE_NODE_START_ENTRY == node->m_type ) { // start node out << "node" << num << " [label=\"START\", color=limegreen]" << endl; - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_END_ENTRY ) ) + } else if( VF_TYPE_NODE_END_ENTRY == node->m_type ) { // end node out << "node" << num << " [label=\"END\", color=orangered]" << endl; - } else if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_start], - VF_FLAG_HANDLER ) ) + } else if( VF_TYPE_NODE_HANDLER == node->m_type ) { // handler node out << "node" << num << " [label=\"Handler #" - << num << "\\n---------\\n" << "Type: #" << GetNode( num )->m_len - << "\", shape=ellipse, color=aquamarine]" << endl; - } else { // another nodes + << num << "\", shape=ellipse, color=aquamarine]" << endl; + } else { // other nodes out << "node" << num << " [label=\""; DumpDotNodeInternal( num, "\\n---------\\n", "\\l", out, ctex ); @@ -928,20 +694,19 @@ // print node outcoming edges to dot file unsigned index; unsigned edge_num; - for( index = 0, edge_num = GetNode( num )->m_outedge; - index < GetNode( num )->m_outnum; + for( index = 0, edge_num = node->m_outedge; + index < node->m_outnum; index++ ) { - vf_Edge_t *edge = GetEdge( edge_num ); + vf_EdgeHandle edge = GetEdge( edge_num ); out << "node" << num << " -> " << "node" << edge->m_end; - if( vf_is_instruction_has_flags( &ctex->m_code[GetNode( edge->m_end )->m_start], - VF_FLAG_HANDLER ) ) + if( VF_TYPE_NODE_HANDLER == GetNode( edge->m_end )->m_type ) { out << "[color=red]" << endl; - } else if( num + 1 != edge->m_end // it's a subroutine call branch - && vf_is_instruction_has_flags( &ctex->m_code[GetNode( num )->m_end], - VF_FLAG_SUBROUTINE ) ) + } else if( ( VF_TYPE_NODE_CODE_RANGE == node->m_type ) + && ( VF_TYPE_INSTR_SUBROUTINE == + vf_get_last_instruction_type( ctex, edge->m_start ) ) ) { out << "[color=blue]" << endl; } @@ -997,134 +762,169 @@ ********************** Graph Creation ********************** ************************************************************/ + /** - * Function creates bytecode control flow graph. + * Creates bytecode control flow graph. */ Verifier_Result -vf_create_graph( vf_Context_t *ctex ) // verifier context +vf_create_graph( vf_Context_t* ctex ) { - /** - * Create graph - */ - ctex->m_graph = new vf_Graph( ctex->m_nodeNum, ctex->m_edgeNum, ctex->m_pool ); + ctex->m_graph = new vf_Graph( ctex->m_nodeNum, + ctex->m_edgeNum, + ctex->m_pool ); // use numbers pre-calculated at vf_parse_bytecode + vf_Graph* graph = ctex->m_graph; - /** - * Create decoding array: code to node - */ + // the array contains a corresponding node for each instruction unsigned* code2node = (unsigned*)vf_alloc_pool_memory( ctex->m_pool, - ctex->m_codeNum * sizeof(unsigned) ); - /** - * Create start-entry and handler nodes - */ - unsigned index; - unsigned short handlcount = method_get_exc_handler_number( ctex->m_method ); - ctex->m_graph->NewNode( 0, 0, 0 ); - for( index = 1; index < (unsigned)handlcount + 1; index++ ) { - ctex->m_graph->NewNode( index, index, 0 ); - ctex->m_graph->SetNodeStackModifier( index, 1 ); + ctex->m_codeNum * sizeof( unsigned ) ); + + graph->NewNode( VF_TYPE_NODE_START_ENTRY ); + + // create handler nodes + unsigned node_index; + unsigned short handler_count = method_get_exc_handler_number( ctex->m_method ); + for (node_index = 1; node_index <= (unsigned) handler_count; node_index++) + { + graph->NewNode( VF_TYPE_NODE_HANDLER ); + graph->SetNodeStackModifier( node_index, 1 ); } /** - * Create nodes - * Node count begins from the first basic block after the last handler node. - * Skip the first instruction, because we create the first node - * at his end instruction. + * Create code range nodes. New node correspond to the subsequent + * basic blocks of instructions. + * Note: code range nodes follow after the last handler node. */ - unsigned len; - unsigned last; - unsigned nodeCount; - for( last = nodeCount = 1 + handlcount, index = last + 1; - index < ctex->m_codeNum - 1; - index++ ) + // adding a basic block which starts + for( unsigned bb_start = 0; + bb_start < ctex->m_codeNum; + node_index++ ) { - if( vf_is_begin_basic_block( &ctex->m_code[index] ) ) { - // set graph nodes - len = ctex->m_code[index].m_addr - ctex->m_code[last].m_addr; - ctex->m_graph->NewNode( last, index - 1, len ); - ctex->m_graph->SetNodeStackModifier( nodeCount, - vf_get_node_stack_deep( &ctex->m_code[last], &ctex->m_code[index - 1] ) ); - code2node[last] = nodeCount++; - last = index; + // find a basic block end + unsigned next_bb_start = bb_start + 1; + while ((next_bb_start < ctex->m_codeNum) + && (!ctex->m_code[next_bb_start].m_basic_block_start)) + { + next_bb_start++; } + + graph->NewNode( bb_start, next_bb_start - 1, + vf_get_node_stack_depth( &ctex->m_code[bb_start], + &ctex->m_code[next_bb_start - 1] ) ); + code2node[bb_start] = node_index; + bb_start = next_bb_start; } - // set last node with code segment - unsigned char* code_end = method_get_bytecode( ctex->m_method ) - + method_get_code_length( ctex->m_method ); - len = code_end - ctex->m_code[last].m_addr; - ctex->m_graph->NewNode( last, index - 1, len ); - ctex->m_graph->SetNodeStackModifier( nodeCount, - vf_get_node_stack_deep( &ctex->m_code[last], &ctex->m_code[index - 1] ) ); - code2node[last] = nodeCount++; + // set exit node - ctex->m_graph->NewNode( ctex->m_codeNum - 1, 0, 0 ); - code2node[ctex->m_codeNum - 1] = nodeCount++; - assert( ctex->m_nodeNum == nodeCount ); + graph->NewNode( VF_TYPE_NODE_END_ENTRY ); + unsigned node_num = node_index + 1; + assert( ctex->m_nodeNum == node_num ); /** * Create edges - * First edge from start-entry node to first code node */ - ctex->m_graph->NewEdge( 0, handlcount + 1 ); - for( index = 1; index < nodeCount - 1; index++ ) { - vf_Code_t* codeInstr = &ctex->m_code[ ctex->m_graph->GetNodeLastInstr( index ) ]; - // check correct branching - if( codeInstr->m_addr && *codeInstr->m_addr == OPCODE_WIDE ) { - // node ends in wide instruction - 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" ); - return VER_ErrorBranch; - } + + // from start-entry node to the first code node + node_index = handler_count + 1; + graph->NewEdge( 0, node_index ); + + // create code range edges + for (; node_index < node_num - 1; node_index++) + { + vf_Code_t* code = &ctex->m_code[ + graph->GetNodeLastInstr( node_index )]; + // set control flow edges - if( codeInstr->m_offcount ) { - for( unsigned count = 0; count < codeInstr->m_offcount; count++ ) { -#if _VERIFY_DEBUG - if( code2node[ codeInstr->m_off[count] ] == 0 ) { - VERIFY_DEBUG( "vf_create_graph: error graph construction" ); - vf_error(); + if( code->m_offcount ) { + for( unsigned count = 0; + count < code->m_offcount; count++ ) { + int offset = vf_get_code_branch( code, count ); + unsigned node = code2node[ + ctex->m_bc[offset].m_instr - 1]; + assert( node ); + + graph->NewEdge( node_index, node ); + if( node < node_index ) { + // node has a backward branch, thus any + // object on the stack should be initialized + graph->SetNodeInitFlag( node, true ); } -#endif // _VERIFY_DEBUG - unsigned node = code2node[ codeInstr->m_off[count] ]; - ctex->m_graph->NewEdge( index, node ); - if( node < index ) { - // node has backward branch, - // thus the reference in local variables have to be initialized - ctex->m_graph->SetNodeInitFlag( node, true ); - } } + } else if (code->m_type) { + // FIXME compatibility issue - no need to + // have these branches + graph->NewEdge( node_index, node_num - 1 ); + } else if (node_index + 1 < node_num) { + graph->NewEdge( node_index, node_index + 1 ); } else { - if( index + 1 == nodeCount - 1 ) { - // set edge to end-entry node without return - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Falling off the end of the code" ); - return VER_ErrorBranch; - } - ctex->m_graph->NewEdge( index, index + 1 ); + VERIFY_REPORT_METHOD( ctex, + "Falling off the end of the code" ); + return VER_ErrorBranch; } - if( codeInstr->m_handler != NULL ) { - // node is protected by exception handler, - // thus the reference in local variables have to be initialized - ctex->m_graph->SetNodeInitFlag( index, true ); - // set exception handler edges - for( unsigned count = 0; count < handlcount; count++ ) { - if( codeInstr->m_handler[count] ) { - // set edge to exception handler entry - ctex->m_graph->NewEdge( index, count + 1 ); + } + + unsigned char* start_bc = method_get_bytecode( ctex->m_method ); + unsigned bytecode_len = method_get_code_length( ctex->m_method ); + for (unsigned short 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 ); + + vf_ValidType_t *type = NULL; + if (handler_cp_index) { + const char* name = vf_get_cp_class_name( ctex->m_class, + handler_cp_index ); + assert( name ); + + 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); } } + + // create out vector for a handler + struct vf_MapVector* p_outvector = (struct vf_MapVector*) + graph->GetNodeOutVector( handler_index + 1 ); + + p_outvector->m_stack = (vf_MapEntry_t*) graph->AllocMemory( + sizeof(vf_MapEntry_t)); + p_outvector->m_depth = 1; + vf_set_vector_stack_entry_ref( p_outvector->m_stack, 0, type ); + + // outcoming handler edge + graph->NewEdge( handler_index + 1, + code2node[ctex->m_bc[handler_pc].m_instr - 1] ); + + // node range start + node_index = code2node[ctex->m_bc[start_pc].m_instr - 1]; + + unsigned last_node = (end_pc == bytecode_len) ? + node_num - 1 : + code2node[ctex->m_bc[end_pc].m_instr - 1]; + + for (; node_index < last_node; node_index++) { + // node is protected by exception handler, thus the + // reference in local variables have to be initialized + graph->SetNodeInitFlag( node_index, true ); + graph->NewEdge( node_index, handler_index + 1 ); } } + // one edge is reserved + assert( graph->GetEdgeCount() == ctex->m_edgeNum ); #if _VERIFY_DEBUG if( ctex->m_dump.m_graph ) { - ctex->m_graph->DumpGraph( ctex ); + graph->DumpGraph( ctex ); } if( ctex->m_dump.m_dot_graph ) { - ctex->m_graph->DumpDotGraph( ctex ); + graph->DumpDotGraph( ctex ); } #endif // _VERIFY_DEBUG @@ -1136,44 +936,32 @@ ************************************************************/ /** - * Function evaluates stack deep of graph node. + * Function evaluates stack depth of graph code range node. */ static int -vf_get_node_stack_deep( vf_Code_t *begin, // begin code instruction of node - vf_Code_t *end) // end code instruction of node +vf_get_node_stack_depth( vf_Code_t *start, // beginning instruction + vf_Code_t *end) // ending instruction { int result = 0; vf_Code_t *pointer; - /** - * For start, end and handler nodes - */ - if( vf_is_instruction_has_flags( begin, - VF_FLAG_HANDLER | VF_FLAG_START_ENTRY | VF_FLAG_END_ENTRY ) ) - { - return 0; - } -#if _VERIFY_DEBUG - if( begin > end ) { - VERIFY_DEBUG( "vf_get_node_stack_deep: stack evaluation error" ); - vf_error(); - } -#endif // _VERIFY_DEBUG + assert( start <= end ); /** - * Evaluate stack deep + * Evaluate stack depth */ - for( pointer = begin; pointer <= end; pointer++ ) { + for( pointer = start; pointer <= end; pointer++ ) { result += pointer->m_stack; } return result; -} // vf_get_node_stack_deep +} // vf_get_node_stack_depth + /** * Function provides some checks of control flow and data flow structures of graph. */ Verifier_Result -vf_graph_checks( vf_Context_t *ctex ) // verifier context +vf_check_graph( vf_Context_t *ctex ) // verifier context { unsigned count, inedge, @@ -1182,26 +970,26 @@ /** * Gem method max stack */ - vf_Graph_t *vGraph = ctex->m_graph; + vf_Graph* vGraph = ctex->m_graph; unsigned maxstack = method_get_max_stack( ctex->m_method ); unsigned short handlcount = method_get_exc_handler_number( ctex->m_method ); vf_Code_t *code = ctex->m_code; /** - * Check stack deep correspondence + * Check stack depth correspondence */ unsigned index = 1; - Verifier_Result result = vf_check_stack_deep( 0, VERIFY_START_MARK, + Verifier_Result result = vf_check_stack_depth( 0, VERIFY_START_MARK, maxstack + VERIFY_START_MARK, &index, ctex ); if( result != VER_OK ) { goto labelEnd_bypassGraphStructure; } - assert( index <= vGraph->GetNodeNumber() ); + assert( index <= vGraph->GetNodeCount() ); /** * Determine dead code nodes */ - index = vGraph->GetNodeNumber() - index; // number of dead code nodes + index = vGraph->GetNodeCount() - index; // number of dead code nodes /** * Override all dead nodes @@ -1209,12 +997,14 @@ if( index ) { /** - * Identify dead code nodes and fill by nop instruction + * Identify dead code nodes and fill by nop instruction. */ - for( index = handlcount + 1; index < vGraph->GetNodeNumber() - 1; index++ ) { + for( index = handlcount + 1; index < vGraph->GetNodeCount() - 1; index++ ) { if( !vGraph->IsNodeMarked( index ) ) { unsigned char *instr = code[ vGraph->GetNodeFirstInstr( index ) ].m_addr; - for( count = 0; count < vGraph->GetNodeByteCodeLen( index ); count++ ) { + unsigned len = vGraph->GetNodeBytecodeLen( ctex, vGraph->GetNode( index ) ); + for( count = 0; count < len; count++ ) + { instr[count] = OPCODE_NOP; } vGraph->SetNodeStackModifier( index, 0 ); @@ -1232,10 +1022,11 @@ #endif // _VERIFY_DEBUG /** - * Check code execution drops - * Override all incoming edges to the end-entry node + * Check that execution flow terminates with + * return or athrow bytecodes. + * Override all incoming edges to the end-entry node. */ - for( inedge = vGraph->GetNodeFirstInEdge( vGraph->GetNodeNumber() - 1 ); + for( inedge = vGraph->GetNodeFirstInEdge( vGraph->GetNodeCount() - 1 ); inedge; inedge = vGraph->GetEdgeNextInEdge( inedge ) ) { @@ -1249,10 +1040,8 @@ || !((*instr) >= OPCODE_IRETURN && (*instr) <= OPCODE_RETURN || (*instr) == OPCODE_ATHROW) ) { // illegal instruction - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Falling off the end of the code" ); + VERIFY_REPORT_METHOD( ctex, + "Falling off the end of the code" ); result = VER_ErrorCodeEnd; goto labelEnd_bypassGraphStructure; } @@ -1266,121 +1055,123 @@ labelEnd_bypassGraphStructure: return result; -} // vf_graph_checks +} // vf_check_graph /** + * Frees memory allocated for graph, if any. + */ +void +vf_free_graph( vf_ContextHandle context ) // verifier context +{ + if( context->m_graph ) { + delete context->m_graph; + } +} // vf_free_graph + +/** * Function checks stack overflow of graph node instruction. */ static inline Verifier_Result -vf_check_node_stack_deep( unsigned nodenum, // graph node number - int deep, // initial stack deep +vf_check_node_stack_depth( unsigned nodenum, // graph node number + int depth, // initial stack depth unsigned max_stack, // maximal stack vf_Context_t *ctex) // verifier context { - /** - * Get begin and end code instruction of graph node - */ - unsigned begin = ctex->m_graph->GetNodeFirstInstr( nodenum ); - unsigned end = ctex->m_graph->GetNodeLastInstr( nodenum ); - assert( begin <= end ); - + vf_NodeHandle node = ctex->m_graph->GetNode( nodenum ); /** * For start, end and handler nodes */ - if( vf_is_instruction_has_flags( &ctex->m_code[begin], - VF_FLAG_HANDLER | VF_FLAG_START_ENTRY | VF_FLAG_END_ENTRY ) ) - { + if( node->m_type != VF_TYPE_NODE_CODE_RANGE ) { return VER_OK; } /** - * Evaluate stack deep + * Get begin and end code instruction of graph node */ + unsigned start = node->m_start; + unsigned end = node->m_end; + assert( start <= end ); + + /** + * Evaluate stack depth + */ unsigned index; vf_Code_t *pointer; - int stack_deep = 0; - for( index = begin, pointer = &ctex->m_code[index]; index <= end; index++, pointer++ ) { - if( pointer->m_minstack + VERIFY_START_MARK > stack_deep + deep ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Unable to pop operand off an empty stack" ); + int stack_depth = 0; + for( index = start, pointer = &ctex->m_code[index]; index <= end; index++, pointer++ ) { + if( pointer->m_minstack + VERIFY_START_MARK > stack_depth + depth ) { + VERIFY_REPORT_METHOD( ctex, + "Unable to pop operand off an empty stack" ); return VER_ErrorStackOverflow; } - stack_deep += pointer->m_stack; - if( stack_deep + deep > (int)max_stack || stack_deep + deep < VERIFY_START_MARK ) { - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Instruction stack overflow" ); + stack_depth += pointer->m_stack; + if( stack_depth + depth > (int)max_stack || stack_depth + depth < VERIFY_START_MARK ) { + VERIFY_REPORT_METHOD( ctex, + "Instruction stack overflow" ); return VER_ErrorStackOverflow; } } #if _VERIFY_DEBUG - if( stack_deep != ctex->m_graph->GetNodeStackModifier( nodenum ) ) { - VERIFY_DEBUG( "vf_check_node_stack_deep: error stack modifier calculate" ); + if( stack_depth != ctex->m_graph->GetNodeStackModifier( nodenum ) ) { + VERIFY_DEBUG( "vf_check_node_stack_depth: error stack modifier calculate" ); vf_error(); } #endif // _VERIFY_DEBUG return VER_OK; -} // vf_check_node_stack_deep +} // vf_check_node_stack_depth /** - * Function checks graph nodes stack deep consistency. It's recursive function. + * Function checks graph nodes stack depth consistency. It's recursive function. * Function returns result of check. */ static Verifier_Result -vf_check_stack_deep( unsigned nodenum, // graph node number - int stack_deep, // initial stack deep of node +vf_check_stack_depth( unsigned nodenum, // graph node number + int stack_depth, // initial stack depth of node unsigned maxstack, // maximal stack unsigned *count, // pointer to checked node count vf_Context_t *ctex) // verifier context { - int deep; + int depth; unsigned outnode, outedge; Verifier_Result result = VER_OK; + vf_NodeHandle node = ctex->m_graph->GetNode( nodenum ); + /** * Skip end-entry node */ - if( vf_is_instruction_has_flags( &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( nodenum )], - VF_FLAG_END_ENTRY) ) - { + if( VF_TYPE_NODE_END_ENTRY == node->m_type ) { return VER_OK; } /** * Check handler node */ - if( vf_is_instruction_has_flags( &ctex->m_code[ctex->m_graph->GetNodeFirstInstr( nodenum )], - VF_FLAG_HANDLER) ) - { + if( VF_TYPE_NODE_HANDLER == node->m_type ) { // Reset stack for handler nodes - stack_deep = VERIFY_START_MARK; + stack_depth = VERIFY_START_MARK; } /** - * Check node stack deep + * Check node stack depth */ - deep = ctex->m_graph->GetNodeMark( nodenum ); - if( !deep ) { - // stack deep don't set, mark node by his stack deep - ctex->m_graph->SetNodeMark( nodenum, stack_deep ); + depth = ctex->m_graph->GetNodeMark( nodenum ); + if( !depth ) { + // stack depth don't set, mark node by his stack depth + ctex->m_graph->SetNodeMark( nodenum, stack_depth ); (*count)++; } else { - if( stack_deep == deep ) { - // consistent stack deep in graph + if( stack_depth == depth ) { + // consistent stack depth in graph return VER_OK; } else { - // inconsistent stack deep in graph - VERIFY_REPORT( ctex, "(class: " << class_get_name( ctex->m_class ) - << ", method: " << method_get_name( ctex->m_method ) - << method_get_descriptor( ctex->m_method ) - << ") Inconsistent stack deep: " - << stack_deep - VERIFY_START_MARK << " != " - << deep - VERIFY_START_MARK ); + // inconsistent stack depth in graph + VERIFY_REPORT_METHOD( ctex, + "Inconsistent stack depth: " + << stack_depth - VERIFY_START_MARK << " != " + << depth - VERIFY_START_MARK ); return VER_ErrorStackDeep; } } @@ -1388,15 +1179,15 @@ /** * Check node stack overflow */ - result = vf_check_node_stack_deep( nodenum, stack_deep, maxstack, ctex ); + result = vf_check_node_stack_depth( nodenum, stack_depth, maxstack, ctex ); if( result != VER_OK ) { return result; } /** - * Override all out edges and set stack deep for out nodes + * Override all out edges and set stack depth for out nodes */ - deep = stack_deep + ctex->m_graph->GetNodeStackModifier( nodenum ); + depth = stack_depth + ctex->m_graph->GetNodeStackModifier( nodenum ); for( outedge = ctex->m_graph->GetNodeFirstOutEdge( nodenum ); outedge; outedge = ctex->m_graph->GetEdgeNextOutEdge( outedge ) ) @@ -1404,12 +1195,12 @@ // get out node outnode = ctex->m_graph->GetEdgeEndNode( outedge ); // mark out node with its out nodes - result = vf_check_stack_deep( outnode, deep, maxstack, count, ctex ); + result = vf_check_stack_depth( outnode, depth, maxstack, count, ctex ); if( result != VER_OK ) { return result; } } return result; -} // vf_check_stack_deep +} // vf_check_stack_depth -} // namescape Verifier + Index: vm/vmcore/src/verifier/ver_graph.h =================================================================== --- vm/vmcore/src/verifier/ver_graph.h (revision 0) +++ vm/vmcore/src/verifier/ver_graph.h (revision 0) @@ -0,0 +1,661 @@ +/* + * 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. + */ +/** + * @author Pavel Rebriy, Alexei Fedotov + * @version $Revision: 1.1.2.3.4.4 $ + */ + + +#ifndef _VERIFIER_GRAPH_H_ +#define _VERIFIER_GRAPH_H_ +/** + * @file + * Control flow graph structures. + */ + +#include "ver_real.h" + +/** + * @ingroup Handles + * The stack map handle vector handle. + */ +typedef const struct vf_MapVector* vf_MapVectorHandle; +/** + * @ingroup Handles + * The handle of the graph node. + */ +typedef const struct vf_Node* vf_NodeHandle; +/** + * @ingroup Handles + * The handle of the graph edge. + */ +typedef const struct vf_Edge* vf_EdgeHandle; + +/** + * Structure of stack map vector. + */ +struct vf_MapVector { + 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_depth; ///< stack depth + unsigned short m_maxstack; ///< max stack length + unsigned short m_maxlocal; ///< max local number +}; + +/** + * Each node has a descriptive bitmap. + */ +typedef enum { + VF_TYPE_NODE_CODE_RANGE = 0, + VF_TYPE_NODE_START_ENTRY = 1, + VF_TYPE_NODE_END_ENTRY = 2, + VF_TYPE_NODE_HANDLER = 3 +} vf_NodeType; + +/** + * Graph node structure. + */ +struct vf_Node +{ + struct vf_MapVector m_inMapVector; ///< stack map IN node vector + struct vf_MapVector m_outMapVector; ///< stack map OUT node vector + unsigned m_start; ///< index of the first instruction at vf_Context.m_code + unsigned m_end; ///< index of the last instruction at vf_Context.m_code + unsigned m_inedge; ///< the first incoming edge + unsigned m_outedge; ///< the first outcoming edge + 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 depth + int m_mark; ///< node mark + vf_NodeType m_type; ///< node type + bool m_initialized : 1; ///< reference in a local variable + ///< should be initialized +}; + +/** + * Graph edge structure. + */ +struct vf_Edge +{ + 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 +{ + struct vf_NodeContainer* m_next; ///< next container + unsigned m_max; ///< max number of nodes in container + unsigned m_used; ///< number of nodes in container + struct vf_Node m_node[1]; ///< array of contained nodes +}; + +/** + * Graph edge container structure. + */ +struct vf_EdgeContainer +{ + struct vf_EdgeContainer* m_next; ///< next container + unsigned m_max; ///< max number of edges in container + unsigned m_used; ///< number of edges in container + struct vf_Edge m_edge[1]; ///< array of contained edges +}; + +/** + * Verifier control flow graph structure. + */ +class vf_Graph +{ +public: + /** + * 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 a graph node. + * + * @param[in] node_num a node number, should be in range + * @return a handle of the node + */ + vf_NodeHandle GetNode( unsigned node_num ); + + /** + * Gets the first node. + * + * @return a handle of the node + */ + vf_NodeHandle GetFirstNode() + { + return GetNode( 0 ); + } + + /** + * Creates a new node of a specific type. + * Node array must have enough free space for a new element. + * + * @param[in] m_type node type + * @return a handle of the created node + */ + vf_NodeHandle NewNode( vf_NodeType m_type ); + + /** + * Creates a new node for a bytecode range. + * Node array must have enough free space for a new element. + * + * @param[in] start an instruction start index + * @param[in] end an instruction end index + * @param[in] stack a stack modifier (signed value) + * @return a handle of the created node + */ + vf_NodeHandle NewNode( unsigned start, + unsigned end, + int stack) + { + // get node + struct vf_Node* node = (struct vf_Node*) NewNode( VF_TYPE_NODE_CODE_RANGE ); + node->m_start = start; + node->m_end = end; + node->m_stack = stack; + return node; + } // NewNode( start, end, len ) + + /** + * Gets graph edge. + * Parameter edge_num must be in range. + * + * @param[in] edge_num - edge number + * + * @return The pointer to edge structure. + */ + vf_EdgeHandle 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); + + /** + * Gets the first code instruction of a node. + * @param node_num the node number + * @return a number of the first code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. + */ + unsigned GetNodeFirstInstr( unsigned node_num ) + { + vf_NodeHandle node = GetNode( node_num ); + assert( VF_TYPE_NODE_CODE_RANGE == node->m_type ); + return node->m_start; + } // GetNodeFirstInstr + + /** + * Gets the last code instruction of a node. + * @param node_num the node number + * @return a number of the last code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. + */ + unsigned GetNodeLastInstr( unsigned node_num ) + { + vf_NodeHandle node = GetNode( node_num ); + assert( VF_TYPE_NODE_CODE_RANGE == node->m_type ); + return node->m_end; + } // GetNodeLastInstr + + /** + * Gets a bytecode length of a graph node instructions. + * @param context a verifier context handle + * @param node a node handle + * @return a number of the last code instruction of graph node + * @note Assertion is raised if node_num is not a + * code range node. + */ + unsigned GetNodeBytecodeLen( vf_ContextHandle context, + vf_NodeHandle node ); + + /** + * Gets a stack modifier of a graph node. + * @param node_num a node number + * @return a stack modifier of graph node + */ + int GetNodeStackModifier( unsigned node_num ) + { + return GetNode( node_num )->m_stack; + } // GetNodeStackModifier + + /** + * Sets graph node stack modifier. + * @param node_num a graph node number + * @param stack a stack modifier (signed value) + */ + void SetNodeStackModifier( unsigned node_num, int stack ) + { + struct vf_Node* node = (struct vf_Node*) GetNode( node_num ); + node->m_stack = stack; + } // SetNodeStackModifier + + /** + * Counts graph nodes. + * @return a number of graph nodes + */ + unsigned GetNodeCount() + { + return m_nodenum; + } // GetNodeCount + + /** + * Counts graph edges excluding + * the reserved edge. + * @return a number of graph edges + */ + unsigned GetEdgeCount() + { + return m_edgenum - 1; + } // GetEdgeCount + + /** + * Marks a graph node with a given number. + * @param node_num a graph node number + * @param mark a mark + */ + void SetNodeMark( unsigned node_num, int mark ) + { + struct vf_Node* node = (struct vf_Node*) GetNode( node_num ); + node->m_mark = mark; + } // SetNodeMark + + /** + * Gets a graph node mark. + * @param node_num a node number + * @return a graph node mark + */ + int GetNodeMark( unsigned node_num ) + { + return GetNode( node_num )->m_mark; + } // GetNodeMark + + /** + * Checks if a node is marked. + * @param node_num a graph node number + * @return true if node is marked, false otherwise + */ + bool IsNodeMarked( unsigned node_num ) + { + return 0 != GetNode( node_num )->m_mark; + } + + /** + * Function removes node mark. + */ + void CleanNodesMark(); + + /** + * Sets local variable reference initialization flag for a anode. + * @param node_num a graph node number + * @param flag a node flag + */ + void SetNodeInitFlag( unsigned node_num, bool flag ) + { + struct vf_Node* node = (struct vf_Node*) GetNode( node_num ); + node->m_initialized = flag; + } + + /** + * Gets an initialization flag for local variable reference for a given node. + * @param node_num a graph node number + * @return true if the local variable reference has + * to be initialized, false otherwise. + */ + bool GetNodeInitFlag( unsigned node_num ) + { + return GetNode( node_num )->m_initialized; + } + + /** + * Function creates IN data flow vector of a node. + * @param node_num a graph node number + * @param example a handle of copied data flow vector + * @param need_copy a 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. + */ + void SetNodeInVector( unsigned node_num, + vf_MapVectorHandle example, + bool need_copy) + { + SetVector( GetNodeInVector( node_num ), example, need_copy ); + } + + /** + * Creates OUT data flow vector of a node. + * @param node_num a graph node number + * @param example a handle of copied data flow vector + * @param need_copy a 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. + */ + void SetNodeOutVector( unsigned node_num, + vf_MapVectorHandle example, + bool need_copy ) + { + SetVector( GetNodeOutVector( node_num ), example, need_copy ); + } + + /** + * Gets IN data flow vector for the node. + * @param node_num graph node number + * @return a reference to IN data flow stack map vector + * @note Assertion is raised if node_num is out of range. + * @see vf_MapVector_t + */ + vf_MapVectorHandle GetNodeInVector( unsigned node_num ) + { + return &( GetNode( node_num )->m_inMapVector ); + } // GetNodeInVector + + /** + * Gets OUT data flow vector for the node. + * @param node_num graph node number + * @return a reference to OUT data flow stack map vector + * @see vf_MapVector_t + */ + vf_MapVectorHandle GetNodeOutVector( unsigned node_num ) + { + return &( GetNode( node_num )->m_outMapVector ); + } // GetNodeOutVector + + /** + * 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 ); + + /** + * Allocates memory from the graph memory pool. + * @param size a size of memory block + * @return a pointer to allocated memory, + * or NULL if memory allocation failed. + */ + void* AllocMemory( unsigned size ) { + assert( size ); + return vf_alloc_pool_memory( m_pool, 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: + struct vf_NodeContainer* m_nodes; ///< array of nodes + struct vf_EdgeContainer* 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 + + /** + * Creates a data flow vector from a given example. + * @param vector_handle a vector to set + * @param example a handle of an example vector + * @param need_copy a copy flag + * @note If copy flag true, incoming vector is copied to, + * otherwise IN vector is created + * with parameters of current vector. + */ + void SetVector( vf_MapVectorHandle vector_handle, + vf_MapVectorHandle example, + bool need_copy); + + /** + * 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 + +/** + * Checks if a code range node ends with a specific + * instruction type. + * @param[in] context a verifier context + * @param[in] node_index the node identifier + * @return a type of the last instruction of code range node + */ +static inline vf_CodeType +vf_get_last_instruction_type( vf_ContextHandle context, + unsigned node_index) +{ + vf_NodeHandle node = context->m_graph->GetNode( node_index ); + assert( VF_TYPE_NODE_CODE_RANGE == node->m_type ); + return context->m_code[node->m_end].m_type; +} + +#endif // _VERIFIER_GRAPH_H_ Index: vm/vmcore/src/verifier/ver_real.h =================================================================== --- vm/vmcore/src/verifier/ver_real.h (revision 507588) +++ vm/vmcore/src/verifier/ver_real.h (working copy) @@ -15,15 +15,18 @@ * limitations under the License. */ /** - * @author Pavel Rebriy + * @author Pavel Rebriy, Alexei Fedotov * @version $Revision: 1.1.2.3.4.4 $ */ #ifndef _VERIFIER_REAL_H_ #define _VERIFIER_REAL_H_ +/** + * @file + * Verifier interfaces. + */ -#include #include #include #include @@ -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