@@ -222,8 +222,9 @@ static ManagedValue emitPartialSuperMethod(SILGenFunction &SGF,
222
222
223
223
namespace {
224
224
225
- // / Abstractly represents a callee, and knows how to emit the entry point
226
- // / reference for a callee at any valid uncurry level.
225
+ // / Abstractly represents a callee, which may be a constant or function value,
226
+ // / and knows how to perform dynamic dispatch and reference the appropriate
227
+ // / entry point at any valid uncurry level.
227
228
class Callee {
228
229
public:
229
230
enum class Kind {
@@ -834,12 +835,28 @@ static Callee prepareArchetypeCallee(SILGenFunction &gen, SILLocation loc,
834
835
constant, substFnType, loc);
835
836
}
836
837
837
- // / An ASTVisitor for building SIL function calls.
838
+ // / An ASTVisitor for decomposing a a nesting of ApplyExprs into an initial
839
+ // / Callee and a list of CallSites. The CallEmission class below uses these
840
+ // / to generate the actual SIL call.
838
841
// /
839
- // / Nested ApplyExprs applied to an underlying curried function or method
840
- // / reference are flattened into a single SIL apply to the most uncurried entry
841
- // / point fitting the call site, avoiding pointless intermediate closure
842
- // / construction.
842
+ // / Formally, an ApplyExpr in the AST always has a single argument, which may
843
+ // / be of tuple type, possibly empty. Also, some callees have a formal type
844
+ // / which is curried -- for example, methods have type Self -> Arg -> Result.
845
+ // /
846
+ // / However, SIL functions take zero or more parameters and the natural entry
847
+ // / point of a method takes Self as an additional argument, rather than
848
+ // / returning a partial application.
849
+ // /
850
+ // / Therefore, nested ApplyExprs applied to a constant are flattened into a
851
+ // / single call of the most uncurried entry point fitting the call site.
852
+ // / This avoids intermediate closure construction.
853
+ // /
854
+ // / For example, a method reference 'self.method' decomposes into curry thunk
855
+ // / as the callee, with a single call site '(self)'.
856
+ // /
857
+ // / On the other hand, a call of a method 'self.method(x)(y)' with a function
858
+ // / return type decomposes into the method's natural entry point as the callee,
859
+ // / and two call sites, first '(x, self)' then '(y)'.
843
860
class SILGenApply : public Lowering ::ExprVisitor<SILGenApply> {
844
861
public:
845
862
// / The SILGenFunction that we are emitting SIL into.
@@ -1200,7 +1217,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
1200
1217
SILDeclRef::ConstructAtNaturalUncurryLevel,
1201
1218
SGF.SGM .requiresObjCDispatch (e->getDecl ()));
1202
1219
1203
- // Otherwise, we have a direct call.
1220
+ // Otherwise, we have a statically-dispatched call.
1204
1221
CanFunctionType substFnType = getSubstFnType ();
1205
1222
ArrayRef<Substitution> subs;
1206
1223
@@ -2988,6 +3005,8 @@ namespace {
2988
3005
}
2989
3006
};
2990
3007
3008
+ // / An application of possibly unevaluated arguments in the form of an
3009
+ // / ArgumentSource to a Callee.
2991
3010
class CallSite {
2992
3011
public:
2993
3012
SILLocation Loc;
@@ -3027,6 +3046,7 @@ namespace {
3027
3046
3028
3047
bool throws () const { return Throws; }
3029
3048
3049
+ // / Evaluate arguments and begin any inout formal accesses.
3030
3050
void emit (SILGenFunction &gen, AbstractionPattern origParamType,
3031
3051
ParamLowering &lowering, SmallVectorImpl<ManagedValue> &args,
3032
3052
SmallVectorImpl<InOutArgument> &inoutArgs,
@@ -3039,6 +3059,7 @@ namespace {
3039
3059
emitter.emitTopLevel (std::move (ArgValue), origParamType);
3040
3060
}
3041
3061
3062
+ // / Take the arguments for special processing, in place of the above.
3042
3063
ArgumentSource &&forward() && {
3043
3064
return std::move (ArgValue);
3044
3065
}
@@ -3079,6 +3100,18 @@ namespace {
3079
3100
}
3080
3101
};
3081
3102
3103
+ // / Once the Callee and CallSites have been prepared by SILGenApply,
3104
+ // / generate SIL for a fully-formed call.
3105
+ // /
3106
+ // / The lowered function type of the callee defines an abstraction pattern
3107
+ // / for evaluating argument values of tuple type directly into explosions of
3108
+ // / scalars where possible.
3109
+ // /
3110
+ // / If there are more call sites than the natural uncurry level, they are
3111
+ // / have to be applied recursively to each intermediate callee.
3112
+ // /
3113
+ // / Also inout formal access and parameter and result conventions are
3114
+ // / handled here, with some special logic required for calls with +0 self.
3082
3115
class CallEmission {
3083
3116
SILGenFunction &gen;
3084
3117
@@ -3091,6 +3124,7 @@ namespace {
3091
3124
bool AssumedPlusZeroSelf;
3092
3125
3093
3126
public:
3127
+ // / Create an emission for a call of the given callee.
3094
3128
CallEmission (SILGenFunction &gen, Callee &&callee,
3095
3129
WritebackScope &&writebackScope,
3096
3130
bool assumedPlusZeroSelf = false )
@@ -3102,6 +3136,8 @@ namespace {
3102
3136
AssumedPlusZeroSelf(assumedPlusZeroSelf)
3103
3137
{}
3104
3138
3139
+ // / Add a level of function application by passing in its possibly
3140
+ // / unevaluated arguments and their formal type.
3105
3141
void addCallSite (CallSite &&site) {
3106
3142
assert (!applied && " already applied!" );
3107
3143
@@ -3115,7 +3151,9 @@ namespace {
3115
3151
// Otherwise, apply these arguments to the result of the previous call.
3116
3152
extraSites.push_back (std::move (site));
3117
3153
}
3118
-
3154
+
3155
+ // / Add a level of function application by passing in its possibly
3156
+ // / unevaluated arguments and their formal type
3119
3157
template <typename ...T>
3120
3158
void addCallSite (T &&...args) {
3121
3159
addCallSite (CallSite{std::forward<T>(args)...});
@@ -3134,12 +3172,15 @@ namespace {
3134
3172
uncurriedSites[0 ].convertToPlusOneFromPlusZero (gen);
3135
3173
}
3136
3174
3175
+ // / Emit the fully-formed call.
3137
3176
ManagedValue apply (SGFContext C = SGFContext()) {
3138
3177
assert (!applied && " already applied!" );
3139
3178
3140
3179
applied = true ;
3141
3180
3142
- // Get the callee value at the needed uncurry level.
3181
+ // Get the callee value at the needed uncurry level, uncurrying as
3182
+ // much as possible. If the number of calls is less than the natural
3183
+ // uncurry level, the callee emission might create a curry thunk.
3143
3184
unsigned uncurryLevel = callee.getNaturalUncurryLevel () - uncurries;
3144
3185
3145
3186
// Get either the specialized emitter for a known function, or the
@@ -3263,6 +3304,8 @@ namespace {
3263
3304
args = {};
3264
3305
3265
3306
// Emit the uncurried call.
3307
+
3308
+ // Handle a regular call.
3266
3309
if (!specializedEmitter) {
3267
3310
result = gen.emitApply (uncurriedLoc.getValue (), mv,
3268
3311
callee.getSubstitutions (),
@@ -3273,6 +3316,7 @@ namespace {
3273
3316
initialOptions, None,
3274
3317
foreignError,
3275
3318
uncurriedContext);
3319
+ // Handle a specialized emitter operating on evaluated arguments.
3276
3320
} else if (specializedEmitter->isLateEmitter ()) {
3277
3321
auto emitter = specializedEmitter->getLateEmitter ();
3278
3322
result = emitter (gen,
@@ -3281,6 +3325,7 @@ namespace {
3281
3325
uncurriedArgs,
3282
3326
formalApplyType,
3283
3327
uncurriedContext);
3328
+ // Special case for superclass method calls.
3284
3329
} else if (specializedEmitter->isLatePartialSuperEmitter ()) {
3285
3330
auto emitter = specializedEmitter->getLatePartialSuperEmitter ();
3286
3331
result = emitter (gen,
@@ -3290,6 +3335,8 @@ namespace {
3290
3335
uncurriedArgs,
3291
3336
formalApplyType,
3292
3337
uncurriedContext);
3338
+
3339
+ // Builtins.
3293
3340
} else {
3294
3341
assert (specializedEmitter->isNamedBuiltin ());
3295
3342
auto builtinName = specializedEmitter->getBuiltinName ();
0 commit comments