std::string RewriteBlocks::SynthesizeBlockHelperFuncs(BlockExpr *CE, int i, const char *funcName, std::string Tag) { std::string StructRef = "struct " + Tag; std::string S = "static void __"; S += funcName; S += "_block_copy_" + utostr(i); S += "(" + StructRef; S += "*dst, " + StructRef; S += "*src) {"; for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), E = ImportedBlockDecls.end(); I != E; ++I) { S += "_Block_copy_assign(&dst->"; S += (*I)->getNameAsString(); S += ", src->"; S += (*I)->getNameAsString(); S += ");}"; } S += "\nstatic void __"; S += funcName; S += "_block_dispose_" + utostr(i); S += "(" + StructRef; S += "*src) {"; for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = ImportedBlockDecls.begin(), E = ImportedBlockDecls.end(); I != E; ++I) { S += "_Block_destroy(src->"; S += (*I)->getNameAsString(); S += ");"; } S += "}\n"; return S; }
void RewriteBlocks::SynthesizeBlockLiterals(SourceLocation FunLocStart, const char *FunName) { // Insert closures that were part of the function. for (unsigned i = 0; i < Blocks.size(); i++) { CollectBlockDeclRefInfo(Blocks[i]); std::string Tag = "__" + std::string(FunName) + "_block_impl_" + utostr(i); std::string CI = SynthesizeBlockImpl(Blocks[i], Tag, ImportedBlockDecls.size() > 0); InsertText(FunLocStart, CI.c_str(), CI.size()); std::string CF = SynthesizeBlockFunc(Blocks[i], i, FunName, Tag); InsertText(FunLocStart, CF.c_str(), CF.size()); if (ImportedBlockDecls.size()) { std::string HF = SynthesizeBlockHelperFuncs(Blocks[i], i, FunName, Tag); InsertText(FunLocStart, HF.c_str(), HF.size()); } BlockDeclRefs.clear(); BlockByRefDecls.clear(); BlockByCopyDecls.clear(); BlockCallExprs.clear(); ImportedBlockDecls.clear(); } Blocks.clear(); RewrittenBlockExprs.clear(); }
std::string RewriteBlocks::SynthesizeBlockInitExpr(BlockExpr *Exp, VarDecl *VD) { Blocks.push_back(Exp); CollectBlockDeclRefInfo(Exp); std::string FuncName; if (CurFunctionDef) FuncName = std::string(CurFunctionDef->getNameAsString()); else if (CurMethodDef) { FuncName = CurMethodDef->getSelector().getAsString(); // Convert colons to underscores. std::string::size_type loc = 0; while ((loc = FuncName.find(":", loc)) != std::string::npos) FuncName.replace(loc, 1, "_"); } else if (VD) FuncName = std::string(VD->getNameAsString()); std::string BlockNumber = utostr(Blocks.size()-1); std::string Tag = "__" + FuncName + "_block_impl_" + BlockNumber; std::string Func = "__" + FuncName + "_block_func_" + BlockNumber; std::string FunkTypeStr; // Get a pointer to the function type so we can cast appropriately. Context->getPointerType(QualType(Exp->getFunctionType(),0)).getAsStringInternal(FunkTypeStr); // Rewrite the closure block with a compound literal. The first cast is // to prevent warnings from the C compiler. std::string Init = "(" + FunkTypeStr; Init += ")&" + Tag; // Initialize the block function. Init += "((void*)" + Func; if (ImportedBlockDecls.size()) { std::string Buf = "__" + FuncName + "_block_copy_" + BlockNumber; Init += ",(void*)" + Buf; Buf = "__" + FuncName + "_block_dispose_" + BlockNumber; Init += ",(void*)" + Buf; } // Add initializers for any closure decl refs. if (BlockDeclRefs.size()) { // Output all "by copy" declarations. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { Init += ","; if (isObjCType((*I)->getType())) { Init += "[["; Init += (*I)->getNameAsString(); Init += " retain] autorelease]"; } else if (isBlockPointerType((*I)->getType())) { Init += "(void *)"; Init += (*I)->getNameAsString(); } else { Init += (*I)->getNameAsString(); } } // Output all "by ref" declarations. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { Init += ",&"; Init += (*I)->getNameAsString(); } } Init += ")"; BlockDeclRefs.clear(); BlockByRefDecls.clear(); BlockByCopyDecls.clear(); ImportedBlockDecls.clear(); return Init; }
std::string RewriteBlocks::SynthesizeBlockFunc(BlockExpr *CE, int i, const char *funcName, std::string Tag) { const FunctionType *AFT = CE->getFunctionType(); QualType RT = AFT->getResultType(); std::string StructRef = "struct " + Tag; std::string S = "static " + RT.getAsString() + " __" + funcName + "_" + "block_func_" + utostr(i); BlockDecl *BD = CE->getBlockDecl(); if (isa<FunctionNoProtoType>(AFT)) { S += "()"; } else if (BD->param_empty()) { S += "(" + StructRef + " *__cself)"; } else { const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); assert(FT && "SynthesizeBlockFunc: No function proto"); S += '('; // first add the implicit argument. S += StructRef + " *__cself, "; std::string ParamStr; for (BlockDecl::param_iterator AI = BD->param_begin(), E = BD->param_end(); AI != E; ++AI) { if (AI != BD->param_begin()) S += ", "; ParamStr = (*AI)->getNameAsString(); (*AI)->getType().getAsStringInternal(ParamStr); S += ParamStr; } if (FT->isVariadic()) { if (!BD->param_empty()) S += ", "; S += "..."; } S += ')'; } S += " {\n"; // Create local declarations to avoid rewriting all closure decl ref exprs. // First, emit a declaration for all "by ref" decls. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByRefDecls.begin(), E = BlockByRefDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); Context->getPointerType((*I)->getType()).getAsStringInternal(Name); S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by ref\n"; } // Next, emit a declaration for all "by copy" declarations. for (llvm::SmallPtrSet<ValueDecl*,8>::iterator I = BlockByCopyDecls.begin(), E = BlockByCopyDecls.end(); I != E; ++I) { S += " "; std::string Name = (*I)->getNameAsString(); // Handle nested closure invocation. For example: // // void (^myImportedClosure)(void); // myImportedClosure = ^(void) { setGlobalInt(x + y); }; // // void (^anotherClosure)(void); // anotherClosure = ^(void) { // myImportedClosure(); // import and invoke the closure // }; // if (isBlockPointerType((*I)->getType())) S += "struct __block_impl *"; else (*I)->getType().getAsStringInternal(Name); S += Name + " = __cself->" + (*I)->getNameAsString() + "; // bound by copy\n"; } std::string RewrittenStr = RewrittenBlockExprs[CE]; const char *cstr = RewrittenStr.c_str(); while (*cstr++ != '{') ; S += cstr; S += "\n"; return S; }