void DtoInitClass(TypeClass* tc, LLValue* dst) { DtoResolveClass(tc->sym); // Set vtable field. Doing this seperately might be optimized better. LLValue* tmp = DtoGEPi(dst, 0, 0, "vtbl"); LLValue* val = DtoBitCast(getIrAggr(tc->sym)->getVtblSymbol(), tmp->getType()->getContainedType(0)); DtoStore(val, tmp); // For D classes, set the monitor field to null. const bool isCPPclass = tc->sym->isCPPclass() ? true : false; if (!isCPPclass) { tmp = DtoGEPi(dst, 0, 1, "monitor"); val = LLConstant::getNullValue(tmp->getType()->getContainedType(0)); DtoStore(val, tmp); } // Copy the rest from the static initializer, if any. unsigned const firstDataIdx = isCPPclass ? 1 : 2; uint64_t const dataBytes = tc->sym->structsize - Target::ptrsize * firstDataIdx; if (dataBytes == 0) return; LLValue* dstarr = DtoGEPi(dst, 0, firstDataIdx); // init symbols might not have valid types LLValue* initsym = getIrAggr(tc->sym)->getInitSymbol(); initsym = DtoBitCast(initsym, DtoType(tc)); LLValue* srcarr = DtoGEPi(initsym, 0, firstDataIdx); DtoMemCpy(dstarr, srcarr, DtoConstSize_t(dataBytes)); }
LLValue* DtoIndexClass(LLValue* src, ClassDeclaration* cd, VarDeclaration* vd) { Logger::println("indexing class field %s:", vd->toPrettyChars()); LOG_SCOPE; if (Logger::enabled()) Logger::cout() << "src: " << *src << '\n'; // make sure class is resolved DtoResolveClass(cd); // vd must be a field IrField* field = vd->ir.irField; assert(field); // get the start pointer LLType* st = DtoType(cd->type); // cast to the struct type src = DtoBitCast(src, st); // gep to the index #if 0 if (Logger::enabled()) { Logger::cout() << "src2: " << *src << '\n'; Logger::cout() << "index: " << field->index << '\n'; Logger::cout() << "srctype: " << *src->getType() << '\n'; } #endif LLValue* val = DtoGEPi(src, 0, field->index); // do we need to offset further? (union area) if (field->unionOffset) { // cast to void* val = DtoBitCast(val, getVoidPtrType()); // offset val = DtoGEPi1(val, field->unionOffset); } // cast it to the right type val = DtoBitCast(val, getPtrToType(DtoType(vd->type))); if (Logger::enabled()) Logger::cout() << "value: " << *val << '\n'; return val; }
void DtoResolveClass(ClassDeclaration* cd) { if (cd->ir.isResolved()) return; cd->ir.setResolved(); IF_LOG Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure the base classes are processed first for (BaseClasses::iterator I = cd->baseclasses->begin(), E = cd->baseclasses->end(); I != E; ++I) { DtoResolveClass((*I)->base); } // make sure type exists DtoType(cd->type); // create IrAggr IrAggr* irAggr = getIrAggr(cd, true); // make sure all fields really get their ir field for (VarDeclarations::iterator I = cd->fields.begin(), E = cd->fields.end(); I != E; ++I) { VarDeclaration* vd = *I; IF_LOG { if (isIrFieldCreated(vd)) Logger::println("class field already exists"); } getIrField(vd, true); } // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irAggr->initializeInterface(); } }
void DtoResolveClass(ClassDeclaration *cd) { if (cd->ir->isResolved()) { return; } cd->ir->setResolved(); IF_LOG Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars()); LOG_SCOPE; // make sure the base classes are processed first for (auto bc : *cd->baseclasses) { DtoResolveClass(bc->sym); } // make sure type exists DtoType(cd->type); // create IrAggr IrAggr *irAggr = getIrAggr(cd, true); // make sure all fields really get their ir field for (auto vd : cd->fields) { IF_LOG { if (isIrFieldCreated(vd)) { Logger::println("class field already exists"); } } getIrField(vd, true); } // emit the interfaceInfosZ symbol if necessary if (cd->vtblInterfaces && cd->vtblInterfaces->dim > 0) { irAggr->getInterfaceArraySymbol(); // initializer is applied when it's built } // interface only emit typeinfo and classinfo if (cd->isInterfaceDeclaration()) { irAggr->initializeInterface(); } }
LLStructType* DtoInterfaceInfoType() { if (gIR->interfaceInfoType) return gIR->interfaceInfoType; // build interface info type LLSmallVector<LLType*, 3> types; // ClassInfo classinfo ClassDeclaration* cd2 = ClassDeclaration::classinfo; DtoResolveClass(cd2); types.push_back(DtoType(cd2->type)); // void*[] vtbl LLSmallVector<LLType*, 2> vtbltypes; vtbltypes.push_back(DtoSize_t()); LLType* byteptrptrty = getPtrToType(getPtrToType(LLType::getInt8Ty(gIR->context()))); vtbltypes.push_back(byteptrptrty); types.push_back(LLStructType::get(gIR->context(), vtbltypes)); // int offset types.push_back(LLType::getInt32Ty(gIR->context())); // create type gIR->interfaceInfoType = LLStructType::get(gIR->context(), types); return gIR->interfaceInfoType; }
DValue* DtoNewClass(Loc& loc, TypeClass* tc, NewExp* newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue* mem; if (newexp->onstack) { // FIXME align scope class to its largest member mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), 0, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, getIrFunc(newexp->allocator)->func); DValue* res = DtoCallFunction(newexp->loc, NULL, &dfn, newexp->newargs); mem = DtoBitCast(res->getRVal(), DtoType(tc), ".newclass_custom"); } // default allocator else { llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass"); LLConstant* ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(Type::typeinfoclass->type)); mem = gIR->CreateCallOrInvoke(fn, ci, ".newclass_gc_alloc").getInstruction(); mem = DtoBitCast(mem, DtoType(tc), ".newclass_gc"); } // init DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; DValue* thisval = toElem(newexp->thisexp); unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue* src = thisval->getRVal(); LLValue* dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, getIrFunc(newexp->member)->func, mem); return DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); } // return default constructed class return new DImValue(tc, mem); }
DValue* DtoCastClass(Loc& loc, DValue* val, Type* _to) { IF_LOG Logger::println("DtoCastClass(%s, %s)", val->getType()->toChars(), _to->toChars()); LOG_SCOPE; Type* to = _to->toBasetype(); // class -> pointer if (to->ty == Tpointer) { IF_LOG Logger::println("to pointer"); LLType* tolltype = DtoType(_to); LLValue* rval = DtoBitCast(val->getRVal(), tolltype); return new DImValue(_to, rval); } // class -> bool else if (to->ty == Tbool) { IF_LOG Logger::println("to bool"); LLValue* llval = val->getRVal(); LLValue* zero = LLConstant::getNullValue(llval->getType()); return new DImValue(_to, gIR->ir->CreateICmpNE(llval, zero)); } // class -> integer else if (to->isintegral()) { IF_LOG Logger::println("to %s", to->toChars()); // get class ptr LLValue* v = val->getRVal(); // cast to size_t v = gIR->ir->CreatePtrToInt(v, DtoSize_t(), ""); // cast to the final int type DImValue im(Type::tsize_t, v); return DtoCastInt(loc, &im, _to); } // must be class/interface assert(to->ty == Tclass); TypeClass* tc = static_cast<TypeClass*>(to); // from type Type* from = val->getType()->toBasetype(); TypeClass* fc = static_cast<TypeClass*>(from); // x -> interface if (InterfaceDeclaration* it = tc->sym->isInterfaceDeclaration()) { Logger::println("to interface"); // interface -> interface if (fc->sym->isInterfaceDeclaration()) { Logger::println("from interface"); return DtoDynamicCastInterface(loc, val, _to); } // class -> interface - static cast else if (it->isBaseOf(fc->sym,NULL)) { Logger::println("static down cast"); // get the from class ClassDeclaration* cd = fc->sym->isClassDeclaration(); DtoResolveClass(cd); // add this IrTypeClass* typeclass = stripModifiers(fc)->ctype->isClass(); // find interface impl size_t i_index = typeclass->getInterfaceIndex(it); assert(i_index != ~0UL && "requesting interface that is not implemented by this class"); // offset pointer LLValue* v = val->getRVal(); LLValue* orig = v; v = DtoGEPi(v, 0, i_index); LLType* ifType = DtoType(_to); IF_LOG { Logger::cout() << "V = " << *v << std::endl; Logger::cout() << "T = " << *ifType << std::endl; } v = DtoBitCast(v, ifType); // Check whether the original value was null, and return null if so. // Sure we could have jumped over the code above in this case, but // it's just a GEP and (maybe) a pointer-to-pointer BitCast, so it // should be pretty cheap and perfectly safe even if the original was null. LLValue* isNull = gIR->ir->CreateICmpEQ(orig, LLConstant::getNullValue(orig->getType()), ".nullcheck"); v = gIR->ir->CreateSelect(isNull, LLConstant::getNullValue(ifType), v, ".interface"); // return r-value return new DImValue(_to, v); }
// Put out instance of ModuleInfo for this Module void Module::genmoduleinfo() { // resolve ModuleInfo if (!moduleinfo) { error("object.d is missing the ModuleInfo struct"); fatal(); } // check for patch else { // The base struct should consist only of _flags/_index. if (moduleinfo->structsize != 4 + 4) { error("object.d ModuleInfo class is incorrect"); fatal(); } } // use the RTTIBuilder RTTIBuilder b(moduleinfo); // some types LLType* moduleinfoTy = moduleinfo->type->irtype->getLLType(); LLType* classinfoTy = Type::typeinfoclass->type->irtype->getLLType(); // importedModules[] std::vector<LLConstant*> importInits; LLConstant* importedModules = 0; llvm::ArrayType* importedModulesTy = 0; for (size_t i = 0; i < aimports.dim; i++) { Module *m = static_cast<Module *>(aimports.data[i]); if (!m->needModuleInfo() || m == this) continue; // declare the imported module info std::string m_name("_D"); m_name.append(m->mangle()); m_name.append("12__ModuleInfoZ"); llvm::GlobalVariable* m_gvar = gIR->module->getGlobalVariable(m_name); if (!m_gvar) m_gvar = new llvm::GlobalVariable(*gIR->module, moduleinfoTy, false, llvm::GlobalValue::ExternalLinkage, NULL, m_name); importInits.push_back(m_gvar); } // has import array? if (!importInits.empty()) { importedModulesTy = llvm::ArrayType::get(getPtrToType(moduleinfoTy), importInits.size()); importedModules = LLConstantArray::get(importedModulesTy, importInits); } // localClasses[] LLConstant* localClasses = 0; llvm::ArrayType* localClassesTy = 0; ClassDeclarations aclasses; //printf("members->dim = %d\n", members->dim); for (size_t i = 0; i < members->dim; i++) { Dsymbol *member; member = static_cast<Dsymbol *>(members->data[i]); //printf("\tmember '%s'\n", member->toChars()); member->addLocalClass(&aclasses); } // fill inits std::vector<LLConstant*> classInits; for (size_t i = 0; i < aclasses.dim; i++) { ClassDeclaration* cd = aclasses[i]; DtoResolveClass(cd); if (cd->isInterfaceDeclaration()) { IF_LOG Logger::println("skipping interface '%s' in moduleinfo", cd->toPrettyChars()); continue; } else if (cd->sizeok != SIZEOKdone) { IF_LOG Logger::println("skipping opaque class declaration '%s' in moduleinfo", cd->toPrettyChars()); continue; } IF_LOG Logger::println("class: %s", cd->toPrettyChars()); LLConstant *c = DtoBitCast(getIrAggr(cd)->getClassInfoSymbol(), classinfoTy); classInits.push_back(c); } // has class array? if (!classInits.empty()) { localClassesTy = llvm::ArrayType::get(classinfoTy, classInits.size()); localClasses = LLConstantArray::get(localClassesTy, classInits); } // These must match the values in druntime/src/object_.d #define MIstandalone 4 #define MItlsctor 8 #define MItlsdtor 0x10 #define MIctor 0x20 #define MIdtor 0x40 #define MIxgetMembers 0x80 #define MIictor 0x100 #define MIunitTest 0x200 #define MIimportedModules 0x400 #define MIlocalClasses 0x800 #define MInew 0x80000000 // it's the "new" layout llvm::Function* fsharedctor = build_module_shared_ctor(); llvm::Function* fshareddtor = build_module_shared_dtor(); llvm::Function* funittest = build_module_unittest(); llvm::Function* fctor = build_module_ctor(); llvm::Function* fdtor = build_module_dtor(); unsigned flags = MInew; if (fctor) flags |= MItlsctor; if (fdtor) flags |= MItlsdtor; if (fsharedctor) flags |= MIctor; if (fshareddtor) flags |= MIdtor; #if 0 if (fgetmembers) flags |= MIxgetMembers; if (fictor) flags |= MIictor; #endif if (funittest) flags |= MIunitTest; if (importedModules) flags |= MIimportedModules; if (localClasses) flags |= MIlocalClasses; if (!needmoduleinfo) flags |= MIstandalone; b.push_uint(flags); // flags b.push_uint(0); // index if (fctor) b.push(fctor); if (fdtor) b.push(fdtor); if (fsharedctor) b.push(fsharedctor); if (fshareddtor) b.push(fshareddtor); #if 0 if (fgetmembers) b.push(fgetmembers); if (fictor) b.push(fictor); #endif if (funittest) b.push(funittest); if (importedModules) { b.push_size(importInits.size()); b.push(importedModules); } if (localClasses) { b.push_size(classInits.size()); b.push(localClasses); } // Put out module name as a 0-terminated string. const char *name = toPrettyChars(); const size_t len = strlen(name) + 1; llvm::IntegerType *it = llvm::IntegerType::getInt8Ty(gIR->context()); llvm::ArrayType *at = llvm::ArrayType::get(it, len); b.push(toConstantArray(it, at, name, len, false)); // create and set initializer LLGlobalVariable *moduleInfoSym = moduleInfoSymbol(); b.finalize(moduleInfoSym->getType()->getPointerElementType(), moduleInfoSym); moduleInfoSym->setLinkage(llvm::GlobalValue::ExternalLinkage); if (global.params.isLinux) { build_dso_registry_calls(moduleInfoSym); } else { // build the modulereference and ctor for registering it LLFunction* mictor = build_module_reference_and_ctor(moduleInfoSym); AppendFunctionToLLVMGlobalCtorsDtors(mictor, 65535, true); } }
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) { assert(catchBlocks.empty()); auto &PGO = irs.funcGen().pgo; const auto entryCount = PGO.setCurrentStmt(stmt); struct CBPrototype { Type *t; llvm::BasicBlock *catchBB; uint64_t catchCount; uint64_t uncaughtCount; }; llvm::SmallVector<CBPrototype, 8> cbPrototypes; cbPrototypes.reserve(stmt->catches->dim); for (auto c : *stmt->catches) { auto catchBB = irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars()); irs.scope() = IRScope(catchBB); irs.DBuilder.EmitBlockStart(c->loc); PGO.emitCounterIncrement(c); bool isCPPclass = false; if (auto lp = c->langPlugin()) // CALYPSO lp->codegen()->toBeginCatch(irs, c); else { const auto cd = c->type->toBasetype()->isClassHandle(); isCPPclass = cd->isCPPclass(); const auto enterCatchFn = getRuntimeFunction( Loc(), irs.module, isCPPclass ? "__cxa_begin_catch" : "_d_eh_enter_catch"); const auto ptr = DtoLoad(ehPtrSlot); const auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr); // For catches that use the Throwable object, create storage for it. // We will set it in the code that branches from the landing pads // (there might be more than one) to catchBB. if (c->var) { // This will alloca if we haven't already and take care of nested refs // if there are any. DtoDeclarationExp(c->var); // Copy the exception reference over from the _d_eh_enter_catch return // value. DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)), getIrLocal(c->var)->value); } } // Emit handler, if there is one. The handler is zero, for instance, // when building 'catch { debug foo(); }' in non-debug mode. if (isCPPclass) { // from DMD: /* C++ catches need to end with call to __cxa_end_catch(). * Create: * try { handler } finally { __cxa_end_catch(); } * Note that this is worst case code because it always sets up an * exception handler. At some point should try to do better. */ FuncDeclaration *fdend = FuncDeclaration::genCfunc(nullptr, Type::tvoid, "__cxa_end_catch"); Expression *efunc = VarExp::create(Loc(), fdend); Expression *ecall = CallExp::create(Loc(), efunc); ecall->type = Type::tvoid; Statement *call = ExpStatement::create(Loc(), ecall); Statement *stmt = c->handler ? TryFinallyStatement::create(Loc(), c->handler, call) : call; Statement_toIR(stmt, &irs); } else { if (c->handler) Statement_toIR(c->handler, &irs); } if (!irs.scopereturned()) { // CALYPSO FIXME: _cxa_end_catch won't be called if it has already returned if (auto lp = c->langPlugin()) lp->codegen()->toEndCatch(irs, c); irs.ir->CreateBr(endbb); } irs.DBuilder.EmitBlockEnd(); // PGO information, currently unused auto catchCount = PGO.getRegionCount(c); // uncaughtCount is handled in a separate pass below cbPrototypes.push_back({c->type->toBasetype(), catchBB, catchCount, 0}); // CALYPSO } // Total number of uncaught exceptions is equal to the execution count at // the start of the try block minus the one after the continuation. // uncaughtCount keeps track of the exception type mismatch count while // iterating through the catch block prototypes in reversed order. auto uncaughtCount = entryCount - PGO.getRegionCount(stmt); for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end; ++it) { it->uncaughtCount = uncaughtCount; // Add this catch block's match count to the uncaughtCount, because these // failed to match the remaining (lexically preceding) catch blocks. uncaughtCount += it->catchCount; } catchBlocks.reserve(stmt->catches->dim); auto c_it = stmt->catches->begin(); // CALYPSO for (const auto &p : cbPrototypes) { auto branchWeights = PGO.createProfileWeights(p.catchCount, p.uncaughtCount); LLGlobalVariable *ci; if (auto lp = (*c_it)->langPlugin()) // CALYPSO ci = lp->codegen()->toCatchScopeType(irs, p.t); else { ClassDeclaration *cd = p.t->isClassHandle(); DtoResolveClass(cd); if (cd->isCPPclass()) { const char *name = Target::cppTypeInfoMangle(cd); auto cpp_ti = getOrCreateGlobal( cd->loc, irs.module, getVoidPtrType(), /*isConstant=*/true, LLGlobalValue::ExternalLinkage, /*init=*/nullptr, name); // Wrap std::type_info pointers inside a __cpp_type_info_ptr class instance so that // the personality routine may differentiate C++ catch clauses from D ones. OutBuffer mangleBuf; mangleBuf.writestring("_D"); mangleToBuffer(cd, &mangleBuf); mangleBuf.printf("%d%s", 18, "_cpp_type_info_ptr"); const auto wrapperMangle = getIRMangledVarName(mangleBuf.peekString(), LINKd); RTTIBuilder b(ClassDeclaration::cpp_type_info_ptr); b.push(cpp_ti); auto wrapperType = llvm::cast<llvm::StructType>( static_cast<IrTypeClass*>(ClassDeclaration::cpp_type_info_ptr->type->ctype)->getMemoryLLType()); auto wrapperInit = b.get_constant(wrapperType); ci = getOrCreateGlobal( cd->loc, irs.module, wrapperType, /*isConstant=*/true, LLGlobalValue::LinkOnceODRLinkage, wrapperInit, wrapperMangle); } else { ci = getIrAggr(cd)->getClassInfoSymbol(); } } catchBlocks.push_back({ci, p.catchBB, branchWeights}); c_it++; } }
void TryCatchScope::emitCatchBodies(IRState &irs, llvm::Value *ehPtrSlot) { assert(catchBlocks.empty()); auto &PGO = irs.funcGen().pgo; const auto entryCount = PGO.setCurrentStmt(stmt); struct CBPrototype { ClassDeclaration *cd; llvm::BasicBlock *catchBB; uint64_t catchCount; uint64_t uncaughtCount; }; llvm::SmallVector<CBPrototype, 8> cbPrototypes; cbPrototypes.reserve(stmt->catches->dim); for (auto c : *stmt->catches) { auto catchBB = irs.insertBBBefore(endbb, llvm::Twine("catch.") + c->type->toChars()); irs.scope() = IRScope(catchBB); irs.DBuilder.EmitBlockStart(c->loc); PGO.emitCounterIncrement(c); const auto enterCatchFn = getRuntimeFunction(Loc(), irs.module, "_d_eh_enter_catch"); auto ptr = DtoLoad(ehPtrSlot); auto throwableObj = irs.ir->CreateCall(enterCatchFn, ptr); // For catches that use the Throwable object, create storage for it. // We will set it in the code that branches from the landing pads // (there might be more than one) to catchBB. if (c->var) { // This will alloca if we haven't already and take care of nested refs // if there are any. DtoDeclarationExp(c->var); // Copy the exception reference over from the _d_eh_enter_catch return // value. DtoStore(DtoBitCast(throwableObj, DtoType(c->var->type)), getIrLocal(c->var)->value); } // Emit handler, if there is one. The handler is zero, for instance, // when building 'catch { debug foo(); }' in non-debug mode. if (c->handler) Statement_toIR(c->handler, &irs); if (!irs.scopereturned()) irs.ir->CreateBr(endbb); irs.DBuilder.EmitBlockEnd(); // PGO information, currently unused auto catchCount = PGO.getRegionCount(c); // uncaughtCount is handled in a separate pass below auto cd = c->type->toBasetype()->isClassHandle(); cbPrototypes.push_back({cd, catchBB, catchCount, 0}); } // Total number of uncaught exceptions is equal to the execution count at // the start of the try block minus the one after the continuation. // uncaughtCount keeps track of the exception type mismatch count while // iterating through the catch block prototypes in reversed order. auto uncaughtCount = entryCount - PGO.getRegionCount(stmt); for (auto it = cbPrototypes.rbegin(), end = cbPrototypes.rend(); it != end; ++it) { it->uncaughtCount = uncaughtCount; // Add this catch block's match count to the uncaughtCount, because these // failed to match the remaining (lexically preceding) catch blocks. uncaughtCount += it->catchCount; } catchBlocks.reserve(stmt->catches->dim); for (const auto &p : cbPrototypes) { auto branchWeights = PGO.createProfileWeights(p.catchCount, p.uncaughtCount); DtoResolveClass(p.cd); auto ci = getIrAggr(p.cd)->getClassInfoSymbol(); catchBlocks.push_back({ci, p.catchBB, branchWeights}); } }
DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) { // resolve type DtoResolveClass(tc->sym); // allocate LLValue *mem; bool doInit = true; if (newexp->onstack) { unsigned alignment = tc->sym->alignsize; if (alignment == STRUCTALIGN_DEFAULT) alignment = 0; mem = DtoRawAlloca(DtoType(tc)->getContainedType(0), alignment, ".newclass_alloca"); } // custom allocator else if (newexp->allocator) { DtoResolveFunction(newexp->allocator); DFuncValue dfn(newexp->allocator, DtoCallee(newexp->allocator)); DValue *res = DtoCallFunction(newexp->loc, nullptr, &dfn, newexp->newargs); mem = DtoBitCast(DtoRVal(res), DtoType(tc), ".newclass_custom"); } // default allocator else { const bool useEHAlloc = global.params.ehnogc && newexp->thrownew; llvm::Function *fn = getRuntimeFunction( loc, gIR->module, useEHAlloc ? "_d_newThrowable" : "_d_allocclass"); LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(), DtoType(getClassInfoType())); mem = gIR->CreateCallOrInvoke(fn, ci, useEHAlloc ? ".newthrowable_alloc" : ".newclass_gc_alloc") .getInstruction(); mem = DtoBitCast(mem, DtoType(tc), useEHAlloc ? ".newthrowable" : ".newclass_gc"); doInit = !useEHAlloc; } // init if (doInit) DtoInitClass(tc, mem); // init inner-class outer reference if (newexp->thisexp) { Logger::println("Resolving outer class"); LOG_SCOPE; unsigned idx = getFieldGEPIndex(tc->sym, tc->sym->vthis); LLValue *src = DtoRVal(newexp->thisexp); LLValue *dst = DtoGEPi(mem, 0, idx); IF_LOG Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n'; DtoStore(src, DtoBitCast(dst, getPtrToType(src->getType()))); } // set the context for nested classes else if (tc->sym->isNested() && tc->sym->vthis) { DtoResolveNestedContext(loc, tc->sym, mem); } // call constructor if (newexp->member) { // evaluate argprefix if (newexp->argprefix) { toElemDtor(newexp->argprefix); } Logger::println("Calling constructor"); assert(newexp->arguments != NULL); DtoResolveFunction(newexp->member); DFuncValue dfn(newexp->member, DtoCallee(newexp->member), mem); // ignore ctor return value (C++ ctors on Posix may not return `this`) DtoCallFunction(newexp->loc, tc, &dfn, newexp->arguments); return new DImValue(tc, mem); } assert(newexp->argprefix == NULL); // return default constructed class return new DImValue(tc, mem); }