diff options
-rw-r--r-- | lib/CodeGen/CGCXX.cpp | 120 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenFunction.h | 3 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.h | 4 | ||||
-rw-r--r-- | lib/CodeGen/Mangle.cpp | 37 | ||||
-rw-r--r-- | lib/CodeGen/Mangle.h | 2 |
5 files changed, 101 insertions, 65 deletions
diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 4f0d9a0c5c..b9ef9e607a 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -855,17 +855,23 @@ private: llvm::DenseMap<const CXXMethodDecl *, Index_t> Index; llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall; llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset; + typedef llvm::DenseMap<const CXXMethodDecl *, + std::pair<Index_t, Index_t> > Thunks_t; + Thunks_t Thunks; std::vector<Index_t> VCalls; typedef CXXRecordDecl::method_iterator method_iter; // FIXME: Linkage should follow vtable const bool Extern; + const uint32_t LLVMPointerWidth; + Index_t extra; public: VtableBuilder(std::vector<llvm::Constant *> &meth, const CXXRecordDecl *c, CodeGenModule &cgm) : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)), rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()), - CGM(cgm), Extern(true) { + CGM(cgm), Extern(true), + LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) { Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); } @@ -913,7 +919,6 @@ public: // and just replace each instance of an overridden method once. Would be // nice to measure the cost/benefit on real code. - // If we can find a previously allocated slot for this, reuse it. for (meth_iter mi = MD->begin_overridden_methods(), e = MD->end_overridden_methods(); mi != e; ++mi) { @@ -925,28 +930,51 @@ public: for (Index_t i = AddressPoint, e = submethods.size(); i != e; ++i) { // FIXME: begin_overridden_methods might be too lax, covariance */ - if (submethods[i] == om) { - int64_t O = VCallOffset[OMD] - Offset/8; - // FIXME: thunks - if (O) { - submethods[i] = CGM.BuildThunk(MD, Extern, true, 0, O); - } else - submethods[i] = m; - // FIXME: audit - Index[MD] = i - AddressPoint; - if (MorallyVirtual) { - VCallOffset[MD] = Offset/8; - VCalls[VCall[OMD]] = Offset/8 - VCallOffset[OMD]; + if (submethods[i] != om) + continue; + submethods[i] = m; + Index[MD] = i - AddressPoint; + + Thunks.erase(OMD); + if (MorallyVirtual) { + VCallOffset[MD] = Offset/8; + Index_t &idx = VCall[OMD]; + if (idx == 0) { + idx = VCalls.size()+1; + VCalls.push_back(0); } - // submethods[VCall[OMD]] = wrap(Offset/8 - VCallOffset[OMD]); + VCalls[idx] = Offset/8 - VCallOffset[OMD]; + VCall[MD] = idx; + // FIXME: 0? + Thunks[MD] = std::make_pair(0, -((idx+extra+2)*LLVMPointerWidth/8)); return true; } +#if 0 + // FIXME: finish off + int64_t O = VCallOffset[OMD] - Offset/8; + if (O) { + Thunks[MD] = std::make_pair(O, 0); + } +#endif + return true; } } return false; } + void InstallThunks(Index_t AddressPoint) { + for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end(); + i != e; ++i) { + const CXXMethodDecl *MD = i->first; + Index_t idx = Index[MD]; + Index_t nv_O = i->second.first; + Index_t v_O = i->second.second; + methods[AddressPoint + idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O); + } + Thunks.clear(); + } + void OverrideMethods(const CXXRecordDecl *RD, Index_t AddressPoint, bool MorallyVirtual, Index_t Offset) { for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me; @@ -961,19 +989,18 @@ public: void AddMethod(const CXXMethodDecl *MD, Index_t AddressPoint, bool MorallyVirtual, Index_t Offset) { llvm::Constant *m = wrap(CGM.GetAddrOfFunction(GlobalDecl(MD), Ptr8Ty)); + // If we can find a previously allocated slot for this, reuse it. if (OverrideMethod(MD, m, MorallyVirtual, Offset, submethods, 0)) return; // else allocate a new slot. Index[MD] = submethods.size(); - // VCall[MD] = Offset; if (MorallyVirtual) { VCallOffset[MD] = Offset/8; Index_t &idx = VCall[MD]; // Allocate the first one, after that, we reuse the previous one. if (idx == 0) { idx = VCalls.size()+1; - VCallOffset[MD] = Offset/8; VCalls.push_back(0); } } @@ -988,6 +1015,27 @@ public: AddMethod(*mi, AddressPoint, MorallyVirtual, Offset); } + void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout, + const CXXRecordDecl *PrimaryBase, + bool PrimaryBaseWasVirtual, bool MorallyVirtual, + int64_t Offset) { + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + if (i->isVirtual()) + continue; + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + if (Base != PrimaryBase || PrimaryBaseWasVirtual) { + uint64_t o = Offset + Layout.getBaseClassOffset(Base); + StartNewTable(); + Index_t AP; + AP = GenerateVtableForBase(Base, true, true, MorallyVirtual, o, false); + OverrideMethods(RD, AP, MorallyVirtual, o); + InstallThunks(AP); + } + } + } + int64_t GenerateVtableForBase(const CXXRecordDecl *RD, bool forPrimary, bool Bottom, bool MorallyVirtual, int64_t Offset, bool ForVirtualBase) { @@ -1004,8 +1052,12 @@ public: std::vector<llvm::Constant *> offsets; // FIXME: Audit, is this right? if (Bottom && (PrimaryBase == 0 || forPrimary || !PrimaryBaseWasVirtual - || Bottom)) + || Bottom)) { + extra = 0; GenerateVBaseOffsets(offsets, RD, Offset); + if (ForVirtualBase) + extra = offsets.size(); + } bool Top = true; @@ -1026,6 +1078,7 @@ public: return AddressPoint; StartNewTable(); + extra = 0; // FIXME: Cleanup. if (!ForVirtualBase) { // then virtual base offsets... @@ -1054,22 +1107,11 @@ public: methods.insert(methods.end(), submethods.begin(), submethods.end()); submethods.clear(); + InstallThunks(AddressPoint); // and then the non-virtual bases. - for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), - e = RD->bases_end(); i != e; ++i) { - if (i->isVirtual()) - continue; - const CXXRecordDecl *Base = - cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); - if (Base != PrimaryBase || PrimaryBaseWasVirtual) { - uint64_t o = Offset + Layout.getBaseClassOffset(Base); - StartNewTable(); - Index_t AP; - AP = GenerateVtableForBase(Base, true, true, MorallyVirtual, o, false); - OverrideMethods(RD, AP, MorallyVirtual, o); - } - } + NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual, + Offset); return AddressPoint; } @@ -1087,6 +1129,7 @@ public: Index_t AP; AP = GenerateVtableForBase(Base, false, true, true, BaseOffset, true); OverrideMethods(RD, AP, true, BaseOffset); + InstallThunks(AP); } if (Base->getNumVBases()) GenerateVtableForVBases(Base, Class); @@ -1168,8 +1211,8 @@ static VtableInfo *vtableinfo; llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, - bool Extern, bool Virtual, - int64_t nv, int64_t v) { + bool Extern, int64_t nv, + int64_t v) { QualType R = MD->getType()->getAsFunctionType()->getResultType(); FunctionArgList Args; @@ -1198,12 +1241,11 @@ llvm::Constant *CodeGenFunction::GenerateThunk(llvm::Function *Fn, return Fn; } -llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, - bool Extern, bool Virtual, int64_t nv, - int64_t v) { +llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, bool Extern, + int64_t nv, int64_t v) { llvm::SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); - mangleThunk(MD, Virtual, nv, v, getContext(), Out); + mangleThunk(MD, nv, v, getContext(), Out); llvm::GlobalVariable::LinkageTypes linktype; linktype = llvm::GlobalValue::WeakAnyLinkage; if (!Extern) @@ -1216,7 +1258,7 @@ llvm::Constant *CodeGenModule::BuildThunk(const CXXMethodDecl *MD, llvm::Function *Fn = llvm::Function::Create(FTy, linktype, Out.str(), &getModule()); - CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, Virtual, nv, v); + CodeGenFunction(*this).GenerateThunk(Fn, MD, Extern, nv, v); // Fn = Builder.CreateBitCast(Fn, Ptr8Ty); llvm::Constant *m = llvm::ConstantExpr::getBitCast(Fn, Ptr8Ty); return m; diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 312ab7576a..d7f9ec2812 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -366,8 +366,7 @@ public: /// GenerateThunk - Generate a thunk for the given method llvm::Constant *GenerateThunk(llvm::Function *Fn, const CXXMethodDecl *MD, - bool Extern, bool Virtual, int64_t nv, - int64_t v); + bool Extern, int64_t nv, int64_t v); void EmitCtorPrologue(const CXXConstructorDecl *CD); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 2368a082cb..2aa97de2b0 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -236,8 +236,8 @@ public: llvm::Constant *GenerateRtti(const CXXRecordDecl *RD); /// BuildThunk - Build a thunk for the given method - llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, bool Virtual, - int64_t nv, int64_t v); + llvm::Constant *BuildThunk(const CXXMethodDecl *MD, bool Extern, int64_t nv, + int64_t v); /// GetStringForStringLiteral - Return the appropriate bytes for a string /// literal, properly padded to match the literal type. If only the address of diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 29b4c8a837..3d3efc62f9 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -39,10 +39,10 @@ namespace { : Context(C), Out(os), Structor(0), StructorType(0) { } bool mangle(const NamedDecl *D); - void mangleCalloffset(bool Virtual, int64_t nv, int64_t v); - void mangleThunk(const NamedDecl *ND, bool Virtual, int64_t nv, int64_t v); - void mangleCovariantThunk(const NamedDecl *ND, bool VirtualThis, - int64_t nv_t, int64_t v_t, bool VirtualResult, + void mangleCalloffset(int64_t nv, int64_t v); + void mangleThunk(const NamedDecl *ND, int64_t nv, int64_t v); + void mangleCovariantThunk(const NamedDecl *ND, + int64_t nv_t, int64_t v_t, int64_t nv_r, int64_t v_r); void mangleGuardVariable(const VarDecl *D); @@ -241,14 +241,13 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { mangleNestedName(ND); } -void CXXNameMangler::mangleCalloffset(bool Virtual, int64_t nv, - int64_t v) { +void CXXNameMangler::mangleCalloffset(int64_t nv, int64_t v) { // <call-offset> ::= h <nv-offset> _ // ::= v <v-offset> _ // <nv-offset> ::= <offset number> # non-virtual base override // <v-offset> ::= <offset nubmer> _ <virtual offset number> // # virtual base override, with vcall offset - if (!Virtual) { + if (v == 0) { Out << "h"; if (nv < 0) { Out << "n"; @@ -272,26 +271,24 @@ void CXXNameMangler::mangleCalloffset(bool Virtual, int64_t nv, Out << "_"; } -void CXXNameMangler::mangleThunk(const NamedDecl *D, bool Virtual, int64_t nv, - int64_t v) { +void CXXNameMangler::mangleThunk(const NamedDecl *D, int64_t nv, int64_t v) { // <special-name> ::= T <call-offset> <base encoding> // # base is the nominal target function of thunk Out << "_T"; - mangleCalloffset(Virtual, nv, v); + mangleCalloffset(nv, v); mangleName(D); } void CXXNameMangler::mangleCovariantThunk(const NamedDecl *D, - bool VirtualThis, int64_t nv_t, - int64_t v_t, bool VirtualResult, + int64_t nv_t, int64_t v_t, int64_t nv_r, int64_t v_r) { // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> // # base is the nominal target function of thunk // # first call-offset is 'this' adjustment // # second call-offset is result adjustment Out << "_Tc"; - mangleCalloffset(VirtualThis, nv_t, v_t); - mangleCalloffset(VirtualResult, nv_r, v_r); + mangleCalloffset(nv_t, v_t); + mangleCalloffset(nv_r, v_r); mangleName(D); } @@ -859,7 +856,7 @@ namespace clang { /// \brief Mangles the a thunk with the offset n for the declaration D and /// emits that name to the given output stream. - void mangleThunk(const NamedDecl *D, bool Virtual, int64_t nv, int64_t v, + void mangleThunk(const NamedDecl *D, int64_t nv, int64_t v, ASTContext &Context, llvm::raw_ostream &os) { // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXConstructorDecl>(D) && @@ -868,15 +865,14 @@ namespace clang { "Use mangleCXXDtor for destructor decls!"); CXXNameMangler Mangler(Context, os); - Mangler.mangleThunk(D, Virtual, nv, v); + Mangler.mangleThunk(D, nv, v); os.flush(); } /// \brief Mangles the a covariant thunk for the declaration D and emits that /// name to the given output stream. - void mangleCovariantThunk(const NamedDecl *D, bool VirtualThis, int64_t nv_t, - int64_t v_t, bool VirtualResult, int64_t nv_r, - int64_t v_r, ASTContext &Context, + void mangleCovariantThunk(const NamedDecl *D, int64_t nv_t, int64_t v_t, + int64_t nv_r, int64_t v_r, ASTContext &Context, llvm::raw_ostream &os) { // FIXME: Hum, we might have to thunk these, fix. assert(!isa<CXXConstructorDecl>(D) && @@ -885,8 +881,7 @@ namespace clang { "Use mangleCXXDtor for destructor decls!"); CXXNameMangler Mangler(Context, os); - Mangler.mangleCovariantThunk(D, VirtualThis, nv_t, v_t, VirtualResult, - nv_r, v_r); + Mangler.mangleCovariantThunk(D, nv_t, v_t, nv_r, v_r); os.flush(); } diff --git a/lib/CodeGen/Mangle.h b/lib/CodeGen/Mangle.h index 41629c4c51..5490a7f601 100644 --- a/lib/CodeGen/Mangle.h +++ b/lib/CodeGen/Mangle.h @@ -34,7 +34,7 @@ namespace clang { bool mangleName(const NamedDecl *D, ASTContext &Context, llvm::raw_ostream &os); - void mangleThunk(const NamedDecl *D, bool Virtual, int64_t n, int64_t vn, + void mangleThunk(const NamedDecl *D, int64_t n, int64_t vn, ASTContext &Context, llvm::raw_ostream &os); void mangleCovariantThunk(const NamedDecl *D, bool VirtualThis, int64_t nv_t, int64_t v_t, bool VirtualResult, int64_t nv_r, |