bool Emitter::needs_excessive_magic(PerlJIT::AST::Op *ast) { std::deque<Term *> nodes(1, ast); while (nodes.size()) { Term *node = nodes.front(); nodes.pop_front(); if ((node->get_type() == pj_ttype_lexical || node->get_type() == pj_ttype_variabledeclaration) && node->get_value_type()->is_opaque()) return true; if (node->get_type() != pj_ttype_op) continue; Op *op = static_cast<Op *>(node); bool known = Jittable_Ops.find(op->get_op_type()) != Jittable_Ops.end(); if (!known || !op->may_have_explicit_overload()) continue; std::vector<Term *> kids = node->get_kids(); nodes.insert(nodes.end(), kids.begin(), kids.end()); } return false; }
bool Emitter::is_jittable(PerlJIT::AST::Term *ast) { switch (ast->get_type()) { case pj_ttype_constant: case pj_ttype_lexical: case pj_ttype_variabledeclaration: return true; case pj_ttype_optree: return false; case pj_ttype_statement: return is_jittable(static_cast<PerlJIT::AST::Statement *>(ast)->kids[0]); case pj_ttype_statementsequence: { std::vector<Term *> all = ast->get_kids(); unsigned int jittable = 0; for (size_t i = 0, max = all.size(); i < max; ++i) jittable += is_jittable(all[i]); // TODO arbitrary threshold, it's probably better to look for // long stretches of JITtable ops return jittable * 2 >= all.size(); } case pj_ttype_op: { Op *op = static_cast<Op *>(ast); bool known = Jittable_Ops.find(op->get_op_type()) != Jittable_Ops.end(); if (!known) return false; if (op->may_have_explicit_overload()) return true; if (op->op_class() == pj_opc_binop && static_cast<Binop *>(op)->is_synthesized_assignment()) return is_jittable(op->kids[1]); return !needs_excessive_magic(op); } default: return false; } }