/// Perform a foreign error check by testing whether the call result is zero. /// The call result is otherwise ignored. static void emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc, ManagedValue result, ManagedValue errorSlot, bool suppressErrorCheck, bool zeroIsError) { // Just ignore the call result if we're suppressing the error check. if (suppressErrorCheck) { return; } SILValue resultValue = emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue()); SILValue zero = gen.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = gen.getASTContext(); SILValue resultIsError = gen.B.createBuiltinBinaryFunction(loc, zeroIsError ? "cmp_eq" : "cmp_ne", resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = gen.createBasicBlock(); gen.B.createCondBranch(loc, resultIsError, errorBB, contBB); gen.emitForeignErrorBlock(loc, errorBB, errorSlot); gen.B.emitBlock(contBB); }
/// Emit a materializeForSet operation that projects storage, assuming /// that no cleanups or callbacks are required. SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &SGF, SILLocation loc, ManagedValue self, RValue &&indices, SILValue callbackBuffer, SILFunction *&callback) { LValue lvalue = buildLValue(SGF, loc, self, std::move(indices), AccessKind::ReadWrite); SILGenFunction::UnpairedAccesses unpairedAccesses(callbackBuffer); SGF.UnpairedAccessesForMaterializeForSet = &unpairedAccesses; ManagedValue address = SGF.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite); SGF.UnpairedAccessesForMaterializeForSet = nullptr; // Create a callback to end the unpaired accesses if any were pushed. if (unpairedAccesses.NumAccesses) { // If it ever proves necessary, we can make this work by allocating // a (ValueBuffer x N) tuple in callbackBuffer and rewriting the existing // uses. But it probably won't ever prove necessary. assert(unpairedAccesses.NumAccesses == 1 && "multiple unpaired accesses not supported"); callback = createEndUnpairedAccessesCallback(SGF.F, unpairedAccesses); } return address.getUnmanagedValue(); }
void SILGenFunction::emitDeallocatingDestructor(DestructorDecl *dd) { MagicFunctionName = DeclName(SGM.M.getASTContext().getIdentifier("deinit")); // The deallocating destructor is always auto-generated. RegularLocation loc(dd); loc.markAutoGenerated(); // Emit the prolog. SILValue initialSelfValue = emitSelfDecl(dd->getImplicitSelfDecl()); // Form a reference to the destroying destructor. SILDeclRef dtorConstant(dd, SILDeclRef::Kind::Destroyer); auto classTy = initialSelfValue->getType(); auto classDecl = classTy.getASTType()->getAnyNominal(); ManagedValue dtorValue; SILType dtorTy; auto subMap = classTy.getASTType() ->getContextSubstitutionMap(SGM.M.getSwiftModule(), classDecl); std::tie(dtorValue, dtorTy) = emitSiblingMethodRef(loc, initialSelfValue, dtorConstant, subMap); // Call the destroying destructor. SILValue selfForDealloc; { FullExpr CleanupScope(Cleanups, CleanupLocation::get(loc)); ManagedValue borrowedSelf = emitManagedBeginBorrow(loc, initialSelfValue); SILType objectPtrTy = SILType::getNativeObjectType(F.getASTContext()); selfForDealloc = B.createApply(loc, dtorValue.forward(*this), dtorTy, objectPtrTy, subMap, borrowedSelf.getUnmanagedValue()); } // Balance out the +1 from the self argument using end_lifetime. // // The issue here is that: // // 1. Self is passed into deallocating deinits at +1. // 2. Destroying deinits take in self as a +0 value that is then returned at // +1. // // This means that the lifetime of self can not be modeled statically in a // deallocating deinit without analyzing the body of the destroying deinit // (something that violates semantic sil). Thus we add an artificial destroy of // self before the actual destroy of self so that the verifier can understand // that self is being properly balanced. B.createEndLifetime(loc, initialSelfValue); // Deallocate the object. selfForDealloc = B.createUncheckedRefCast(loc, selfForDealloc, classTy); B.createDeallocRef(loc, selfForDealloc, false); emitProfilerIncrement(dd->getBody()); // Return. B.createReturn(loc, emitEmptyTuple(loc)); }
/// Emit a materializeForSet operation that projects storage, assuming /// that no cleanups or callbacks are required. SILValue MaterializeForSetEmitter::emitUsingStorage(SILGenFunction &gen, SILLocation loc, ManagedValue self, RValue &&indices) { LValue lvalue = buildLValue(gen, loc, self, std::move(indices), AccessKind::ReadWrite); ManagedValue address = gen.emitAddressOfLValue(loc, std::move(lvalue), AccessKind::ReadWrite); return address.getUnmanagedValue(); }
ManagedValue SILGenFunction::emitClassMetatypeToObject(SILLocation loc, ManagedValue v, SILType resultTy) { SILValue value = v.getUnmanagedValue(); // Convert the metatype to objc representation. auto metatypeTy = value->getType().castTo<MetatypeType>(); auto objcMetatypeTy = CanMetatypeType::get(metatypeTy.getInstanceType(), MetatypeRepresentation::ObjC); value = B.createThickToObjCMetatype(loc, value, SILType::getPrimitiveObjectType(objcMetatypeTy)); // Convert to an object reference. value = B.createObjCMetatypeToObject(loc, value, resultTy); return emitManagedRValueWithCleanup(value); }
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); }
ManagedValue SILGenFunction::emitExistentialMetatypeToObject(SILLocation loc, ManagedValue v, SILType resultTy) { SILValue value = v.getUnmanagedValue(); // Convert the metatype to objc representation. auto metatypeTy = value.getType().castTo<ExistentialMetatypeType>(); auto objcMetatypeTy = CanExistentialMetatypeType::get( metatypeTy.getInstanceType(), MetatypeRepresentation::ObjC); value = B.createThickToObjCMetatype(loc, value, SILType::getPrimitiveObjectType(objcMetatypeTy)); // Convert to an object reference. value = B.createObjCExistentialMetatypeToObject(loc, value, resultTy); return ManagedValue::forUnmanaged(value); }
/// Perform a foreign error check by testing whether the call result is zero. /// The call result is otherwise ignored. static void emitResultIsZeroErrorCheck(SILGenFunction &SGF, SILLocation loc, ManagedValue result, ManagedValue errorSlot, bool suppressErrorCheck, bool zeroIsError) { // Just ignore the call result if we're suppressing the error check. if (suppressErrorCheck) { return; } SILValue resultValue = emitUnwrapIntegerResult(SGF, loc, result.getUnmanagedValue()); CanType resultType = resultValue->getType().getSwiftRValueType(); if (!resultType->isBuiltinIntegerType(1)) { SILValue zero = SGF.B.createIntegerLiteral(loc, resultValue->getType(), 0); ASTContext &ctx = SGF.getASTContext(); resultValue = SGF.B.createBuiltinBinaryFunction(loc, "cmp_ne", resultValue->getType(), SILType::getBuiltinIntegerType(1, ctx), {resultValue, zero}); } SILBasicBlock *errorBB = SGF.createBasicBlock(FunctionSection::Postmatter); SILBasicBlock *contBB = SGF.createBasicBlock(); if (zeroIsError) SGF.B.createCondBranch(loc, resultValue, contBB, errorBB); else SGF.B.createCondBranch(loc, resultValue, errorBB, contBB); SGF.emitForeignErrorBlock(loc, errorBB, errorSlot); SGF.B.emitBlock(contBB); }