Index: build/custom/msvc_2003/vmcore/vmcore.vcproj
===================================================================
--- build/custom/msvc_2003/vmcore/vmcore.vcproj (revision 501401)
+++ build/custom/msvc_2003/vmcore/vmcore.vcproj (working copy)
@@ -994,6 +994,9 @@
RelativePath="..\..\..\..\vm\vmcore\src\verifier\ver_real.h">
+
+
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_Node_t*
+vf_Graph::NewNode( vf_NodeType_t type )
{
// get node
assert( m_nodes );
@@ -163,35 +147,17 @@
// 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;
+ node->m_type = type;
+ return node;
} // vf_Graph::NewNode
/**
- * Function set data to graph 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
-{
- vf_Node_t* node = GetNode( num );
- node->m_start = begin;
- node->m_end = end;
- node->m_len = len;
- return;
-} // vf_Graph::SetNode
-
-/**
* Gets graph edge.
*/
vf_Edge_t*
@@ -255,40 +221,8 @@
return;
} // 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
@@ -304,7 +238,7 @@
*/
inline void
vf_Graph::SetNodeStackModifier( unsigned num, // graph node number
- int stack) // stack deep modifier
+ int stack) // stack depth modifier
{
// check node number is in range.
assert( num < m_nodenum );
@@ -312,14 +246,6 @@
return;
} // vf_Graph::SetNodeStackModifier
-/**
- * Function returns number of graph nodes.
- */
-unsigned
-vf_Graph::GetNodeNumber()
-{
- return m_nodenum;
-} // vf_Graph::GetNodeNumber
/**
* Function marks graph node.
@@ -399,27 +325,6 @@
} // 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
@@ -441,7 +346,7 @@
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_depth = example->m_depth;
vector->m_maxstack = example->m_maxstack;
}
if( need_copy ) {
@@ -449,7 +354,7 @@
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];
}
}
@@ -478,7 +383,7 @@
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_depth = example->m_depth;
vector->m_maxstack = example->m_maxstack;
}
if( need_copy ) {
@@ -486,7 +391,7 @@
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];
}
}
@@ -722,7 +627,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
@@ -750,17 +655,14 @@
}
// 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 == GetNode( num )->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 ) )
+ } else if( VF_TYPE_NODE_END_ENTRY == GetNode( num )->m_type)
{ // end node
VERIFY_DEBUG( "node[" << num << "]: " << GetNode( num )->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 == GetNode( num )->m_type )
{ // handler node
VERIFY_DEBUG( "node[" << num << "]: " << num << "handler entry" );
} else { // another nodes
@@ -903,22 +805,21 @@
vf_Context_t *ctex) // verifier contex
{
#if _VERIFY_DEBUG
+ vf_Node_t* 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
+ << num << "\\n---------\\n" << "Type: #0" // FIXME remove type after testing
<< "\", shape=ellipse, color=aquamarine]" << endl;
- } else { // another nodes
+ } else { // other nodes
out << "node" << num
<< " [label=\"";
DumpDotNodeInternal( num, "\\n---------\\n", "\\l", out, ctex );
@@ -928,20 +829,18 @@
// 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 );
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_is_subroutine_call( ctex, edge ) )
{
out << "[color=blue]" << endl;
}
@@ -997,134 +896,171 @@
********************** Graph Creation **********************
************************************************************/
+
/**
- * Function creates bytecode control flow graph.
+ * Creates bytecode control flow graph.
*/
Verifier_Result
vf_create_graph( vf_Context_t *ctex ) // verifier context
{
- /**
- * 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_t* graph = ctex->m_graph;
- /**
- * Create decoding array: code to node
- */
+ // the array contains a corresponding node for each pc
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 );
+
+ unsigned node_index;
+ graph->NewNode( VF_TYPE_NODE_START_ENTRY );
+
+ // create handler nodes
+ 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++ )
+ unsigned bb_start = 0;
+ unsigned bytecode_len = method_get_code_length( ctex->m_method );
+ // adding a basic block which starts
+ for (; 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++;
}
+
+ unsigned char* code_end = (next_bb_start < ctex->m_codeNum) ?
+ ctex->m_code[ next_bb_start ].m_addr :
+ method_get_bytecode( ctex->m_method )
+ + bytecode_len;
+
+ unsigned len = code_end - ctex->m_code[ bb_start ].m_addr;
+
+ graph->NewNode( bb_start, next_bb_start - 1, len );
+ graph->SetNodeStackModifier( node_index,
+ 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();
- }
-#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
+ 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);
+
+ ctex->m_graph->NewEdge( node_index, node );
+ if( node < node_index ) {
+ // node has a backward branch, thus any
+ // object on the stack should 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 );
+ 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
+ vf_MapVector_t* p_outvector =
+ ctex->m_graph->GetNodeOutVector(handler_index + 1);
+
+ vf_new_vector(&p_outvector->m_stack, 1, ctex->m_pool);
+ 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,39 +1072,27 @@
************************************************************/
/**
- * 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.
*/
@@ -1188,20 +1112,20 @@
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 +1133,12 @@
if( index )
{
/**
- * Identify dead code nodes and fill by nop inctruction
+ * Identify dead code nodes and fill by nop inctruction.
*/
- 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++ ) {
+ for( count = 0; count < vGraph->GetNodeBytecodeLen( ctex, index ); count++ ) {
instr[count] = OPCODE_NOP;
}
vGraph->SetNodeStackModifier( index, 0 );
@@ -1222,6 +1146,14 @@
}
}
+ if( ctex->m_dump.m_with_subroutine ) {
+ result = vf_inline_subroutines( ctex );
+ if( result != VER_OK ) {
+ goto labelEnd_bypassGraphStructure;
+ }
+ }
+
+
#if _VERIFY_DEBUG
if( ctex->m_dump.m_mod_graph ) {
vGraph->DumpGraph( ctex );
@@ -1232,10 +1164,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 +1182,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;
}
@@ -1272,115 +1203,106 @@
* 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_Node_t* 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;
}
+
+ /**
+ * Get begin and end code instruction of graph node
+ */
+ unsigned start = node->m_start;
+ unsigned end = node->m_end;
+ assert( start <= end );
/**
- * Evaluate stack deep
+ * 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( 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_Node_t* 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( ctex,
+ "Inconsistent stack depth: "
+ << stack_depth - VERIFY_START_MARK << " != "
+ << depth - VERIFY_START_MARK );
return VER_ErrorStackDeep;
}
}
@@ -1388,15 +1310,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 +1326,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_real.h
===================================================================
--- vm/vmcore/src/verifier/ver_real.h (revision 501435)
+++ vm/vmcore/src/verifier/ver_real.h (working copy)
@@ -15,13 +15,17 @@
* 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
@@ -37,7 +41,8 @@
using namespace std;
/**
- * Set namespace Verifier.
+ * @namespace Verifier
+ * Contains bytecode verificator.
*/
namespace Verifier {
@@ -72,6 +77,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,20 +282,26 @@
} 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 = -1
+} vf_CodeType_t;
/**
+ * 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 = -1
+} vf_NodeType_t;
+
+/**
* Verifier structures.
*/
//===========================================================
@@ -319,16 +336,15 @@
/**
* 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_mark : 1; ///< control flow branch flag
-} vf_Instr_t;
+ unsigned m_instr; ///< a number + 1 of code instruction at
+ ///< vf_Context.m_code
+ unsigned m_mark : 1; ///< control flow branch flag
+} vf_BCode_t;
/**
* Valid types structure.
@@ -361,17 +377,19 @@
* Complete struct of bytecode instructions.
*/
struct vf_Code_s {
- unsigned char *m_addr; ///< address of bytecode instruction
- unsigned *m_off; ///< array of instruction branches
- unsigned char *m_handler; ///< array of instruction handlers
- 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
+ unsigned char *m_addr; ///< address of bytecode instruction
+ unsigned m_offcount; ///< number of instruction branches
+ unsigned *m_off; ///< array of instruction branches
+ 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 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
+ bool m_basic_block_start : 1; ///< begin of a basic block
+ vf_CodeType_t m_type : 2; ///< instruction flag @see vf_CodeType_t
};
/**
@@ -402,7 +420,7 @@
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_depth; ///< stack depth
unsigned short m_maxstack; ///< max stack length
unsigned short m_maxlocal; ///< max local number
} vf_MapVector_t;
@@ -412,19 +430,21 @@
*/
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
+ vf_MapVector_t m_inMapVector; ///< stack map IN node vector
+ vf_MapVector_t 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_len; ///< length of the basic block
+ 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
+ bool m_initialized : 1; ///< reference in a local variable
+ ///< should be initialized
+ vf_NodeType_t m_type : 2; ///< node type
};
/**
@@ -508,29 +528,32 @@
vf_Node_t* GetNode( unsigned node_num );
/**
- * Creates a new node and sets data to it.
+ * Creates a new node of a specific type.
* 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
+ * @param[in] m_type node type
+ * @return created node
*/
- void NewNode( unsigned begin_instr,
- unsigned end_instr,
- unsigned bytecode_len);
+ vf_Node_t* NewNode( vf_NodeType_t m_type );
/**
- * 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.
+ * Creates a new node for a bytecode range.
+ * Node array must have enough free space for a new element.
+ *
+ * @param[in] start instruction start index
+ * @param[in] end instruction end index
+ * @param[in] len bytecode length of node instructions
*/
- void SetNode( unsigned node_num,
- unsigned begin_instr,
- unsigned end_instr,
- unsigned bytecode_len );
+ void NewNode( unsigned start,
+ unsigned end,
+ unsigned len ) {
+ // get node
+ vf_Node_t* node = NewNode( VF_TYPE_NODE_CODE_RANGE );
+ node->m_start = start;
+ node->m_end = end;
+ node->m_len = len;
+ return;
+ } // NewNode(start, end, len)
/**
* Gets graph edge.
@@ -553,28 +576,44 @@
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.
+ * 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 );
+ unsigned GetNodeFirstInstr( unsigned node_num ) {
+ vf_Node_t* node = GetNode( node_num );
+ assert( VF_TYPE_NODE_CODE_RANGE == node->m_type );
+ return node->m_start;
+ } // GetNodeFirstInstr
/**
- * 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.
+ * 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 );
+ unsigned GetNodeLastInstr( unsigned node_num ) {
+ vf_Node_t* node = GetNode( node_num );
+ assert( VF_TYPE_NODE_CODE_RANGE == node->m_type );
+ return node->m_end;
+ } // GetNodeLastInstr
/**
- * 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.
+ * Gets a bytecode length of a graph node instructions.
+ * @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 GetNodeByteCodeLen( unsigned node_num );
+ unsigned GetNodeBytecodeLen( vf_Context_t *context,
+ unsigned node_num ) {
+ vf_Node_t* node = GetNode( node_num );
+ assert( VF_TYPE_NODE_CODE_RANGE == node->m_type );
+ return node->m_len;
+ }
/**
* Function receive stack modifier of graph.
@@ -593,12 +632,23 @@
void SetNodeStackModifier( unsigned node_num, int stack );
/**
- * Function returns number of graph nodes.
- * @return Number of graph nodes.
+ * Counts graph nodes.
+ * @return a number of graph nodes
*/
- unsigned GetNodeNumber();
+ unsigned GetNodeCount() {
+ return m_nodenum;
+ }
/**
+ * Counts graph edges excluding
+ * the reserved edge.
+ * @return a number of graph edges
+ */
+ unsigned GetEdgeCount() {
+ return m_edgenum - 1;
+ }
+
+ /**
* Function marks graph node.
* @param node_num - graph node number
* @param mark - node mark
@@ -671,24 +721,29 @@
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.
+ * 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_MapVector_t * GetNodeInVector( unsigned node_num );
+ vf_MapVector_t* GetNodeInVector(unsigned node_num) {
+ assert( node_num < m_nodenum );
+ return &(GetNode( node_num )->m_inMapVector);
+ } // GetNodeInVector
/**
- * Function receives OUT data flow vector of node.
- * @param node_num - graph node number
- * @return OUT data flow stack map vector of node.
+ * Gets OUT data flow vector for the node.
+ * @param node_num graph node number
+ * @return a reference to OUT data flow stack map vector
* @note Assertion is raised if node_num is out of range.
* @see vf_MapVector_t
*/
- vf_MapVector_t * GetNodeOutVector( unsigned node_num );
+ vf_MapVector_t* GetNodeOutVector(unsigned node_num) {
+ assert(node_num < m_nodenum);
+ return &(GetNode(node_num)->m_outMapVector);
+ } // GetNodeOutVector
/**
* Function creates graph edges.
@@ -1182,9 +1237,12 @@
vf_TypePool *m_type; ///< context type constraint collection
char *m_error; ///< context error message
method_handler m_method; ///< context method
+ bool m_is_constructor; ///< true if the
+ ///< method is a constructor
vf_Graph_t *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 +1275,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
/**
@@ -1450,6 +1509,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 +1587,10 @@
vf_Context::ClearContext()
{
m_method = NULL;
- m_graph = 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 +1598,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,15 +1624,152 @@
} // 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 )
-{
+vf_is_class_version_14( vf_Context_t *context ) {
return (class_get_version(context->m_class) < 49) ? true : false;
} // vf_is_class_version_14
+/**
+ * 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
+
+/**
+ * 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
+
+/**
+ * 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 true if the edge is a subroutine call
+ */
+static inline bool
+is_node_last_instruction(vf_Context_t *context,
+ unsigned node_index, unsigned flag) {
+ vf_Node_t* node = context->m_graph->GetNode( node_index );
+ assert(VF_TYPE_NODE_CODE_RANGE == node->m_type);
+ return (VF_TYPE_INSTR_SUBROUTINE == context->m_code[node->m_end].m_type);
+}
+
+
+/**
+ * Checks if a graph edge is produced from jsr or
+ * jsr_w branch.
+ * @param[in] context a verifier context
+ * @param[in] edge the edge
+ * @return true if the edge is a subroutine call
+ */
+static inline bool
+vf_is_subroutine_call(vf_Context_t *context, vf_Edge_t* edge) {
+ return (edge->m_start + 1 != edge->m_end)
+ && is_node_last_instruction(context, edge->m_start, VF_TYPE_INSTR_SUBROUTINE);
+}
+
+/**
+ * Inline subroutines in the call graph.
+ *
+ * Algorithm:
+ *
+ *
+ *
+ * - Starting from the first basic block we mark all reachable
+ * nodes.
+ *
+ *
+ * - For each node which ends with
jsr
+ * statement we start a control flow analysis to find a list of
+ * reachable nodes and ret statement which ends
+ * this subroutine. The jsr node is marked as processing.
+ *
+ *
+ * - If an execution path comes to a node which is reachable
+ * from the first node, we stop. All reachable code shouldn't
+ * be inlined.
+ *
+ * - If an execution path comes to a processed
jsr node,
+ * it follows inlined subroutine. If an execution path comes to
+ * new jsr node, it continues with the basic block
+ * which starts at the next instruction after the jsr.
+ * If an execution path comes
+ * to the processing jsr node, this violates the 23-rd
+ * requirement of 4.10.2 and java.lang.VerifyError: Recursive
+ * call to jsr entry is reported.
+ *
+ * - If more than one
ret is found,
+ * this violates the 22-nd requirement of 4.10.2 that the
+ * each subroutine ends with a common ret,
+ * and java.lang.VerifyError: Multiple returns to
+ * single jsr is reported.
+ *
+ * - Corresponding
ret node is redirected to the
+ * basic block, which follows jsr.
+ *
+ * - If the corresponding
ret is already redirected
+ * to some basic block, all reachable nodes are duplicated and
+ * a copied node, which contains a ret instruction
+ * is redirected to the basic block, which follows jsr.
+ *
+ *
+ * - The
jsr node is marked as processed.
+ * The process continues until all jsr nodes
+ * are marked as processed including newly copied nodes.
+ *
+ * - Finally, the subroutine checks that a return address is
+ * loaded once and used by
ret instruction only
+ * (claims 21, 24 of 4.10.2).
+ *
+ *
+ * @param[in] context a verifier context
+ * @return VER_OK if subroutines were inlined successfully,
+ * an error code otherwise
+ */
+Verifier_Result
+vf_inline_subroutines(vf_Context_t *ctex);
+
} // namespace Verifier
using namespace Verifier;
Index: vm/vmcore/src/verifier/Verifier.cpp
===================================================================
--- vm/vmcore/src/verifier/Verifier.cpp (revision 501435)
+++ vm/vmcore/src/verifier/Verifier.cpp (working copy)
@@ -30,11 +30,9 @@
#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
*/
@@ -115,23 +113,24 @@
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 ) {
+ }
+ if( ctex->m_dump.m_with_subroutine ) {
result = VER_NoSupportJSR;
goto labelEnd_verifyClassBytecode;
- }
-
+ }
/**
* Build bytecode graph
*/
@@ -167,39 +166,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
- unsigned value, // offset value
- vf_VerifyPool_t *pool) // memory pool
+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 +234,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 +242,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_t 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 +263,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 +280,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 +293,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)
@@ -315,18 +311,32 @@
}
return local;
} // vf_get_local_var_number
-
/**
- * Function returns instruction branch offset for given branch number.
+ * Function parses local variable number from instruction bytecode.
*/
-static inline int
-vf_get_instruction_branch( vf_Instr_t *code, // instruction
- unsigned branch_num) // branch number
+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
+ bool *wide_flag) // if this is a wide instruction
{
- assert( branch_num < code->m_offcount );
- return code->m_off[branch_num];
-} // vf_get_instruction_branch
+ unsigned local;
+ if( (*wide_flag) ) {
+ // get number of local variable
+ local = (unsigned)( (bytecode[(*index_p)] << 8)|(bytecode[(*index_p)+ 1]) );
+ // skip parameter (u2)
+ (*index_p) += 2;
+ *wide_flag = false;
+ } else {
+ // get number of local variable
+ local = (unsigned)bytecode[(*index_p)];
+ // skip parameter (u1)
+ (*index_p)++;
+ }
+ return local;
+} // vf_get_local_var_number
+
/**
* Function receives half word (2 bytes) instruction branch offset
* value from bytecode array.
@@ -366,7 +376,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 +385,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 +394,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 +403,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,20 +413,20 @@
* Function returns recieved offset.
*/
static inline int
-vf_get_double_hword_branch_offset( vf_Instr_t *code, // instruction
- unsigned code_pc, // instruction offset in bytcode array
- unsigned char *bytecode, // bytecode array
- unsigned *index_p, // offset index in bytecode array
- vf_VerifyPool_t *pool) // memory pool
+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
+ vf_VerifyPool_t *pool) // memory pool
{
// get first branch offset
int offset = vf_get_hword_offset( code_pc, bytecode, index_p );
// create and set edge branchs 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,39 +436,39 @@
* Function returns recieved offset.
*/
static inline int
-vf_get_double_word_branch_offset( vf_Instr_t *code, // instruction
- unsigned code_pc, // instruction offset in bytcode array
- unsigned char *bytecode, // bytecode array
- unsigned *index_p, // offset index in bytecode array
- vf_VerifyPool_t *pool) // memory pool
+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
+ vf_VerifyPool_t *pool) // memory pool
{
// get first branch offset
int offset = vf_get_word_offset( code_pc, bytecode, index_p );
// create and set edge branchs 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
/**
* Function receives tableswitch branch from bytecode array and
- * sets reseived offset into instruction.
+ * sets received offset into instruction.
* Function returns recieved branch.
*/
static inline int
-vf_get_tableswitch_alternative( vf_Instr_t *code, // instruction
- unsigned code_pc, // offset in bytcode array
- unsigned alternative, // number of tableswitch branch
- unsigned char *bytecode, // bytecode array
- unsigned *index_p) // offset index in bytecode array
+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
+ unsigned *index_p) // offset index in bytecode array
{
// 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 +478,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 +494,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 +513,7 @@
* Function returns number of alternatives.
*/
static inline Verifier_Result
-vf_set_lookupswitch_offsets( vf_Instr_t *code, // inctruction
+vf_set_lookupswitch_offsets( vf_Code_t *code, // inctruction
unsigned code_pc, // instruction offset in bytecode
unsigned *index_p, // offset index in bytecode array
unsigned char *bytecode, // array of bytecode
@@ -519,7 +529,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 +540,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 +558,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 +659,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
@@ -1590,20 +1571,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 *
@@ -1684,10 +1651,10 @@
assert(descr);
// get class name if it's needed
- if( class_name ) {
+ 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_get_cp_ref_class_index(ctex->m_class, index);
+ *class_name = vf_get_cp_class_name(ctex->m_class, class_cp_index);
}
// get name and descriptor from NameAndType constant pool entry
@@ -1836,10 +1803,8 @@
}
// 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)
? ": CONSTANT_Integer, CONSTANT_Float or CONSTANT_String"
@@ -1878,10 +1843,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;
}
@@ -1899,12 +1862,12 @@
vf_Context_t *ctex) // verifier context
{
// check constant pool index and type
- unsigned short len = class_get_cp_size( ctex->m_class );
+ unsigned short len = class_get_cp_size(ctex->m_class);
CHECK_CONST_POOL_ID( index, len, ctex );
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 );
@@ -3401,8 +3364,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 +3387,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 +3411,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 +3455,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 +3472,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 +3489,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 +3506,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 +3523,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 +3666,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 +3713,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 +3762,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 +3811,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 +3902,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 +3917,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 +3965,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 +4050,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 +4060,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 +4074,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 +4088,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 +4107,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 +4134,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 +4158,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 +4177,61 @@
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++;
- /**
- * 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 );
- }
+ // first instruction is always begin of basic block
+ vf_BCode_t* bc = ctex->m_bc;
+ bc[0].m_mark = 1;
/**
- * 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
+ 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 +4264,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 +4275,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 +4292,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 +4300,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 +4308,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 +4316,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 +4408,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 +4416,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 +4424,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 +4432,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 +4440,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 +4618,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 +4686,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 +4696,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 +4705,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 +4715,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 +4730,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_double_hword_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -4833,43 +4758,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 +4801,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 +4938,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 +4948,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 +4982,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 +5012,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 +5036,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_double_word_branch_offset( code,
instr, bytecode, &index, pool );
result = vf_check_branch_offset( offset, len, ctex );
if( result != VER_OK ) {
@@ -5149,174 +5064,138 @@
}
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 ) )
- {
- 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" );
+ 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_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_METHOD( ctex,
+ "Exception handler range starting point should be before ending point" );
+ result = VER_ErrorHandler;
+ goto labelEnd_vf_parse_bytecode;
+ }
+
+ // if end_pc == len, set it to 0
+ end_pc %= len;
+
+ // check that handlers point to instruction
+ // boundaries
+ if( (bc[ start_pc ].m_instr == 0)
+ || (bc[ end_pc ].m_instr == 0)
+ || (bc[ handler_pc ].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 )
- << ") Handler pc is out of instruction set" );
+ VERIFY_REPORT_METHOD( ctex,
+ "Handler pc is out of instruction set" );
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;
+ bc[ start_pc ].m_mark = 1;
+ bc[ end_pc ].m_mark = 1;
+ bc[ 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);
+ /**
+ * 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 );
- 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 );
- }
+ // 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;
}
- // 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 );
- /**
- * Set handler branchs
- * 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 existen 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;
- }
- }
+ 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;
+ } else {
+ continue;
}
- 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;
- }
- }
+
+ code = &ctex->m_code[instr - 1];
+ if( bc[ index ].m_mark ) {
+ code->m_basic_block_start = true;
+ nodes++;
}
+
+ if( code->m_offcount ) {
+ // basic block should start next, so we will
+ // count one branch anyway
+ edges += code->m_offcount - 1;
+ }
}
-labelEnd_vf_parse_bytecode:
-
/**
- * Free alocated 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,50 +5215,50 @@
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 );
}
- 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 << "]" );
- }
+
+ 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 << "]" );
}
}
VERIFY_DEBUG( index << " [-]: -> END-ENTRY" << endl );
@@ -5438,7 +5317,7 @@
memcpy( &type_name[1], class_name, class_name_len );
type_name[0] = 'L';
type_name[class_name_len + 1] = '\0';
- context.m_vtype.m_class = context.m_type->NewType( type_name, class_name_len + 1 );
+ context. m_vtype.m_class = context.m_type->NewType( type_name, class_name_len + 1 );
context.m_vtype.m_throwable = context.m_type->NewType( "Ljava/lang/Throwable", 20 );
context.m_vtype.m_object = context.m_type->NewType( "Ljava/lang/Object", 17 );
context.m_vtype.m_array = context.m_type->NewType( "[Ljava/lang/Object", 18 );
@@ -5467,6 +5346,9 @@
//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;
+ //context.m_dump.m_code = 1;
+ //context.m_dump.m_dot_mod_graph = 1;
result = vf_verify_method_bytecode( &context );
context.ClearContext();
}
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,34 @@
+/*
+ * 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_real.h"
+
+namespace Verifier {
+
+Verifier_Result
+vf_inline_subroutines( vf_Context_t *ctex ) {
+ bool are_subroutines_to_inline = true;
+
+ // clear graph node marks
+ vf_Graph_t *graph = ctex->m_graph;
+
+ while (are_subroutines_to_inline) {
+ are_subroutines_to_inline = false;
+ }
+ return VER_OK;
+}
+
+} // namescape Verifier
Index: vm/vmcore/src/verifier/ver_utils.cpp
===================================================================
--- vm/vmcore/src/verifier/ver_utils.cpp (revision 501435)
+++ vm/vmcore/src/verifier/ver_utils.cpp (working copy)
@@ -1031,52 +1031,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( 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:
DIE( "Verifier: vf_set_error: unknown check type" );
Index: vm/vmcore/src/verifier/ver_dataflow.cpp
===================================================================
--- vm/vmcore/src/verifier/ver_dataflow.cpp (revision 501435)
+++ vm/vmcore/src/verifier/ver_dataflow.cpp (working copy)
@@ -152,7 +152,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 +162,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 ) {
@@ -288,8 +288,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
@@ -344,8 +344,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++ ) {
@@ -365,7 +365,7 @@
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 +383,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 )
{
@@ -469,10 +469,8 @@
// a local variable if no backward branch is taken or
// the code isn't 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,10 +719,10 @@
vf_MapEntry_t zero_entry = {0};
// zero stack vector
- for( index = 0; index < vector->m_deep; index++ ) {
+ for( 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
@@ -804,10 +802,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;
@@ -816,10 +812,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;
}
@@ -829,18 +823,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( ctex,
+ "Data flow analysis error (uninitialized)" );
return result;
}
// check initialization class in constructor
@@ -859,10 +849,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;
}
}
@@ -891,8 +879,8 @@
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
@@ -904,22 +892,22 @@
}
// 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 ) ) {
+ } else if( VF_TYPE_INSTR_THROW == 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
invector->m_stack->m_type = SM_TERMINATE;
return VER_OK;
@@ -943,7 +931,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 )
{
@@ -954,8 +942,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 );
@@ -971,19 +959,24 @@
} // vf_get_instruction_out_vector
/**
- * Function receives handler OUT data flow vector.
+ * Copies a stored handler vector to the out vector.
+ * @param[in, out] invector IN handler vector
+ * @param[in] handler_vector stored handler 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(vf_MapVector_t* invector,
+ vf_MapVector_t* 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
@@ -998,53 +991,50 @@
{
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_Node_t* 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 )];
+ instruction = graph->GetNodeLastInstr( node_num )
+ - graph->GetNodeFirstInstr( node_num ) + 1;
+
+ // set out vector for each instruction
+ for( index = 0; index < instruction; index++ ) {
+ if( instr[index].m_inlen + instr[index].m_outlen == 0
+ && ( 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
@@ -1103,8 +1093,8 @@
#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;
@@ -1114,8 +1104,7 @@
* Function checkes data flow for 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_MapVector_t *invector, // end node incoming data flow vector
vf_Context_t *ctex) // verifier context
{
bool copy;
@@ -1128,23 +1117,21 @@
}
// 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 ) {
- 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_Node_t* 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
@@ -1154,32 +1141,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;
}
}
@@ -1201,8 +1189,8 @@
vf_Graph_t *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_Node_t* node = graph->GetNode( node_num );
+ if( VF_TYPE_NODE_END_ENTRY == node->m_type )
{
return VER_OK;
}
@@ -1237,11 +1225,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;
@@ -1254,9 +1240,7 @@
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 );
@@ -1274,9 +1258,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
@@ -1311,20 +1293,19 @@
} // 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
+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_MapEntry_t *invector;
vf_MapVector_t *vector;
// get method values
@@ -1333,6 +1314,7 @@
// alloc memory for vector structure
vector = (vf_MapVector_t*)ctex->m_graph->AllocMemory( sizeof(vf_MapVector_t) );
+
// alloc memory for stack vector
if( maxstack ) {
vector->m_maxstack = (unsigned short)maxstack;
@@ -1349,19 +1331,31 @@
// get method signature
const char *descr = method_get_descriptor( ctex->m_method );
- // get method vectors
+ // get the end node IN vector
+ vf_MapVector_t* p_outvector =
+ 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;
@@ -1372,7 +1366,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;
@@ -1380,7 +1374,6 @@
}
vector->m_number = (unsigned short)index;
- // FIXME - need set end entry vector
return vector;
} // vf_create_method_begin_vector
@@ -1399,7 +1392,7 @@
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 ) {
@@ -1442,8 +1435,8 @@
// enumerate graph
vf_enumerate_graph_node( ctex );
- // get begin vector
- vf_MapVector_t *begin = vf_create_method_begin_vector( ctex );
+ // get a start vector
+ vf_MapVector_t *start = 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,
@@ -1454,14 +1447,14 @@
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;
}
Index: vm/doc/doc.properties
===================================================================
--- vm/doc/doc.properties (revision 501435)
+++ vm/doc/doc.properties (working copy)
@@ -16,7 +16,7 @@
# Set absolute paths below
doc.dir=${basedir}
doc.suffix=
-classlib.dir=${basedir}/../../../working_classlib
+classlib.dir=${basedir}/../../../../classlib/trunk
classlib.doc.dir=${classlib.dir}/doc