@@ -159,6 +159,8 @@ class Translator with KernelNodes {
159159 final Map <w.BaseFunction , w.Global > functionRefCache = {};
160160 final Map <Procedure , ClosureImplementation > tearOffFunctionCache = {};
161161
162+ final Map <FunctionNode , ClosureImplementation > closureImplementations = {};
163+
162164 // Some convenience accessors for commonly used values.
163165 late final ClassInfo topInfo = classes[0 ];
164166 late final ClassInfo objectInfo = classInfo[coreTypes.objectClass]! ;
@@ -723,6 +725,23 @@ class Translator with KernelNodes {
723725
724726 ClosureImplementation getClosure (FunctionNode functionNode,
725727 w.BaseFunction target, ParameterInfo paramInfo, String name) {
728+ // We compile a block multiple times in try-catch, to catch Dart exceptions
729+ // and then again to catch JS exceptions. We may also ask for
730+ // `ClosureImplementation` for a local function multiple times as we see
731+ // direct calls to the closure (in TFA direct-call metadata). Avoid
732+ // recompiling the closures in these cases by caching implementations.
733+ //
734+ // Note that every `FunctionNode` passed to this method will have one
735+ // `ParameterInfo` for them. For local functions, the `ParameterInfo` will
736+ // be the one generated by `ParameterInfo.fromLocalFunction`, for others it
737+ // will be the value returned by `paramInfoForDirectCall`. So the key for
738+ // this cache can be just `FunctionNode`, instead of `(FunctionNode,
739+ // ParameterInfo)`.
740+ final existingImplementation = closureImplementations[functionNode];
741+ if (existingImplementation != null ) {
742+ return existingImplementation;
743+ }
744+
726745 final targetModule = target.enclosingModule;
727746
728747 // Look up the closure representation for the signature.
@@ -850,8 +869,10 @@ class Translator with KernelNodes {
850869 ib.struct_new (representation.vtableStruct);
851870 ib.end ();
852871
853- return ClosureImplementation (
872+ final implementation = ClosureImplementation (
854873 representation, functions, dynamicCallEntry, vtable, targetModule);
874+ closureImplementations[functionNode] = implementation;
875+ return implementation;
855876 }
856877
857878 w.ValueType outputOrVoid (List <w.ValueType > outputs) {
0 commit comments