Exemple #1
0
/// Generate code to emit a thunk with native conventions that calls a
/// function with foreign conventions.
void SILGenFunction::emitForeignToNativeThunk(SILDeclRef thunk) {
  assert(!thunk.isForeign && "foreign-to-native thunks only");

  // Wrap the function in its original form.

  auto fd = cast<AbstractFunctionDecl>(thunk.getDecl());
  auto nativeCI = getConstantInfo(thunk);
  auto nativeFormalResultTy = nativeCI.LoweredInterfaceType.getResult();
  auto nativeFnTy = F.getLoweredFunctionType();
  assert(nativeFnTy == nativeCI.SILFnType);

  // Find the foreign error convention and 'self' parameter index.
  Optional<ForeignErrorConvention> foreignError;
  if (nativeFnTy->hasErrorResult()) {
    foreignError = fd->getForeignErrorConvention();
    assert(foreignError && "couldn't find foreign error convention!");
  }
  ImportAsMemberStatus memberStatus = fd->getImportAsMemberStatus();

  // Forward the arguments.
  auto forwardedParameters = fd->getParameterLists();

  // For allocating constructors, 'self' is a metatype, not the 'self' value
  // formally present in the constructor body.
  Type allocatorSelfType;
  if (thunk.kind == SILDeclRef::Kind::Allocator) {
    allocatorSelfType = forwardedParameters[0]->getType(getASTContext())
      ->getLValueOrInOutObjectType();
    forwardedParameters = forwardedParameters.slice(1);
  }

  SmallVector<SILValue, 8> params;
  for (auto *paramList : reversed(forwardedParameters))
    bindParametersForForwarding(paramList, params);

  if (allocatorSelfType) {
    auto selfMetatype =
      CanMetatypeType::get(allocatorSelfType->getCanonicalType());
    auto selfArg = new (F.getModule()) SILArgument(
                                 F.begin(),
                                 getLoweredLoadableType(selfMetatype),
                                 fd->getImplicitSelfDecl());
    params.push_back(selfArg);
  }

  // Set up the throw destination if necessary.
  CleanupLocation cleanupLoc(fd);
  if (foreignError) {
    prepareRethrowEpilog(cleanupLoc);
  }

  SILValue result;
  {
    Scope scope(Cleanups, fd);

    SILDeclRef foreignDeclRef = thunk.asForeign(true);
    SILConstantInfo foreignCI = getConstantInfo(foreignDeclRef);
    auto foreignFnTy = foreignCI.SILFnType;

    // Bridge all the arguments.
    SmallVector<ManagedValue, 8> args;
    unsigned foreignArgIndex = 0;

    // A helper function to add a function error argument in the
    // appropriate position.
    auto maybeAddForeignErrorArg = [&] {
      if (foreignError &&
          foreignArgIndex == foreignError->getErrorParameterIndex()) {
        args.push_back(ManagedValue());
        foreignArgIndex++;
      }
    };

    for (unsigned nativeParamIndex : indices(params)) {
      // Bring the parameter to +1.
      auto paramValue = params[nativeParamIndex];
      auto thunkParam = nativeFnTy->getParameters()[nativeParamIndex];
      // TODO: Could avoid a retain if the bridged parameter is also +0 and
      // doesn't require a bridging conversion.
      ManagedValue param;
      switch (thunkParam.getConvention()) {
      case ParameterConvention::Direct_Owned:
        param = emitManagedRValueWithCleanup(paramValue);
        break;
      case ParameterConvention::Direct_Guaranteed:
      case ParameterConvention::Direct_Unowned:
        param = emitManagedRetain(fd, paramValue);
        break;
      case ParameterConvention::Direct_Deallocating:
        param = ManagedValue::forUnmanaged(paramValue);
        break;
      case ParameterConvention::Indirect_Inout:
      case ParameterConvention::Indirect_InoutAliasable:
        param = ManagedValue::forUnmanaged(paramValue);
        break;
      case ParameterConvention::Indirect_In:
      case ParameterConvention::Indirect_In_Guaranteed:
        llvm_unreachable("indirect args in foreign thunked method not implemented");
      }

      maybeAddForeignErrorArg();

      bool isSelf = nativeParamIndex == params.size() - 1;

      if (memberStatus.isInstance()) {
        // Leave space for `self` to be filled in later.
        if (foreignArgIndex == memberStatus.getSelfIndex()) {
          args.push_back({});
          foreignArgIndex++;
        }
        
        // Use the `self` space we skipped earlier if it's time.
        if (isSelf) {
          foreignArgIndex = memberStatus.getSelfIndex();
        }
      } else if (memberStatus.isStatic() && isSelf) {
        // Lose a static `self` parameter.
        break;
      }

      auto foreignParam = foreignFnTy->getParameters()[foreignArgIndex++];
      SILType foreignArgTy = foreignParam.getSILType();
      auto bridged = emitNativeToBridgedValue(fd, param,
                                SILFunctionTypeRepresentation::CFunctionPointer,
                                foreignArgTy.getSwiftRValueType());
      // Handle C pointer arguments imported as indirect `self` arguments.
      if (foreignParam.getConvention() == ParameterConvention::Indirect_In) {
        auto temp = emitTemporaryAllocation(fd, bridged.getType());
        bridged.forwardInto(*this, fd, temp);
        bridged = emitManagedBufferWithCleanup(temp);
      }
      
      if (memberStatus.isInstance() && isSelf) {
        // Fill in the `self` space.
        args[memberStatus.getSelfIndex()] = bridged;
      } else {
        args.push_back(bridged);
      }
    }

    maybeAddForeignErrorArg();
    
    // Call the original.
    auto subs = getForwardingSubstitutions();
    auto fn = getThunkedForeignFunctionRef(*this, fd, foreignDeclRef, args, subs,
                                           foreignCI);

    auto fnType = fn->getType().castTo<SILFunctionType>();
    fnType = fnType->substGenericArgs(SGM.M, SGM.SwiftModule, subs);

    result = emitApply(fd, ManagedValue::forUnmanaged(fn),
                       subs, args, fnType,
                       AbstractionPattern(nativeFormalResultTy),
                       nativeFormalResultTy,
                       ApplyOptions::None, None, foreignError,
                       SGFContext())
      .forwardAsSingleValue(*this, fd);
  }
  B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(fd), result);

  // Emit the throw destination.
  emitRethrowEpilog(fd);
}
Exemple #2
0
static std::string mangleConstant(SILDeclRef c, StringRef prefix) {
  using namespace Mangle;
  Mangler mangler;

  // Almost everything below gets one of the common prefixes:
  //   mangled-name ::= '_T' global     // Native symbol
  //   mangled-name ::= '_TTo' global   // ObjC interop thunk
  //   mangled-name ::= '_TTO' global   // Foreign function thunk
  //   mangled-name ::= '_TTd' global   // Direct
  StringRef introducer = "_T";
  if (!prefix.empty()) {
    introducer = prefix;
  } else if (c.isForeign) {
    assert(prefix.empty() && "can't have custom prefix on thunk");
    introducer = "_TTo";
  } else if (c.isDirectReference) {
    introducer = "_TTd";
  } else if (c.isForeignToNativeThunk()) {
    assert(prefix.empty() && "can't have custom prefix on thunk");
    introducer = "_TTO";
  }
  
  // As a special case, Clang functions and globals don't get mangled at all.
  if (c.hasDecl()) {
    if (auto clangDecl = c.getDecl()->getClangDecl()) {
      if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk()
          && !c.isCurried) {
        if (auto namedClangDecl = dyn_cast<clang::DeclaratorDecl>(clangDecl)) {
          if (auto asmLabel = namedClangDecl->getAttr<clang::AsmLabelAttr>()) {
            mangler.append('\01');
            mangler.append(asmLabel->getLabel());
          } else if (namedClangDecl->hasAttr<clang::OverloadableAttr>()) {
            std::string storage;
            llvm::raw_string_ostream SS(storage);
            // FIXME: When we can import C++, use Clang's mangler all the time.
            mangleClangDecl(SS, namedClangDecl,
                            c.getDecl()->getASTContext());
            mangler.append(SS.str());
          } else {
            mangler.append(namedClangDecl->getName());
          }
          return mangler.finalize();
        }
      }
    }
  }
  
  switch (c.kind) {
  //   entity ::= declaration                     // other declaration
  case SILDeclRef::Kind::Func:
    if (!c.hasDecl()) {
      mangler.append(introducer);
      mangler.mangleClosureEntity(c.getAbstractClosureExpr(),
                                  c.uncurryLevel);
      return mangler.finalize();
    }

    // As a special case, functions can have manually mangled names.
    // Use the SILGen name only for the original non-thunked, non-curried entry
    // point.
    if (auto NameA = c.getDecl()->getAttrs().getAttribute<SILGenNameAttr>())
      if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk()
          && !c.isCurried) {
        mangler.append(NameA->Name);
        return mangler.finalize();
      }
      
    // Use a given cdecl name for native-to-foreign thunks.
    if (auto CDeclA = c.getDecl()->getAttrs().getAttribute<CDeclAttr>())
      if (c.isNativeToForeignThunk()) {
        mangler.append(CDeclA->Name);
        return mangler.finalize();
      }

    // Otherwise, fall through into the 'other decl' case.
    SWIFT_FALLTHROUGH;

  case SILDeclRef::Kind::EnumElement:
    mangler.append(introducer);
    mangler.mangleEntity(c.getDecl(), c.uncurryLevel);
    return mangler.finalize();

  //   entity ::= context 'D'                     // deallocating destructor
  case SILDeclRef::Kind::Deallocator:
    mangler.append(introducer);
    mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()),
                                   /*isDeallocating*/ true);
    return mangler.finalize();

  //   entity ::= context 'd'                     // destroying destructor
  case SILDeclRef::Kind::Destroyer:
    mangler.append(introducer);
    mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()),
                                   /*isDeallocating*/ false);
    return mangler.finalize();

  //   entity ::= context 'C' type                // allocating constructor
  case SILDeclRef::Kind::Allocator:
    mangler.append(introducer);
    mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()),
                                    /*allocating*/ true,
                                    c.uncurryLevel);
    return mangler.finalize();

  //   entity ::= context 'c' type                // initializing constructor
  case SILDeclRef::Kind::Initializer:
    mangler.append(introducer);
    mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()),
                                    /*allocating*/ false,
                                    c.uncurryLevel);
    return mangler.finalize();

  //   entity ::= declaration 'e'                 // ivar initializer
  //   entity ::= declaration 'E'                 // ivar destroyer
  case SILDeclRef::Kind::IVarInitializer:
  case SILDeclRef::Kind::IVarDestroyer:
    mangler.append(introducer);
    mangler.mangleIVarInitDestroyEntity(
      cast<ClassDecl>(c.getDecl()),
      c.kind == SILDeclRef::Kind::IVarDestroyer);
    return mangler.finalize();

  //   entity ::= declaration 'a'                 // addressor
  case SILDeclRef::Kind::GlobalAccessor:
    mangler.append(introducer);
    mangler.mangleAddressorEntity(c.getDecl());
    return mangler.finalize();

  //   entity ::= declaration 'G'                 // getter
  case SILDeclRef::Kind::GlobalGetter:
    mangler.append(introducer);
    mangler.mangleGlobalGetterEntity(c.getDecl());
    return mangler.finalize();

  //   entity ::= context 'e' index           // default arg generator
  case SILDeclRef::Kind::DefaultArgGenerator:
    mangler.append(introducer);
    mangler.mangleDefaultArgumentEntity(cast<AbstractFunctionDecl>(c.getDecl()),
                                        c.defaultArgIndex);
    return mangler.finalize();
  }

  llvm_unreachable("bad entity kind!");
}
Exemple #3
0
void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
  assert(thunk.isForeign);
  SILDeclRef native = thunk.asForeign(false);

  auto loc = thunk.getAsRegularLocation();
  loc.markAutoGenerated();
  Scope scope(Cleanups, CleanupLocation::get(loc));

  // Bridge the arguments.
  SmallVector<SILValue, 4> args;
  Optional<ForeignErrorConvention> foreignError;
  SILValue foreignErrorSlot;
  auto objcFnTy = emitObjCThunkArguments(*this, loc, thunk, args,
                                         foreignErrorSlot, foreignError);
  auto nativeInfo = getConstantInfo(native);
  auto swiftResultTy =
    F.mapTypeIntoContext(nativeInfo.SILFnType->getSILResult());
  auto objcResultTy =
    F.mapTypeIntoContext(objcFnTy->getSILResult());

  // Call the native entry point.
  SILValue nativeFn = emitGlobalFunctionRef(loc, native, nativeInfo);
  auto subs = F.getForwardingSubstitutions();
  auto substTy = nativeInfo.SILFnType->substGenericArgs(
    SGM.M, SGM.M.getSwiftModule(), subs);
  SILType substSILTy = SILType::getPrimitiveObjectType(substTy);

  CanType bridgedResultType = objcResultTy.getSwiftRValueType();

  SILValue result;
  assert(foreignError.hasValue() == substTy->hasErrorResult());
  if (!substTy->hasErrorResult()) {
    // Create the apply.
    result = B.createApply(loc, nativeFn, substSILTy,
                           swiftResultTy, subs, args);

    // Leave the scope immediately.  This isn't really necessary; it
    // just limits lifetimes a little bit more.
    scope.pop();

    // Now bridge the return value.
    result = emitBridgeReturnValue(*this, loc, result,
                                   objcFnTy->getRepresentation(),
                                   bridgedResultType);
  } else {
    SILBasicBlock *contBB = createBasicBlock();
    SILBasicBlock *errorBB = createBasicBlock();
    SILBasicBlock *normalBB = createBasicBlock();
    B.createTryApply(loc, nativeFn, substSILTy, subs, args,
                     normalBB, errorBB);

    // Emit the non-error destination.
    {
      B.emitBlock(normalBB);
      SILValue nativeResult = normalBB->createBBArg(swiftResultTy);

      // In this branch, the eventual return value is mostly created
      // by bridging the native return value, but we may need to
      // adjust it slightly.
      SILValue bridgedResult =
        emitBridgeReturnValueForForeignError(loc, nativeResult, 
                                             objcFnTy->getRepresentation(),
                                             objcResultTy,
                                             foreignErrorSlot, *foreignError);
      B.createBranch(loc, contBB, bridgedResult);
    }

    // Emit the error destination.
    {
      B.emitBlock(errorBB);
      SILValue nativeError =
        errorBB->createBBArg(substTy->getErrorResult().getSILType());

      // In this branch, the eventual return value is mostly invented.
      // Store the native error in the appropriate location and return.
      SILValue bridgedResult =
        emitBridgeErrorForForeignError(loc, nativeError, objcResultTy,
                                       foreignErrorSlot, *foreignError);
      B.createBranch(loc, contBB, bridgedResult);
    }

    // Emit the join block.
    B.emitBlock(contBB);
    result = contBB->createBBArg(objcResultTy);

    // Leave the scope now.
    scope.pop();
  }

  B.createReturn(loc, result);
}
Exemple #4
0
ManagedValue
SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
                                 CanType expectedType,
                                 SubstitutionList subs) {
  auto closure = *constant.getAnyFunctionRef();
  auto captureInfo = closure.getCaptureInfo();
  auto loweredCaptureInfo = SGM.Types.getLoweredLocalCaptures(closure);
  auto hasCaptures = SGM.Types.hasLoweredLocalCaptures(closure);

  auto constantInfo = getConstantInfo(constant);
  SILValue functionRef = emitGlobalFunctionRef(loc, constant, constantInfo);
  SILType functionTy = functionRef->getType();

  // Apply substitutions.
  auto pft = constantInfo.SILFnType;

  auto *dc = closure.getAsDeclContext()->getParent();
  if (dc->isLocalContext() && !loweredCaptureInfo.hasGenericParamCaptures()) {
    // If the lowered function type is not polymorphic but we were given
    // substitutions, we have a closure in a generic context which does not
    // capture generic parameters. Just drop the substitutions.
    subs = { };
  } else if (closure.getAbstractClosureExpr()) {
    // If we have a closure expression in generic context, Sema won't give
    // us substitutions, so we just use the forwarding substitutions from
    // context.
    subs = getForwardingSubstitutions();
  }

  bool wasSpecialized = false;
  if (!subs.empty()) {
    auto specialized = pft->substGenericArgs(F.getModule(), subs);
    functionTy = SILType::getPrimitiveObjectType(specialized);
    wasSpecialized = true;
  }

  // If we're in top-level code, we don't need to physically capture script
  // globals, but we still need to mark them as escaping so that DI can flag
  // uninitialized uses.
  if (this == SGM.TopLevelSGF) {
    SGM.emitMarkFunctionEscapeForTopLevelCodeGlobals(
        loc, captureInfo);
  }

  if (!hasCaptures && !wasSpecialized) {
    auto result = ManagedValue::forUnmanaged(functionRef);
    return emitOrigToSubstValue(loc, result,
                                AbstractionPattern(expectedType),
                                expectedType);
  }

  SmallVector<ManagedValue, 4> capturedArgs;
  emitCaptures(loc, closure, CaptureEmission::PartialApplication,
               capturedArgs);

  // The partial application takes ownership of the context parameters.
  SmallVector<SILValue, 4> forwardedArgs;
  for (auto capture : capturedArgs)
    forwardedArgs.push_back(capture.forward(*this));

  auto calleeConvention = ParameterConvention::Direct_Guaranteed;

  SILType closureTy = SILGenBuilder::getPartialApplyResultType(
      functionRef->getType(), capturedArgs.size(), SGM.M, subs,
      calleeConvention);

  auto toClosure =
    B.createPartialApply(loc, functionRef, functionTy,
                         subs, forwardedArgs, closureTy);
  auto result = emitManagedRValueWithCleanup(toClosure);

  // Get the lowered AST types:
  //  - the original type
  auto origFormalType = AbstractionPattern(constantInfo.LoweredType);

  // - the substituted type
  auto substFormalType = expectedType;

  // Generalize if necessary.
  result = emitOrigToSubstValue(loc, result, origFormalType,
                                substFormalType);

  return result;
}
Exemple #5
0
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) {
  auto dd = cast<DestructorDecl>(dtor.getDecl());
  auto cd = cast<ClassDecl>(dd->getDeclContext());
  MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));

  RegularLocation loc(dd);
  if (dd->isImplicit())
    loc.markAutoGenerated();

  SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl());

  // Create a basic block to jump to for the implicit destruction behavior
  // of releasing the elements and calling the superclass destructor.
  // We won't actually emit the block until we finish with the destructor body.
  prepareEpilog(Type(), false, CleanupLocation::get(loc));

  // Emit the destructor body.
  emitStmt(dd->getBody());

  Optional<SILValue> maybeReturnValue;
  SILLocation returnLoc(loc);
  std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc);

  if (!maybeReturnValue)
    return;

  auto cleanupLoc = CleanupLocation::get(loc);

  // Note: the ivar destroyer is responsible for destroying the
  // instance variables before the object is actually deallocated.

  // Form a reference to the superclass -dealloc.
  Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass());
  assert(superclassTy && "Emitting Objective-C -dealloc without superclass?");
  ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass();
  auto superclassDtorDecl = superclass->getDestructor();
  SILDeclRef superclassDtor(superclassDtorDecl,
                            SILDeclRef::Kind::Deallocator,
                            SILDeclRef::ConstructAtBestResilienceExpansion,
                            SILDeclRef::ConstructAtNaturalUncurryLevel,
                            /*isForeign=*/true);
  auto superclassDtorType = SGM.getConstantType(superclassDtor);
  SILValue superclassDtorValue = B.createSuperMethod(
                                   cleanupLoc, selfValue, superclassDtor,
                                   superclassDtorType);

  // Call the superclass's -dealloc.
  SILType superclassSILTy = getLoweredLoadableType(superclassTy);
  SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy);
  ArrayRef<Substitution> subs
    = superclassTy->gatherAllSubstitutions(SGM.M.getSwiftModule(), nullptr);
  auto substDtorType = superclassDtorType.castTo<SILFunctionType>()
    ->substGenericArgs(SGM.M, subs);
  B.createApply(cleanupLoc, superclassDtorValue,
                SILType::getPrimitiveObjectType(substDtorType),
                substDtorType->getSILResult(),
                subs, superSelf);

  // Return.
  B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc));
}
Exemple #6
0
static std::string mangleConstant(SILDeclRef c, SILDeclRef::ManglingKind Kind) {
  using namespace NewMangling;
  ASTMangler mangler;

  // As a special case, Clang functions and globals don't get mangled at all.
  if (c.hasDecl()) {
    if (auto clangDecl = c.getDecl()->getClangDecl()) {
      if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk()
          && !c.isCurried) {
        if (auto namedClangDecl = dyn_cast<clang::DeclaratorDecl>(clangDecl)) {
          if (auto asmLabel = namedClangDecl->getAttr<clang::AsmLabelAttr>()) {
            std::string s(1, '\01');
            s += asmLabel->getLabel();
            return s;
          } else if (namedClangDecl->hasAttr<clang::OverloadableAttr>()) {
            std::string storage;
            llvm::raw_string_ostream SS(storage);
            // FIXME: When we can import C++, use Clang's mangler all the time.
            mangleClangDecl(SS, namedClangDecl,
                            c.getDecl()->getASTContext());
            return SS.str();
          }
          return namedClangDecl->getName();
        }
      }
    }
  }

  ASTMangler::SymbolKind SKind = ASTMangler::SymbolKind::Default;
  switch (Kind) {
    case SILDeclRef::ManglingKind::Default:
      if (c.isForeign) {
        SKind = ASTMangler::SymbolKind::SwiftAsObjCThunk;
      } else if (c.isDirectReference) {
        SKind = ASTMangler::SymbolKind::DirectMethodReferenceThunk;
      } else if (c.isForeignToNativeThunk()) {
        SKind = ASTMangler::SymbolKind::ObjCAsSwiftThunk;
      }
      break;
    case SILDeclRef::ManglingKind::VTableMethod:
      SKind = ASTMangler::SymbolKind::VTableMethod;
      break;
    case SILDeclRef::ManglingKind::DynamicThunk:
      SKind = ASTMangler::SymbolKind::DynamicThunk;
      break;
  }

  switch (c.kind) {
  case SILDeclRef::Kind::Func:
    if (!c.hasDecl())
      return mangler.mangleClosureEntity(c.getAbstractClosureExpr(), SKind);

    // As a special case, functions can have manually mangled names.
    // Use the SILGen name only for the original non-thunked, non-curried entry
    // point.
    if (auto NameA = c.getDecl()->getAttrs().getAttribute<SILGenNameAttr>())
      if (!c.isForeignToNativeThunk() && !c.isNativeToForeignThunk()
          && !c.isCurried) {
        return NameA->Name;
      }
      
    // Use a given cdecl name for native-to-foreign thunks.
    if (auto CDeclA = c.getDecl()->getAttrs().getAttribute<CDeclAttr>())
      if (c.isNativeToForeignThunk()) {
        return CDeclA->Name;
      }

    // Otherwise, fall through into the 'other decl' case.
    SWIFT_FALLTHROUGH;

  case SILDeclRef::Kind::EnumElement:
    return mangler.mangleEntity(c.getDecl(), c.isCurried, SKind);

  case SILDeclRef::Kind::Deallocator:
    assert(!c.isCurried);
    return mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()),
                                          /*isDeallocating*/ true,
                                          SKind);

  case SILDeclRef::Kind::Destroyer:
    assert(!c.isCurried);
    return mangler.mangleDestructorEntity(cast<DestructorDecl>(c.getDecl()),
                                          /*isDeallocating*/ false,
                                          SKind);

  case SILDeclRef::Kind::Allocator:
    return mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()),
                                           /*allocating*/ true,
                                           c.isCurried,
                                           SKind);

  case SILDeclRef::Kind::Initializer:
    return mangler.mangleConstructorEntity(cast<ConstructorDecl>(c.getDecl()),
                                           /*allocating*/ false,
                                           c.isCurried,
                                           SKind);

  case SILDeclRef::Kind::IVarInitializer:
  case SILDeclRef::Kind::IVarDestroyer:
    assert(!c.isCurried);
    return mangler.mangleIVarInitDestroyEntity(cast<ClassDecl>(c.getDecl()),
                                  c.kind == SILDeclRef::Kind::IVarDestroyer,
                                  SKind);

  case SILDeclRef::Kind::GlobalAccessor:
    assert(!c.isCurried);
    return mangler.mangleAccessorEntity(AccessorKind::IsMutableAddressor,
                                        AddressorKind::Unsafe,
                                        c.getDecl(),
                                        /*isStatic*/ false,
                                        SKind);

  case SILDeclRef::Kind::GlobalGetter:
    assert(!c.isCurried);
    return mangler.mangleGlobalGetterEntity(c.getDecl(), SKind);

  case SILDeclRef::Kind::DefaultArgGenerator:
    assert(!c.isCurried);
    return mangler.mangleDefaultArgumentEntity(
                                        cast<AbstractFunctionDecl>(c.getDecl()),
                                        c.defaultArgIndex,
                                        SKind);

  case SILDeclRef::Kind::StoredPropertyInitializer:
    assert(!c.isCurried);
    return mangler.mangleInitializerEntity(cast<VarDecl>(c.getDecl()), SKind);
  }

  llvm_unreachable("bad entity kind!");
}
void SILGenFunction::emitObjCDestructor(SILDeclRef dtor) {
  auto dd = cast<DestructorDecl>(dtor.getDecl());
  auto cd = cast<ClassDecl>(dd->getDeclContext());
  MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit"));

  RegularLocation loc(dd);
  if (dd->isImplicit())
    loc.markAutoGenerated();

  SILValue selfValue = emitSelfDecl(dd->getImplicitSelfDecl());

  // Create a basic block to jump to for the implicit destruction behavior
  // of releasing the elements and calling the superclass destructor.
  // We won't actually emit the block until we finish with the destructor body.
  prepareEpilog(Type(), false, CleanupLocation::get(loc));

  emitProfilerIncrement(dd->getBody());
  // Emit the destructor body.
  emitStmt(dd->getBody());

  Optional<SILValue> maybeReturnValue;
  SILLocation returnLoc(loc);
  std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(loc);

  if (!maybeReturnValue)
    return;

  auto cleanupLoc = CleanupLocation::get(loc);

  // Note: the ivar destroyer is responsible for destroying the
  // instance variables before the object is actually deallocated.

  // Form a reference to the superclass -dealloc.
  Type superclassTy = dd->mapTypeIntoContext(cd->getSuperclass());
  assert(superclassTy && "Emitting Objective-C -dealloc without superclass?");
  ClassDecl *superclass = superclassTy->getClassOrBoundGenericClass();
  auto superclassDtorDecl = superclass->getDestructor();
  auto superclassDtor = SILDeclRef(superclassDtorDecl,
                                   SILDeclRef::Kind::Deallocator)
    .asForeign();
  auto superclassDtorType = SGM.Types.getConstantType(superclassDtor);
  SILValue superclassDtorValue = B.createObjCSuperMethod(
                                   cleanupLoc, selfValue, superclassDtor,
                                   superclassDtorType);

  // Call the superclass's -dealloc.
  SILType superclassSILTy = getLoweredLoadableType(superclassTy);
  SILValue superSelf = B.createUpcast(cleanupLoc, selfValue, superclassSILTy);
  assert(superSelf.getOwnershipKind() == ValueOwnershipKind::Owned);

  auto subMap
    = superclassTy->getContextSubstitutionMap(SGM.M.getSwiftModule(),
                                              superclass);

  auto substDtorType = superclassDtorType.substGenericArgs(SGM.M, subMap);
  CanSILFunctionType substFnType = substDtorType.castTo<SILFunctionType>();
  SILFunctionConventions dtorConv(substFnType, SGM.M);
  assert(substFnType->getSelfParameter().getConvention() ==
             ParameterConvention::Direct_Unowned &&
         "Objective C deinitializing destructor takes self as unowned");

  B.createApply(cleanupLoc, superclassDtorValue, substDtorType,
                dtorConv.getSILResultType(), subMap, superSelf);

  // We know that the givne value came in at +1, but we pass the relevant value
  // as unowned to the destructor. Create a fake balance for the verifier to be
  // happy.
  B.createEndLifetime(cleanupLoc, superSelf);

  // Return.
  B.createReturn(returnLoc, emitEmptyTuple(cleanupLoc));
}
Exemple #8
0
 void addMethod(SILDeclRef method) {
   if (method.getDecl()->getDeclContext() == CD)
     TBD.addDispatchThunk(method);
 }
Exemple #9
0
Optional<SpecializedEmitter>
SpecializedEmitter::forDecl(SILGenModule &SGM, SILDeclRef function) {
  // Only consider standalone declarations in the Builtin module.
  if (function.kind != SILDeclRef::Kind::Func)
    return None;
  if (!function.hasDecl())
    return None;  
  ValueDecl *decl = function.getDecl();
  if (!isa<BuiltinUnit>(decl->getDeclContext()))
    return None;

  auto name = decl->getBaseName().getIdentifier();
  const BuiltinInfo &builtin = SGM.M.getBuiltinInfo(name);
  switch (builtin.ID) {
  // All the non-SIL, non-type-trait builtins should use the
  // named-builtin logic, which just emits the builtin as a call to a
  // builtin function.  This includes builtins that aren't even declared
  // in Builtins.def, i.e. all of the LLVM intrinsics.
  //
  // We do this in a separate pass over Builtins.def to avoid creating
  // a bunch of identical cases.
#define BUILTIN(Id, Name, Attrs)                                            \
  case BuiltinValueKind::Id:
#define BUILTIN_SIL_OPERATION(Id, Name, Overload)
#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs)
#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name)
#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name)
#include "swift/AST/Builtins.def"
  case BuiltinValueKind::None:
    return SpecializedEmitter(name);

  // Do a second pass over Builtins.def, ignoring all the cases for
  // which we emitted something above.
#define BUILTIN(Id, Name, Attrs)

  // Use specialized emitters for SIL builtins.
#define BUILTIN_SIL_OPERATION(Id, Name, Overload)                           \
  case BuiltinValueKind::Id:                                                \
    return SpecializedEmitter(&emitBuiltin##Id);

  // Sanitizer builtins should never directly be called; they should only
  // be inserted as instrumentation by SILGen.
#define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs)                        \
  case BuiltinValueKind::Id:                                                \
    llvm_unreachable("Sanitizer builtin called directly?");

#define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name)                               \
  case BuiltinValueKind::Id:                                                   \
    llvm_unreachable(                                                          \
        "Compile-time type checker operation should not make it to SIL!");

    // Lower away type trait builtins when they're trivially solvable.
#define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name)                              \
  case BuiltinValueKind::Id:                                                \
    return SpecializedEmitter(&emitBuiltinTypeTrait<&TypeBase::Name,        \
                                                    BuiltinValueKind::Id>);

#include "swift/AST/Builtins.def"
  }
  llvm_unreachable("bad builtin kind");
}
Exemple #10
0
void SILGenFunction::emitCurryThunk(SILDeclRef thunk) {
  assert(thunk.isCurried);

  auto *vd = thunk.getDecl();

  if (auto *fd = dyn_cast<AbstractFunctionDecl>(vd)) {
    assert(!SGM.M.Types.hasLoweredLocalCaptures(fd) &&
           "methods cannot have captures");
    (void) fd;
  }

  SILLocation loc(vd);
  Scope S(*this, vd);

  auto thunkInfo = SGM.Types.getConstantInfo(thunk);
  auto thunkFnTy = thunkInfo.SILFnType;
  SILFunctionConventions fromConv(thunkFnTy, SGM.M);

  auto selfTy = fromConv.getSILType(thunkFnTy->getSelfParameter());
  selfTy = F.mapTypeIntoContext(selfTy);
  ManagedValue selfArg = B.createInputFunctionArgument(selfTy, loc);

  // Forward substitutions.
  auto subs = F.getForwardingSubstitutionMap();

  auto toFnAndRef = getNextUncurryLevelRef(*this, loc, thunk, selfArg, subs);
  ManagedValue toFn = toFnAndRef.first;
  SILDeclRef calleeRef = toFnAndRef.second;

  SILType resultTy = fromConv.getSingleSILResultType();
  resultTy = F.mapTypeIntoContext(resultTy);

  // Partially apply the next uncurry level and return the result closure.
  selfArg = selfArg.ensurePlusOne(*this, loc);
  auto calleeConvention = ParameterConvention::Direct_Guaranteed;
  ManagedValue toClosure =
      B.createPartialApply(loc, toFn, subs, {selfArg},
                           calleeConvention);
  if (resultTy != toClosure.getType()) {
    CanSILFunctionType resultFnTy = resultTy.castTo<SILFunctionType>();
    CanSILFunctionType closureFnTy = toClosure.getType().castTo<SILFunctionType>();
    if (resultFnTy->isABICompatibleWith(closureFnTy).isCompatible()) {
      toClosure = B.createConvertFunction(loc, toClosure, resultTy);
    } else {
      // Compute the partially-applied abstraction pattern for the callee:
      // just grab the pattern for the curried fn ref and "call" it.
      assert(!calleeRef.isCurried);
      calleeRef.isCurried = true;
      auto appliedFnPattern = SGM.Types.getConstantInfo(calleeRef).FormalPattern
                                       .getFunctionResultType();

      auto appliedThunkPattern =
        thunkInfo.FormalPattern.getFunctionResultType();

      // The formal type should be the same for the callee and the thunk.
      auto formalType = thunkInfo.FormalType;
      if (auto genericSubstType = dyn_cast<GenericFunctionType>(formalType)) {
        formalType = genericSubstType.substGenericArgs(subs);
      }
      formalType = cast<AnyFunctionType>(formalType.getResult());

      toClosure =
        emitTransformedValue(loc, toClosure,
                             appliedFnPattern, formalType,
                             appliedThunkPattern, formalType);
    }
  }
  toClosure = S.popPreservingValue(toClosure);
  B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(loc), toClosure);
}