Exemple #1
0
static LLConstant* build_class_dtor(ClassDeclaration* cd)
{
    FuncDeclaration* dtor = cd->dtor;

    // if no destructor emit a null
    if (!dtor)
        return getNullPtr(getVoidPtrType());

    dtor->codegen(Type::sir);
    return llvm::ConstantExpr::getBitCast(dtor->ir.irFunc->func, getPtrToType(LLType::getInt8Ty(gIR->context())));
}
Exemple #2
0
static void build_dso_registry_calls(std::string moduleMangle,
                                     llvm::Constant *thisModuleInfo) {
  // Build the ModuleInfo reference and bracketing symbols.
  llvm::Type *const moduleInfoPtrTy = DtoPtrToType(Module::moduleinfo->type);

  // Order is important here: We must create the symbols in the
  // bracketing sections right before/after the ModuleInfo reference
  // so that they end up in the correct order in the object file.
  auto minfoBeg =
      new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy,
                               false, // FIXME: mRelocModel != llvm::Reloc::PIC_
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(moduleInfoPtrTy), "_minfo_beg");
  minfoBeg->setSection(".minfo_beg");
  minfoBeg->setVisibility(llvm::GlobalValue::HiddenVisibility);

  std::string thismrefname = "_D";
  thismrefname += moduleMangle;
  thismrefname += "11__moduleRefZ";
  auto thismref = new llvm::GlobalVariable(
      gIR->module, moduleInfoPtrTy,
      false, // FIXME: mRelocModel != llvm::Reloc::PIC_
      llvm::GlobalValue::LinkOnceODRLinkage,
      DtoBitCast(thisModuleInfo, moduleInfoPtrTy), thismrefname);
  thismref->setSection(".minfo");
  gIR->usedArray.push_back(thismref);

  auto minfoEnd =
      new llvm::GlobalVariable(gIR->module, moduleInfoPtrTy,
                               false, // FIXME: mRelocModel != llvm::Reloc::PIC_
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(moduleInfoPtrTy), "_minfo_end");
  minfoEnd->setSection(".minfo_end");
  minfoEnd->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // Build the ctor to invoke _d_dso_registry.

  // This is the DSO slot for use by the druntime implementation.
  auto dsoSlot =
      new llvm::GlobalVariable(gIR->module, getVoidPtrType(), false,
                               llvm::GlobalValue::LinkOnceODRLinkage,
                               getNullPtr(getVoidPtrType()), "ldc.dso_slot");
  dsoSlot->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // Okay, so the theory is easy: We want to have one global constructor and
  // destructor per object (i.e. executable/shared library) that calls
  // _d_dso_registry with the respective DSO record. However, there are a
  // couple of issues that make this harder than necessary:
  //
  //  1) The natural way to implement the "one-per-image" part would be to
  //     emit a weak reference to a weak function into a .ctors.<somename>
  //     section (llvm.global_ctors doesn't support the necessary
  //     functionality, so we'd use our knowledge of the linker script to work
  //     around that). But as of LLVM 3.4, emitting a symbol both as weak and
  //     into a custom section is not supported by the MC layer. Thus, we have
  //     to use a normal ctor/dtor and manually ensure that we only perform
  //     the call once. This is done by introducing ldc.dso_initialized.
  //
  //  2) To make sure the .minfo section isn't removed by the linker when
  //     using --gc-sections, we need to keep a reference to it around in
  //     _every_ object file (as --gc-sections works per object file). The
  //     natural place for this is the ctor, where we just load a reference
  //     on the stack after the DSO record (to ensure LLVM doesn't optimize
  //     it out). However, this way, we need to have at least one ctor
  //     instance per object file be pulled into the final executable. We
  //     do this here by making the module mangle string part of its name,
  //     even thoguht this is slightly wasteful on -singleobj builds.
  //
  // It might be a better idea to simply use a custom linker script (using
  // INSERT AFTER… so as to still keep the default one) to avoid all these
  // problems. This would mean that it is no longer safe to link D objects
  // directly using e.g. "g++ dcode.o cppcode.o", though.

  auto dsoInitialized = new llvm::GlobalVariable(
      gIR->module, llvm::Type::getInt8Ty(gIR->context()), false,
      llvm::GlobalValue::LinkOnceODRLinkage,
      llvm::ConstantInt::get(llvm::Type::getInt8Ty(gIR->context()), 0),
      "ldc.dso_initialized");
  dsoInitialized->setVisibility(llvm::GlobalValue::HiddenVisibility);

  // There is no reason for this cast to void*, other than that removing it
  // seems to trigger a bug in the llvm::Linker (at least on LLVM 3.4)
  // causing it to not merge the %object.ModuleInfo types properly. This
  // manifests itself in a type mismatch assertion being triggered on the
  // minfoUsedPointer store in the ctor as soon as the optimizer runs.
  llvm::Value *minfoRefPtr = DtoBitCast(thismref, getVoidPtrType());

  std::string ctorName = "ldc.dso_ctor.";
  ctorName += moduleMangle;
  llvm::Function *dsoCtor = llvm::Function::Create(
      llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false),
      llvm::GlobalValue::LinkOnceODRLinkage, ctorName, &gIR->module);
  dsoCtor->setVisibility(llvm::GlobalValue::HiddenVisibility);
  build_dso_ctor_dtor_body(dsoCtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd,
                           minfoRefPtr, false);
  llvm::appendToGlobalCtors(gIR->module, dsoCtor, 65535);

  std::string dtorName = "ldc.dso_dtor.";
  dtorName += moduleMangle;
  llvm::Function *dsoDtor = llvm::Function::Create(
      llvm::FunctionType::get(llvm::Type::getVoidTy(gIR->context()), false),
      llvm::GlobalValue::LinkOnceODRLinkage, dtorName, &gIR->module);
  dsoDtor->setVisibility(llvm::GlobalValue::HiddenVisibility);
  build_dso_ctor_dtor_body(dsoDtor, dsoInitialized, dsoSlot, minfoBeg, minfoEnd,
                           minfoRefPtr, true);
  llvm::appendToGlobalDtors(gIR->module, dsoDtor, 65535);
}
Exemple #3
0
llvm::BasicBlock *
TryCatchFinallyScopes::runCleanupPad(CleanupCursor scope,
                                     llvm::BasicBlock *unwindTo) {
  // a catch switch never needs to be cloned and is an unwind target itself
  if (isCatchSwitchBlock(cleanupScopes[scope].beginBlock()))
    return cleanupScopes[scope].beginBlock();

  // each cleanup block is bracketed by a pair of cleanuppad/cleanupret
  // instructions, any unwinding should also just continue at the next
  // cleanup block, e.g.:
  //
  // cleanuppad:
  //   %0 = cleanuppad within %funclet[]
  //   %frame = nullptr
  //   if (!_d_enter_cleanup(%frame)) br label %cleanupret
  //                                  else br label %copy
  //
  // copy:
  //   invoke _dtor to %cleanupret unwind %unwindTo [ "funclet"(token %0) ]
  //
  // cleanupret:
  //   _d_leave_cleanup(%frame)
  //   cleanupret %0 unwind %unwindTo
  //
  llvm::BasicBlock *cleanupbb = irs.insertBB("cleanuppad");
  auto funcletToken = llvm::ConstantTokenNone::get(irs.context());
  auto cleanuppad =
      llvm::CleanupPadInst::Create(funcletToken, {}, "", cleanupbb);

  llvm::BasicBlock *cleanupret = irs.insertBBAfter(cleanupbb, "cleanupret");

  // preparation to allocate some space on the stack where _d_enter_cleanup
  //  can place an exception frame (but not done here)
  auto frame = getNullPtr(getVoidPtrType());

  auto savedInsertBlock = irs.ir->GetInsertBlock();
  auto savedInsertPoint = irs.ir->GetInsertPoint();
  auto savedDbgLoc = irs.DBuilder.GetCurrentLoc();

  auto endFn = getRuntimeFunction(Loc(), irs.module, "_d_leave_cleanup");
  irs.ir->SetInsertPoint(cleanupret);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  irs.ir->CreateCall(endFn, frame,
                     {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::CleanupReturnInst::Create(cleanuppad, unwindTo, cleanupret);

  auto copybb = cleanupScopes[scope].runCopying(irs, cleanupbb, cleanupret,
                                                unwindTo, cleanuppad);

  auto beginFn = getRuntimeFunction(Loc(), irs.module, "_d_enter_cleanup");
  irs.ir->SetInsertPoint(cleanupbb);
  irs.DBuilder.EmitStopPoint(irs.func()->decl->loc);
  auto exec = irs.ir->CreateCall(
      beginFn, frame, {llvm::OperandBundleDef("funclet", cleanuppad)}, "");
  llvm::BranchInst::Create(copybb, cleanupret, exec, cleanupbb);

  irs.ir->SetInsertPoint(savedInsertBlock, savedInsertPoint);
  irs.DBuilder.EmitStopPoint(savedDbgLoc);

  return cleanupbb;
}