// Generate code that initializes the elements of an array. // Expects an array ref on the top of the stack. dt_t* BackEnd::toDt(ArrayInitializer& init) { ModuleEmitter& modScope = getModuleScope(init.loc); IRState* irstate = modScope.getCurrentIRState(); if (!irstate) { fatalError(init.loc, "null IR state"); } irstate->getBlock(); VarDeclaration* varDecl = irstate->hasVarDecl(); if (!varDecl) { BackEnd::fatalError(init.loc, "initializer expects var decl"); } TYPE& type = toILType(init.loc, varDecl->type); ArrayType* aType = type.isArrayType(); if (!aType) { BackEnd::fatalError(init.loc, "initializer expects array type"); } aType->init(*irstate, *varDecl, init.dim); block& blk = irstate->getBlock(); IRState temp(blk); ArrayAdapter<Initializer*> value(init.value); ArrayAdapter<Expression*> index(init.index); // // and here's where the elements are initialized: // for (size_t i = 0; i != init.dim; ++i) { if (i >= value.size() || i >= index.size()) { assert(false); break; } if (i + 1 != init.dim) { // For each element duplicate the reference to the array // on the top of the stack, so that one is left on the stack for // the next element to use -- except when reaching the last element Instruction::create(blk, IL_dup); } #if 0 //todo:revisit, indices may be null, what are they useful for anyway? DEREF(index[i]).toElem(irstate); #else Const<int>::create(*TYPE::Int32, i, blk, init.loc); #endif auto_ptr<dt_t>(DEREF(value[i]).toDt()); ArrayElemAccess::store(blk, aType->elemTYPE()); } return NULL; }
void visit(DefaultStatement *s) { Blockx *blx = irs->blx; block *bcase = blx->curblock; block *bdefault = irs->getDefaultBlock(); block_next(blx,BCgoto,bdefault); bcase->appendSucc(blx->curblock); if (blx->tryblock != irs->getSwitchBlock()->Btry) s->error("default cannot be in different try block level from switch"); incUsage(irs, s->loc); if (s->statement) Statement_toIR(s->statement, irs); }
void ModuleEmitter::createVar(VarDeclaration& decl) { //IF_DEBUG(clog << __FUNCSIG__ << ": "<< decl.toChars() << endl); // do not expect the decl to have a backend symbol associated with it assert(decl.csym == NULL); IRState* irState = getCurrentIRState(); // variable is at module scope, or function-scope static? if ((irState == irState_) || (irState->hasFuncDecl() && (decl.storage_class & STCstatic)) ) { createGlobalVar(decl, irState); } else { //create it inside function, or aggregate irState->createVar(decl); //make a temp state for the initializer IRState initState(DEREF(irState).getBlock()); //initialize static fields inside the aggregate's static init block if (decl.storage_class & STCstatic) { prepStaticInit(irState, initState, decl); } if (decl.init) { initState.setDecl(&decl); #if !VALUETYPE_STRUCT TYPE& type = toILType(decl); if (StructType* sType = type.isStructType()) { //make sure that the struct is not NULL BackEnd::construct(decl.loc, *sType); } #endif auto_ptr<dt_t> (decl.init->toDt()); } else { TYPE& t = toILType(decl.loc, decl.type); // give static arrays a chance to initialize if (t.isArrayType()) { t.initVar(initState, decl, NULL, NULL); } } } }
void visit(GotoDefaultStatement *s) { block *b; Blockx *blx = irs->blx; block *bdest = irs->getDefaultBlock(); b = blx->curblock; // The rest is equivalent to GotoStatement // Adjust exception handler scope index if in different try blocks if (b->Btry != bdest->Btry) { // Check that bdest is in an enclosing try block for (block *bt = b->Btry; bt != bdest->Btry; bt = bt->Btry) { if (!bt) { //printf("b->Btry = %p, bdest->Btry = %p\n", b->Btry, bdest->Btry); s->error("cannot goto into try block"); break; } } //setScopeIndex(blx, b, bdest->Btry ? bdest->Btry->Bscope_index : -1); } b->appendSucc(bdest); incUsage(irs, s->loc); block_next(blx,BCgoto,NULL); }
// Prepare block for static initializer static void prepStaticInit(IRState* irState, IRState& initState, VarDeclaration& decl) { if (AggregateDeclaration* aggrDecl = irState->hasAggregateDecl()) { if (Class* c = DEREF(aggrDecl->csym).isClass()) { // static members are initialized in a separate block // (which is eventually merged into the class' .cctor) initState.setBlock(c->getStaticInitBlock()); } else if (Struct* s = DEREF(aggrDecl->csym).isStruct()) { initState.setBlock(s->getStaticInitBlock()); } else { BackEnd::fatalError(decl.loc, "unhandled static initializer"); } } }
void TryCatchScope::emitCatchBodiesMSVC(IRState &irs, llvm::Value *) { assert(catchBlocks.empty()); auto &scopes = irs.funcGen().scopes; auto &PGO = irs.funcGen().pgo; auto catchSwitchBlock = irs.insertBBBefore(endbb, "catch.dispatch"); llvm::BasicBlock *unwindto = scopes.currentCleanupScope() > 0 ? scopes.getLandingPad() : nullptr; auto catchSwitchInst = llvm::CatchSwitchInst::Create( llvm::ConstantTokenNone::get(irs.context()), unwindto, stmt->catches->dim, "", catchSwitchBlock); 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); emitBeginCatchMSVC(irs, c, catchSwitchInst); // 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(); } scopes.pushCleanup(catchSwitchBlock, catchSwitchBlock); // if no landing pad is created, the catch blocks are unused, but // the verifier complains if there are catchpads without personality // so we can just set it unconditionally if (!irs.func()->func->hasPersonalityFn()) { const char *personality = "__CxxFrameHandler3"; LLFunction *personalityFn = getRuntimeFunction(Loc(), irs.module, personality); irs.func()->func->setPersonalityFn(personalityFn); } }
void visit(LabelStatement *stmt) override { IF_LOG Logger::println("LabelStatement::toNakedIR(): %s", stmt->loc.toChars()); LOG_SCOPE; printLabelName(irs->nakedAsm, mangleExact(irs->func()->decl), stmt->ident->toChars()); irs->nakedAsm << ":"; if (stmt->statement) { stmt->statement->accept(this); } }
void visit(CaseStatement *s) { Blockx *blx = irs->blx; block *bcase = blx->curblock; Label *clabel = getLabel(irs, blx, s); block_next(blx, BCgoto, clabel->lblock); block *bsw = irs->getSwitchBlock(); if (bsw->BC == BCswitch) bsw->appendSucc(clabel->lblock); // second entry in pair bcase->appendSucc(clabel->lblock); if (blx->tryblock != bsw->Btry) s->error("case cannot be in different try block level from switch"); incUsage(irs, s->loc); if (s->statement) Statement_toIR(s->statement, irs); }
void visit(BreakStatement *s) { block *bbreak; block *b; Blockx *blx = irs->blx; bbreak = irs->getBreakBlock(s->ident); assert(bbreak); b = blx->curblock; incUsage(irs, s->loc); // Adjust exception handler scope index if in different try blocks if (b->Btry != bbreak->Btry) { //setScopeIndex(blx, b, bbreak->Btry ? bbreak->Btry->Bscope_index : -1); } /* Nothing more than a 'goto' to the current break destination */ b->appendSucc(bbreak); block_setLoc(b, s->loc); block_next(blx, BCgoto, NULL); }
void visit(ContinueStatement *s) { block *bcont; block *b; Blockx *blx = irs->blx; //printf("ContinueStatement::toIR() %p\n", this); bcont = irs->getContBlock(s->ident); assert(bcont); b = blx->curblock; incUsage(irs, s->loc); // Adjust exception handler scope index if in different try blocks if (b->Btry != bcont->Btry) { //setScopeIndex(blx, b, bcont->Btry ? bcont->Btry->Bscope_index : -1); } /* Nothing more than a 'goto' to the current continue destination */ b->appendSucc(bcont); block_setLoc(b, s->loc); block_next(blx, BCgoto, NULL); }
TryCatchScope::TryCatchScope(IRState &irs, llvm::Value *ehPtrSlot, TryCatchStatement *stmt, llvm::BasicBlock *endbb) : stmt(stmt), endbb(endbb) { assert(stmt->catches); cleanupScope = irs.funcGen().scopes.currentCleanupScope(); catchesNonExceptions = std::any_of(stmt->catches->begin(), stmt->catches->end(), [](Catch *c) { for (auto cd = c->type->toBasetype()->isClassHandle(); cd; cd = isClassDeclarationOrNull(cd->baseClass)) { // CALYPSO if (cd == ClassDeclaration::exception) return false; } return true; }); #if LDC_LLVM_VER >= 308 if (useMSVCEH()) { emitCatchBodiesMSVC(irs, ehPtrSlot); return; } #endif emitCatchBodies(irs, ehPtrSlot); }
void visit(ReturnStatement *s) { Blockx *blx = irs->blx; enum BC bc; incUsage(irs, s->loc); if (s->exp) { elem *e; FuncDeclaration *func = irs->getFunc(); assert(func); assert(func->type->ty == Tfunction); TypeFunction *tf = (TypeFunction *)(func->type); RET retmethod = retStyle(tf); if (retmethod == RETstack) { elem *es; /* If returning struct literal, write result * directly into return value */ if (s->exp->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)s->exp; char save[sizeof(StructLiteralExp)]; memcpy(save, (void*)se, sizeof(StructLiteralExp)); se->sym = irs->shidden; se->soffset = 0; se->fillHoles = 1; e = toElemDtor(s->exp, irs); memcpy((void*)se, save, sizeof(StructLiteralExp)); } else e = toElemDtor(s->exp, irs); assert(e); if (s->exp->op == TOKstructliteral || (func->nrvo_can && func->nrvo_var)) { // Return value via hidden pointer passed as parameter // Write exp; return shidden; es = e; } else { // Return value via hidden pointer passed as parameter // Write *shidden=exp; return shidden; int op; tym_t ety; ety = e->Ety; es = el_una(OPind,ety,el_var(irs->shidden)); op = (tybasic(ety) == TYstruct) ? OPstreq : OPeq; es = el_bin(op, ety, es, e); if (op == OPstreq) es->ET = Type_toCtype(s->exp->type); } e = el_var(irs->shidden); e = el_bin(OPcomma, e->Ety, es, e); } else if (tf->isref) { // Reference return, so convert to a pointer e = toElemDtor(s->exp, irs); e = addressElem(e, s->exp->type->pointerTo()); } else { e = toElemDtor(s->exp, irs); assert(e); } elem_setLoc(e, s->loc); block_appendexp(blx->curblock, e); bc = BCretexp; } else bc = BCret; if (block *finallyBlock = irs->getFinallyBlock()) { assert(finallyBlock->BC == BC_finally); blx->curblock->appendSucc(finallyBlock); } block_next(blx, bc, NULL); }
int main( int pArgc, const char** pArgs ) { const char* lQueryPtr; int lLock; int lMemId; char lQuery[4096]; char lOp[12]; BOOL lPrintTitle; #ifndef _NO_IPC_ union semun lNULL; #endif #ifdef _NO_IPC_ gGlobalState.Clear(); if( InitLogFile() ) { fprintf( gLogFile, "IMR Init version 0.13.13b %s\n", GetTime( time(NULL)) ); } #endif #ifdef _FAST_CGI_ while( FCGI_Accept() >= 0 ) { #endif lPrintTitle = TRUE; /* Send the header required by the server */ printf("Content-type: text/plain%c%c", 10, 10); lQueryPtr = getenv( "QUERY_STRING" ); if( lQueryPtr == NULL ) { printf( "No parameters\n" ); } else { StrMaxCopy( lQuery, lQueryPtr, 4096 ); UnpadQuery( lQuery ); if( sscanf( lQuery, "=%11s", lOp ) == 1 ) { #ifndef _FAST_CGI_ /* Change the local directory */ char* lPathEnd = strrchr( pArgs[0], '/' ); if( lPathEnd != NULL ) { *lPathEnd = 0; chdir( pArgs[0] ); } #endif if( !strcmp( lOp, "RESET" ) ) { printf( "RESET OK\n\n" ); #ifdef _NO_IPC_ /* // gGlobalState.Clear(); // sleep( 2 ); // return 0; // break; */ #else lLock = semget( IR_SEM_KEY, 1, 0777 ); lMemId = shmget( IR_SHMEM_KEY, sizeof( IRState ), 0666 ); if( lLock != -1 ) { semctl( lLock, 0, IPC_RMID, lNULL ); } if( lMemId != -1 ) { shmctl( lMemId, IPC_RMID, NULL ); } #endif if( InitLogFile() ) { fprintf( gLogFile, "IMR Reset %s\n", GetTime( time(NULL)) ); } #ifdef _FAST_CGI_ break; #endif } else if( !strcmp( lOp, "SET_MESSAGE" ) ) { } /* else if( !strcmp( lOp, "STICK" ) ) { // Fork and leave a child running for 1 hour int lCode = fork(); if( lCode == 0 ) { if( InitLogFile() ) { fprintf( gLogFile, "STICK Start %s\n", GetTime( time(NULL)) ); CloseLogFile(); } close( 0 ); close( 1 ); close( 2 ); sleep( 3600 ); if( InitLogFile() ) { fprintf( gLogFile, "STICK End %s\n", GetTime( time(NULL)) ); CloseLogFile(); } } else if( lCode == -1 ) { printf( "ERROR\n" ); } else { printf( "SUCCESS\n" ); } } */ else { IRState* lState = NULL; #ifdef _NO_IPC_ lState = &gGlobalState; #else int lLock; /* Semaphore */ int lMemId; /* Shared memory */ struct sembuf lSemOp; lSemOp.sem_flg = 0; /*Avoid corruption but must not core-dump SEM_UNDO; // Risky but prevents dead-lock */ lSemOp.sem_num = 0; /* First try to create the structure for the first time */ /* Lock the data struct */ lLock = semget( IR_SEM_KEY, 1, 0777|IPC_CREAT|IPC_EXCL ); if( lLock != -1 ) { union semun lArg; /* Initialize the newly created semaphore */ lArg.val = 1; semctl( lLock, 0, SETVAL, lArg ); } else { lLock = semget( IR_SEM_KEY, 1, 0777 ); } if( lLock == -1 ) { printf( "Unable to get semaphore\n" ); } else { lSemOp.sem_op = -1; if( semop( lLock, &lSemOp, 1 ) == -1 ) { printf( "Unable to decrement semaphore\n" ); lLock = -1; } else { /* From here we can work safely */ lMemId = shmget( IR_SHMEM_KEY, sizeof( IRState ), 0666|IPC_CREAT|IPC_EXCL ); if( lMemId != -1 ) { lState = (IRState*)shmat( lMemId, NULL, 0 ); if( (int)lState == -1 ) { lState = NULL; } if( lState == NULL ) { printf( "Unable to attach shmem\n" ); } else { Clear( lState ); if( InitLogFile() ) { fprintf( gLogFile, "IMR Init %s\n", GetTime( time(NULL)) ); } } } else { lMemId = shmget( IR_SHMEM_KEY, sizeof( IRState ), 0666 ); if( lMemId == -1 ) { printf( "Unable to get shmem\n" ); } else { lState = (IRState*)shmat( lMemId, NULL, 0 ); if( (int)lState == -1 ) { lState = NULL; } if( lState == NULL ) { printf( "Unable to attach shmem\n" ); } } } } } #endif if( lState != NULL ) { lPrintTitle = FALSE; VerifyExpirations( lState ); if( !strcmp( lOp, "REFRESH" ) ) { int lUserIndex; int lUserId; int lTimeStamp; if( sscanf( lQuery, "%*s %d-%u %d", &lUserIndex, &lUserId, &lTimeStamp )==3 ) { PrintStateChange( lState, lUserIndex, lUserId, lTimeStamp ); } } else if( !strcmp( lOp, "ADD_CHAT" ) ) { int lUserIndex; int lUserId; char lChatMessage[200]; if( sscanf( lQuery, "%*s %d-%u %200s", &lUserIndex, &lUserId, lChatMessage )==3 ) { Unpad( lChatMessage ); AddChatMessage( lState, lUserIndex, lUserId, lChatMessage ); } } /* URL?=ADD_USER MAJOR-MINORID VERSION KEY2 KEY3 ALIAS */ else if( !strcmp( lOp, "ADD_USER" ) ) { int lMajorID; int lMinorID; int lVersion; unsigned int lKey2; unsigned int lKey3; char lUserName[40]; #ifdef _EXPIRED_ AddUser( lState, "User", 1,-1, -1, 0, 0 ); #else if( sscanf( lQuery, "%*s %d-%d %d %d %d %40s", &lMajorID, &lMinorID, &lVersion, &lKey2, &lKey3, lUserName )==6 ) { Unpad( lUserName ); AddUser( lState, lUserName, lVersion,lMajorID, lMinorID, lKey2, lKey3 ); } #endif } /* URL?=ADD_GAME USER_ID GAME_NAME TRACK_NAME NBLAP WEAPON PORT */ else if( !strcmp( lOp, "ADD_GAME" ) ) { int lUserIndex; int lUserId; int lNbLap; char lGameName[40]; char lTrackName[40]; int lWeapon; unsigned lPort; if( sscanf( lQuery, "%*s %d-%u %40s %40s %d %d %u", &lUserIndex, &lUserId, lGameName, lTrackName, &lNbLap, &lWeapon, &lPort )==7 ) { const char* lRemoteAddr = getenv( "REMOTE_ADDR" ); if( (lRemoteAddr != NULL)&&(strlen(lRemoteAddr) != 0) ) { Unpad( lTrackName ); Unpad( lGameName ); AddGame( lState, lGameName, lTrackName, lNbLap, lUserIndex, lUserId, lRemoteAddr, lPort, lWeapon ); } } } else if( !strcmp( lOp, "JOIN_GAME" ) ) { int lUserIndex; int lUserId; int lGameIndex; int lGameId; if( sscanf( lQuery, "%*s %d-%u %d-%u", &lGameIndex, &lGameId, &lUserIndex, &lUserId )==4 ) { JoinGame( lState, lGameIndex, lGameId, lUserIndex, lUserId ); } } else if( !strcmp( lOp, "DEL_GAME" ) ) { int lUserIndex; int lUserId; int lGameIndex; int lGameId; if( sscanf( lQuery, "%*s %d-%u %d-%u", &lGameIndex, &lGameId, &lUserIndex, &lUserId )==4 ) { DeleteGame( lState, lGameIndex, lGameId, lUserIndex, lUserId ); } } else if( !strcmp( lOp, "LEAVE_GAME" ) ) { int lUserIndex; int lUserId; int lGameIndex; int lGameId; if( sscanf( lQuery, "%*s %d-%u %d-%u", &lGameIndex, &lGameId, &lUserIndex, &lUserId )==4 ) { LeaveGame( lState, lGameIndex, lGameId, lUserIndex, lUserId ); } } else if( !strcmp( lOp, "DEL_USER" ) ) { int lUserIndex; int lUserId; if( sscanf( lQuery, "%*s %d-%u", &lUserIndex, &lUserId )==2 ) { DeleteUser( lState, lUserIndex, lUserId ); } } else if( !strcmp( lOp, "START_GAME" ) ) { int lUserIndex; int lUserId; int lGameIndex; int lGameId; if( sscanf( lQuery, "%*s %d-%u %d-%u", &lGameIndex, &lGameId, &lUserIndex, &lUserId )==4 ) { StartGame( lState, lGameIndex, lGameId, lUserIndex, lUserId ); } } else { lPrintTitle = TRUE; } } #ifdef _NO_IPC_ lState = NULL; #else /* Release lock */ if( lLock != -1 ) { lSemOp.sem_op = 1; semop( lLock, &lSemOp, 1 ); /* Release memory */ if( lState != NULL ) { shmdt( (char*)lState ); } } #endif } } } CloseLogFile(); if( lPrintTitle ) { printf( "Internet Meeting Room (c)1996,97 GrokkSoft inc.\n" ); } #ifdef _FAST_CGI_ } #endif return 0; }
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}); } }