/** * Check if a visibility/accessibility change would turn a method referenced * in a callee to virtual methods as they are inlined into the caller. * That is, once a callee is inlined we need to ensure that everything that was * referenced by a callee is visible and accessible in the caller context. * This step would not be needed if we changed all private instance to static. */ bool MultiMethodInliner::create_vmethod(DexInstruction* insn) { auto opcode = insn->opcode(); if (opcode == OPCODE_INVOKE_DIRECT || opcode == OPCODE_INVOKE_DIRECT_RANGE) { auto method = static_cast<DexOpcodeMethod*>(insn)->get_method(); method = resolver(method, MethodSearch::Direct); if (method == nullptr) { info.need_vmethod++; return true; } always_assert(method->is_def()); if (is_init(method)) { if (!method->is_concrete() && !is_public(method)) { info.non_pub_ctor++; return true; } // concrete ctors we can handle because they stay invoke_direct return false; } info.need_vmethod++; return true; } return false; }
// Check that visibility / accessibility changes to the current method // won't need to change a referenced method into a virtual or static one. bool gather_invoked_methods_that_prevent_relocation( const DexMethod* method, std::unordered_set<DexMethodRef*>* methods_preventing_relocation) { auto code = method->get_code(); always_assert(code); bool can_relocate = true; for (const auto& mie : InstructionIterable(code)) { auto insn = mie.insn; auto opcode = insn->opcode(); if (is_invoke(opcode)) { auto meth = resolve_method(insn->get_method(), opcode_to_search(insn)); if (!meth && opcode == OPCODE_INVOKE_VIRTUAL && unknown_virtuals::is_method_known_to_be_public(insn->get_method())) { continue; } if (meth) { always_assert(meth->is_def()); if (meth->is_external() && !is_public(meth)) { meth = nullptr; } else if (opcode == OPCODE_INVOKE_DIRECT && !is_init(meth)) { meth = nullptr; } } if (!meth) { can_relocate = false; if (!methods_preventing_relocation) { break; } methods_preventing_relocation->emplace(insn->get_method()); } } } return can_relocate; }
void bparse_test( FILE *FH ) { char *s; size_t bd_sz = 0, i; struct bdeque **bd=xmalloc(bd_sz), /* Array of bdeque pointers */ *deque; while ( !feof(FH) ) { /* Get a line from the file */ s=b_gets(FH,INPUT_BLOCKSIZE); /* Remove comments */ strtrunc(s,comment_chars); /* Remove trailing new line */ chomp(s); /* Tokenize line and load into a deque */ deque = blex(s); if ( bdeque_count( deque ) > 0 ) { /* Grow the bdeque pointer array by one and append the new deque to the end */ struct bdeque **temp = xrealloc(bd,sizeof(*bd)*(++bd_sz)); bd = temp; bd[bd_sz-1] = deque; } } printf("<<DEQUE PRINT>>\n"); /* Print the bdeques */ for (i=0; i<bd_sz; i++) bdeque_print(bd[i]); printf("<<END DEQUE PRINT>>\n"); for (i=0; i<bd_sz; i++) { struct bdeque *deque = bd[i], *dupdeque = bdeque_create(); struct d_elem *node = deque->head; /* Keep track of operation count. If the line isn't 'done' and we can't do operations on it, we don't want to loop on it forever */ unsigned int ops = 0; while ( node != NULL ) { struct d_elem *retnode = NULL; // Node returned by the current operation int def = is_def(*node->var->value); if ( def != -1 ) { if ( defs[def].operands == 2 ) { retnode = defs[def].op( node->prev, node->next ); // Perform the binary operation of the current defined operator and place the result into retnode. //bdeque_npush( dupdeque, defs[def].op( node->prev, node->next ) ); // FIXME: I don't put my return value back into the deque. } else if ( defs[def].operands == 1 ) { //struct d_elem *retval = defs[def].op( node->next ); retnode = defs[def].op( node->next ); // Perform the unary operation of the current defined operator and place the result into retnode. //defs[def].op( node->next ); //if ( retval != NULL ) // bdeque_npush( dupdeque, retval ); } else if ( defs[def].operands == 0 ) { defs[def].op( node->next ); } else { bdeque_npush( dupdeque, d_elem_copy(node) ); } } //else { //bdeque_npush( dupdeque, d_elem_copy(node) ); //} /* int def = is_def(*node->var->value); if ( def != -1 ) { if ( defs[def].operands == 1 ) b_PRINT( defs[def].op( node->next ) ); else if ( defs[def].operands == 2 ) b_PRINT( defs[def].op( node->prev, node->next ) ); } */ if ( node->next == NULL ) break; //else if ( node->next->prev == node ) if ( retnode != NULL ) { } node = node->next; } bdeque_print( dupdeque ); } }