//===--- GenThunk.cpp - IR Generation for Method Dispatch Thunks ----------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR generation for class and protocol method dispatch // thunks, which are used in resilient builds to hide vtable and witness table // offsets from clients. // //===----------------------------------------------------------------------===// #include "Callee.h" #include "Explosion.h" #include "GenDecl.h" #include "GenClass.h" #include "GenHeap.h" #include "GenOpaque.h" #include "GenProto.h" #include "IRGenFunction.h" #include "IRGenModule.h" #include "MetadataLayout.h" #include "ProtocolInfo.h" #include "Signature.h" #include "swift/IRGen/Linking.h" #include "llvm/IR/Function.h" using namespace swift; using namespace irgen; /// Find the entry point for a method dispatch thunk. llvm::Function * IRGenModule::getAddrOfDispatchThunk(SILDeclRef declRef, ForDefinition_t forDefinition) { LinkEntity entity = LinkEntity::forDispatchThunk(declRef); llvm::Function *&entry = GlobalFuncs[entity]; if (entry) { if (forDefinition) updateLinkageForDefinition(*this, entry, entity); return entry; } auto fnType = getSILModule().Types.getConstantFunctionType(declRef); Signature signature = getSignature(fnType); LinkInfo link = LinkInfo::get(*this, entity, forDefinition); entry = createFunction(*this, link, signature); return entry; } static FunctionPointer lookupMethod(IRGenFunction &IGF, SILDeclRef declRef) { auto *decl = cast(declRef.getDecl()); // Protocol case. if (isa(decl->getDeclContext())) { // Find the witness table. llvm::Value *wtable = (IGF.CurFn->arg_end() - 1); // Find the witness we're interested in. return emitWitnessMethodValue(IGF, wtable, declRef); } // Class case. auto funcTy = IGF.IGM.getSILModule().Types.getConstantFunctionType(declRef); // Load the metadata, or use the 'self' value if we have a static method. llvm::Value *self; // Non-throwing class methods always have the 'self' parameter at the end. // Throwing class methods have 'self' right before the error parameter. // // FIXME: Should find a better way of expressing this. if (funcTy->hasErrorResult()) self = (IGF.CurFn->arg_end() - 2); else self = (IGF.CurFn->arg_end() - 1); auto selfTy = funcTy->getSelfParameter().getSILStorageType(); llvm::Value *metadata; if (selfTy.is()) { metadata = self; } else { metadata = emitHeapMetadataRefForHeapObject(IGF, self, selfTy, /*suppress cast*/ true); } return emitVirtualMethodValue(IGF, metadata, declRef, funcTy); } llvm::Function *IRGenModule::emitDispatchThunk(SILDeclRef declRef) { auto *f = getAddrOfDispatchThunk(declRef, ForDefinition); IRGenFunction IGF(*this, f); // Look up the method. auto fn = lookupMethod(IGF, declRef); // Call the witness, forwarding all of the parameters. auto params = IGF.collectParameters(); auto result = IGF.Builder.CreateCall(fn, params.claimAll()); // Return the result, if we have one. if (result->getType()->isVoidTy()) IGF.Builder.CreateRetVoid(); else IGF.Builder.CreateRet(result); return f; }