Exemplo n.º 1
0
extern "C" void PyString_InternInPlace(PyObject** p) noexcept {
    BoxedString* s = (BoxedString*)*p;
    if (s == NULL || !PyString_Check(s))
        Py_FatalError("PyString_InternInPlace: strings only please!");
    /* If it's a string subclass, we don't really know what putting
       it in the interned dict might do. */
    if (!PyString_CheckExact(s))
        return;

    if (PyString_CHECK_INTERNED(s))
        return;

    auto it = interned_strings.find(s);
    if (it != interned_strings.end()) {
        auto entry = *it;
        Py_INCREF(entry);
        Py_DECREF(*p);
        *p = entry;
    } else {
        // TODO: do CPython's refcounting here
        num_interned_strings.log();
        interned_strings.insert(s);

        Py_INCREF(s);

        // CPython returns mortal but in our current implementation they are inmortal
        s->interned_state = SSTATE_INTERNED_IMMORTAL;
    }
}
Exemplo n.º 2
0
uint32_t SymbolFilePDB::FindTypes(
    const lldb_private::SymbolContext &sc,
    const lldb_private::ConstString &name,
    const lldb_private::CompilerDeclContext *parent_decl_ctx, bool append,
    uint32_t max_matches,
    llvm::DenseSet<lldb_private::SymbolFile *> &searched_symbol_files,
    lldb_private::TypeMap &types) {
  if (!append)
    types.Clear();
  if (!name)
    return 0;

  searched_symbol_files.clear();
  searched_symbol_files.insert(this);

  std::string name_str = name.AsCString();

  // If this might be a regex, we have to return EVERY symbol and process them
  // one by one, which is going
  // to destroy performance on large PDB files.  So try really hard not to use a
  // regex match.
  if (name_str.find_first_of("[]?*.-+\\") != std::string::npos)
    FindTypesByRegex(name_str, max_matches, types);
  else
    FindTypesByName(name_str, max_matches, types);
  return types.GetSize();
}
Exemplo n.º 3
0
BoxedString* internStringImmortal(llvm::StringRef s) noexcept {
    auto it = interned_strings.find_as(s);
    if (it != interned_strings.end())
        return incref(*it);

    num_interned_strings.log();
    BoxedString* entry = boxString(s);
    // CPython returns mortal but in our current implementation they are inmortal
    entry->interned_state = SSTATE_INTERNED_IMMORTAL;
    interned_strings.insert((BoxedString*)entry);

    Py_INCREF(entry);
    return entry;
}
Exemplo n.º 4
0
extern "C" void _Py_ReleaseInternedStrings() noexcept {
    // printf("%ld interned strings\n", interned_strings.size());
    for (const auto& p : interned_strings) {
        Py_DECREF(p);
    }
    interned_strings.clear();
}
Exemplo n.º 5
0
void addVarDeclsVisible(clang::ForStmt const *Parent,
                        clang::Decl const *PriorToDecl,
                        clang::Stmt const *PriorToStmt,
                        seec::seec_clang::MappedAST const &Map,
                        llvm::DenseSet<clang::VarDecl const *> &Set)
{
  // The initialisation statement.
  if (auto const Init = Parent->getInit()) {
    if (PriorToStmt && Init == PriorToStmt)
      return;
    
    if (auto const DeclStmt = llvm::dyn_cast<clang::DeclStmt>(Init))
      addVarDeclsVisible(DeclStmt, nullptr, nullptr, Map, Set);
  }
  
  // The condition statement.
  if (PriorToStmt && Parent->getCond() == PriorToStmt)
    return;
  
  if (auto const CV = Parent->getConditionVariable())
    Set.insert(CV);
  
  // The increment statement.
  if (PriorToStmt && Parent->getInc() == PriorToStmt)
    return;
  
  // Any VarDecls in the Body should have already been added.
}
Exemplo n.º 6
0
ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
               int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs,
               assembler::GenericRegister return_register, TypeRecorder* type_recorder)
    : next_slot_to_try(0),
      stack_info(stack_info),
      num_slots(num_slots),
      slot_size(slot_size),
      calling_conv(calling_conv),
      live_outs(std::move(_live_outs)),
      return_register(return_register),
      type_recorder(type_recorder),
      retry_in(0),
      retry_backoff(1),
      times_rewritten(0),
      start_addr(start_addr),
      slowpath_rtn_addr(slowpath_rtn_addr),
      continue_addr(continue_addr) {
    for (int i = 0; i < num_slots; i++) {
        slots.emplace_back(this, i);
    }

#if MOVING_GC
    assert(ics_list.count(this) == 0);
#endif
}
Exemplo n.º 7
0
  void addSymbol(const CVSymbol &Symbol) {
    if (Symbol.kind() == S_UDT) {
      auto Iter = UdtHashes.insert(Symbol);
      if (!Iter.second)
        return;
    }

    Records.push_back(Symbol);
  }
Exemplo n.º 8
0
static void
addAllChildren(llvm::DenseSet<clang::Stmt const *> &Set, clang::Stmt const *S)
{
  for (auto const &Child : S->children()) {
    if (Child) {
      Set.insert(Child);
      addAllChildren(Set, Child);
    }
  }
}
Exemplo n.º 9
0
  void visitModuleFile(StringRef Filename,
                       serialization::ModuleKind Kind) override {
    auto *File = CI.getFileManager().getFile(Filename);
    assert(File && "missing file for loaded module?");

    // Only rewrite each module file once.
    if (!Rewritten.insert(File).second)
      return;

    serialization::ModuleFile *MF =
        CI.getModuleManager()->getModuleManager().lookup(File);
    assert(File && "missing module file for loaded module?");

    // Not interested in PCH / preambles.
    if (!MF->isModule())
      return;

    auto OS = Out.lock();
    assert(OS && "loaded module file after finishing rewrite action?");

    (*OS) << "#pragma clang module build ";
    if (isValidIdentifier(MF->ModuleName))
      (*OS) << MF->ModuleName;
    else {
      (*OS) << '"';
      OS->write_escaped(MF->ModuleName);
      (*OS) << '"';
    }
    (*OS) << '\n';

    // Rewrite the contents of the module in a separate compiler instance.
    CompilerInstance Instance(CI.getPCHContainerOperations(),
                              &CI.getPreprocessor().getPCMCache());
    Instance.setInvocation(
        std::make_shared<CompilerInvocation>(CI.getInvocation()));
    Instance.createDiagnostics(
        new ForwardingDiagnosticConsumer(CI.getDiagnosticClient()),
        /*ShouldOwnClient=*/true);
    Instance.getFrontendOpts().DisableFree = false;
    Instance.getFrontendOpts().Inputs.clear();
    Instance.getFrontendOpts().Inputs.emplace_back(
        Filename, InputKind(InputKind::Unknown, InputKind::Precompiled));
    Instance.getFrontendOpts().ModuleFiles.clear();
    Instance.getFrontendOpts().ModuleMapFiles.clear();
    // Don't recursively rewrite imports. We handle them all at the top level.
    Instance.getPreprocessorOutputOpts().RewriteImports = false;

    llvm::CrashRecoveryContext().RunSafelyOnThread([&]() {
      RewriteIncludesAction Action;
      Action.OutputStream = OS;
      Instance.ExecuteAction(Action);
    });

    (*OS) << "#pragma clang module endbuild /*" << MF->ModuleName << "*/\n";
  }
Exemplo n.º 10
0
 void Fix(CompoundStmt* CS) {
   if (!CS->size())
     return;
   typedef llvm::SmallVector<Stmt*, 32> Statements;
   Statements Stmts;
   Stmts.append(CS->body_begin(), CS->body_end());
   for (Statements::iterator I = Stmts.begin(); I != Stmts.end(); ++I) {
     if (!TraverseStmt(*I) && !m_HandledDecls.count(m_FoundDRE->getDecl())) {
       Sema::DeclGroupPtrTy VDPtrTy 
         = m_Sema->ConvertDeclToDeclGroup(m_FoundDRE->getDecl());
       StmtResult DS = m_Sema->ActOnDeclStmt(VDPtrTy, 
                                             m_FoundDRE->getLocStart(), 
                                             m_FoundDRE->getLocEnd());
       assert(!DS.isInvalid() && "Invalid DeclStmt.");
       I = Stmts.insert(I, DS.take());
       m_HandledDecls.insert(m_FoundDRE->getDecl());
     }
   }
   CS->setStmts(m_Sema->getASTContext(), Stmts.data(), Stmts.size());
 }
Exemplo n.º 11
0
    void foundDecl(ValueDecl *D, DeclVisibilityKind Reason) override {
      // If the declaration has an override, name lookup will also have found
      // the overridden method.  Skip this declaration, because we prefer the
      // overridden method.
      if (D->getOverriddenDecl())
        return;

      // Initializers cannot be found by dynamic lookup.
      if (isa<ConstructorDecl>(D))
        return;

      // Check if we already reported a decl with the same signature.
      if (auto *FD = dyn_cast<FuncDecl>(D)) {
        assert(FD->getImplicitSelfDecl() && "should not find free functions");
        (void)FD;

        // Get the type without the first uncurry level with 'self'.
        CanType T = D->getType()
                        ->castTo<AnyFunctionType>()
                        ->getResult()
                        ->getCanonicalType();

        auto Signature = std::make_pair(D->getName(), T);
        if (!FunctionsReported.insert(Signature).second)
          return;
      } else if (isa<SubscriptDecl>(D)) {
        auto Signature = D->getType()->getCanonicalType();
        if (!SubscriptsReported.insert(Signature).second)
          return;
      } else if (isa<VarDecl>(D)) {
        auto Signature =
            std::make_pair(D->getName(), D->getType()->getCanonicalType());
        if (!PropertiesReported.insert(Signature).second)
          return;
      } else {
        llvm_unreachable("unhandled decl kind");
      }

      if (isDeclVisibleInLookupMode(D, LS, CurrDC, TypeResolver))
        ChainedConsumer.foundDecl(D, DeclVisibilityKind::DynamicLookup);
    }
Exemplo n.º 12
0
bool
ConsumedResultToEpilogueRetainMatcher::
isTransitiveSuccessorsRetainFree(llvm::DenseSet<SILBasicBlock *> BBs) {
  // For every block with retain, we need to check the transitive
  // closure of its successors are retain-free.
  for (auto &I : EpilogueRetainInsts) {
    auto *CBB = I->getParent();
    for (auto &Succ : CBB->getSuccessors()) {
      if (BBs.find(Succ) != BBs.end())
        continue;
      return false;
    }
  }
  for (auto CBB : BBs) {
    for (auto &Succ : CBB->getSuccessors()) {
      if (BBs.find(Succ) != BBs.end())
        continue;
      return false;
    }
  }
  return true;
}
Exemplo n.º 13
0
void addVarDeclsVisible(clang::DeclStmt const *Parent,
                        clang::Decl const *PriorToDecl,
                        clang::Stmt const *PriorToStmt,
                        seec::seec_clang::MappedAST const &Map,
                        llvm::DenseSet<clang::VarDecl const *> &Set)
{
  if (Parent->isSingleDecl()) {
    auto const Decl = Parent->getSingleDecl();
    
    if (auto const VarDecl = llvm::dyn_cast<clang::VarDecl>(Decl))
      Set.insert(VarDecl);
  }
  else {
    for (auto const Decl : Parent->getDeclGroup()) {
      if (auto const VarDecl = llvm::dyn_cast<clang::VarDecl>(Decl))
        Set.insert(VarDecl);

      if (PriorToDecl && Decl == PriorToDecl)
        return;
    }
  }
}
Exemplo n.º 14
0
void addVarDeclsVisible(clang::WhileStmt const *Parent,
                        clang::Decl const *PriorToDecl,
                        clang::Stmt const *PriorToStmt,
                        seec::seec_clang::MappedAST const &Map,
                        llvm::DenseSet<clang::VarDecl const *> &Set)
{
  if (PriorToStmt && Parent->getCond() == PriorToStmt)
    return;
  
  if (auto const CV = Parent->getConditionVariable())
    Set.insert(CV);
  
  // Any VarDecls in the Body should have already been added.
}
Exemplo n.º 15
0
bool ConsumedResultToEpilogueRetainMatcher::isTransitiveSuccessorsRetainFree(
    const llvm::DenseSet<SILBasicBlock *> &BBs) {
  // For every block with retain, we need to check the transitive
  // closure of its successors are retain-free.
  for (auto &I : EpilogueRetainInsts) {
    for (auto &Succ : I->getParent()->getSuccessors()) {
      if (BBs.count(Succ))
        continue;
      return false;
    }
  }

  // FIXME: We are iterating over a DenseSet. That can lead to non-determinism
  // and is in general pretty inefficient since we are iterating over a hash
  // table.
  for (auto CBB : BBs) {
    for (auto &Succ : CBB->getSuccessors()) {
      if (BBs.count(Succ))
        continue;
      return false;
    }
  }
  return true;
}
Exemplo n.º 16
0
/// Check whether all operands are loop invariant.
static bool hasLoopInvariantOperands(SILInstruction *I, SILLoop *L,
                                     llvm::DenseSet<SILInstruction *> &Inv) {
  auto Opds = I->getAllOperands();

  return std::all_of(Opds.begin(), Opds.end(), [=](Operand &Op) {

    ValueBase *Def = Op.get();
    // Operand is outside the loop or marked invariant.
    if (auto *Inst = Def->getDefiningInstruction())
      return !L->contains(Inst->getParent()) || Inv.count(Inst);
    if (auto *Arg = dyn_cast<SILArgument>(Def))
      return !L->contains(Arg->getParent());

    return false;
  });
}
Exemplo n.º 17
0
namespace pyston {

using namespace pyston::assembler;

#define MAX_RETRY_BACKOFF 1024

// TODO not right place for this...
int64_t ICInvalidator::version() {
    return cur_version;
}

void ICInvalidator::addDependent(ICSlotInfo* entry_info) {
    dependents.insert(entry_info);
}

void ICInvalidator::invalidateAll() {
    cur_version++;
    for (ICSlotInfo* slot : dependents) {
        slot->clear();
    }
    dependents.clear();
}

void ICSlotInfo::clear() {
    ic->clear(this);
}

ICSlotRewrite::ICSlotRewrite(ICInfo* ic, const char* debug_name)
    : ic(ic), debug_name(debug_name), buf((uint8_t*)malloc(ic->getSlotSize())), assembler(buf, ic->getSlotSize()) {
    assembler.nop();

    if (VERBOSITY() >= 4)
        printf("starting %s icentry\n", debug_name);
}

ICSlotRewrite::~ICSlotRewrite() {
    free(buf);
}

void ICSlotRewrite::abort() {
    ic->retry_backoff = std::min(MAX_RETRY_BACKOFF, 2 * ic->retry_backoff);
    ic->retry_in = ic->retry_backoff;
}

ICSlotInfo* ICSlotRewrite::prepareEntry() {
    this->ic_entry = ic->pickEntryForRewrite(debug_name);
    return this->ic_entry;
}

uint8_t* ICSlotRewrite::getSlotStart() {
    assert(ic_entry != NULL);
    return (uint8_t*)ic->start_addr + ic_entry->idx * ic->getSlotSize();
}

// Map of gc pointers -> number of ics that point tot hem.
static llvm::DenseMap<void*, int> ic_gc_references;

void ICSlotRewrite::commit(CommitHook* hook, std::vector<void*> gc_references) {
    bool still_valid = true;
    for (int i = 0; i < dependencies.size(); i++) {
        int orig_version = dependencies[i].second;
        ICInvalidator* invalidator = dependencies[i].first;
        if (orig_version != invalidator->version()) {
            still_valid = false;
            break;
        }
    }
    if (!still_valid) {
        if (VERBOSITY() >= 3)
            printf("not committing %s icentry since a dependency got updated before commit\n", debug_name);
        return;
    }

    uint8_t* slot_start = getSlotStart();
    uint8_t* continue_point = (uint8_t*)ic->continue_addr;

    bool do_commit = hook->finishAssembly(continue_point - slot_start);

    if (!do_commit)
        return;

    assert(!assembler.hasFailed());

    for (int i = 0; i < dependencies.size(); i++) {
        ICInvalidator* invalidator = dependencies[i].first;
        invalidator->addDependent(ic_entry);
    }

    ic->next_slot_to_try++;

    // if (VERBOSITY()) printf("Commiting to %p-%p\n", start, start + ic->slot_size);
    memcpy(slot_start, buf, ic->getSlotSize());

    for (auto p : ic_entry->gc_references) {
        int& i = ic_gc_references[p];
        if (i == 1)
            ic_gc_references.erase(p);
        else
            --i;
    }
    ic_entry->gc_references = std::move(gc_references);
    for (auto p : ic_entry->gc_references)
        ic_gc_references[p]++;

    ic->times_rewritten++;

    if (ic->times_rewritten == IC_MEGAMORPHIC_THRESHOLD) {
        static StatCounter megamorphic_ics("megamorphic_ics");
        megamorphic_ics.log();
    }

    llvm::sys::Memory::InvalidateInstructionCache(slot_start, ic->getSlotSize());
}

void ICSlotRewrite::gc_visit(GCVisitor* visitor) {
    for (auto& dependency : dependencies) {
        visitor->visitPotentialRedundant(dependency.first);
    }
}

void ICSlotRewrite::addDependenceOn(ICInvalidator& invalidator) {
    dependencies.push_back(std::make_pair(&invalidator, invalidator.version()));
}

int ICSlotRewrite::getSlotSize() {
    return ic->getSlotSize();
}

int ICSlotRewrite::getScratchRspOffset() {
    assert(ic->stack_info.scratch_size);
    return ic->stack_info.scratch_rsp_offset;
}

int ICSlotRewrite::getScratchSize() {
    return ic->stack_info.scratch_size;
}

TypeRecorder* ICSlotRewrite::getTypeRecorder() {
    return ic->type_recorder;
}

assembler::GenericRegister ICSlotRewrite::returnRegister() {
    return ic->return_register;
}



std::unique_ptr<ICSlotRewrite> ICInfo::startRewrite(const char* debug_name) {
    return std::unique_ptr<ICSlotRewrite>(new ICSlotRewrite(this, debug_name));
}

ICSlotInfo* ICInfo::pickEntryForRewrite(const char* debug_name) {
    int num_slots = getNumSlots();
    for (int _i = 0; _i < num_slots; _i++) {
        int i = (_i + next_slot_to_try) % num_slots;

        ICSlotInfo& sinfo = slots[i];
        assert(sinfo.num_inside >= 0);
        if (sinfo.num_inside)
            continue;

        if (VERBOSITY() >= 4) {
            printf("picking %s icentry to in-use slot %d at %p\n", debug_name, i, start_addr);
        }

        next_slot_to_try = i;
        return &sinfo;
    }
    if (VERBOSITY() >= 4)
        printf("not committing %s icentry since there are no available slots\n", debug_name);
    return NULL;
}

// Keep track of all ICInfo(s) that we create because they contain pointers to Pyston heap objects
// that we have written into the generated code and we may need to scan those.
static llvm::DenseSet<ICInfo*> ics_list;
static llvm::DenseMap<void*, ICInfo*> ics_by_return_addr;

void registerGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
    assert(ics_list.count(ic) == 0);
    ics_list.insert(ic);
#endif
}

void deregisterGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
    assert(ics_list.count(ic) == 1);
    ics_list.erase(ic);
#endif
}

ICInfo::ICInfo(void* start_addr, void* slowpath_rtn_addr, void* continue_addr, StackInfo stack_info, int num_slots,
               int slot_size, llvm::CallingConv::ID calling_conv, LiveOutSet _live_outs,
               assembler::GenericRegister return_register, TypeRecorder* type_recorder)
    : next_slot_to_try(0),
      stack_info(stack_info),
      num_slots(num_slots),
      slot_size(slot_size),
      calling_conv(calling_conv),
      live_outs(std::move(_live_outs)),
      return_register(return_register),
      type_recorder(type_recorder),
      retry_in(0),
      retry_backoff(1),
      times_rewritten(0),
      start_addr(start_addr),
      slowpath_rtn_addr(slowpath_rtn_addr),
      continue_addr(continue_addr) {
    for (int i = 0; i < num_slots; i++) {
        slots.emplace_back(this, i);
    }

#if MOVING_GC
    assert(ics_list.count(this) == 0);
#endif
}

ICInfo::~ICInfo() {
#if MOVING_GC
    assert(ics_list.count(this) == 0);
#endif
}

std::unique_ptr<ICInfo> registerCompiledPatchpoint(uint8_t* start_addr, uint8_t* slowpath_start_addr,
                                                   uint8_t* continue_addr, uint8_t* slowpath_rtn_addr,
                                                   const ICSetupInfo* ic, StackInfo stack_info, LiveOutSet live_outs) {
    assert(slowpath_start_addr - start_addr >= ic->num_slots * ic->slot_size);
    assert(slowpath_rtn_addr > slowpath_start_addr);
    assert(slowpath_rtn_addr <= start_addr + ic->totalSize());

    assembler::GenericRegister return_register;
    assert(ic->getCallingConvention() == llvm::CallingConv::C
           || ic->getCallingConvention() == llvm::CallingConv::PreserveAll);

    if (ic->hasReturnValue()) {
        static const int DWARF_RAX = 0;
        // It's possible that the return value doesn't get used, in which case
        // we can avoid copying back into RAX at the end
        live_outs.clear(DWARF_RAX);

        // TODO we only need to do this if 0 was in live_outs, since if it wasn't, that indicates
        // the return value won't be used and we can optimize based on that.
        return_register = assembler::RAX;
    }

    // we can let the user just slide down the nop section, but instead
    // emit jumps to the end.
    // Not sure if this is worth it or not?
    for (int i = 0; i < ic->num_slots; i++) {
        uint8_t* start = start_addr + i * ic->slot_size;
        // std::unique_ptr<MCWriter> writer(createMCWriter(start, ic->slot_size * (ic->num_slots - i), 0));
        // writer->emitNop();
        // writer->emitGuardFalse();

        Assembler writer(start, ic->slot_size);
        writer.nop();
        // writer.trap();
        // writer.jmp(JumpDestination::fromStart(ic->slot_size * (ic->num_slots - i)));
        writer.jmp(JumpDestination::fromStart(slowpath_start_addr - start));
    }

    ICInfo* icinfo = new ICInfo(start_addr, slowpath_rtn_addr, continue_addr, stack_info, ic->num_slots, ic->slot_size,
                                ic->getCallingConvention(), std::move(live_outs), return_register, ic->type_recorder);

    assert(!ics_by_return_addr.count(slowpath_rtn_addr));
    ics_by_return_addr[slowpath_rtn_addr] = icinfo;

    registerGCTrackedICInfo(icinfo);

    return std::unique_ptr<ICInfo>(icinfo);
}

void deregisterCompiledPatchpoint(ICInfo* ic) {
    assert(ics_by_return_addr.count(ic->slowpath_rtn_addr));
    ics_by_return_addr.erase(ic->slowpath_rtn_addr);

    deregisterGCTrackedICInfo(ic);
}

ICInfo* getICInfo(void* rtn_addr) {
    // TODO: load this from the CF instead of tracking it separately
    auto&& it = ics_by_return_addr.find(rtn_addr);
    if (it == ics_by_return_addr.end())
        return NULL;
    return it->second;
}

void ICInfo::clear(ICSlotInfo* icentry) {
    assert(icentry);

    uint8_t* start = (uint8_t*)start_addr + icentry->idx * getSlotSize();

    if (VERBOSITY() >= 4)
        printf("clearing patchpoint %p, slot at %p\n", start_addr, start);

    Assembler writer(start, getSlotSize());
    writer.nop();
    writer.jmp(JumpDestination::fromStart(getSlotSize()));
    assert(writer.bytesWritten() <= IC_INVALDITION_HEADER_SIZE);

    // std::unique_ptr<MCWriter> writer(createMCWriter(start, getSlotSize(), 0));
    // writer->emitNop();
    // writer->emitGuardFalse();

    // writer->endWithSlowpath();
    llvm::sys::Memory::InvalidateInstructionCache(start, getSlotSize());
}

bool ICInfo::shouldAttempt() {
    if (retry_in) {
        retry_in--;
        return false;
    }
    // Note(kmod): in some pathological deeply-recursive cases, it's important that we set the
    // retry counter even if we attempt it again.  We could probably handle this by setting
    // the backoff to 0 on commit, and then setting the retry to the backoff here.

    return !isMegamorphic();
}

bool ICInfo::isMegamorphic() {
    return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD;
}

void ICInfo::visitGCReferences(gc::GCVisitor* v) {
    for (auto&& p : ic_gc_references) {
        v->visitNonRelocatable(p.first);
    }
#if MOVING_GC
    for (const auto& p : ics_list) {
        for (auto& slot : p->slots) {
            v->visitNonRelocatableRange(&slot.gc_references[0], &slot.gc_references[slot.gc_references.size()]);
        }
    }
#endif
}
}
Exemplo n.º 18
0
ICInfo::~ICInfo() {
#if MOVING_GC
    assert(ics_list.count(this) == 0);
#endif
}
Exemplo n.º 19
0
void deregisterGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
    assert(ics_list.count(ic) == 1);
    ics_list.erase(ic);
#endif
}
Exemplo n.º 20
0
void registerGCTrackedICInfo(ICInfo* ic) {
#if MOVING_GC
    assert(ics_list.count(ic) == 0);
    ics_list.insert(ic);
#endif
}
Exemplo n.º 21
0
    void foundDecl(ValueDecl *D, DeclVisibilityKind Reason) override {
      // If the declaration has an override, name lookup will also have found
      // the overridden method.  Skip this declaration, because we prefer the
      // overridden method.
      if (D->getOverriddenDecl())
        return;

      // If the declaration is not @objc, it cannot be called dynamically.
      if (!D->isObjC())
        return;

      // Ensure that the declaration has a type.
      if (!D->hasInterfaceType()) {
        if (!TypeResolver) return;
        TypeResolver->resolveDeclSignature(D);
        if (!D->hasInterfaceType()) return;
      }

      switch (D->getKind()) {
#define DECL(ID, SUPER) \
      case DeclKind::ID:
#define VALUE_DECL(ID, SUPER)
#include "swift/AST/DeclNodes.def"
        llvm_unreachable("not a ValueDecl!");

      // Types cannot be found by dynamic lookup.
      case DeclKind::GenericTypeParam:
      case DeclKind::AssociatedType:
      case DeclKind::TypeAlias:
      case DeclKind::Enum:
      case DeclKind::Class:
      case DeclKind::Struct:
      case DeclKind::Protocol:
        return;

      // Initializers cannot be found by dynamic lookup.
      case DeclKind::Constructor:
      case DeclKind::Destructor:
        return;

      // These cases are probably impossible here but can also just
      // be safely ignored.
      case DeclKind::EnumElement:
      case DeclKind::Param:
      case DeclKind::Module:
        return;

      // For other kinds of values, check if we already reported a decl
      // with the same signature.

      case DeclKind::Accessor:
      case DeclKind::Func: {
        auto FD = cast<FuncDecl>(D);
        assert(FD->getImplicitSelfDecl() && "should not find free functions");
        (void)FD;

        if (FD->isInvalid())
          break;

        // Get the type without the first uncurry level with 'self'.
        CanType T = D->getInterfaceType()
                        ->castTo<AnyFunctionType>()
                        ->getResult()
                        ->getCanonicalType();

        auto Signature = std::make_pair(D->getBaseName(), T);
        if (!FunctionsReported.insert(Signature).second)
          return;
        break;
      }

      case DeclKind::Subscript: {
        auto Signature = D->getInterfaceType()->getCanonicalType();
        if (!SubscriptsReported.insert(Signature).second)
          return;
        break;
      }

      case DeclKind::Var: {
        auto *VD = cast<VarDecl>(D);
        auto Signature =
            std::make_pair(VD->getName(),
                           VD->getInterfaceType()->getCanonicalType());
        if (!PropertiesReported.insert(Signature).second)
          return;
        break;
      }
      }

      if (isDeclVisibleInLookupMode(D, LS, CurrDC, TypeResolver))
        ChainedConsumer.foundDecl(D, DeclVisibilityKind::DynamicLookup);
    }
Exemplo n.º 22
0
 bool isInterceptedFunction(uintptr_t Address) const {
   return InterceptorAddresses.count(Address);
 }
Exemplo n.º 23
0
void ClosureSpecializer::gatherCallSites(
    SILFunction *Caller,
    llvm::SmallVectorImpl<ClosureInfo*> &ClosureCandidates,
    llvm::DenseSet<FullApplySite> &MultipleClosureAI) {

  // A set of apply inst that we have associated with a closure. We use this to
  // make sure that we do not handle call sites with multiple closure arguments.
  llvm::DenseSet<FullApplySite> VisitedAI;

  // For each basic block BB in Caller...
  for (auto &BB : *Caller) {

    // For each instruction II in BB...
    for (auto &II : BB) {
      // If II is not a closure that we support specializing, skip it...
      if (!isSupportedClosure(&II))
        continue;

      ClosureInfo *CInfo = nullptr;

      // Go through all uses of our closure.
      for (auto *Use : II.getUses()) {
        // If this use is not an apply inst or an apply inst with
        // substitutions, there is nothing interesting for us to do, so
        // continue...
        auto AI = FullApplySite::isa(Use->getUser());
        if (!AI || AI.hasSubstitutions())
          continue;

        // Check if we have already associated this apply inst with a closure to
        // be specialized. We do not handle applies that take in multiple
        // closures at this time.
        if (!VisitedAI.insert(AI).second) {
          MultipleClosureAI.insert(AI);
          continue;
        }

        // If AI does not have a function_ref definition as its callee, we can
        // not do anything here... so continue...
        SILFunction *ApplyCallee = AI.getReferencedFunction();
        if (!ApplyCallee || ApplyCallee->isExternalDeclaration())
          continue;

        // Ok, we know that we can perform the optimization but not whether or
        // not the optimization is profitable. Find the index of the argument
        // corresponding to our partial apply.
        Optional<unsigned> ClosureIndex;
        for (unsigned i = 0, e = AI.getNumArguments(); i != e; ++i) {
          if (AI.getArgument(i) != SILValue(&II))
            continue;
          ClosureIndex = i;
          DEBUG(llvm::dbgs() << "    Found callsite with closure argument at "
                << i << ": " << *AI.getInstruction());
          break;
        }

        // If we did not find an index, there is nothing further to do,
        // continue.
        if (!ClosureIndex.hasValue())
          continue;

        // Make sure that the Closure is invoked in the Apply's callee. We only
        // want to perform closure specialization if we know that we will be
        // able to change a partial_apply into an apply.
        //
        // TODO: Maybe just call the function directly instead of moving the
        // partial apply?
        SILValue Arg = ApplyCallee->getArgument(ClosureIndex.getValue());
        if (std::none_of(Arg->use_begin(), Arg->use_end(),
                         [&Arg](Operand *Op) -> bool {
                           auto UserAI = FullApplySite::isa(Op->getUser());
                           return UserAI && UserAI.getCallee() == Arg;
                         })) {
          continue;
        }

        auto NumIndirectResults =
          AI.getSubstCalleeType()->getNumIndirectResults();
        assert(ClosureIndex.getValue() >= NumIndirectResults);
        auto ClosureParamIndex = ClosureIndex.getValue() - NumIndirectResults;

        auto ParamInfo = AI.getSubstCalleeType()->getParameters();
        SILParameterInfo ClosureParamInfo = ParamInfo[ClosureParamIndex];

        // Get all non-failure exit BBs in the Apply Callee if our partial apply
        // is guaranteed. If we do not understand one of the exit BBs, bail.
        //
        // We need this to make sure that we insert a release in the appropriate
        // locations to balance the +1 from the creation of the partial apply.
        llvm::TinyPtrVector<SILBasicBlock *> NonFailureExitBBs;
        if (ClosureParamInfo.isGuaranteed() &&
            !findAllNonFailureExitBBs(ApplyCallee, NonFailureExitBBs)) {
          continue;
        }

        // Compute the final release points of the closure. We will insert
        // release of the captured arguments here.
        if (!CInfo) {
          CInfo = new ClosureInfo(&II);
          ValueLifetimeAnalysis VLA(CInfo->Closure);
          VLA.computeFrontier(CInfo->LifetimeFrontier,
                              ValueLifetimeAnalysis::AllowToModifyCFG);
        }

        // Now we know that CSDesc is profitable to specialize. Add it to our
        // call site list.
        CInfo->CallSites.push_back(
          CallSiteDescriptor(CInfo, AI, ClosureIndex.getValue(),
                             ClosureParamInfo, std::move(NonFailureExitBBs)));
      }
      if (CInfo)
        ClosureCandidates.push_back(CInfo);
    }
  }
}
Exemplo n.º 24
0
namespace pyston {
static llvm::DenseSet<BoxedString*> interned_strings;

static StatCounter num_interned_strings("num_interned_string");
extern "C" PyObject* PyString_InternFromString(const char* s) noexcept {
    RELEASE_ASSERT(s, "");
    return internStringImmortal(s);
}

BoxedString* internStringImmortal(llvm::StringRef s) noexcept {
    auto it = interned_strings.find_as(s);
    if (it != interned_strings.end())
        return incref(*it);

    num_interned_strings.log();
    BoxedString* entry = boxString(s);
    // CPython returns mortal but in our current implementation they are inmortal
    entry->interned_state = SSTATE_INTERNED_IMMORTAL;
    interned_strings.insert((BoxedString*)entry);

    Py_INCREF(entry);
    return entry;
}

extern "C" void PyString_InternInPlace(PyObject** p) noexcept {
    BoxedString* s = (BoxedString*)*p;
    if (s == NULL || !PyString_Check(s))
        Py_FatalError("PyString_InternInPlace: strings only please!");
    /* If it's a string subclass, we don't really know what putting
       it in the interned dict might do. */
    if (!PyString_CheckExact(s))
        return;

    if (PyString_CHECK_INTERNED(s))
        return;

    auto it = interned_strings.find(s);
    if (it != interned_strings.end()) {
        auto entry = *it;
        Py_INCREF(entry);
        Py_DECREF(*p);
        *p = entry;
    } else {
        // TODO: do CPython's refcounting here
        num_interned_strings.log();
        interned_strings.insert(s);

        Py_INCREF(s);

        // CPython returns mortal but in our current implementation they are inmortal
        s->interned_state = SSTATE_INTERNED_IMMORTAL;
    }
}

extern "C" void _Py_ReleaseInternedStrings() noexcept {
    // printf("%ld interned strings\n", interned_strings.size());
    for (const auto& p : interned_strings) {
        Py_DECREF(p);
    }
    interned_strings.clear();
}
}
Exemplo n.º 25
0
/// TODO: We should consult the cached LoweredLocalCaptures the SIL
/// TypeConverter calculates, but that would require plumbing SILModule&
/// through every SILDeclRef constructor. Since this is only used to determine
/// "natural uncurry level", and "uncurry level" is a concept we'd like to
/// phase out, it's not worth it.
static bool hasLoweredLocalCaptures(AnyFunctionRef AFR,
                                    llvm::DenseSet<AnyFunctionRef> &visited) {
  if (!AFR.getCaptureInfo().hasLocalCaptures())
    return false;
  
  // Scan for local, non-function captures.
  bool functionCapturesToRecursivelyCheck = false;
  auto addFunctionCapture = [&](AnyFunctionRef capture) {
    if (visited.find(capture) == visited.end())
      functionCapturesToRecursivelyCheck = true;
  };
  for (auto &capture : AFR.getCaptureInfo().getCaptures()) {
    if (!capture.getDecl()->getDeclContext()->isLocalContext())
      continue;
    // We transitively capture a local function's captures.
    if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) {
      addFunctionCapture(func);
      continue;
    }
    // We may either directly capture properties, or capture through their
    // accessors.
    if (auto var = dyn_cast<VarDecl>(capture.getDecl())) {
      switch (var->getStorageKind()) {
      case VarDecl::StoredWithTrivialAccessors:
        llvm_unreachable("stored local variable with trivial accessors?");

      case VarDecl::InheritedWithObservers:
        llvm_unreachable("inherited local variable?");

      case VarDecl::StoredWithObservers:
      case VarDecl::Addressed:
      case VarDecl::AddressedWithTrivialAccessors:
      case VarDecl::AddressedWithObservers:
      case VarDecl::ComputedWithMutableAddress:
        // Directly capture storage if we're supposed to.
        if (capture.isDirect())
          return true;

        // Otherwise, transitively capture the accessors.
        SWIFT_FALLTHROUGH;

      case VarDecl::Computed:
        addFunctionCapture(var->getGetter());
        if (auto setter = var->getSetter())
          addFunctionCapture(setter);
        continue;
      
      case VarDecl::Stored:
        return true;
      }
    }
    // Anything else is directly captured.
    return true;
  }
  
  // Recursively consider function captures, since we didn't have any direct
  // captures.
  auto captureHasLocalCaptures = [&](AnyFunctionRef capture) -> bool {
    if (visited.insert(capture).second)
      return hasLoweredLocalCaptures(capture, visited);
    return false;
  };
  
  if (functionCapturesToRecursivelyCheck) {
    for (auto &capture : AFR.getCaptureInfo().getCaptures()) {
      if (!capture.getDecl()->getDeclContext()->isLocalContext())
        continue;
      if (auto func = dyn_cast<AbstractFunctionDecl>(capture.getDecl())) {
        if (captureHasLocalCaptures(func))
          return true;
        continue;
      }
      if (auto var = dyn_cast<VarDecl>(capture.getDecl())) {
        switch (var->getStorageKind()) {
        case VarDecl::StoredWithTrivialAccessors:
          llvm_unreachable("stored local variable with trivial accessors?");
          
        case VarDecl::InheritedWithObservers:
          llvm_unreachable("inherited local variable?");
          
        case VarDecl::StoredWithObservers:
        case VarDecl::Addressed:
        case VarDecl::AddressedWithTrivialAccessors:
        case VarDecl::AddressedWithObservers:
        case VarDecl::ComputedWithMutableAddress:
          assert(!capture.isDirect() && "should have short circuited out");
          // Otherwise, transitively capture the accessors.
          SWIFT_FALLTHROUGH;
          
        case VarDecl::Computed:
          if (captureHasLocalCaptures(var->getGetter()))
            return true;
          if (auto setter = var->getSetter())
            if (captureHasLocalCaptures(setter))
              return true;
          continue;
        
        case VarDecl::Stored:
          llvm_unreachable("should have short circuited out");
        }
      }
      llvm_unreachable("should have short circuited out");
    }
  }
  
  return false;
}
Exemplo n.º 26
0
 /// \brief Check if a Decl is referenced by non-system code.
 ///
 bool isReferenced(::clang::Decl const *D) const {
   return DeclsReferenced.count(D);
 }