Exemple #1
0
void TryCatchFinallyScopes::pushTryCatch(TryCatchStatement *stmt,
                                         llvm::BasicBlock *endbb) {
  TryCatchScope scope(irs, getOrCreateEhPtrSlot(), stmt, endbb);
  // Only after emitting all the catch bodies, register the catch scopes.
  // This is so that (re)throwing inside a catch does not match later
  // catches.
  tryCatchScopes.push_back(scope);

  if (!useMSVCEH())
    landingPadsPerCleanupScope[currentCleanupScope()].push_back(nullptr);
}
Exemple #2
0
llvm::BasicBlock *TryCatchFinallyScopes::getOrCreateResumeUnwindBlock() {
  if (!resumeUnwindBlock) {
    resumeUnwindBlock = irs.insertBB("eh.resume");

    llvm::BasicBlock *oldBB = irs.scopebb();
    irs.scope() = IRScope(resumeUnwindBlock);

    llvm::Function *resumeFn =
        getRuntimeFunction(Loc(), irs.module, "_d_eh_resume_unwind");
    irs.ir->CreateCall(resumeFn, DtoLoad(getOrCreateEhPtrSlot()));
    irs.ir->CreateUnreachable();

    irs.scope() = IRScope(oldBB);
  }
  return resumeUnwindBlock;
}
Exemple #3
0
llvm::BasicBlock *IrFunction::getOrCreateResumeUnwindBlock() {
  assert(func == gIR->topfunc() &&
         "Should only access unwind resume block while emitting function.");
  if (!resumeUnwindBlock) {
    resumeUnwindBlock =
        llvm::BasicBlock::Create(gIR->context(), "eh.resume", func);

    llvm::BasicBlock *oldBB = gIR->scopebb();
    gIR->scope() = IRScope(resumeUnwindBlock);

    llvm::Function *resumeFn =
        getRuntimeFunction(Loc(), gIR->module, "_d_eh_resume_unwind");
    gIR->ir->CreateCall(resumeFn, gIR->ir->CreateLoad(getOrCreateEhPtrSlot()));
    gIR->ir->CreateUnreachable();

    gIR->scope() = IRScope(oldBB);
  }
  return resumeUnwindBlock;
}
Exemple #4
0
llvm::BasicBlock *TryCatchFinallyScopes::emitLandingPad() {
#if LDC_LLVM_VER >= 308
  if (useMSVCEH()) {
    assert(currentCleanupScope() > 0);
    return emitLandingPadMSVC(currentCleanupScope() - 1);
  }
#endif

  // save and rewrite scope
  IRScope savedIRScope = irs.scope();

  // insert landing pads at the end of the function, in emission order,
  // to improve human-readability of the IR
  llvm::BasicBlock *beginBB = irs.insertBBBefore(nullptr, "landingPad");
  irs.scope() = IRScope(beginBB);

  llvm::LandingPadInst *landingPad = createLandingPadInst(irs);

  // Stash away the exception object pointer and selector value into their
  // stack slots.
  llvm::Value *ehPtr = DtoExtractValue(landingPad, 0);
  irs.ir->CreateStore(ehPtr, getOrCreateEhPtrSlot());

  llvm::Value *ehSelector = DtoExtractValue(landingPad, 1);
  if (!ehSelectorSlot)
    ehSelectorSlot = DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
  irs.ir->CreateStore(ehSelector, ehSelectorSlot);

  // Add landingpad clauses, emit finallys and 'if' chain to catch the
  // exception.
  CleanupCursor lastCleanup = currentCleanupScope();
  for (auto it = tryCatchScopes.rbegin(), end = tryCatchScopes.rend();
       it != end; ++it) {
    const auto &tryCatchScope = *it;

    // Insert any cleanups in between the previous (inner-more) try-catch scope
    // and this one.
    const auto newCleanup = tryCatchScope.getCleanupScope();
    assert(lastCleanup >= newCleanup);
    if (lastCleanup > newCleanup) {
      landingPad->setCleanup(true);
      llvm::BasicBlock *afterCleanupBB =
          irs.insertBB(beginBB->getName() + llvm::Twine(".after.cleanup"));
      runCleanups(lastCleanup, newCleanup, afterCleanupBB);
      irs.scope() = IRScope(afterCleanupBB);
      lastCleanup = newCleanup;
    }

    for (const auto &cb : tryCatchScope.getCatchBlocks()) {
      // Add the ClassInfo reference to the landingpad instruction so it is
      // emitted to the EH tables.
      landingPad->addClause(cb.classInfoPtr);

      llvm::BasicBlock *mismatchBB =
          irs.insertBB(beginBB->getName() + llvm::Twine(".mismatch"));

      // "Call" llvm.eh.typeid.for, which gives us the eh selector value to
      // compare the landing pad selector value with.
      llvm::Value *ehTypeId =
          irs.ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
                             DtoBitCast(cb.classInfoPtr, getVoidPtrType()));

      // Compare the selector value from the unwinder against the expected
      // one and branch accordingly.
      irs.ir->CreateCondBr(
          irs.ir->CreateICmpEQ(irs.ir->CreateLoad(ehSelectorSlot), ehTypeId),
          cb.bodyBB, mismatchBB, cb.branchWeights);
      irs.scope() = IRScope(mismatchBB);
    }
  }

  // No catch matched. Execute all finallys and resume unwinding.
  auto resumeUnwindBlock = getOrCreateResumeUnwindBlock();
  if (lastCleanup > 0) {
    landingPad->setCleanup(true);
    runCleanups(lastCleanup, 0, resumeUnwindBlock);
  } else if (!tryCatchScopes.empty()) {
    // Directly convert the last mismatch branch into a branch to the
    // unwind resume block.
    irs.scopebb()->replaceAllUsesWith(resumeUnwindBlock);
    irs.scopebb()->eraseFromParent();
  } else {
    irs.ir->CreateBr(resumeUnwindBlock);
  }

  irs.scope() = savedIRScope;
  return beginBB;
}