Пример #1
0
/**
 * Link primary body blocks to exception handler blocks as follows:
 * 1. For each block in the body, traverse from the innermost to
 *    outermost exception handler that includes the block.  For
 *    catch handlers, add an edge to each handler entry point. For
 *    fault handlers, add an edge to the fault handler and stop.
 * 2. For each fault handler block ending in Unwind, find the EH
 *    entry for the funclet, then traverse outwards starting from the
 *    next outermost.  Add any catch edges found, and stop at the first
 *    enclosing fault funclet, as in step 1.
 * The resulting linkage reflects exception control-flow; fault funclets
 * unconditionally handle any exception in their protected region, so they
 * "dominate" outer-more handlers.
 */
void GraphBuilder::linkExBlocks() {
  // For every block, add edges to reachable fault and catch handlers.
  for (LinearBlocks i = linearBlocks(m_graph); !i.empty(); ) {
    Block* b = i.popFront();
    assert(m_func->findEH(offset(b->start)) == m_func->findEH(offset(b->last)));
    Offset off = offset(b->start);
    const EHEnt* eh = m_func->findEH(off);
    if (eh != nullptr) {
      assert(eh->m_base <= off && off < eh->m_past);
      // the innermost exception handler is reachable from b
      b->exn = at(eh->m_handler);
    }
  }
}
Пример #2
0
/**
 * Link primary body blocks to exception handler blocks as follows:
 * 1. For each block in the body, traverse from the innermost to
 *    outermost exception handler that includes the block.  For
 *    catch handlers, add an edge to each handler entry point. For
 *    fault handlers, add an edge to the fault handler and stop.
 * 2. For each fault handler block ending in Unwind, find the EH
 *    entry for the funclet, then traverse outwards starting from the
 *    next outermost.  Add any catch edges found, and stop at the first
 *    enclosing fault funclet, as in step 1.
 * The resulting linkage reflects exception control-flow; fault funclets
 * unconditionally handle any exception in their protected region, so they
 * "dominate" outer-more handlers.
 */
void GraphBuilder::linkExBlocks() {
  const Func::EHEntVec& ehtab = m_func->ehtab();
  // For every block, add edges to reachable fault and catch handlers.
  for (LinearBlocks i = linearBlocks(m_graph); !i.empty(); ) {
    Block* b = i.popFront();
    assert(m_func->findEH(offset(b->start)) == m_func->findEH(offset(b->last)));
    Offset off = offset(b->start);
    int exn_index = 0;
    for (const EHEnt* eh = m_func->findEH(off); eh != 0; ) {
      assert(eh->m_base <= off && off < eh->m_past);
      if (eh->m_type == EHEnt::Type::Catch) {
        // each catch block is reachable from b
        for (Range<EHEnt::CatchVec> j(eh->m_catches); !j.empty(); ) {
          exns(b)[exn_index++] = at(j.popFront().second);
        }
        eh = nextOuter(ehtab, eh);
      } else {
        // this is the innermost fault funclet reachable from b.
        exns(b)[exn_index++] = at(eh->m_fault);
        break;
      }
    }
    if (Op(*b->last) == OpUnwind) {
      // We're in a fault funclet.  Find which one, then add edges
      // to reachable catches and the enclosing fault funclet, if any.
      const EHEnt* eh = findFunclet(ehtab, offset(b->last));
      eh = nextOuter(ehtab, eh);
      while (eh) {
        if (eh->m_type == EHEnt::Type::Catch) {
          // each catch target for eh is reachable from b
          for (Range<EHEnt::CatchVec> j(eh->m_catches); !j.empty(); ) {
            exns(b)[exn_index++] = at(j.popFront().second);
          }
          eh = nextOuter(ehtab, eh);
        } else {
          // eh is the innermost fault funclet reachable from b.
          exns(b)[exn_index++] = at(eh->m_fault);
          break;
        }
      }
    }
  }
}
Пример #3
0
bool ProfData::anyBlockEndsAt(const Func* func, Offset offset) {
  auto const mapIt = m_blockEndOffsets.find(func->getFuncId());
  if (mapIt != end(m_blockEndOffsets)) {
    return mapIt->second.count(offset);
  }

  using namespace Verifier;

  Arena arena;
  GraphBuilder builder{arena, func};
  auto cfg = builder.build();
  auto& offsets = m_blockEndOffsets[func->getFuncId()];

  for (LinearBlocks blocks = linearBlocks(cfg); !blocks.empty(); ) {
    auto last = blocks.popFront()->last - func->unit()->entry();
    offsets.insert(last);
  }

  return offsets.count(offset);
}
Пример #4
0
Файл: func.cpp Проект: BwRy/hhvm
bool Func::anyBlockEndsAt(Offset off) const {
  assert(JIT::Translator::WriteLease().amOwner());
  // The empty() check relies on a Func's bytecode always being nonempty
  assert(base() != past());
  if (m_shared->m_blockEnds.empty()) {
    using namespace Verifier;

    Arena arena;
    GraphBuilder builder{arena, this};
    Graph* cfg = builder.build();

    for (LinearBlocks blocks = linearBlocks(cfg); !blocks.empty(); ) {
      auto last = blocks.popFront()->last - m_unit->entry();
      m_shared->m_blockEnds.insert(last);
    }

    assert(!m_shared->m_blockEnds.empty());
  }

  return m_shared->m_blockEnds.count(off) != 0;
}
Пример #5
0
void printGml(const Unit* unit) {
  string filename = unit->md5().toString() + ".gml";
  FILE* file = fopen(filename.c_str(), "w");
  if (!file) {
    std::cerr << "Couldn't open GML output file " << filename << std::endl;
    return;
  }
  int nextid = 1;
  fprintf(file, "graph [\n"
                "  hierarchic 1\n"
                "  directed 1\n");
  for (AllFuncs i(unit); !i.empty(); ) {
    const Func* func = i.popFront();
    Arena scratch;
    GraphBuilder builder(scratch, func);
    const Graph* g = builder.build();
    int gid = nextid++;
    fprintf(file, "node [ isGroup 1 id %d ]\n", gid);
    // nodes
    for (LinearBlocks j = linearBlocks(g); !j.empty();) {
      const Block* b = j.popFront();
      std::stringstream strbuf;
      unit->prettyPrint(strbuf,
                        Unit::PrintOpts().range(unit->offsetOf(b->start),
                                                unit->offsetOf(b->end)));
      std::string code = strbuf.str();
      for (int i = 0, n = code.size(); i < n; ++i) {
        if (code[i] == '"') code[i] = '\'';
      }
      fprintf(file, "  node [ id %d gid %d\n"
                    "    graphics [ type \"roundrectangle\" ]"
                    "    LabelGraphics ["
                    "      anchor \"e\""
                    "      alignment \"left\""
                    "      fontName \"Consolas\"\n"
                    "      text \"%s\"\n"
                    "    ]\n"
                    "  ]\n",
              nextid + b->id, gid, code.c_str());
    }
    // edges
    for (LinearBlocks j = linearBlocks(g); !j.empty();) {
      const Block* b = j.popFront();
      for (BlockPtrRange k = succBlocks(b); !k.empty();) {
        const Block* s = k.popFront();
        fprintf(file, "  edge [ source %d target %d ]\n",
                nextid + b->id, nextid + s->id);
      }
      for (BlockPtrRange k = exnBlocks(g, b); !k.empty();) {
        const Block* s = k.popFront();
        fprintf(file, "  edge [ source %d target %d"
                      "    graphics [ style \"dotted\" ]"
                      "  ]\n",
                nextid + b->id, nextid + s->id);
      }
    }
    nextid += g->block_count + 1;
  }
  fprintf(file, "]\n");
  fclose(file);
}