| //===--- SILGenProlog.cpp - Function prologue emission --------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SILGenFunction.h" |
| #include "Initialization.h" |
| #include "ManagedValue.h" |
| #include "Scope.h" |
| #include "ArgumentSource.h" |
| #include "swift/SIL/SILArgument.h" |
| #include "swift/AST/CanTypeVisitor.h" |
| #include "swift/AST/GenericEnvironment.h" |
| #include "swift/AST/ParameterList.h" |
| |
| using namespace swift; |
| using namespace Lowering; |
| |
| SILValue SILGenFunction::emitSelfDecl(VarDecl *selfDecl) { |
| // Emit the implicit 'self' argument. |
| SILType selfType = getLoweredLoadableType(selfDecl->getType()); |
| SILValue selfValue = F.begin()->createFunctionArgument(selfType, selfDecl); |
| VarLocs[selfDecl] = VarLoc::get(selfValue); |
| SILLocation PrologueLoc(selfDecl); |
| PrologueLoc.markAsPrologue(); |
| uint16_t ArgNo = 1; // Hardcoded for destructors. |
| B.createDebugValue(PrologueLoc, selfValue, |
| SILDebugVariable(selfDecl->isLet(), ArgNo)); |
| return selfValue; |
| } |
| |
| namespace { |
| class EmitBBArguments : public CanTypeVisitor<EmitBBArguments, |
| /*RetTy*/ ManagedValue> |
| { |
| public: |
| SILGenFunction &SGF; |
| SILBasicBlock *parent; |
| SILLocation loc; |
| CanSILFunctionType fnTy; |
| ArrayRef<SILParameterInfo> ¶meters; |
| |
| EmitBBArguments(SILGenFunction &sgf, SILBasicBlock *parent, SILLocation l, |
| CanSILFunctionType fnTy, |
| ArrayRef<SILParameterInfo> ¶meters) |
| : SGF(sgf), parent(parent), loc(l), fnTy(fnTy), parameters(parameters) {} |
| |
| ManagedValue visitType(CanType t) { |
| return visitType(t, /*isInOut=*/false); |
| } |
| |
| ManagedValue visitType(CanType t, bool isInOut) { |
| // The calling convention always uses minimal resilience expansion but |
| // inside the function we lower/expand types in context of the current |
| // function. |
| auto argType = SGF.SGM.Types.getLoweredType(t, SGF.getTypeExpansionContext()); |
| auto argTypeConv = |
| SGF.SGM.Types.getLoweredType(t, TypeExpansionContext::minimal()); |
| argType = argType.getCategoryType(argTypeConv.getCategory()); |
| |
| if (isInOut) |
| argType = SILType::getPrimitiveAddressType(argType.getASTType()); |
| |
| // Pop the next parameter info. |
| auto parameterInfo = parameters.front(); |
| parameters = parameters.slice(1); |
| |
| auto paramType = |
| SGF.F.mapTypeIntoContext(SGF.getSILType(parameterInfo, fnTy)); |
| ManagedValue mv = SGF.B.createInputFunctionArgument( |
| paramType, loc.getAsASTNode<ValueDecl>()); |
| |
| if (argType != paramType) { |
| // This is a hack to deal with the fact that Self.Type comes in as a |
| // static metatype, but we have to downcast it to a dynamic Self |
| // metatype to get the right semantics. |
| assert( |
| cast<DynamicSelfType>( |
| argType.castTo<MetatypeType>().getInstanceType()) |
| .getSelfType() |
| == paramType.castTo<MetatypeType>().getInstanceType()); |
| mv = SGF.B.createUncheckedBitCast(loc, mv, argType); |
| } |
| |
| if (isInOut) |
| return mv; |
| |
| // This can happen if the value is resilient in the calling convention |
| // but not resilient locally. |
| if (argType.isLoadable(SGF.F) && argType.isAddress()) { |
| if (mv.isPlusOne(SGF)) |
| mv = SGF.B.createLoadTake(loc, mv); |
| else |
| mv = SGF.B.createLoadBorrow(loc, mv); |
| } |
| |
| // If the value is a (possibly optional) ObjC block passed into the entry |
| // point of the function, then copy it so we can treat the value reliably |
| // as a heap object. Escape analysis can eliminate this copy if it's |
| // unneeded during optimization. |
| CanType objectType = t; |
| if (auto theObjTy = t.getOptionalObjectType()) |
| objectType = theObjTy; |
| if (isa<FunctionType>(objectType) && |
| cast<FunctionType>(objectType)->getRepresentation() |
| == FunctionType::Representation::Block) { |
| SILValue blockCopy = SGF.B.createCopyBlock(loc, mv.getValue()); |
| mv = SGF.emitManagedRValueWithCleanup(blockCopy); |
| } |
| return mv; |
| } |
| |
| ManagedValue visitTupleType(CanTupleType t) { |
| SmallVector<ManagedValue, 4> elements; |
| |
| auto &tl = SGF.SGM.Types.getTypeLowering(t, SGF.getTypeExpansionContext()); |
| bool canBeGuaranteed = tl.isLoadable(); |
| |
| // Collect the exploded elements. |
| for (auto fieldType : t.getElementTypes()) { |
| auto elt = visit(fieldType); |
| // If we can't borrow one of the elements as a guaranteed parameter, then |
| // we have to +1 the tuple. |
| if (elt.hasCleanup()) |
| canBeGuaranteed = false; |
| elements.push_back(elt); |
| } |
| |
| if (tl.isLoadable() || !SGF.silConv.useLoweredAddresses()) { |
| SmallVector<SILValue, 4> elementValues; |
| if (canBeGuaranteed) { |
| // If all of the elements were guaranteed, we can form a guaranteed tuple. |
| for (auto element : elements) |
| elementValues.push_back(element.getUnmanagedValue()); |
| } else { |
| // Otherwise, we need to move or copy values into a +1 tuple. |
| for (auto element : elements) { |
| SILValue value = element.hasCleanup() |
| ? element.forward(SGF) |
| : element.copyUnmanaged(SGF, loc).forward(SGF); |
| elementValues.push_back(value); |
| } |
| } |
| auto tupleValue = SGF.B.createTuple(loc, tl.getLoweredType(), |
| elementValues); |
| return canBeGuaranteed |
| ? ManagedValue::forUnmanaged(tupleValue) |
| : SGF.emitManagedRValueWithCleanup(tupleValue); |
| } else { |
| // If the type is address-only, we need to move or copy the elements into |
| // a tuple in memory. |
| // TODO: It would be a bit more efficient to use a preallocated buffer |
| // in this case. |
| auto buffer = SGF.emitTemporaryAllocation(loc, tl.getLoweredType()); |
| for (auto i : indices(elements)) { |
| auto element = elements[i]; |
| auto elementBuffer = SGF.B.createTupleElementAddr(loc, buffer, |
| i, element.getType().getAddressType()); |
| if (element.hasCleanup()) |
| element.forwardInto(SGF, loc, elementBuffer); |
| else |
| element.copyInto(SGF, loc, elementBuffer); |
| } |
| return SGF.emitManagedRValueWithCleanup(buffer); |
| } |
| } |
| }; |
| } // end anonymous namespace |
| |
| |
| namespace { |
| |
| /// A helper for creating SILArguments and binding variables to the argument |
| /// names. |
| struct ArgumentInitHelper { |
| SILGenFunction &SGF; |
| SILFunction &f; |
| SILGenBuilder &initB; |
| |
| /// An ArrayRef that we use in our SILParameterList queue. Parameters are |
| /// sliced off of the front as they're emitted. |
| ArrayRef<SILParameterInfo> parameters; |
| uint16_t ArgNo = 0; |
| |
| ArgumentInitHelper(SILGenFunction &SGF, SILFunction &f) |
| : SGF(SGF), f(f), initB(SGF.B), |
| parameters( |
| f.getLoweredFunctionTypeInContext(SGF.B.getTypeExpansionContext()) |
| ->getParameters()) {} |
| |
| unsigned getNumArgs() const { return ArgNo; } |
| |
| ManagedValue makeArgument(Type ty, bool isInOut, SILBasicBlock *parent, |
| SILLocation l) { |
| assert(ty && "no type?!"); |
| |
| // Create an RValue by emitting destructured arguments into a basic block. |
| CanType canTy = ty->getCanonicalType(); |
| EmitBBArguments argEmitter(SGF, parent, l, |
| f.getLoweredFunctionType(), parameters); |
| |
| // Note: inouts of tuples are not exploded, so we bypass visit(). |
| if (isInOut) |
| return argEmitter.visitType(canTy, /*isInOut=*/true); |
| return argEmitter.visit(canTy); |
| } |
| |
| /// Create a SILArgument and store its value into the given Initialization, |
| /// if not null. |
| void makeArgumentIntoBinding(Type ty, SILBasicBlock *parent, ParamDecl *pd) { |
| SILLocation loc(pd); |
| loc.markAsPrologue(); |
| |
| ManagedValue argrv = makeArgument(ty, pd->isInOut(), parent, loc); |
| |
| if (pd->isInOut()) { |
| assert(argrv.getType().isAddress() && "expected inout to be address"); |
| } else { |
| assert(pd->isImmutable() && "expected parameter to be immutable!"); |
| // If the variable is immutable, we can bind the value as is. |
| // Leave the cleanup on the argument, if any, in place to consume the |
| // argument if we're responsible for it. |
| } |
| SGF.VarLocs[pd] = SILGenFunction::VarLoc::get(argrv.getValue()); |
| SILValue value = argrv.getValue(); |
| SILDebugVariable varinfo(pd->isImmutable(), ArgNo); |
| if (!argrv.getType().isAddress()) { |
| SGF.B.createDebugValue(loc, value, varinfo); |
| } else { |
| if (auto AllocStack = dyn_cast<AllocStackInst>(value)) |
| AllocStack->setArgNo(ArgNo); |
| else |
| SGF.B.createDebugValueAddr(loc, value, varinfo); |
| } |
| } |
| |
| void emitParam(ParamDecl *PD) { |
| auto type = PD->getType(); |
| |
| assert(type->isMaterializable()); |
| |
| ++ArgNo; |
| if (PD->hasName()) { |
| makeArgumentIntoBinding(type, &*f.begin(), PD); |
| return; |
| } |
| |
| emitAnonymousParam(type, PD, PD); |
| } |
| |
| void emitAnonymousParam(Type type, SILLocation paramLoc, ParamDecl *PD) { |
| // A value bound to _ is unused and can be immediately released. |
| Scope discardScope(SGF.Cleanups, CleanupLocation(PD)); |
| |
| // Manage the parameter. |
| auto argrv = makeArgument(type, PD->isInOut(), &*f.begin(), paramLoc); |
| |
| // Emit debug information for the argument. |
| SILLocation loc(PD); |
| loc.markAsPrologue(); |
| if (argrv.getType().isAddress()) |
| SGF.B.createDebugValueAddr(loc, argrv.getValue(), |
| SILDebugVariable(PD->isLet(), ArgNo)); |
| else |
| SGF.B.createDebugValue(loc, argrv.getValue(), |
| SILDebugVariable(PD->isLet(), ArgNo)); |
| } |
| }; |
| } // end anonymous namespace |
| |
| |
| static void makeArgument(Type ty, ParamDecl *decl, |
| SmallVectorImpl<SILValue> &args, SILGenFunction &SGF) { |
| assert(ty && "no type?!"); |
| |
| // Destructure tuple value arguments. |
| if (TupleType *tupleTy = decl->isInOut() ? nullptr : ty->getAs<TupleType>()) { |
| for (auto fieldType : tupleTy->getElementTypes()) |
| makeArgument(fieldType, decl, args, SGF); |
| } else { |
| auto loweredTy = SGF.getLoweredTypeForFunctionArgument(ty); |
| if (decl->isInOut()) |
| loweredTy = SILType::getPrimitiveAddressType(loweredTy.getASTType()); |
| auto arg = SGF.F.begin()->createFunctionArgument(loweredTy, decl); |
| args.push_back(arg); |
| } |
| } |
| |
| |
| void SILGenFunction::bindParameterForForwarding(ParamDecl *param, |
| SmallVectorImpl<SILValue> ¶meters) { |
| makeArgument(param->getType(), param, parameters, *this); |
| } |
| |
| void SILGenFunction::bindParametersForForwarding(const ParameterList *params, |
| SmallVectorImpl<SILValue> ¶meters) { |
| for (auto param : *params) |
| bindParameterForForwarding(param, parameters); |
| } |
| |
| static void emitCaptureArguments(SILGenFunction &SGF, |
| GenericSignature origGenericSig, |
| CapturedValue capture, |
| uint16_t ArgNo) { |
| |
| auto *VD = cast<VarDecl>(capture.getDecl()); |
| SILLocation Loc(VD); |
| Loc.markAsPrologue(); |
| |
| // Local function to get the captured variable type within the capturing |
| // context. |
| auto getVarTypeInCaptureContext = [&]() -> Type { |
| auto interfaceType = VD->getInterfaceType()->getCanonicalType( |
| origGenericSig); |
| return SGF.F.mapTypeIntoContext(interfaceType); |
| }; |
| |
| auto expansion = SGF.getTypeExpansionContext(); |
| switch (SGF.SGM.Types.getDeclCaptureKind(capture, expansion)) { |
| case CaptureKind::Constant: { |
| auto type = getVarTypeInCaptureContext(); |
| auto &lowering = SGF.getTypeLowering(type); |
| // Constant decls are captured by value. |
| SILType ty = lowering.getLoweredType(); |
| SILValue val = SGF.F.begin()->createFunctionArgument(ty, VD); |
| |
| bool NeedToDestroyValueAtExit = false; |
| |
| // If the original variable was settable, then Sema will have treated the |
| // VarDecl as an lvalue, even in the closure's use. As such, we need to |
| // allow formation of the address for this captured value. Create a |
| // temporary within the closure to provide this address. |
| if (VD->isSettable(VD->getDeclContext())) { |
| auto addr = SGF.emitTemporaryAllocation(VD, ty); |
| // We have created a copy that needs to be destroyed. |
| val = SGF.B.emitCopyValueOperation(Loc, val); |
| NeedToDestroyValueAtExit = true; |
| lowering.emitStore(SGF.B, VD, val, addr, StoreOwnershipQualifier::Init); |
| val = addr; |
| } |
| |
| SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(val); |
| if (auto *AllocStack = dyn_cast<AllocStackInst>(val)) |
| AllocStack->setArgNo(ArgNo); |
| else { |
| SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); |
| SGF.B.createDebugValue(Loc, val, DbgVar); |
| } |
| |
| // TODO: Closure contexts should always be guaranteed. |
| if (NeedToDestroyValueAtExit && !lowering.isTrivial()) |
| SGF.enterDestroyCleanup(val); |
| break; |
| } |
| |
| case CaptureKind::Box: { |
| // LValues are captured as a retained @box that owns |
| // the captured value. |
| auto type = getVarTypeInCaptureContext(); |
| // Get the content for the box in the minimal resilience domain because we |
| // are declaring a type. |
| auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture( |
| VD, |
| SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(), |
| type), |
| SGF.F.getGenericEnvironment(), /*mutable*/ true); |
| SILValue box = SGF.F.begin()->createFunctionArgument( |
| SILType::getPrimitiveObjectType(boxTy), VD); |
| SILValue addr = SGF.B.createProjectBox(VD, box, 0); |
| SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box); |
| SILDebugVariable DbgVar(/*Constant*/ false, ArgNo); |
| SGF.B.createDebugValueAddr(Loc, addr, DbgVar); |
| break; |
| } |
| case CaptureKind::Immutable: |
| case CaptureKind::StorageAddress: { |
| // Non-escaping stored decls are captured as the address of the value. |
| auto type = getVarTypeInCaptureContext(); |
| SILType ty = SGF.getLoweredType(type).getAddressType(); |
| SILValue addr = SGF.F.begin()->createFunctionArgument(ty, VD); |
| SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr); |
| SILDebugVariable DbgVar(/*Constant*/ true, ArgNo); |
| SGF.B.createDebugValueAddr(Loc, addr, DbgVar); |
| break; |
| } |
| } |
| } |
| |
| void SILGenFunction::emitProlog(CaptureInfo captureInfo, |
| ParameterList *paramList, |
| ParamDecl *selfParam, |
| DeclContext *DC, |
| Type resultType, |
| bool throws, |
| SourceLoc throwsLoc) { |
| uint16_t ArgNo = emitProlog(paramList, selfParam, resultType, |
| DC, throws, throwsLoc); |
| |
| // Emit the capture argument variables. These are placed last because they |
| // become the first curry level of the SIL function. |
| assert(captureInfo.hasBeenComputed() && |
| "can't emit prolog of function with uncomputed captures"); |
| for (auto capture : captureInfo.getCaptures()) { |
| if (capture.isDynamicSelfMetadata()) { |
| auto selfMetatype = MetatypeType::get( |
| captureInfo.getDynamicSelfType()); |
| SILType ty = getLoweredType(selfMetatype); |
| SILValue val = F.begin()->createFunctionArgument(ty); |
| (void) val; |
| |
| continue; |
| } |
| |
| if (capture.isOpaqueValue()) { |
| OpaqueValueExpr *opaqueValue = capture.getOpaqueValue(); |
| Type type = opaqueValue->getType()->mapTypeOutOfContext(); |
| type = F.mapTypeIntoContext(type); |
| auto &lowering = getTypeLowering(type); |
| SILType ty = lowering.getLoweredType(); |
| SILValue val = F.begin()->createFunctionArgument(ty); |
| OpaqueValues[opaqueValue] = ManagedValue::forUnmanaged(val); |
| |
| // Opaque values are always passed 'owned', so add a clean up if needed. |
| if (!lowering.isTrivial()) |
| enterDestroyCleanup(val); |
| |
| continue; |
| } |
| |
| emitCaptureArguments(*this, DC->getGenericSignatureOfContext(), |
| capture, ++ArgNo); |
| } |
| |
| // Emit an unreachable instruction if a parameter type is |
| // uninhabited |
| if (paramList) { |
| for (auto *param : *paramList) { |
| if (param->getType()->isStructurallyUninhabited()) { |
| SILLocation unreachableLoc(param); |
| unreachableLoc.markAsPrologue(); |
| B.createUnreachable(unreachableLoc); |
| break; |
| } |
| } |
| } |
| |
| if (!F.isAsync()) |
| return; |
| |
| // Initialize 'actor' if the function is an actor-isolated function or |
| // closure. |
| if (auto *funcDecl = |
| dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) { |
| auto actorIsolation = getActorIsolation(funcDecl); |
| switch (actorIsolation.getKind()) { |
| case ActorIsolation::Unspecified: |
| case ActorIsolation::Independent: |
| case ActorIsolation::IndependentUnsafe: |
| break; |
| |
| case ActorIsolation::ActorInstance: { |
| assert(selfParam && "no self parameter for ActorInstance isolation"); |
| ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument()); |
| actor = selfArg.borrow(*this, F.getLocation()).getValue(); |
| break; |
| } |
| |
| case ActorIsolation::GlobalActor: |
| actor = emitLoadGlobalActorExecutor(actorIsolation.getGlobalActor()); |
| break; |
| } |
| } else if (auto *closureExpr = dyn_cast<AbstractClosureExpr>(FunctionDC)) { |
| auto actorIsolation = closureExpr->getActorIsolation(); |
| switch (actorIsolation.getKind()) { |
| case ClosureActorIsolation::Independent: |
| break; |
| |
| case ClosureActorIsolation::ActorInstance: |
| actor = emitLoadActorExecutor(actorIsolation.getActorInstance()); |
| break; |
| |
| case ClosureActorIsolation::GlobalActor: |
| actor = emitLoadGlobalActorExecutor(actorIsolation.getGlobalActor()); |
| break; |
| } |
| } |
| |
| emitHopToCurrentExecutor(F.getLocation()); |
| } |
| |
| SILValue SILGenFunction::emitLoadActorExecutor(VarDecl *actorDecl) { |
| RValue actorInstanceRV = emitRValueForDecl(F.getLocation(), |
| actorDecl, actorDecl->getType(), AccessSemantics::Ordinary); |
| ManagedValue actorInstance = std::move(actorInstanceRV).getScalarValue(); |
| return actorInstance.borrow(*this, F.getLocation()).getValue(); |
| } |
| |
| SILValue SILGenFunction::emitLoadGlobalActorExecutor(Type globalActor) { |
| assert(F.isAsync()); |
| CanType actorType = CanType(globalActor); |
| NominalTypeDecl *nominal = actorType->getNominalOrBoundGenericNominal(); |
| VarDecl *sharedInstanceDecl = nominal->getGlobalActorInstance(); |
| assert(sharedInstanceDecl && "no shared actor field in global actor"); |
| SubstitutionMap subs = |
| actorType->getContextSubstitutionMap(SGM.SwiftModule, nominal); |
| SILLocation loc = F.getLocation(); |
| Type instanceType = |
| actorType->getTypeOfMember(SGM.SwiftModule, sharedInstanceDecl); |
| |
| ManagedValue actorMetaType = |
| ManagedValue::forUnmanaged(B.createMetatype(loc, |
| SILType::getPrimitiveObjectType( |
| CanMetatypeType::get(actorType, MetatypeRepresentation::Thin)))); |
| |
| RValue actorInstanceRV = emitRValueForStorageLoad(loc, actorMetaType, |
| actorType, /*isSuper*/ false, sharedInstanceDecl, PreparedArguments(), |
| subs, AccessSemantics::Ordinary, instanceType, SGFContext()); |
| ManagedValue actorInstance = std::move(actorInstanceRV).getScalarValue(); |
| return actorInstance.borrow(*this, loc).getValue(); |
| } |
| |
| static void emitIndirectResultParameters(SILGenFunction &SGF, Type resultType, |
| DeclContext *DC) { |
| // Expand tuples. |
| if (auto tupleType = resultType->getAs<TupleType>()) { |
| for (auto eltType : tupleType->getElementTypes()) { |
| emitIndirectResultParameters(SGF, eltType, DC); |
| } |
| return; |
| } |
| |
| // If the return type is address-only, emit the indirect return argument. |
| |
| // The calling convention always uses minimal resilience expansion. |
| auto &resultTI = |
| SGF.SGM.Types.getTypeLowering(DC->mapTypeIntoContext(resultType), |
| SGF.getTypeExpansionContext()); |
| auto &resultTIConv = SGF.SGM.Types.getTypeLowering( |
| DC->mapTypeIntoContext(resultType), TypeExpansionContext::minimal()); |
| |
| if (!SILModuleConventions::isReturnedIndirectlyInSIL( |
| resultTIConv.getLoweredType(), SGF.SGM.M)) { |
| return; |
| } |
| auto &ctx = SGF.getASTContext(); |
| auto var = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), |
| ctx.getIdentifier("$return_value"), SourceLoc(), |
| ctx.getIdentifier("$return_value"), |
| DC); |
| var->setSpecifier(ParamSpecifier::InOut); |
| var->setInterfaceType(resultType); |
| auto *arg = SGF.F.begin()->createFunctionArgument( |
| resultTI.getLoweredType().getAddressType(), var); |
| (void)arg; |
| } |
| |
| uint16_t SILGenFunction::emitProlog(ParameterList *paramList, |
| ParamDecl *selfParam, |
| Type resultType, |
| DeclContext *DC, |
| bool throws, |
| SourceLoc throwsLoc) { |
| // Create the indirect result parameters. |
| auto genericSig = DC->getGenericSignatureOfContext(); |
| resultType = resultType->getCanonicalType(genericSig); |
| |
| emitIndirectResultParameters(*this, resultType, DC); |
| |
| // Emit the argument variables in calling convention order. |
| ArgumentInitHelper emitter(*this, F); |
| |
| // Add the SILArguments and use them to initialize the local argument |
| // values. |
| if (paramList) |
| for (auto *param : *paramList) |
| emitter.emitParam(param); |
| if (selfParam) |
| emitter.emitParam(selfParam); |
| |
| // Record the ArgNo of the artificial $error inout argument. |
| unsigned ArgNo = emitter.getNumArgs(); |
| if (throws) { |
| auto NativeErrorTy = SILType::getExceptionType(getASTContext()); |
| ManagedValue Undef = emitUndef(NativeErrorTy); |
| SILDebugVariable DbgVar("$error", /*Constant*/ false, ++ArgNo); |
| RegularLocation loc = RegularLocation::getAutoGeneratedLocation(); |
| if (throwsLoc.isValid()) |
| loc = throwsLoc; |
| B.createDebugValue(loc, Undef.getValue(), DbgVar); |
| } |
| |
| return ArgNo; |
| } |