示例#1
0
void UnitEmitter::initMain(int line1, int line2) {
  assertx(m_fes.size() == 0);
  StringData* name = staticEmptyString();
  FuncEmitter* pseudomain = newFuncEmitter(name);
  Attr attrs = AttrMayUseVV;
  pseudomain->init(line1, line2, 0, attrs, false, name);
}
示例#2
0
ExnTreeInfo build_exn_tree(const FuncEmitter& fe,
                           php::Func& func,
                           FindBlock findBlock) {
  ExnTreeInfo ret;

  uint32_t nextExnNode = 0;

  for (auto& eh : fe.ehtab()) {
    auto node = folly::make_unique<php::ExnNode>();
    node->id = nextExnNode++;
    node->parent = nullptr;

    switch (eh.m_type) {
    case EHEnt::Type::Fault:
      {
        auto const fault = findBlock(eh.m_fault);
        assert(ret.funcletNodes[fault] == nullptr);
        ret.funcletNodes[fault] = borrow(node);

        /*
         * We know the block for this offset starts a fault funclet,
         * but we won't know its extents until we've built the cfg and
         * can look at the control flow in the funclet.  Set the block
         * type to Fault for now, but we won't propagate the value to
         * the rest of the funclet blocks until find_fault_funclets.
         */
        fault->kind = php::Block::Kind::Fault;
        node->info = php::FaultRegion { fault, eh.m_iterId, eh.m_itRef };
      }
      break;
    case EHEnt::Type::Catch:
      {
        auto treg = php::TryRegion {};
        for (auto& centry : eh.m_catches) {
          auto const catchBlk = findBlock(centry.second);
          catchBlk->kind = php::Block::Kind::CatchEntry;
          treg.catches.emplace_back(
            fe.ue().lookupLitstr(centry.first),
            catchBlk
          );
        }
        node->info = treg;
      }
      break;
    }

    ret.ehMap[&eh] = borrow(node);

    if (eh.m_parentIndex != -1) {
      auto it = ret.ehMap.find(&fe.ehtab()[eh.m_parentIndex]);
      assert(it != end(ret.ehMap));
      node->parent = it->second;
      it->second->children.emplace_back(std::move(node));
    } else {
      func.exnNodes.emplace_back(std::move(node));
    }
  }

  return ret;
}
示例#3
0
文件: parse.cpp 项目: aloiret/hhvm
void add_frame_variables(php::Func& func, const FuncEmitter& fe) {
  for (auto& param : fe.params) {
    func.params.push_back(
      php::Param {
        param.defaultValue,
        NoBlockId,
        param.typeConstraint,
        param.userType,
        param.phpCode,
        param.userAttributes,
        param.builtinType,
        param.byRef,
        param.byRef,
        param.variadic
      }
    );
  }

  func.locals.reserve(fe.numLocals());
  for (LocalId id = 0; id < fe.numLocals(); ++id) {
    func.locals.push_back({nullptr, id, false});
  }
  for (auto& kv : fe.localNameMap()) {
    func.locals[kv.second].name = kv.first;
  }

  func.numIters = fe.numIterators();

  func.staticLocals.reserve(fe.staticVars.size());
  for (auto& sv : fe.staticVars) {
    func.staticLocals.push_back(
      php::StaticLocalInfo { sv.name, sv.phpCode }
    );
  }
}
示例#4
0
void UnitEmitter::initMain(int line1, int line2) {
  ASSERT(m_fes.size() == 0);
  StringData* name = StringData::GetStaticString("");
  FuncEmitter* pseudomain = newFuncEmitter(name, false);
  Attr attrs = AttrMayUseVV;
  pseudomain->init(line1, line2, 0, attrs, false, name);
}
示例#5
0
文件: emit.cpp 项目: nadanomics/hhvm
void emit_init_func(FuncEmitter& fe, const php::Func& func) {
  fe.init(
    std::get<0>(func.srcInfo.loc),
    std::get<1>(func.srcInfo.loc),
    fe.ue().bcPos(),
    func.attrs,
    func.top,
    func.srcInfo.docComment
  );
}
示例#6
0
文件: parse.cpp 项目: fmarcos83/hhvm
void build_cfg(ParseUnitState& puState,
               php::Func& func,
               const FuncEmitter& fe) {
  auto const blockStarts = findBasicBlocks(fe);

  FTRACE(3, "    blocks are at: {}\n",
    [&]() -> std::string {
      using namespace folly::gen;
      return from(blockStarts)
        | eachTo<std::string>()
        | unsplit<std::string>(" ");
    }()
  );

  std::map<Offset,std::unique_ptr<php::Block>> blockMap;
  auto const bc = fe.ue().bc();

  auto findBlock = [&] (Offset off) {
    auto& ptr = blockMap[off];
    if (!ptr) {
      ptr               = folly::make_unique<php::Block>();
      ptr->id           = func.nextBlockId++;
      ptr->section      = php::Block::Section::Main;
      ptr->exnNode      = nullptr;
    }
    return borrow(ptr);
  };

  auto exnTreeInfo = build_exn_tree(fe, func, findBlock);

  for (auto it = begin(blockStarts);
      boost::next(it) != end(blockStarts);
      ++it) {
    auto const block   = findBlock(*it);
    auto const bcStart = bc + *it;
    auto const bcStop  = bc + *boost::next(it);

    if (auto const eh = findEH(fe.ehtab(), *it)) {
      auto it = exnTreeInfo.ehMap.find(eh);
      assert(it != end(exnTreeInfo.ehMap));
      block->exnNode = it->second;
      add_factored_exits(*block, block->exnNode);
    }

    populate_block(puState, fe, func, *block, bcStart, bcStop, findBlock);
  }

  link_entry_points(func, fe, findBlock);
  find_fault_funclets(exnTreeInfo, func, blockStarts, findBlock);

  for (auto& kv : blockMap) {
    func.blocks.emplace_back(std::move(kv.second));
  }
}
示例#7
0
文件: parse.cpp 项目: fmarcos83/hhvm
void link_entry_points(php::Func& func,
                       const FuncEmitter& fe,
                       FindBlk findBlock) {
  func.dvEntries.resize(fe.params().size());
  for (size_t i = 0, sz = fe.params().size(); i < sz; ++i) {
    if (fe.params()[i].hasDefaultValue()) {
      auto const dv = findBlock(fe.params()[i].funcletOff());
      func.params[i].dvEntryPoint = dv;
      func.dvEntries[i] = dv;
    }
  }
  func.mainEntry = findBlock(fe.base());
}
示例#8
0
文件: parse.cpp 项目: fmarcos83/hhvm
ExnTreeInfo build_exn_tree(const FuncEmitter& fe,
                           php::Func& func,
                           FindBlock findBlock) {
  ExnTreeInfo ret;
  auto nextExnNode = uint32_t{0};

  for (auto& eh : fe.ehtab()) {
    auto node = folly::make_unique<php::ExnNode>();
    node->id = nextExnNode++;
    node->parent = nullptr;

    switch (eh.m_type) {
    case EHEnt::Type::Fault:
      {
        auto const fault = findBlock(eh.m_fault);
        ret.funcletNodes[fault].push_back(borrow(node));
        ret.faultFuncletStarts.insert(eh.m_fault);
        node->info = php::FaultRegion { fault, eh.m_iterId, eh.m_itRef };
      }
      break;
    case EHEnt::Type::Catch:
      {
        auto treg = php::TryRegion {};
        for (auto& centry : eh.m_catches) {
          auto const catchBlk = findBlock(centry.second);
          treg.catches.emplace_back(
            fe.ue().lookupLitstr(centry.first),
            catchBlk
          );
        }
        node->info = treg;
      }
      break;
    }

    ret.ehMap[&eh] = borrow(node);

    if (eh.m_parentIndex != -1) {
      auto it = ret.ehMap.find(&fe.ehtab()[eh.m_parentIndex]);
      assert(it != end(ret.ehMap));
      node->parent = it->second;
      it->second->children.emplace_back(std::move(node));
    } else {
      func.exnNodes.emplace_back(std::move(node));
    }
  }

  ret.faultFuncletStarts.insert(fe.past());

  return ret;
}
示例#9
0
std::unique_ptr<UnitEmitter>
createFatalUnit(StringData* filename, const MD5& md5, FatalOp /*op*/,
                StringData* err) {
  auto ue = std::make_unique<UnitEmitter>(md5);
  ue->m_filepath = filename;
  ue->initMain(1, 1);
  ue->emitOp(OpString);
  ue->emitInt32(ue->mergeLitstr(err));
  ue->emitOp(OpFatal);
  ue->emitByte(static_cast<uint8_t>(FatalOp::Runtime));
  FuncEmitter* fe = ue->getMain();
  fe->maxStackCells = 1;
  // XXX line numbers are bogus
  fe->finish(ue->bcPos(), false);
  ue->recordFunction(fe);
  return ue;
}
示例#10
0
文件: emit.cpp 项目: nadanomics/hhvm
void emit_eh_region(FuncEmitter& fe,
                    borrowed_ptr<const EHRegion> region,
                    const BlockInfo& blockInfo,
                    ParentIndexMap& parentIndexMap) {
  // A region on a single empty block.
  if (region->start == region->past) return;

  auto& eh = fe.addEHEnt();
  eh.m_base = region->start;
  eh.m_past = region->past;
  assert(eh.m_past >= eh.m_base);
  assert(eh.m_base != kInvalidOffset && eh.m_past != kInvalidOffset);

  if (region->parent) {
    auto parentIt = parentIndexMap.find(region->parent);
    assert(parentIt != end(parentIndexMap));
    eh.m_parentIndex = parentIt->second;
  } else {
    eh.m_parentIndex = -1;
  }
  parentIndexMap[region] = fe.ehtab.size() - 1;

  match<void>(
    region->node->info,
    [&] (const php::TryRegion& tr) {
      eh.m_type = EHEnt::Type::Catch;
      for (auto& c : tr.catches) {
        eh.m_catches.emplace_back(
          fe.ue().mergeLitstr(c.first),
          blockInfo[c.second->id].offset
        );
      }
      eh.m_fault = kInvalidOffset;
      eh.m_iterId = -1;
      eh.m_itRef = false;
    },
    [&] (const php::FaultRegion& fr) {
      eh.m_type = EHEnt::Type::Fault;
      eh.m_fault = blockInfo[fr.faultEntry->id].offset;
      eh.m_iterId = fr.iterId;
      eh.m_itRef = fr.itRef;
    }
  );
}
示例#11
0
文件: parse.cpp 项目: MatmaRex/hhvm
void add_frame_variables(php::Func& func, const FuncEmitter& fe) {
  for (auto& param : fe.params) {
    func.params.push_back(
      php::Param {
        param.defaultValue,
        nullptr,
        param.typeConstraint,
        param.userType,
        param.phpCode,
        param.userAttributes,
        param.builtinType,
        param.byRef,
        param.variadic
      }
    );
  }

  func.locals.resize(fe.numLocals());
  for (size_t id = 0; id < func.locals.size(); ++id) {
    auto& loc = func.locals[id];
    loc = folly::make_unique<php::Local>();
    loc->id = id;
    loc->name = nullptr;
  }
  for (auto& kv : fe.localNameMap()) {
    func.locals[kv.second]->name = kv.first;
  }

  func.iters.resize(fe.numIterators());
  for (uint32_t i = 0; i < func.iters.size(); ++i) {
    func.iters[i] = folly::make_unique<php::Iter>();
    func.iters[i]->id = i;
  }

  func.staticLocals.reserve(fe.staticVars.size());
  for (auto& sv : fe.staticVars) {
    func.staticLocals.push_back(
      php::StaticLocalInfo { sv.name, sv.phpCode }
    );
  }
}
示例#12
0
文件: emit.cpp 项目: nadanomics/hhvm
void emit_finish_func(const php::Func& func,
                      FuncEmitter& fe,
                      const EmitBcInfo& info) {
  if (info.containsCalls) fe.containsCalls = true;;

  for (auto& fpi : info.fpiRegions) {
    auto& e = fe.addFPIEnt();
    e.m_fpushOff = fpi.fpushOff;
    e.m_fcallOff = fpi.fcallOff;
    e.m_fpOff    = fpi.fpDelta;
  }

  emit_locals_and_params(fe, func, info);
  emit_ehent_tree(fe, func, info);

  fe.userAttributes = func.userAttributes;
  fe.retUserType = func.returnUserType;
  fe.originalFilename = func.originalFilename;
  fe.isClosureBody = func.isClosureBody;
  fe.isAsync = func.isAsync;
  fe.isGenerator = func.isGenerator;
  fe.isPairGenerator = func.isPairGenerator;
  if (func.nativeInfo) {
    fe.returnType = func.nativeInfo->returnType;
  }
  fe.retTypeConstraint = func.retTypeConstraint;

  fe.maxStackCells = info.maxStackDepth +
                     fe.numLocals() +
                     fe.numIterators() * kNumIterCells +
                     info.maxFpiDepth * kNumActRecCells;

  fe.finish(fe.ue().bcPos(), false /* load */);
  fe.ue().recordFunction(&fe);
}
示例#13
0
文件: parse.cpp 项目: MatmaRex/hhvm
std::unique_ptr<php::Func> parse_func(ParseUnitState& puState,
                                      borrowed_ptr<php::Unit> unit,
                                      borrowed_ptr<php::Class> cls,
                                      const FuncEmitter& fe) {
  FTRACE(2, "  func: {}\n",
    fe.name->data() && *fe.name->data() ? fe.name->data() : "pseudomain");

  auto ret             = folly::make_unique<php::Func>();
  ret->name            = fe.name;
  ret->srcInfo         = php::SrcInfo { fe.getLocation(),
                                        fe.docComment };
  ret->unit            = unit;
  ret->cls             = cls;
  ret->nextBlockId     = 0;

  ret->attrs              = static_cast<Attr>(fe.attrs & ~AttrNoOverride);
  ret->userAttributes     = fe.userAttributes;
  ret->returnUserType     = fe.retUserType;
  ret->retTypeConstraint  = fe.retTypeConstraint;
  ret->originalFilename   = fe.originalFilename;

  ret->top                = fe.top;
  ret->isClosureBody      = fe.isClosureBody;
  ret->isAsync            = fe.isAsync;
  ret->isGenerator        = fe.isGenerator;
  ret->isPairGenerator    = fe.isPairGenerator;
  ret->isNative           = fe.isNative;

  /*
   * Builtin functions get some extra information.  The returnType flag is only
   * non-folly::none for these, but note that something may be a builtin and
   * still have a folly::none return type.
   */
  if (fe.attrs & AttrBuiltin) {
    ret->nativeInfo             = folly::make_unique<php::NativeInfo>();
    ret->nativeInfo->returnType = fe.returnType;
  }

  add_frame_variables(*ret, fe);
  build_cfg(puState, *ret, fe);

  return ret;
}
示例#14
0
void FuncRepoProxy::GetFuncsStmt
                  ::get(UnitEmitter& ue) {
  RepoTxn txn(m_repo);
  if (!prepared()) {
    std::stringstream ssSelect;
    ssSelect << "SELECT funcSn,preClassId,name,top,extraData "
                "FROM "
             << m_repo.table(m_repoId, "Func")
             << " WHERE unitSn == @unitSn ORDER BY funcSn ASC;";
    txn.prepare(*this, ssSelect.str());
  }
  RepoTxnQuery query(txn, *this);
  query.bindInt64("@unitSn", ue.m_sn);
  do {
    query.step();
    if (query.row()) {
      int funcSn;               /**/ query.getInt(0, funcSn);
      Id preClassId;            /**/ query.getId(1, preClassId);
      StringData* name;         /**/ query.getStaticString(2, name);
      bool top;                 /**/ query.getBool(3, top);
      BlobDecoder extraBlob =   /**/ query.getBlob(4);

      FuncEmitter* fe;
      if (preClassId < 0) {
        fe = ue.newFuncEmitter(name);
      } else {
        PreClassEmitter* pce = ue.pce(preClassId);
        fe = ue.newMethodEmitter(name, pce);
        bool added UNUSED = pce->addMethod(fe);
        assert(added);
      }
      assert(fe->sn() == funcSn);
      fe->top = top;
      fe->serdeMetaData(extraBlob);
      if (!SystemLib::s_inited && !fe->isPseudoMain()) {
        assert(fe->attrs & AttrBuiltin);
        if (preClassId < 0) {
          assert(fe->attrs & AttrPersistent);
          assert(fe->attrs & AttrUnique);
          assert(fe->attrs & AttrSkipFrame);
        }
      }
      fe->setEHTabIsSorted();
      fe->finish(fe->past, true);
      ue.recordFunction(fe);
    }
  } while (!query.done());
  txn.commit();
}
示例#15
0
文件: emit.cpp 项目: Alienfeel/hhvm
void emit_finish_func(const php::Func& func,
                      FuncEmitter& fe,
                      const EmitBcInfo& info) {
  fe.setMaxStackCells(
    info.maxStackDepth + fe.numLocals() +
      info.maxFpiDepth * kNumActRecCells
  );
  if (info.containsCalls) fe.setContainsCalls();

  for (auto& fpi : info.fpiRegions) {
    auto& e = fe.addFPIEnt();
    e.m_fpushOff = fpi.fpushOff;
    e.m_fcallOff = fpi.fcallOff;
    e.m_fpOff    = fpi.fpDelta;
  }

  emit_locals_and_params(fe, func, info);
  emit_ehent_tree(fe, func, info);

  fe.setUserAttributes(func.userAttributes);
  fe.setReturnUserType(func.returnUserType);
  fe.setOriginalFilename(func.originalFilename);
  fe.setIsClosureBody(func.isClosureBody);
  fe.setIsGenerator(func.isGeneratorBody);
  fe.setIsGeneratorFromClosure(func.isGeneratorFromClosure);
  fe.setIsPairGenerator(func.isPairGenerator);
  fe.setGeneratorBodyName(func.generatorBodyName);
  fe.setIsAsync(func.isAsync);

  fe.finish(fe.ue().bcPos(), false /* load */);
  fe.ue().recordFunction(&fe);
}
示例#16
0
文件: parse.cpp 项目: fmarcos83/hhvm
std::unique_ptr<php::Func> parse_func(ParseUnitState& puState,
                                      borrowed_ptr<php::Unit> unit,
                                      borrowed_ptr<php::Class> cls,
                                      const FuncEmitter& fe) {
  FTRACE(2, "  func: {}\n",
    fe.name()->data() && *fe.name()->data() ? fe.name()->data()
                                            : "pseudomain");

  auto ret             = folly::make_unique<php::Func>();
  ret->name            = fe.name();
  ret->srcInfo         = php::SrcInfo { fe.getLocation(),
                                        fe.getDocComment() };
  ret->unit            = unit;
  ret->cls             = cls;
  ret->nextBlockId     = 0;

  ret->attrs                  = fe.attrs();
  ret->userAttributes         = fe.getUserAttributes();
  ret->returnUserType         = fe.returnUserType();
  ret->originalFilename       = fe.originalFilename();

  ret->top                    = fe.top();
  ret->isClosureBody          = fe.isClosureBody();
  ret->isGeneratorBody        = fe.isGenerator();
  ret->isGeneratorFromClosure = fe.isGeneratorFromClosure();
  ret->isPairGenerator        = fe.isPairGenerator();
  ret->isAsync                = fe.isAsync();
  ret->innerGeneratorFunc     = nullptr;
  ret->outerGeneratorFunc     = nullptr;

  /*
   * Generators that aren't inside classes (includes generators from
   * closures) end up with inner generator bodies living as free
   * functions, not on a class.  We track them here to link them after
   * we've finished parsing the whole unit.  parse_methods handles the
   * within-class generator linking cases.
   */
  if (auto const innerName = fe.getGeneratorBodyName()) {
    if (!ret->cls || ret->isClosureBody) {
      puState.generatorsToLink.emplace_back(borrow(ret), innerName);
    }
  }
  if (ret->isGeneratorBody && !cls) {
    always_assert(!puState.innerGenerators.count(ret->name));
    puState.innerGenerators[ret->name] = borrow(ret);
  }

  /*
   * HNI-style native functions get some extra information.
   */
  if (fe.isHNINative()) {
    ret->nativeInfo             = folly::make_unique<php::NativeInfo>();
    ret->nativeInfo->returnType = fe.getReturnType();
  }

  add_frame_variables(*ret, fe);
  build_cfg(puState, *ret, fe);

  return ret;
}
示例#17
0
文件: parse.cpp 项目: aloiret/hhvm
void populate_block(ParseUnitState& puState,
                    const FuncEmitter& fe,
                    php::Func& func,
                    php::Block& blk,
                    PC pc,
                    PC const past,
                    FindBlock findBlock) {
  auto const& ue = fe.ue();

  auto decode_stringvec = [&] {
    auto const vecLen = decode<int32_t>(pc);
    CompactVector<LSString> keys;
    for (auto i = size_t{0}; i < vecLen; ++i) {
      keys.push_back(ue.lookupLitstr(decode<int32_t>(pc)));
    }
    return keys;
  };

  auto decode_switch = [&] (PC opPC) {
    SwitchTab ret;
    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen; ++i) {
      ret.push_back(findBlock(
        opPC + decode<Offset>(pc) - ue.bc()
      )->id);
    }
    return ret;
  };

  auto decode_sswitch = [&] (PC opPC) {
    SSwitchTab ret;

    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen - 1; ++i) {
      auto const id = decode<Id>(pc);
      auto const offset = decode<Offset>(pc);
      ret.emplace_back(ue.lookupLitstr(id),
                       findBlock(opPC + offset - ue.bc())->id);
    }

    // Final case is the default, and must have a litstr id of -1.
    DEBUG_ONLY auto const defId = decode<Id>(pc);
    auto const defOff = decode<Offset>(pc);
    assert(defId == -1);
    ret.emplace_back(nullptr, findBlock(opPC + defOff - ue.bc())->id);
    return ret;
  };

  auto decode_itertab = [&] {
    IterTab ret;
    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen; ++i) {
      auto const kind = static_cast<IterKind>(decode<int32_t>(pc));
      auto const id = decode<int32_t>(pc);
      ret.emplace_back(kind, id);
    }
    return ret;
  };

  auto defcls = [&] (const Bytecode& b) {
    puState.defClsMap[b.DefCls.arg1] = &func;
  };
  auto defclsnop = [&] (const Bytecode& b) {
    puState.defClsMap[b.DefClsNop.arg1] = &func;
  };
  auto createcl = [&] (const Bytecode& b) {
    puState.createClMap[b.CreateCl.arg2].insert(&func);
  };
  auto has_call_unpack = [&] {
    auto const fpi = Func::findFPI(&*fe.fpitab.begin(),
                                   &*fe.fpitab.end(), pc - ue.bc());
    auto const op = peek_op(ue.bc() + fpi->m_fpiEndOff);
    return op == OpFCallArray || op == OpFCallUnpack;
  };

#define IMM_BLA(n)     auto targets = decode_switch(opPC);
#define IMM_SLA(n)     auto targets = decode_sswitch(opPC);
#define IMM_ILA(n)     auto iterTab = decode_itertab();
#define IMM_IVA(n)     auto arg##n = decode_iva(pc);
#define IMM_I64A(n)    auto arg##n = decode<int64_t>(pc);
#define IMM_LA(n)      auto loc##n = [&] {                       \
                         LocalId id = decode_iva(pc);            \
                         always_assert(id < func.locals.size()); \
                         return id;                              \
                       }();
#define IMM_IA(n)      auto iter##n = [&] {                      \
                         IterId id = decode_iva(pc);             \
                         always_assert(id < func.numIters);      \
                         return id;                              \
                       }();
#define IMM_DA(n)      auto dbl##n = decode<double>(pc);
#define IMM_SA(n)      auto str##n = ue.lookupLitstr(decode<Id>(pc));
#define IMM_RATA(n)    auto rat = decodeRAT(ue, pc);
#define IMM_AA(n)      auto arr##n = ue.lookupArray(decode<Id>(pc));
#define IMM_BA(n)      assert(next == past);     \
                       auto target = findBlock(  \
                         opPC + decode<Offset>(pc) - ue.bc())->id;
#define IMM_OA_IMPL(n) subop##n; decode(pc, subop##n);
#define IMM_OA(type)   type IMM_OA_IMPL
#define IMM_VSA(n)     auto keys = decode_stringvec();
#define IMM_KA(n)      auto mkey = make_mkey(func, decode_member_key(pc, &ue));
#define IMM_LAR(n)     auto locrange = [&] {                                 \
                         auto const range = decodeLocalRange(pc);            \
                         always_assert(range.first + range.restCount         \
                                       < func.locals.size());                \
                         return LocalRange { range.first, range.restCount }; \
                       }();

#define IMM_NA
#define IMM_ONE(x)           IMM_##x(1)
#define IMM_TWO(x, y)        IMM_##x(1)          IMM_##y(2)
#define IMM_THREE(x, y, z)   IMM_TWO(x, y)       IMM_##z(3)
#define IMM_FOUR(x, y, z, n) IMM_THREE(x, y, z)  IMM_##n(4)

#define IMM_ARG(which, n)         IMM_NAME_##which(n)
#define IMM_ARG_NA
#define IMM_ARG_ONE(x)            IMM_ARG(x, 1)
#define IMM_ARG_TWO(x, y)         IMM_ARG(x, 1), IMM_ARG(y, 2)
#define IMM_ARG_THREE(x, y, z)    IMM_ARG(x, 1), IMM_ARG(y, 2), \
                                    IMM_ARG(z, 3)
#define IMM_ARG_FOUR(x, y, z, l)  IMM_ARG(x, 1), IMM_ARG(y, 2), \
                                   IMM_ARG(z, 3), IMM_ARG(l, 4)

#define FLAGS_NF
#define FLAGS_TF
#define FLAGS_CF
#define FLAGS_FF
#define FLAGS_PF auto hu = has_call_unpack();
#define FLAGS_CF_TF
#define FLAGS_CF_FF

#define FLAGS_ARG_NF
#define FLAGS_ARG_TF
#define FLAGS_ARG_CF
#define FLAGS_ARG_FF
#define FLAGS_ARG_PF ,hu
#define FLAGS_ARG_CF_TF
#define FLAGS_ARG_CF_FF

#define O(opcode, imms, inputs, outputs, flags)         \
  case Op::opcode:                                      \
    {                                                   \
      auto b = Bytecode {};                             \
      b.op = Op::opcode;                                \
      b.srcLoc = srcLocIx;                              \
      IMM_##imms                                        \
      FLAGS_##flags                                     \
      new (&b.opcode) bc::opcode { IMM_ARG_##imms       \
                                   FLAGS_ARG_##flags }; \
      if (Op::opcode == Op::DefCls)    defcls(b);       \
      if (Op::opcode == Op::DefClsNop) defclsnop(b);    \
      if (Op::opcode == Op::CreateCl)  createcl(b);     \
      blk.hhbcs.push_back(std::move(b));                \
      assert(pc == next);                               \
    }                                                   \
    break;

  assert(pc != past);
  do {
    auto const opPC = pc;
    auto const next = pc + instrLen(opPC);
    assert(next <= past);

    auto const srcLoc = match<php::SrcLoc>(
      puState.srcLocInfo,
      [&] (const SourceLocTable& tab) {
        SourceLoc sloc;
        if (getSourceLoc(tab, opPC - ue.bc(), sloc)) {
          return php::SrcLoc {
            { static_cast<uint32_t>(sloc.line0),
              static_cast<uint32_t>(sloc.char0) },
            { static_cast<uint32_t>(sloc.line1),
              static_cast<uint32_t>(sloc.char1) }
          };
        }
        return php::SrcLoc{};
      },
      [&] (const LineTable& tab) {
        auto const line = getLineNumber(tab, opPC - ue.bc());
        if (line != -1) {
          return php::SrcLoc {
            { static_cast<uint32_t>(line), 0 },
            { static_cast<uint32_t>(line), 0 },
          };
        };
        return php::SrcLoc{};
      }
    );

    auto const srcLocIx = puState.srcLocs.emplace(
      srcLoc, puState.srcLocs.size()).first->second;

    auto const op = decode_op(pc);
    switch (op) { OPCODES }

    if (next == past) {
      if (instrAllowsFallThru(op)) {
        blk.fallthrough = findBlock(next - ue.bc())->id;
      }
    }

    pc = next;
  } while (pc != past);

#undef O

#undef FLAGS_NF
#undef FLAGS_TF
#undef FLAGS_CF
#undef FLAGS_FF
#undef FLAGS_PF
#undef FLAGS_CF_TF
#undef FLAGS_CF_FF

#undef FLAGS_ARG_NF
#undef FLAGS_ARG_TF
#undef FLAGS_ARG_CF
#undef FLAGS_ARG_FF
#undef FLAGS_ARG_PF
#undef FLAGS_ARG_CF_TF
#undef FLAGS_ARG_CF_FF

#undef IMM_BLA
#undef IMM_SLA
#undef IMM_ILA
#undef IMM_IVA
#undef IMM_I64A
#undef IMM_LA
#undef IMM_IA
#undef IMM_DA
#undef IMM_SA
#undef IMM_RATA
#undef IMM_AA
#undef IMM_BA
#undef IMM_OA_IMPL
#undef IMM_OA
#undef IMM_VSA
#undef IMM_LAR

#undef IMM_NA
#undef IMM_ONE
#undef IMM_TWO
#undef IMM_THREE
#undef IMM_FOUR

#undef IMM_ARG
#undef IMM_ARG_NA
#undef IMM_ARG_ONE
#undef IMM_ARG_TWO
#undef IMM_ARG_THREE
#undef IMM_ARG_FOUR

  /*
   * If a block ends with an unconditional jump, change it to a
   * fallthrough edge.
   *
   * Just convert the opcode to a Nop, because this could create an
   * empty block and we have an invariant that no blocks are empty.
   */

  auto make_fallthrough = [&] {
    blk.fallthrough = blk.hhbcs.back().Jmp.target;
    blk.hhbcs.back() = bc_with_loc(blk.hhbcs.back().srcLoc, bc::Nop{});
  };

  switch (blk.hhbcs.back().op) {
  case Op::Jmp:   make_fallthrough();                           break;
  case Op::JmpNS: make_fallthrough(); blk.fallthroughNS = true; break;
  default:                                                      break;
  }
}
示例#18
0
文件: parse.cpp 项目: fmarcos83/hhvm
void populate_block(ParseUnitState& puState,
                    const FuncEmitter& fe,
                    php::Func& func,
                    php::Block& blk,
                    PC pc,
                    PC const past,
                    FindBlock findBlock) {
  auto const& ue = fe.ue();

  auto decode_minstr = [&] {
    auto const immVec = ImmVector::createFromStream(pc);
    pc += immVec.size() + sizeof(int32_t) + sizeof(int32_t);

    auto ret = MVector {};
    auto vec = immVec.vec();

    ret.lcode = static_cast<LocationCode>(*vec++);
    if (numLocationCodeImms(ret.lcode)) {
      assert(numLocationCodeImms(ret.lcode) == 1);
      ret.locBase = borrow(func.locals[decodeVariableSizeImm(&vec)]);
    }

    while (vec < pc) {
      auto elm = MElem {};
      elm.mcode = static_cast<MemberCode>(*vec++);
      switch (memberCodeImmType(elm.mcode)) {
      case MCodeImm::None: break;
      case MCodeImm::Local:
        elm.immLoc = borrow(func.locals[decodeMemberCodeImm(&vec, elm.mcode)]);
        break;
      case MCodeImm::String:
        elm.immStr = ue.lookupLitstr(decodeMemberCodeImm(&vec, elm.mcode));
        break;
      case MCodeImm::Int:
        elm.immInt = decodeMemberCodeImm(&vec, elm.mcode);
        break;
      }
      ret.mcodes.push_back(elm);
    }
    assert(vec == pc);

    return ret;
  };

  auto decode_stringvec = [&] {
    auto const vecLen = decode<int32_t>(pc);
    std::vector<SString> keys;
    for (auto i = size_t{0}; i < vecLen; ++i) {
      keys.push_back(ue.lookupLitstr(decode<int32_t>(pc)));
    }
    return keys;
  };

  auto decode_switch = [&] (PC opPC) {
    SwitchTab ret;
    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen; ++i) {
      ret.push_back(findBlock(
        opPC + decode<Offset>(pc) - ue.bc()
      ));
    }
    return ret;
  };

  auto decode_sswitch = [&] (PC opPC) {
    SSwitchTab ret;

    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen - 1; ++i) {
      auto const id = decode<Id>(pc);
      auto const offset = decode<Offset>(pc);
      ret.emplace_back(
        ue.lookupLitstr(id),
        findBlock(opPC + offset - ue.bc())
      );
    }

    // Final case is the default, and must have a litstr id of -1.
    DEBUG_ONLY auto const defId = decode<Id>(pc);
    auto const defOff = decode<Offset>(pc);
    assert(defId == -1);
    ret.emplace_back(nullptr, findBlock(opPC + defOff - ue.bc()));
    return ret;
  };

  auto decode_itertab = [&] {
    IterTab ret;
    auto const vecLen = decode<int32_t>(pc);
    for (int32_t i = 0; i < vecLen; ++i) {
      auto const kind = static_cast<IterKind>(decode<int32_t>(pc));
      auto const id = decode<int32_t>(pc);
      ret.emplace_back(kind, borrow(func.iters[id]));
    }
    return ret;
  };

  auto defcls = [&] (const Bytecode& b) {
    puState.defClsMap[b.DefCls.arg1] = &func;
  };
  auto nopdefcls = [&] (const Bytecode& b) {
    puState.defClsMap[b.NopDefCls.arg1] = &func;
  };
  auto createcl = [&] (const Bytecode& b) {
    puState.createClMap[b.CreateCl.str2].insert(&func);
  };

#define IMM_MA(n)      auto mvec = decode_minstr();
#define IMM_BLA(n)     auto targets = decode_switch(opPC);
#define IMM_SLA(n)     auto targets = decode_sswitch(opPC);
#define IMM_ILA(n)     auto iterTab = decode_itertab();
#define IMM_IVA(n)     auto arg##n = decodeVariableSizeImm(&pc);
#define IMM_I64A(n)    auto arg##n = decode<int64_t>(pc);
#define IMM_LA(n)      auto loc##n = [&] {                       \
                         auto id = decodeVariableSizeImm(&pc);   \
                         always_assert(id < func.locals.size()); \
                         return borrow(func.locals[id]);         \
                       }();
#define IMM_IA(n)      auto iter##n = [&] {                      \
                         auto id = decodeVariableSizeImm(&pc);   \
                         always_assert(id < func.iters.size());  \
                         return borrow(func.iters[id]);          \
                       }();
#define IMM_DA(n)      auto dbl##n = decode<double>(pc);
#define IMM_SA(n)      auto str##n = ue.lookupLitstr(decode<Id>(pc));
#define IMM_AA(n)      auto arr##n = ue.lookupArray(decode<Id>(pc));
#define IMM_BA(n)      assert(next == past); \
                       auto target = findBlock(  \
                         opPC + decode<Offset>(pc) - ue.bc());
#define IMM_OA_IMPL(n) decode<uint8_t>(pc);
#define IMM_OA(type)   auto subop = (type)IMM_OA_IMPL
#define IMM_VSA(n)     auto keys = decode_stringvec();

#define IMM_NA
#define IMM_ONE(x)           IMM_##x(1)
#define IMM_TWO(x, y)        IMM_##x(1)          IMM_##y(2)
#define IMM_THREE(x, y, z)   IMM_TWO(x, y)       IMM_##z(3)
#define IMM_FOUR(x, y, z, n) IMM_THREE(x, y, z)  IMM_##n(4)

#define IMM_ARG(which, n)         IMM_NAME_##which(n)
#define IMM_ARG_NA
#define IMM_ARG_ONE(x)            IMM_ARG(x, 1)
#define IMM_ARG_TWO(x, y)         IMM_ARG(x, 1), IMM_ARG(y, 2)
#define IMM_ARG_THREE(x, y, z)    IMM_ARG(x, 1), IMM_ARG(y, 2), \
                                    IMM_ARG(z, 3)
#define IMM_ARG_FOUR(x, y, z, l)  IMM_ARG(x, 1), IMM_ARG(y, 2), \
                                   IMM_ARG(z, 3), IMM_ARG(l, 4)


#define O(opcode, imms, inputs, outputs, flags)       \
  case Op::opcode:                                    \
    {                                                 \
      ++pc;                                           \
      auto b = Bytecode {};                           \
      b.op = Op::opcode;                              \
      b.srcLoc = srcLoc;                              \
      IMM_##imms                                      \
      new (&b.opcode) bc::opcode { IMM_ARG_##imms };  \
      if (Op::opcode == Op::DefCls)    defcls(b);     \
      if (Op::opcode == Op::NopDefCls) nopdefcls(b);  \
      if (Op::opcode == Op::CreateCl)  createcl(b);   \
      blk.hhbcs.push_back(std::move(b));              \
      assert(pc == next);                             \
    }                                                 \
    break;

  assert(pc != past);
  do {
    auto const opPC = pc;
    auto const pop  = reinterpret_cast<const Op*>(pc);
    auto const next = pc + instrLen(pop);
    assert(next <= past);

    auto const srcLoc = [&] {
      SourceLoc sloc;
      if (getSourceLoc(puState.srcLocTable, opPC - ue.bc(), sloc)) {
        return php::SrcLoc {
          { static_cast<uint32_t>(sloc.line0),
            static_cast<uint32_t>(sloc.char0) },
          { static_cast<uint32_t>(sloc.line1),
            static_cast<uint32_t>(sloc.char1) }
        };
      }
      return php::SrcLoc{};
    }();

    switch (*pop) { OPCODES }

    if (next == past) {
      if (instrAllowsFallThru(*pop)) {
        blk.fallthrough = findBlock(next - ue.bc());
      }
    }

    pc = next;
  } while (pc != past);

#undef O

#undef IMM_MA
#undef IMM_BLA
#undef IMM_SLA
#undef IMM_ILA
#undef IMM_IVA
#undef IMM_I64A
#undef IMM_LA
#undef IMM_IA
#undef IMM_DA
#undef IMM_SA
#undef IMM_AA
#undef IMM_BA
#undef IMM_OA_IMPL
#undef IMM_OA
#undef IMM_VSA

#undef IMM_NA
#undef IMM_ONE
#undef IMM_TWO
#undef IMM_THREE
#undef IMM_FOUR

#undef IMM_ARG
#undef IMM_ARG_NA
#undef IMM_ARG_ONE
#undef IMM_ARG_TWO
#undef IMM_ARG_THREE
#undef IMM_ARG_FOUR

  /*
   * If a block ends with an unconditional jump, change it to a
   * fallthrough edge.
   *
   * Just convert the opcode to a Nop, because this could create an
   * empty block and we have an invariant that no blocks are empty.
   */

  auto make_fallthrough = [&] {
    blk.fallthrough = blk.hhbcs.back().Jmp.target;
    blk.hhbcs.back() = bc_with_loc(blk.hhbcs.back().srcLoc, bc::Nop{});
  };

  switch (blk.hhbcs.back().op) {
  case Op::Jmp:   make_fallthrough();                           break;
  case Op::JmpNS: make_fallthrough(); blk.fallthroughNS = true; break;
  default:                                                      break;
  }
}
示例#19
0
文件: parse.cpp 项目: aloiret/hhvm
std::unique_ptr<php::Func> parse_func(ParseUnitState& puState,
                                      borrowed_ptr<php::Unit> unit,
                                      borrowed_ptr<php::Class> cls,
                                      const FuncEmitter& fe) {
  FTRACE(2, "  func: {}\n",
    fe.name->data() && *fe.name->data() ? fe.name->data() : "pseudomain");

  auto ret             = folly::make_unique<php::Func>();
  ret->name            = fe.name;
  ret->srcInfo         = php::SrcInfo { fe.getLocation(),
                                        fe.docComment };
  ret->unit            = unit;
  ret->cls             = cls;

  ret->attrs              = static_cast<Attr>(fe.attrs & ~AttrNoOverride);
  ret->userAttributes     = fe.userAttributes;
  ret->returnUserType     = fe.retUserType;
  ret->retTypeConstraint  = fe.retTypeConstraint;
  ret->originalFilename   = fe.originalFilename;

  ret->top                = fe.top;
  ret->isClosureBody      = fe.isClosureBody;
  ret->isAsync            = fe.isAsync;
  ret->isGenerator        = fe.isGenerator;
  ret->isPairGenerator    = fe.isPairGenerator;
  ret->isMemoizeWrapper   = fe.isMemoizeWrapper;

  add_frame_variables(*ret, fe);

  /*
   * Builtin functions get some extra information.  The returnType flag is only
   * non-folly::none for these, but note that something may be a builtin and
   * still have a folly::none return type.
   */
  if (fe.isNative) {
    auto const f = [&] () -> HPHP::Func* {
      if (ret->cls) {
        auto const cls = Unit::lookupClass(ret->cls->name);
        return cls ? cls->lookupMethod(ret->name) : nullptr;
      } else {
        return Unit::lookupFunc(ret->name);
      }
    }();

    ret->nativeInfo                   = folly::make_unique<php::NativeInfo>();
    ret->nativeInfo->returnType       = fe.hniReturnType;
    ret->nativeInfo->dynCallWrapperId = fe.dynCallWrapperId;
    if (f && !ret->cls && ret->params.size()) {
      // There are a handful of functions whose first parameter is by
      // ref, but which don't require a reference.  There is also
      // array_multisort, which has this property for all its
      // parameters; but that
      if (ret->params[0].byRef && !f->mustBeRef(0)) {
        ret->params[0].mustBeRef = false;
      }
    }
    if (!f || !f->nativeFuncPtr() ||
        (f->userAttributes().count(
          LowStringPtr(s_attr_Deprecated.get())))) {
      ret->attrs |= AttrNoFCallBuiltin;
    }
  }

  build_cfg(puState, *ret, fe);

  return ret;
}
示例#20
0
std::unique_ptr<php::Func> parse_func(ParseUnitState& puState,
                                      borrowed_ptr<php::Unit> unit,
                                      borrowed_ptr<php::Class> cls,
                                      const FuncEmitter& fe) {
  FTRACE(2, "  func: {}\n",
    fe.name()->data() && *fe.name()->data() ? fe.name()->data()
                                            : "pseudomain");

  auto ret             = folly::make_unique<php::Func>();
  ret->name            = fe.name();
  ret->srcInfo         = php::SrcInfo { fe.getLocation(),
                                        fe.getDocComment() };
  ret->unit            = unit;
  ret->cls             = cls;
  // Note: probably need to clear AttrLeaf here eventually.
  ret->attrs                  = fe.attrs();
  ret->userAttributes         = fe.getUserAttributes();
  ret->userRetTypeConstraint  = fe.returnTypeConstraint();
  ret->originalFilename       = fe.originalFilename();

  ret->top                    = fe.top();
  ret->isClosureBody          = fe.isClosureBody();
  ret->isGeneratorBody        = fe.isGenerator();
  ret->isGeneratorFromClosure = fe.isGeneratorFromClosure();
  ret->isPairGenerator        = fe.isPairGenerator();
  ret->hasGeneratorAsBody     = fe.hasGeneratorAsBody();

  ret->nextBlockId     = 0;

  add_frame_variables(*ret, fe);
  build_cfg(puState, *ret, fe);

  return ret;
}
示例#21
0
文件: parse.cpp 项目: 409033632/hhvm
std::unique_ptr<php::Func> parse_func(ParseUnitState& puState,
                                      borrowed_ptr<php::Unit> unit,
                                      borrowed_ptr<php::Class> cls,
                                      const FuncEmitter& fe) {
  FTRACE(2, "  func: {}\n",
    fe.name()->data() && *fe.name()->data() ? fe.name()->data()
                                            : "pseudomain");

  auto ret             = folly::make_unique<php::Func>();
  ret->name            = fe.name();
  ret->srcInfo         = php::SrcInfo { fe.getLocation(),
                                        fe.getDocComment() };
  ret->unit            = unit;
  ret->cls             = cls;
  ret->nextBlockId     = 0;

  ret->attrs                  = fe.attrs();
  ret->userAttributes         = fe.getUserAttributes();
  ret->returnUserType         = fe.returnUserType();
  ret->retTypeConstraint      = fe.returnTypeConstraint();
  ret->originalFilename       = fe.originalFilename();

  ret->top                    = fe.top();
  ret->isClosureBody          = fe.isClosureBody();
  ret->isAsync                = fe.isAsync();
  ret->isGenerator            = fe.isGenerator();
  ret->isPairGenerator        = fe.isPairGenerator();

  /*
   * HNI-style native functions get some extra information.
   */
  if (fe.isHNINative()) {
    ret->nativeInfo             = folly::make_unique<php::NativeInfo>();
    ret->nativeInfo->returnType = fe.getReturnType();
  }

  add_frame_variables(*ret, fe);
  build_cfg(puState, *ret, fe);

  return ret;
}
示例#22
0
文件: emit.cpp 项目: nadanomics/hhvm
/*
 * Traverse the actual block layout, and find out the intervals for
 * each exception region in the tree.
 *
 * The basic idea here is that we haven't constrained block layout
 * based on the exception tree, but adjacent blocks are still
 * reasonably likely to have the same ExnNode.  Try to coalesce the EH
 * regions we create for in those cases.
 */
void emit_ehent_tree(FuncEmitter& fe,
                     const php::Func& func,
                     const EmitBcInfo& info) {
  std::map<
    borrowed_ptr<const php::ExnNode>,
    std::vector<std::unique_ptr<EHRegion>>
  > exnMap;

  /*
   * While walking over the blocks in layout order, we track the set
   * of "active" exnNodes.  This are a list of exnNodes that inherit
   * from each other.  When a new active node is pushed, begin an
   * EHEnt, and when it's popped, it's done.
   */
  std::vector<borrowed_ptr<const php::ExnNode>> activeList;

  auto pop_active = [&] (Offset past) {
    auto p = activeList.back();
    activeList.pop_back();
    exnMap[p].back()->past = past;
  };

  auto push_active = [&] (const php::ExnNode* p, Offset start) {
    auto const parent = activeList.empty()
      ? nullptr
      : borrow(exnMap[activeList.back()].back());
    exnMap[p].push_back(
      folly::make_unique<EHRegion>(
        EHRegion { p, parent, start, kInvalidOffset }
      )
    );
    activeList.push_back(p);
  };

  /*
   * Walk over the blocks, and compare the new block's exnNode path to
   * the active one.  Find the least common ancestor of the two paths,
   * then modify the active list by popping and then pushing nodes to
   * set it to the new block's path.
   */
  for (auto& b : info.blockOrder) {
    auto const offset = info.blockInfo[b->id].offset;

    if (!b->exnNode) {
      while (!activeList.empty()) pop_active(offset);
      continue;
    }

    std::vector<borrowed_ptr<const php::ExnNode>> current;
    exn_path(current, b->exnNode);

    auto const prefix = shared_prefix(current, activeList);
    for (size_t i = prefix, sz = activeList.size(); i < sz; ++i) {
      pop_active(offset);
    }
    for (size_t i = prefix, sz = current.size(); i < sz; ++i) {
      push_active(current[i], offset);
    }

    if (debug && !activeList.empty()) {
      current.clear();
      exn_path(current, activeList.back());
      assert(current == activeList);
    }
  }

  while (!activeList.empty()) {
    pop_active(info.blockInfo[info.blockOrder.back()->id].past);
  }

  /*
   * We've created all our regions, but we need to sort them instead
   * of trying to get the UnitEmitter to do it.
   *
   * The UnitEmitter expects EH regions that look a certain way
   * (basically the way emitter.cpp likes them).  There are some rules
   * about the order it needs to have at runtime, which we set up
   * here.
   *
   * Essentially, an entry a is less than an entry b iff:
   *
   *   - a starts before b
   *   - a starts at the same place, but encloses b entirely
   *   - a has the same extents as b, but is a parent of b
   */
  std::vector<borrowed_ptr<EHRegion>> regions;
  for (auto& mapEnt : exnMap) {
    for (auto& region : mapEnt.second) {
      regions.push_back(borrow(region));
    }
  }
  std::sort(
    begin(regions), end(regions),
    [&] (borrowed_ptr<const EHRegion> a, borrowed_ptr<const EHRegion> b) {
      if (a == b) return false;
      if (a->start == b->start) {
        if (a->past == b->past) {
          // When regions exactly overlap, the parent is less than the
          // child.
          for (auto p = b->parent; p != nullptr; p = p->parent) {
            if (p == a) return true;
          }
          // If a is not a parent of b, and they have the same region;
          // then b better be a parent of a.
          if (debug) {
            auto p = a->parent;
            for (; p != b && p != nullptr; p = p->parent) continue;
            assert(p == b);
          }
          return false;
        }
        return a->past > b->past;
      }
      return a->start < b->start;
    }
  );

  std::map<borrowed_ptr<const EHRegion>,uint32_t> parentIndexMap;
  for (auto& r : regions) {
    emit_eh_region(fe, r, info.blockInfo, parentIndexMap);
  }
  fe.setEHTabIsSorted();
}