mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 09:43:08 +00:00
[dart2wasm] Produce wrapper functions for closures
Instead of using top types for the parameters and return of the implementation function for a function expression or local function, use precise types and generate a wrapper function with top types that casts the parameters and calls the implementation function. This unifies the wrapper function generation with tear-offs, setting the stage for the upcoming generalization to support type parameters and optional parameters. The change also brings some benefits in its own right: - Arguments to closures are converted once instead of at every use - Direct calls to local functions avoid the conversion of arguments Also add source location to closure function names and generally avoid parentheses in function names, as they are confusing in stack traces. Change-Id: If83073bb2e2dd17554ffa03fa2596e79d730fb67 Cq-Include-Trybots: luci.dart.try:dart2wasm-linux-x64-d8-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/256665 Reviewed-by: Joshua Litt <joshualitt@google.com>
This commit is contained in:
parent
25b1bfe7a6
commit
0cb91b9824
5 changed files with 48 additions and 32 deletions
|
@ -269,9 +269,18 @@ class CaptureFinder extends RecursiveVisitor {
|
|||
throw "Not supported: Type parameters for "
|
||||
"function expression or local function at ${node.location}";
|
||||
}
|
||||
int parameterCount = node.requiredParameterCount;
|
||||
w.FunctionType type = translator.closureFunctionType(parameterCount);
|
||||
w.DefinedFunction function = m.addFunction(type, "$member (closure)");
|
||||
List<w.ValueType> inputs = [
|
||||
w.RefType.data(nullable: false),
|
||||
for (VariableDeclaration param in node.positionalParameters)
|
||||
translator.translateType(param.type)
|
||||
];
|
||||
List<w.ValueType> outputs = [
|
||||
if (node.returnType != const VoidType())
|
||||
translator.translateType(node.returnType)
|
||||
];
|
||||
w.FunctionType type = m.addFunctionType(inputs, outputs);
|
||||
w.DefinedFunction function =
|
||||
m.addFunction(type, "$member closure at ${node.location}");
|
||||
closures.lambdas[node] = Lambda(node, function);
|
||||
|
||||
depth++;
|
||||
|
|
|
@ -1891,7 +1891,9 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
w.StructType _instantiateClosure(FunctionNode functionNode) {
|
||||
int parameterCount = functionNode.requiredParameterCount;
|
||||
Lambda lambda = closures.lambdas[functionNode]!;
|
||||
w.DefinedGlobal global = translator.makeFunctionRef(lambda.function);
|
||||
w.DefinedFunction wrapper = translator.getClosureWrapper(functionNode,
|
||||
lambda.function, "closure wrapper at ${functionNode.location}");
|
||||
w.DefinedGlobal global = translator.makeFunctionRef(wrapper);
|
||||
|
||||
ClassInfo info = translator.classInfo[translator.functionClass]!;
|
||||
translator.functions.allocateClass(info.classId);
|
||||
|
@ -1901,7 +1903,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
b.i32_const(initialIdentityHash);
|
||||
_pushContext(functionNode);
|
||||
b.global_get(global);
|
||||
b.struct_new(translator.closureStructType(parameterCount));
|
||||
b.struct_new(struct);
|
||||
|
||||
return struct;
|
||||
}
|
||||
|
@ -1948,14 +1950,15 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
w.ValueType visitLocalFunctionInvocation(
|
||||
LocalFunctionInvocation node, w.ValueType expectedType) {
|
||||
var decl = node.variable.parent as FunctionDeclaration;
|
||||
_pushContext(decl.function);
|
||||
for (Expression arg in node.arguments.positional) {
|
||||
wrap(arg, translator.topInfo.nullableType);
|
||||
}
|
||||
Lambda lambda = closures.lambdas[decl.function]!;
|
||||
List<w.ValueType> inputs = lambda.function.type.inputs;
|
||||
_pushContext(decl.function);
|
||||
for (int i = 0; i < node.arguments.positional.length; i++) {
|
||||
wrap(node.arguments.positional[i], inputs[1 + i]);
|
||||
}
|
||||
b.comment("Local call of ${decl.variable.name}");
|
||||
b.call(lambda.function);
|
||||
return translator.topInfo.nullableType;
|
||||
return translator.outputOrVoid(lambda.function.type.outputs);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -201,7 +201,7 @@ class Constants {
|
|||
ClassInfo info = translator.classInfo[cls]!;
|
||||
w.FunctionType ftype = m.addFunctionType(
|
||||
const [w.NumType.i32, w.NumType.i32], [info.nonNullableType]);
|
||||
return m.addFunction(ftype, "makeString (${cls.name})");
|
||||
return m.addFunction(ftype, "makeString ${cls.name}");
|
||||
}
|
||||
|
||||
void makeStringFunctionBody(Class cls, w.DefinedFunction function,
|
||||
|
|
|
@ -132,7 +132,7 @@ class FunctionCollector extends MemberVisitor1<w.FunctionType, Reference> {
|
|||
w.FunctionType ftype = m.addFunctionType(
|
||||
[...outer.type.inputs, asyncStackType],
|
||||
[translator.topInfo.nullableType]);
|
||||
return m.addFunction(ftype, "${outer.functionName} (inner)");
|
||||
return m.addFunction(ftype, "${outer.functionName} inner");
|
||||
}
|
||||
|
||||
void activateSelector(SelectorInfo selector) {
|
||||
|
|
|
@ -689,8 +689,8 @@ class Translator {
|
|||
return tearOffFunctionCache.putIfAbsent(member, () {
|
||||
assert(member.kind == ProcedureKind.Method);
|
||||
FunctionNode functionNode = member.function;
|
||||
int parameterCount = functionNode.requiredParameterCount;
|
||||
if (functionNode.positionalParameters.length != parameterCount ||
|
||||
if (functionNode.positionalParameters.length !=
|
||||
functionNode.requiredParameterCount ||
|
||||
functionNode.namedParameters.isNotEmpty) {
|
||||
throw "Not supported: Tear-off with optional parameters"
|
||||
" at ${member.location}";
|
||||
|
@ -699,28 +699,32 @@ class Translator {
|
|||
throw "Not supported: Tear-off with type parameters"
|
||||
" at ${member.location}";
|
||||
}
|
||||
w.FunctionType memberSignature = signatureFor(member.reference);
|
||||
w.FunctionType closureSignature = closureFunctionType(parameterCount);
|
||||
int signatureOffset = member.isInstanceMember ? 1 : 0;
|
||||
assert(memberSignature.inputs.length == signatureOffset + parameterCount);
|
||||
assert(closureSignature.inputs.length == 1 + parameterCount);
|
||||
w.DefinedFunction function =
|
||||
m.addFunction(closureSignature, "$member (tear-off)");
|
||||
w.BaseFunction target = functions.getFunction(member.reference);
|
||||
w.Instructions b = function.body;
|
||||
for (int i = 0; i < memberSignature.inputs.length; i++) {
|
||||
w.Local paramLocal = function.locals[(1 - signatureOffset) + i];
|
||||
b.local_get(paramLocal);
|
||||
convertType(function, paramLocal.type, memberSignature.inputs[i]);
|
||||
}
|
||||
b.call(target);
|
||||
convertType(function, outputOrVoid(target.type.outputs),
|
||||
outputOrVoid(closureSignature.outputs));
|
||||
b.end();
|
||||
return function;
|
||||
return getClosureWrapper(functionNode, target, "$member tear-off");
|
||||
});
|
||||
}
|
||||
|
||||
w.DefinedFunction getClosureWrapper(
|
||||
FunctionNode functionNode, w.BaseFunction target, String name) {
|
||||
int parameterCount = functionNode.requiredParameterCount;
|
||||
w.FunctionType targetSignature = target.type;
|
||||
w.FunctionType closureSignature = closureFunctionType(parameterCount);
|
||||
assert(closureSignature.inputs.length == 1 + parameterCount);
|
||||
int signatureOffset = targetSignature.inputs.length - parameterCount;
|
||||
w.DefinedFunction function = m.addFunction(closureSignature, name);
|
||||
w.Instructions b = function.body;
|
||||
for (int i = 0; i < targetSignature.inputs.length; i++) {
|
||||
w.Local paramLocal = function.locals[(1 - signatureOffset) + i];
|
||||
b.local_get(paramLocal);
|
||||
convertType(function, paramLocal.type, targetSignature.inputs[i]);
|
||||
}
|
||||
b.call(target);
|
||||
convertType(function, outputOrVoid(target.type.outputs),
|
||||
outputOrVoid(closureSignature.outputs));
|
||||
b.end();
|
||||
return function;
|
||||
}
|
||||
|
||||
w.ValueType outputOrVoid(List<w.ValueType> outputs) {
|
||||
return outputs.isEmpty ? voidMarker : outputs.single;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue