Ejemplo n.º 1
0
ManagedValue
SILGenFunction::emitPreconditionOptionalHasValue(SILLocation loc,
                                                 ManagedValue optional) {
  // Generate code to the optional is present, and if not, abort with a message
  // (provided by the stdlib).
  SILBasicBlock *contBB = createBasicBlock();
  SILBasicBlock *failBB = createBasicBlock();

  bool hadCleanup = optional.hasCleanup();
  bool hadLValue = optional.isLValue();

  auto noneDecl = getASTContext().getOptionalNoneDecl();
  auto someDecl = getASTContext().getOptionalSomeDecl();
  if (optional.getType().isAddress()) {
    // We forward in the creation routine for
    // unchecked_take_enum_data_addr. switch_enum_addr is a +0 operation.
    B.createSwitchEnumAddr(loc, optional.getValue(),
                           /*defaultDest*/ nullptr,
                           {{someDecl, contBB}, {noneDecl, failBB}});
  } else {
    B.createSwitchEnum(loc, optional.forward(*this),
                       /*defaultDest*/ nullptr,
                       {{someDecl, contBB}, {noneDecl, failBB}});
  }
  B.emitBlock(failBB);

  // Call the standard library implementation of _diagnoseUnexpectedNilOptional.
  if (auto diagnoseFailure =
        getASTContext().getDiagnoseUnexpectedNilOptional(nullptr)) {
    ManagedValue args[4];
    emitSourceLocationArgs(*this, loc, args);
    
    emitApplyOfLibraryIntrinsic(loc, diagnoseFailure, SubstitutionMap(), args,
                                SGFContext());
  }

  B.createUnreachable(loc);
  B.clearInsertionPoint();
  B.emitBlock(contBB);

  ManagedValue result;
  SILType payloadType = optional.getType().getAnyOptionalObjectType();

  if (payloadType.isObject()) {
    result = B.createOwnedPHIArgument(payloadType);
  } else {
    result =
        B.createUncheckedTakeEnumDataAddr(loc, optional, someDecl, payloadType);
  }

  if (hadCleanup) {
    return result;
  }

  if (hadLValue) {
    return ManagedValue::forLValue(result.forward(*this));
  }

  return ManagedValue::forUnmanaged(result.forward(*this));
}
Ejemplo n.º 2
0
ManagedValue Scope::popPreservingValue(ManagedValue mv) {
  // If we have a value, make sure that it is an object. The reason why is
  // that we want to make sure that we are not forwarding a cleanup for a
  // stack location that will be destroyed by this scope.
  assert(mv && mv.getType().isObject() &&
         (mv.getType().isTrivial(cleanups.SGF.getModule()) ||
          mv.getOwnershipKind() == ValueOwnershipKind::Trivial ||
          mv.hasCleanup()));
  CleanupCloner cloner(cleanups.SGF, mv);
  SILValue value = mv.forward(cleanups.SGF);
  pop();
  return cloner.clone(value);
}
Ejemplo n.º 3
0
ManagedValue SILGenBuilder::createUncheckedEnumData(SILLocation loc,
                                                    ManagedValue operand,
                                                    EnumElementDecl *element) {
  if (operand.hasCleanup()) {
    SILValue newValue =
        SILBuilder::createUncheckedEnumData(loc, operand.forward(gen), element);
    return gen.emitManagedRValueWithCleanup(newValue);
  }

  ManagedValue borrowedBase = operand.borrow(gen, loc);
  SILValue newValue = SILBuilder::createUncheckedEnumData(
      loc, borrowedBase.getValue(), element);
  return ManagedValue::forUnmanaged(newValue);
}
Ejemplo n.º 4
0
ManagedValue SILGenBuilder::createUncheckedTakeEnumDataAddr(
    SILLocation loc, ManagedValue operand, EnumElementDecl *element,
    SILType ty) {
  // First see if we have a cleanup. If we do, we are going to forward and emit
  // a managed buffer with cleanup.
  if (operand.hasCleanup()) {
    return gen.emitManagedBufferWithCleanup(
        SILBuilder::createUncheckedTakeEnumDataAddr(loc, operand.forward(gen),
                                                    element, ty));
  }

  SILValue result = SILBuilder::createUncheckedTakeEnumDataAddr(
      loc, operand.getUnmanagedValue(), element, ty);
  if (operand.isLValue())
    return ManagedValue::forLValue(result);
  return ManagedValue::forUnmanaged(result);
}
Ejemplo n.º 5
0
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc,
                                                    ManagedValue addrOrValue,
                                                    const TypeLowering &optTL,
                                                    SGFContext C) {
  OptionalTypeKind OTK;
  SILType origPayloadTy =
    addrOrValue.getType().getAnyOptionalObjectType(SGM.M, OTK);

  auto formalOptionalTy = addrOrValue.getType().getSwiftRValueType();
  auto formalPayloadTy = formalOptionalTy
    ->getAnyOptionalObjectType()
    ->getCanonicalType();
  
  auto someDecl = getASTContext().getOptionalSomeDecl(OTK);
 
  ManagedValue payload;

  // Take the payload from the optional.  Cheat a bit in the +0
  // case—UncheckedTakeEnumData will never actually invalidate an Optional enum
  // value.
  SILValue payloadVal;
  if (!addrOrValue.getType().isAddress()) {
    payloadVal = B.createUncheckedEnumData(loc, addrOrValue.forward(*this),
                                           someDecl);
  } else {
    payloadVal =
      B.createUncheckedTakeEnumDataAddr(loc, addrOrValue.forward(*this),
                                        someDecl, origPayloadTy);
  
    if (optTL.isLoadable())
      payloadVal = B.createLoad(loc, payloadVal);
  }

  // Produce a correctly managed value.
  if (addrOrValue.hasCleanup())
    payload = emitManagedRValueWithCleanup(payloadVal);
  else
    payload = ManagedValue::forUnmanaged(payloadVal);
  
  // Reabstract it to the substituted form, if necessary.
  return emitOrigToSubstValue(loc, payload, AbstractionPattern::getOpaque(),
                              formalPayloadTy, C);
}
Ejemplo n.º 6
0
ManagedValue SILGenFunction::emitUncheckedGetOptionalValueFrom(SILLocation loc,
                                                    ManagedValue addrOrValue,
                                                    const TypeLowering &optTL,
                                                    SGFContext C) {
  SILType origPayloadTy =
    addrOrValue.getType().getAnyOptionalObjectType();

  auto someDecl = getASTContext().getOptionalSomeDecl();
 
  ManagedValue payload;

  // Take the payload from the optional.  Cheat a bit in the +0
  // case--UncheckedTakeEnumData will never actually invalidate an Optional enum
  // value.
  SILValue payloadVal;
  if (!addrOrValue.getType().isAddress()) {
    payloadVal = B.createUncheckedEnumData(loc, addrOrValue.forward(*this),
                                           someDecl);
  } else {
    payloadVal =
      B.createUncheckedTakeEnumDataAddr(loc, addrOrValue.forward(*this),
                                        someDecl, origPayloadTy);
  
    if (optTL.isLoadable())
      payloadVal =
          optTL.emitLoad(B, loc, payloadVal, LoadOwnershipQualifier::Take);
  }

  // Produce a correctly managed value.
  if (addrOrValue.hasCleanup())
    payload = emitManagedRValueWithCleanup(payloadVal);
  else
    payload = ManagedValue::forUnmanaged(payloadVal);
  
  return payload;
}
Ejemplo n.º 7
0
SILGenFunction::OpaqueValueState
SILGenFunction::emitOpenExistential(
       SILLocation loc,
       ManagedValue existentialValue,
       CanArchetypeType openedArchetype,
       SILType loweredOpenedType) {
  // Open the existential value into the opened archetype value.
  bool isUnique = true;
  bool canConsume;
  ManagedValue archetypeMV;
  
  SILType existentialType = existentialValue.getType();
  switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) {
  case ExistentialRepresentation::Opaque: {
    if (existentialType.isAddress()) {
      SILValue archetypeValue = B.createOpenExistentialAddr(
          loc, existentialValue.forward(*this), loweredOpenedType);
      if (existentialValue.hasCleanup()) {
        canConsume = true;
        // Leave a cleanup to deinit the existential container.
        enterDeinitExistentialCleanup(existentialValue.getValue(), CanType(),
                                      ExistentialRepresentation::Opaque);
        archetypeMV = emitManagedBufferWithCleanup(archetypeValue);
      } else {
        canConsume = false;
        archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
      }
    } else {
      SILValue archetypeValue = B.createOpenExistentialOpaque(
          loc, existentialValue.forward(*this), loweredOpenedType);
      assert(!existentialValue.hasCleanup());
      canConsume = false;
      archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
    }
    break;
  }
  case ExistentialRepresentation::Metatype:
    assert(existentialType.isObject());
    archetypeMV =
        ManagedValue::forUnmanaged(
            B.createOpenExistentialMetatype(
                       loc, existentialValue.forward(*this),
                       loweredOpenedType));
    // Metatypes are always trivial. Consuming would be a no-op.
    canConsume = false;
    break;
  case ExistentialRepresentation::Class: {
    assert(existentialType.isObject());
    SILValue archetypeValue = B.createOpenExistentialRef(
                       loc, existentialValue.forward(*this),
                       loweredOpenedType);
    canConsume = existentialValue.hasCleanup();
    archetypeMV = (canConsume ? emitManagedRValueWithCleanup(archetypeValue)
                              : ManagedValue::forUnmanaged(archetypeValue));
    break;
  }
  case ExistentialRepresentation::Boxed:
    if (existentialType.isAddress()) {
      existentialValue = emitLoad(loc, existentialValue.getValue(),
                                  getTypeLowering(existentialType),
                                  SGFContext::AllowGuaranteedPlusZero,
                                  IsNotTake);
    }

    existentialType = existentialValue.getType();
    assert(existentialType.isObject());
    // NB: Don't forward the cleanup, because consuming a boxed value won't
    // consume the box reference.
    archetypeMV = ManagedValue::forUnmanaged(
        B.createOpenExistentialBox(loc, existentialValue.getValue(),
                                   loweredOpenedType));
    // The boxed value can't be assumed to be uniquely referenced. We can never
    // consume it.
    // TODO: We could use isUniquelyReferenced to shorten the duration of
    // the box to the point that the opaque value is copied out.
    isUnique = false;
    canConsume = false;
    break;
  case ExistentialRepresentation::None:
    llvm_unreachable("not existential");
  }
  setArchetypeOpeningSite(openedArchetype, archetypeMV.getValue());

  assert(!canConsume || isUnique); (void) isUnique;

  return SILGenFunction::OpaqueValueState{
    archetypeMV,
    /*isConsumable*/ canConsume,
    /*hasBeenConsumed*/ false
  };
}
Ejemplo n.º 8
0
void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
  MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);

  assert(ctor->getBody() && "Class constructor without a body?");

  // True if this constructor delegates to a peer constructor with self.init().
  bool isDelegating = false;
  if (!ctor->hasStubImplementation()) {
    isDelegating = ctor->getDelegatingOrChainedInitKind(nullptr) ==
      ConstructorDecl::BodyInitKind::Delegating;
  }

  // Set up the 'self' argument.  If this class has a superclass, we set up
  // self as a box.  This allows "self reassignment" to happen in super init
  // method chains, which is important for interoperating with Objective-C
  // classes.  We also use a box for delegating constructors, since the
  // delegated-to initializer may also replace self.
  //
  // TODO: If we could require Objective-C classes to have an attribute to get
  // this behavior, we could avoid runtime overhead here.
  VarDecl *selfDecl = ctor->getImplicitSelfDecl();
  auto *dc = ctor->getDeclContext();
  auto selfClassDecl = dc->getAsClassOrClassExtensionContext();
  bool NeedsBoxForSelf = isDelegating ||
    (selfClassDecl->hasSuperclass() && !ctor->hasStubImplementation());
  bool usesObjCAllocator = Lowering::usesObjCAllocator(selfClassDecl);

  // If needed, mark 'self' as uninitialized so that DI knows to
  // enforce its DI properties on stored properties.
  MarkUninitializedInst::Kind MUKind;

  if (isDelegating)
    MUKind = MarkUninitializedInst::DelegatingSelf;
  else if (selfClassDecl->requiresStoredPropertyInits() &&
           usesObjCAllocator) {
    // Stored properties will be initialized in a separate
    // .cxx_construct method called by the Objective-C runtime.
    assert(selfClassDecl->hasSuperclass() &&
           "Cannot use ObjC allocation without a superclass");
    MUKind = MarkUninitializedInst::DerivedSelfOnly;
  } else if (selfClassDecl->hasSuperclass())
    MUKind = MarkUninitializedInst::DerivedSelf;
  else
    MUKind = MarkUninitializedInst::RootSelf;

  if (NeedsBoxForSelf) {
    // Allocate the local variable for 'self'.
    emitLocalVariableWithCleanup(selfDecl, MUKind)->finishInitialization(*this);
  }

  // Emit the prolog for the non-self arguments.
  // FIXME: Handle self along with the other body patterns.
  uint16_t ArgNo = emitProlog(ctor->getParameterList(1),
                              TupleType::getEmpty(F.getASTContext()), ctor,
                              ctor->hasThrows());

  SILType selfTy = getLoweredLoadableType(selfDecl->getType());
  ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl);

  if (!NeedsBoxForSelf) {
    SILLocation PrologueLoc(selfDecl);
    PrologueLoc.markAsPrologue();
    SILDebugVariable DbgVar(selfDecl->isLet(), ++ArgNo);
    B.createDebugValue(PrologueLoc, selfArg.getValue(), DbgVar);
  }

  if (!ctor->hasStubImplementation()) {
    assert(selfTy.hasReferenceSemantics() &&
           "can't emit a value type ctor here");
    if (NeedsBoxForSelf) {
      SILLocation prologueLoc = RegularLocation(ctor);
      prologueLoc.markAsPrologue();
      // SEMANTIC ARC TODO: When the verifier is complete, review this.
      B.emitStoreValueOperation(prologueLoc, selfArg.forward(*this),
                                VarLocs[selfDecl].value,
                                StoreOwnershipQualifier::Init);
    } else {
      selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind);
      VarLocs[selfDecl] = VarLoc::get(selfArg.getValue());
    }
  }

  // Prepare the end of initializer location.
  SILLocation endOfInitLoc = RegularLocation(ctor);
  endOfInitLoc.pointToEnd();

  // Create a basic block to jump to for the implicit 'self' return.
  // We won't emit the block until after we've emitted the body.
  prepareEpilog(Type(), ctor->hasThrows(),
                CleanupLocation::get(endOfInitLoc));

  auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType());

  // If the constructor can fail, set up an alternative epilog for constructor
  // failure.
  SILBasicBlock *failureExitBB = nullptr;
  SILArgument *failureExitArg = nullptr;
  auto &resultLowering = getTypeLowering(resultType);

  if (ctor->getFailability() != OTK_None) {
    SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter);

    RegularLocation loc(ctor);
    loc.markAutoGenerated();

    // On failure, we'll clean up everything and return nil instead.
    SILGenSavedInsertionPoint savedIP(*this, failureBB,
                                      FunctionSection::Postmatter);

    failureExitBB = createBasicBlock();
    failureExitArg = failureExitBB->createPHIArgument(
        resultLowering.getLoweredType(), ValueOwnershipKind::Owned);

    Cleanups.emitCleanupsForReturn(ctor);
    SILValue nilResult =
        B.createEnum(loc, SILValue(), getASTContext().getOptionalNoneDecl(),
                     resultLowering.getLoweredType());
    B.createBranch(loc, failureExitBB, nilResult);

    B.setInsertionPoint(failureExitBB);
    B.createReturn(loc, failureExitArg);

    FailDest = JumpDest(failureBB, Cleanups.getCleanupsDepth(), ctor);
  }

  // Handle member initializers.
  if (isDelegating) {
    // A delegating initializer does not initialize instance
    // variables.
  } else if (ctor->hasStubImplementation()) {
    // Nor does a stub implementation.
  } else if (selfClassDecl->requiresStoredPropertyInits() &&
             usesObjCAllocator) {
    // When the class requires all stored properties to have initial
    // values and we're using Objective-C's allocation, stored
    // properties are initialized via the .cxx_construct method, which
    // will be called by the runtime.

    // Note that 'self' has been fully initialized at this point.
  } else {
    // Emit the member initializers.
    emitMemberInitializers(ctor, selfDecl, selfClassDecl);
  }

  emitProfilerIncrement(ctor->getBody());
  // Emit the constructor body.
  emitStmt(ctor->getBody());

  // Emit the call to super.init() right before exiting from the initializer.
  if (NeedsBoxForSelf) {
    if (auto *SI = ctor->getSuperInitCall()) {
      B.setInsertionPoint(ReturnDest.getBlock());

      emitRValue(SI);

      B.emitBlock(B.splitBlockForFallthrough(), ctor);

      ReturnDest = JumpDest(B.getInsertionBB(),
                            ReturnDest.getDepth(),
                            ReturnDest.getCleanupLocation());
      B.clearInsertionPoint();
    }
  }

  CleanupStateRestorationScope SelfCleanupSave(Cleanups);

  // Build a custom epilog block, since the AST representation of the
  // constructor decl (which has no self in the return type) doesn't match the
  // SIL representation.
  {
    // Ensure that before we add additional cleanups, that we have emitted all
    // cleanups at this point.
    assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(),
                                          ReturnDest.getDepth()) &&
           "emitting epilog in wrong scope");

    SILGenSavedInsertionPoint savedIP(*this, ReturnDest.getBlock());
    auto cleanupLoc = CleanupLocation(ctor);

    // If we're using a box for self, reload the value at the end of the init
    // method.
    if (NeedsBoxForSelf) {
      ManagedValue storedSelf =
          ManagedValue::forUnmanaged(VarLocs[selfDecl].value);
      selfArg = B.createLoadCopy(cleanupLoc, storedSelf);
    } else {
      // We have to do a retain because we are returning the pointer +1.
      //
      // SEMANTIC ARC TODO: When the verifier is complete, we will need to
      // change this to selfArg = B.emitCopyValueOperation(...). Currently due
      // to the way that SILGen performs folding of copy_value, destroy_value,
      // the returned selfArg may be deleted causing us to have a
      // dead-pointer. Instead just use the old self value since we have a
      // class.
      selfArg = B.createCopyValue(cleanupLoc, selfArg);
    }

    // Inject the self value into an optional if the constructor is failable.
    if (ctor->getFailability() != OTK_None) {
      RegularLocation loc(ctor);
      loc.markAutoGenerated();
      selfArg = B.createEnum(loc, selfArg,
                             getASTContext().getOptionalSomeDecl(),
                             getLoweredLoadableType(resultType));
    }

    // Save our cleanup state. We want all other potential cleanups to fire, but
    // not this one.
    if (selfArg.hasCleanup())
      SelfCleanupSave.pushCleanupState(selfArg.getCleanup(),
                                       CleanupState::Dormant);

    // Translate our cleanup to the new top cleanup.
    //
    // This is needed to preserve the invariant in getEpilogBB that when
    // cleanups are emitted, everything above ReturnDest.getDepth() has been
    // emitted. This is not true if we use ManagedValue and friends in the
    // epilogBB, thus the translation. We perform the same check above that
    // getEpilogBB performs to ensure that we still do not have the same
    // problem.
    ReturnDest = std::move(ReturnDest).translate(getTopCleanup());
  }
  
  // Emit the epilog and post-matter.
  auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true);

  // Unpop our selfArg cleanup, so we can forward.
  std::move(SelfCleanupSave).pop();

  // Finish off the epilog by returning.  If this is a failable ctor, then we
  // actually jump to the failure epilog to keep the invariant that there is
  // only one SIL return instruction per SIL function.
  if (B.hasValidInsertionPoint()) {
    if (failureExitBB)
      B.createBranch(returnLoc, failureExitBB, selfArg.forward(*this));
    else
      B.createReturn(returnLoc, selfArg.forward(*this));
  }
}
Ejemplo n.º 9
0
SILGenFunction::OpaqueValueState
SILGenFunction::emitOpenExistential(
       SILLocation loc,
       ManagedValue existentialValue,
       ArchetypeType *openedArchetype,
       SILType loweredOpenedType,
       AccessKind accessKind) {
  // Open the existential value into the opened archetype value.
  bool isUnique = true;
  bool canConsume;
  ManagedValue archetypeMV;
  
  SILType existentialType = existentialValue.getType();
  switch (existentialType.getPreferredExistentialRepresentation(SGM.M)) {
  case ExistentialRepresentation::Opaque: {
    SILValue archetypeValue;
    if (existentialType.isAddress()) {
      OpenedExistentialAccess allowedAccess =
          getOpenedExistentialAccessFor(accessKind);
      if (!loweredOpenedType.isAddress()) {
        assert(!silConv.useLoweredAddresses() &&
               "Non-address loweredOpenedType is only allowed under opaque "
               "value mode");
        loweredOpenedType = loweredOpenedType.getAddressType();
      }
      archetypeValue =
          B.createOpenExistentialAddr(loc, existentialValue.forward(*this),
                                      loweredOpenedType, allowedAccess);
    } else {
      archetypeValue = B.createOpenExistentialOpaque(
          loc, existentialValue.forward(*this), loweredOpenedType);
    }

    if (existentialValue.hasCleanup()) {
      // With CoW existentials we can't consume the boxed value inside of
      // the existential. (We could only do so after a uniqueness check on
      // the box holding the value).
      canConsume = false;
      enterDestroyCleanup(existentialValue.getValue());
      archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
    } else {
      canConsume = false;
      archetypeMV = ManagedValue::forUnmanaged(archetypeValue);
    }
    break;
  }
  case ExistentialRepresentation::Metatype:
    assert(existentialType.isObject());
    archetypeMV =
        ManagedValue::forUnmanaged(
            B.createOpenExistentialMetatype(
                       loc, existentialValue.forward(*this),
                       loweredOpenedType));
    // Metatypes are always trivial. Consuming would be a no-op.
    canConsume = false;
    break;
  case ExistentialRepresentation::Class: {
    assert(existentialType.isObject());
    SILValue archetypeValue = B.createOpenExistentialRef(
                       loc, existentialValue.forward(*this),
                       loweredOpenedType);
    canConsume = existentialValue.hasCleanup();
    archetypeMV = (canConsume ? emitManagedRValueWithCleanup(archetypeValue)
                              : ManagedValue::forUnmanaged(archetypeValue));
    break;
  }
  case ExistentialRepresentation::Boxed:
    if (existentialType.isAddress()) {
      existentialValue = emitLoad(loc, existentialValue.getValue(),
                                  getTypeLowering(existentialType),
                                  SGFContext::AllowGuaranteedPlusZero,
                                  IsNotTake);
    }

    existentialType = existentialValue.getType();
    assert(existentialType.isObject());
    // NB: Don't forward the cleanup, because consuming a boxed value won't
    // consume the box reference.
    archetypeMV = ManagedValue::forUnmanaged(B.createOpenExistentialBox(
        loc, existentialValue.getValue(), loweredOpenedType.getAddressType()));
    // The boxed value can't be assumed to be uniquely referenced. We can never
    // consume it.
    // TODO: We could use isUniquelyReferenced to shorten the duration of
    // the box to the point that the opaque value is copied out.
    isUnique = false;
    canConsume = false;
    break;
  case ExistentialRepresentation::None:
    llvm_unreachable("not existential");
  }

  assert(!canConsume || isUnique); (void) isUnique;

  return SILGenFunction::OpaqueValueState{
    archetypeMV,
    /*isConsumable*/ canConsume,
    /*hasBeenConsumed*/ false
  };
}