int is_prog(t_list *list, int max_elem) { int *index; int *coords; struct termios term; char *buf; char buffer[2048]; if (tgetent(buffer, getenv("TERM")) < 1) return (-1); index = init_prog(&term, list, max_elem, &coords); while (1) { buf = init_read(list, index); if (buf[0] == 27 && buf[1] == 0 && buf[2] == 0) is_escape(term); else if (buf[0] == 27 && buf[1] == 91 && buf[2] != 51) coords = is_arrow(list, buf, index, coords); else if ((buf[0] == 127 && buf[1] == 0 && buf[2] == 0) || (buf[0] == 27 && buf[1] == 91 && buf[2] == 51)) coords = is_del(&list, term, index, coords); else if (buf[0] == 10 && buf[1] == 0 && buf[2] == 0) is_return(term, list); else if (buf[0] == 32 && buf[1] == 0 && buf[2] == 0) coords = is_space(list, index, coords); } return (0); }
/** * Analyze opcodes in the callee to see if they are problematic for inlining. */ bool MultiMethodInliner::cannot_inline_opcodes(DexMethod* callee) { int ret_count = 0; auto code = callee->get_code(); uint16_t temp_regs = static_cast<uint16_t>(code->get_registers_size() - code->get_ins_size()); for (auto insn : callee->get_code()->get_instructions()) { if (create_vmethod(insn)) return true; if (is_invoke_super(insn)) return true; if (writes_ins_reg(insn, temp_regs)) return true; if (unknown_virtual(insn, callee)) return true; if (unknown_field(insn, callee)) return true; if (insn->opcode() == OPCODE_THROW) { info.throws++; return true; } if (insn->opcode() == FOPCODE_FILLED_ARRAY) { info.array_data++; return true; } if (is_return(insn->opcode())) ret_count++; } // no callees that have more than a return statement (normally one, the // way dx generates code). // That allows us to make a simple inline strategy where we don't have to // worry about creating branches from the multiple returns to the main code if (ret_count > 1) { info.multi_ret++; return true; } return false; }
TEST_F(PreVerify, testArrayDataInCaller) { auto cls = find_class_named( classes, "Lcom/facebook/redexinline/InlineTest;"); auto m = find_vmethod_named(*cls, "testArrayDataInCaller"); // check that the callee indeed has a non-terminal if, which will exercise // the inliner code path that searches for fopcodes in the caller auto callee = find_invoke(m, OPCODE_INVOKE_DIRECT, "calleeWithIf"); auto insns = callee->get_method()->get_code()->get_instructions(); auto ret_it = std::find_if(insns.begin(), insns.end(), [&](DexInstruction* insn) { return is_return(insn->opcode()); }); ASSERT_NE(ret_it, insns.end()); auto last_insn = m->get_code()->get_instructions().back(); ASSERT_EQ(last_insn->opcode(), FOPCODE_FILLED_ARRAY); }
void get_key_pressed(t_select *params) { char *key; key = ft_strnew(4); while (read(0, key, 3)) { if (is_escape(key)) break ; else if (is_space(key)) space_key_pressed(params); else if (is_return(key)) return_key_pressed(params); else if (is_arrow(key)) arrow_key_pressed(key[2] - 64, params); ft_bzero(key, 4); } }
// check that the only possible location of a return statement // is the last statement of the code block, and that the return // statement has to be there void check_return_location(Function_blockImpl *p) { list<Stat_ptr>::iterator iter; bool go = false; for(iter = p->m_stat_list->begin(); iter != p->m_stat_list->end(); ++iter) { if (hasFound) { this->t_error(ret_misplaced_err, (*iter)->m_attribute); } else if(is_return(*iter)) { hasFound = true; } } if(!go) { this->t_error(ret_missing_err, p->m_attribute); } }
static int check_key(t_elem **list, struct termios *backup, char *buf) { int key; if ((key = is_return(buf))) { ft_strdel(&buf); handle_rtn(*list, backup); exit(0); } else if ((key = is_del(buf))) { if (handle_del(list)) return (-1); } else if ((key = is_arrow(buf))) handle_arrow(*list, key); else if ((key = is_space(buf))) handle_space(*list); else return (0); return (key); }
char *get_token(char *lexeme , int mode){ char *token=(char*)calloc(strlen(lexeme)+50,sizeof(char)); //printf("Getting token\n"); if(is_long(lexeme)){ sprintf(token,"%d",LONG); } else if(is_static(lexeme)){ sprintf(token,"%d",STATIC); } else if(is_union(lexeme)){ sprintf(token,"%d",UNION); } else if(is_default(lexeme)){ sprintf(token,"%d",DEFAULT); } else if(is_break(lexeme)){ sprintf(token,"%d",BREAK); } else if(is_case(lexeme)){ sprintf(token,"%d",CASE); } else if(is_continue(lexeme)){ sprintf(token,"%d",CONTINUE); } else if(is_goto(lexeme)){ sprintf(token,"%d",GOTO); } else if(is_struct(lexeme)){ sprintf(token,"%d",STRUCT); } else if(is_const(lexeme)){ sprintf(token,"%d",CONST); } else if(is_void(lexeme)){ sprintf(token,"%d",VOID); } else if(is_switch(lexeme)){ sprintf(token,"%d",SWITCH); } else if(is_for(lexeme)){ sprintf(token,"%d",FOR); } else if(is_while(lexeme)){ sprintf(token,"%d",WHILE); } else if(is_do(lexeme)){ sprintf(token,"%d",DO); } else if(is_return(lexeme)){ sprintf(token,"%d",RETURN); } else if(is_bool(lexeme)){ sprintf(token,"%d",BOOL); } else if(is_char(lexeme)){ sprintf(token,"%d",CHAR); } else if(is_signed(lexeme)){ sprintf(token,"%d",SIGNED); } else if(is_unsigned(lexeme)){ sprintf(token,"%d",UNSIGNED); } else if(is_short(lexeme)){ sprintf(token,"%d",SHORT); } else if(is_int(lexeme)){ sprintf(token,"%d",INT); } else if(is_float(lexeme)){ sprintf(token,"%d",FLOAT); } else if(is_double(lexeme)){ sprintf(token,"%d",DOUBLE); } else if(is_l_square(lexeme)){ sprintf(token,"%d",L_SQUARE); } else if(is_r_square(lexeme)){ sprintf(token,"%d",R_SQUARE); } else if(is_l_paraen(lexeme)){ sprintf(token,"%d",L_PARAEN); } else if(is_r_paraen(lexeme)){ sprintf(token,"%d",R_PARAEN); } else if(is_l_cbrace(lexeme)){ sprintf(token,"%d",L_CBRACE); } else if(is_r_cbrace(lexeme)){ sprintf(token,"%d",R_CBRACE); } else if(is_comma(lexeme)){ sprintf(token,"%d",COMMA); } else if(is_semicol(lexeme)){ sprintf(token,"%d",SEMICOL); } else if(is_eq_eq(lexeme)){ sprintf(token,"%d",EQ_EQ); } else if(is_lesser(lexeme)){ sprintf(token,"%d",LESSER); } else if(is_less_eq(lexeme)){ sprintf(token,"%d",LESS_EQ); } else if(is_div(lexeme)){ sprintf(token,"%d",DIV); } else if(is_greater(lexeme)){ sprintf(token,"%d",GREATER); } else if(is_great_eq(lexeme)){ sprintf(token,"%d",GREAT_EQ); } else if(is_plus_eq(lexeme)){ sprintf(token,"%d",PLUS_EQ); } else if(is_minus_eq(lexeme)){ sprintf(token,"%d",MINUS_EQ); } else if(is_div_eq(lexeme)){ sprintf(token,"%d",DIV_EQ); } else if(is_mult_eq(lexeme)){ sprintf(token,"%d",MULT_EQ); } else if(is_minus_minus(lexeme)){ sprintf(token,"%d",MINUS_MINUS); } else if(is_plus_plus(lexeme)){ sprintf(token,"%d",PLUS_PLUS); } else if(is_percent(lexeme)){ sprintf(token,"%d",PERCENT); } else if(is_div(lexeme)){ sprintf(token,"%d",DIV); } else if(is_mult(lexeme)){ sprintf(token,"%d",MULT); } else if(is_minus(lexeme)){ sprintf(token,"%d",MINUS); } else if(is_plus(lexeme)){ sprintf(token,"%d",PLUS); } else if(is_int_const(lexeme)){ printf("int"); sprintf(token,"%d\t%s",INT_CONST,lexeme); } else if(is_flo_const(lexeme)){ printf("float"); sprintf(token,"%d\t%s",FLO_CONST,lexeme); } else if(is_comment_start(lexeme)){ sprintf(token,"$start"); } else if(is_comment_end(lexeme)){ sprintf(token,"$end"); } else if(is_identifier(lexeme)){ printf("Identifier"); if(mode==1) ht_set( symboltable, lexeme, "1"); sprintf(token,"%d\t%s",IDNTIFIER,lexeme); } else sprintf(token,"%d",NOTOK); return token; }
void MethodTransform::build_cfg() { // Find the block boundaries std::unordered_map<MethodItemEntry*, std::vector<Block*>> branch_to_targets; std::vector<std::pair<DexTryItem*, Block*>> try_ends; std::unordered_map<DexTryItem*, std::vector<Block*>> try_catches; size_t id = 0; bool in_try = false; m_blocks.emplace_back(new Block(id++)); m_blocks.back()->m_begin = m_fmethod->begin(); // The first block can be a branch target. auto begin = m_fmethod->begin(); if (begin->type == MFLOW_TARGET) { branch_to_targets[begin->target->src].push_back(m_blocks.back()); } for (auto it = m_fmethod->begin(); it != m_fmethod->end(); ++it) { if (it->type == MFLOW_TRY) { if (it->tentry->type == TRY_START) { in_try = true; } else if (it->tentry->type == TRY_END) { in_try = false; } } if (!end_of_block(m_fmethod, it, in_try)) { continue; } // End the current block. auto next = std::next(it); if (next == m_fmethod->end()) { m_blocks.back()->m_end = next; continue; } // Start a new block at the next MethodItem. auto next_block = new Block(id++); if (next->type == MFLOW_OPCODE) { insert_fallthrough(m_fmethod, &*next); next = std::next(it); } m_blocks.back()->m_end = next; next_block->m_begin = next; m_blocks.emplace_back(next_block); // Record branch targets to add edges in the next pass. if (next->type == MFLOW_TARGET) { branch_to_targets[next->target->src].push_back(next_block); continue; } // Record try/catch blocks to add edges in the next pass. if (next->type == MFLOW_TRY) { if (next->tentry->type == TRY_END) { try_ends.emplace_back(next->tentry->tentry, next_block); } else if (next->tentry->type == TRY_CATCH) { try_catches[next->tentry->tentry].push_back(next_block); } } } // Link the blocks together with edges for (auto it = m_blocks.begin(); it != m_blocks.end(); ++it) { // Set outgoing edge if last MIE falls through auto lastmei = (*it)->rbegin(); bool fallthrough = true; if (lastmei->type == MFLOW_OPCODE) { auto lastop = lastmei->insn->opcode(); if (is_goto(lastop) || is_conditional_branch(lastop) || is_multi_branch(lastop)) { fallthrough = !is_goto(lastop); auto const& targets = branch_to_targets[&*lastmei]; for (auto target : targets) { (*it)->m_succs.push_back(target); target->m_preds.push_back(*it); } } else if (is_return(lastop) || lastop == OPCODE_THROW) { fallthrough = false; } } if (fallthrough && std::next(it) != m_blocks.end()) { Block* next = *std::next(it); (*it)->m_succs.push_back(next); next->m_preds.push_back(*it); } } /* * Now add the catch edges. Every block inside a try-start/try-end region * gets an edge to every catch block. This simplifies dataflow analysis * since you can always get the exception state by looking at successors, * without any additional analysis. * * NB: This algorithm assumes that a try-start/try-end region will consist of * sequentially-numbered blocks, which is guaranteed because catch regions * are contiguous in the bytecode, and we generate blocks in bytecode order. */ for (auto tep : try_ends) { auto tryitem = tep.first; auto tryendblock = tep.second; size_t bid = tryendblock->id(); always_assert(bid > 0); --bid; while (true) { auto block = m_blocks[bid]; if (ends_with_may_throw(block)) { auto& catches = try_catches[tryitem]; for (auto catchblock : catches) { block->m_succs.push_back(catchblock); catchblock->m_preds.push_back(block); } } auto begin = block->begin(); if (begin->type == MFLOW_TRY) { auto tentry = begin->tentry; if (tentry->type == TRY_START && tentry->tentry == tryitem) { break; } } always_assert_log(bid > 0, "No beginning of try region found"); --bid; } } TRACE(CFG, 5, "%s\n", show(m_method).c_str()); TRACE(CFG, 5, "%s", show(m_blocks).c_str()); }
bool MethodTransform::inline_16regs(InlineContext& context, DexMethod *callee, DexOpcodeMethod *invoke) { TRACE(INL, 2, "caller: %s\ncallee: %s\n", SHOW(context.caller), SHOW(callee)); auto caller = context.caller; MethodTransformer mtcaller(caller); MethodTransformer mtcallee(callee); auto fcaller = mtcaller->m_fmethod; auto fcallee = mtcallee->m_fmethod; auto callee_code = callee->get_code(); auto temps_needed = callee_code->get_registers_size() - callee_code->get_ins_size(); uint16_t newregs = caller->get_code()->get_registers_size(); if (context.inline_regs_used < temps_needed) { newregs = newregs + temps_needed - context.inline_regs_used; if (newregs > 16) return false; remap_caller_regs(caller, fcaller, newregs); context.inline_regs_used = temps_needed; } RegMap callee_reg_map; build_remap_regs(callee_reg_map, invoke, callee, context.new_tmp_off); auto pos = std::find_if( fcaller->begin(), fcaller->end(), [invoke](const MethodItemEntry& mei) { return mei.type == MFLOW_OPCODE && mei.insn == invoke; }); // find the move-result after the invoke, if any. Must be the first // instruction after the invoke auto move_res = pos; while (move_res++ != fcaller->end() && move_res->type != MFLOW_OPCODE); if (!is_move_result(move_res->insn->opcode())) { move_res = fcaller->end(); } // Skip dbg prologue in callee, we don't need two. auto it = fcallee->begin(); if (it->type == MFLOW_DEBUG && it->dbgop->opcode() == DBG_SET_PROLOGUE_END) { ++it; } // find the last position entry before the invoke. // we need to decrement the reverse iterator because it gets constructed // as pointing to the element preceding pos auto position_it = --FatMethod::reverse_iterator(pos); while (++position_it != fcaller->rend() && position_it->type != MFLOW_POSITION); auto invoke_position = position_it == fcaller->rend() ? nullptr : position_it->pos; if (invoke_position != nullptr) { TRACE(MTRANS, 5, "Inlining call at %s:%d\n", invoke_position->file->c_str(), invoke_position->line); } // Copy the callee up to the return. Everything else we push at the end // of the caller auto splice = MethodSplicer(callee_reg_map, invoke_position); auto ret_it = std::find_if(it, fcallee->end(), [](const MethodItemEntry& mei) { return mei.type == MFLOW_OPCODE && is_return(mei.insn->opcode()); }); splice(fcaller, pos, it, ret_it); if (move_res != fcaller->end()) { std::unique_ptr<DexInstruction> ret_insn(ret_it->insn->clone()); remap_registers(ret_insn.get(), callee_reg_map); DexInstruction* move = move_result(ret_insn.get(), move_res->insn); auto move_mei = new MethodItemEntry(move); fcaller->insert(pos, *move_mei); } // ensure that the caller's code after the inlined method retain their // original position if (invoke_position != nullptr) { fcaller->insert(pos, *(new MethodItemEntry(invoke_position))); } // remove invoke fcaller->erase_and_dispose(pos, FatMethodDisposer()); // remove move_result if (move_res != fcaller->end()) { fcaller->erase_and_dispose(move_res, FatMethodDisposer()); } // Copy the opcodes in the callee after the return and put them at the end of // the caller. splice(fcaller, fcaller->end(), std::next(ret_it), fcallee->end()); // adjust method header caller->get_code()->set_registers_size(newregs); caller->get_code()->set_outs_size( std::max(callee->get_code()->get_outs_size(), caller->get_code()->get_outs_size())); return true; }
Term NextAction::result() { assert(is_return()); return value; }