From 686faebf707c8e92db41b0d766ffcedd83d168d8 Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Tue, 10 Nov 2015 11:24:56 +0100 Subject: [PATCH] Canonicalize BackendImpact BUG= R=sigurdm@google.com Review URL: https://codereview.chromium.org/1431983003. --- .../lib/src/js_backend/backend_impact.dart | 766 ++++++++++++------ 1 file changed, 536 insertions(+), 230 deletions(-) diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart index 265566e24e2..3320c2f0d10 100644 --- a/pkg/compiler/lib/src/js_backend/backend_impact.dart +++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart @@ -45,291 +45,597 @@ class BackendImpacts { CoreClasses get coreClasses => compiler.coreClasses; - BackendImpact get getRuntimeTypeArgument => new BackendImpact( - staticUses: [ - helpers.getRuntimeTypeArgument, - helpers.getTypeArgumentByIndex, - helpers.copyTypeArguments]); + BackendImpact _getRuntimeTypeArgument; - BackendImpact get computeSignature => new BackendImpact( - staticUses: [ - helpers.setRuntimeTypeInfo, - helpers.getRuntimeTypeInfo, - helpers.computeSignature, - helpers.getRuntimeTypeArguments], - instantiatedClasses: [ - coreClasses.listClass]); - - BackendImpact get asyncBody => new BackendImpact( - staticUses: [ - helpers.asyncHelper, - helpers.syncCompleterConstructor, - helpers.streamIteratorConstructor, - helpers.wrapBody]); - - BackendImpact get syncStarBody => new BackendImpact( - staticUses: [ - helpers.syncStarIterableConstructor, - helpers.endOfIteration, - helpers.yieldStar, - helpers.syncStarUncaughtError], - instantiatedClasses: [ - helpers.syncStarIterable]); - - BackendImpact get asyncStarBody => new BackendImpact( - staticUses: [ - helpers.asyncStarHelper, - helpers.streamOfController, - helpers.yieldSingle, - helpers.yieldStar, - helpers.asyncStarControllerConstructor, - helpers.streamIteratorConstructor, - helpers.wrapBody], - instantiatedClasses: [ - helpers.asyncStarController]); - - BackendImpact get typeVariableBoundCheck => new BackendImpact( - staticUses: [ - helpers.throwTypeError, - helpers.assertIsSubtype]); - - BackendImpact get abstractClassInstantiation => new BackendImpact( - staticUses: [ - helpers.throwAbstractClassInstantiationError], - otherImpacts: [ - needsString('Needed to encode the message.')]); - - BackendImpact get fallThroughError => new BackendImpact( - staticUses: [ - helpers.fallThroughError]); - - BackendImpact get asCheck => new BackendImpact( - staticUses: [ - helpers.throwRuntimeError]); - - BackendImpact get throwNoSuchMethod => new BackendImpact( - staticUses: [ - helpers.throwNoSuchMethod], - otherImpacts: [ - // Also register the types of the arguments passed to this method. - needsList( - 'Needed to encode the arguments for throw NoSuchMethodError.'), - needsString( - 'Needed to encode the name for throw NoSuchMethodError.')]); - - BackendImpact get throwRuntimeError => new BackendImpact( - staticUses: [ - helpers.throwRuntimeError], - // Also register the types of the arguments passed to this method. - instantiatedClasses: [ - coreClasses.stringClass]); - - BackendImpact get superNoSuchMethod => new BackendImpact( - staticUses: [ - helpers.createInvocationMirror, - coreClasses.objectClass.lookupLocalMember(Identifiers.noSuchMethod_)], - otherImpacts: [ - needsInt( - 'Needed to encode the invocation kind of super.noSuchMethod.'), - needsList( - 'Needed to encode the arguments of super.noSuchMethod.'), - needsString( - 'Needed to encode the name of super.noSuchMethod.')]); - - BackendImpact get constantMapLiteral { - - ClassElement find(String name) { - return helpers.find(helpers.jsHelperLibrary, name); + BackendImpact get getRuntimeTypeArgument { + if (_getRuntimeTypeArgument == null) { + _getRuntimeTypeArgument = new BackendImpact( + staticUses: [ + helpers.getRuntimeTypeArgument, + helpers.getTypeArgumentByIndex, + helpers.copyTypeArguments]); } - - return new BackendImpact( - instantiatedClasses: [ - find(JavaScriptMapConstant.DART_CLASS), - find(JavaScriptMapConstant.DART_PROTO_CLASS), - find(JavaScriptMapConstant.DART_STRING_CLASS), - find(JavaScriptMapConstant.DART_GENERAL_CLASS)]); + return _getRuntimeTypeArgument; } - BackendImpact get symbolConstructor => new BackendImpact( - staticUses: [ - helpers.compiler.symbolValidatedConstructor]); + BackendImpact _computeSignature; - BackendImpact get constSymbol => new BackendImpact( - instantiatedClasses: [ - coreClasses.symbolClass], - staticUses: [ - compiler.symbolConstructor.declaration]); + BackendImpact get computeSignature { + if (_computeSignature == null) { + _computeSignature = new BackendImpact( + staticUses: [ + helpers.setRuntimeTypeInfo, + helpers.getRuntimeTypeInfo, + helpers.computeSignature, + helpers.getRuntimeTypeArguments], + instantiatedClasses: [ + coreClasses.listClass]); + } + return _computeSignature; + } - BackendImpact get incDecOperation => - needsInt('Needed for the `+ 1` or `- 1` operation of ++/--.'); + BackendImpact _asyncBody; + + BackendImpact get asyncBody { + if (_asyncBody == null) { + _asyncBody = new BackendImpact( + staticUses: [ + helpers.asyncHelper, + helpers.syncCompleterConstructor, + helpers.streamIteratorConstructor, + helpers.wrapBody]); + } + return _asyncBody; + } + + BackendImpact _syncStarBody; + + BackendImpact get syncStarBody { + if (_syncStarBody == null) { + _syncStarBody = new BackendImpact( + staticUses: [ + helpers.syncStarIterableConstructor, + helpers.endOfIteration, + helpers.yieldStar, + helpers.syncStarUncaughtError], + instantiatedClasses: [ + helpers.syncStarIterable]); + } + return _syncStarBody; + } + + BackendImpact _asyncStarBody; + + BackendImpact get asyncStarBody { + if (_asyncStarBody == null) { + _asyncStarBody = new BackendImpact( + staticUses: [ + helpers.asyncStarHelper, + helpers.streamOfController, + helpers.yieldSingle, + helpers.yieldStar, + helpers.asyncStarControllerConstructor, + helpers.streamIteratorConstructor, + helpers.wrapBody], + instantiatedClasses: [ + helpers.asyncStarController]); + } + return _asyncStarBody; + } + + BackendImpact _typeVariableBoundCheck; + + BackendImpact get typeVariableBoundCheck { + if (_typeVariableBoundCheck == null) { + _typeVariableBoundCheck = new BackendImpact( + staticUses: [ + helpers.throwTypeError, + helpers.assertIsSubtype]); + } + return _typeVariableBoundCheck; + } + + BackendImpact _abstractClassInstantiation; + + BackendImpact get abstractClassInstantiation { + if (_abstractClassInstantiation == null) { + _abstractClassInstantiation = new BackendImpact( + staticUses: [ + helpers.throwAbstractClassInstantiationError], + otherImpacts: [ + _needsString('Needed to encode the message.')]); + } + return _abstractClassInstantiation; + } + + BackendImpact _fallThroughError; + + BackendImpact get fallThroughError { + if (_fallThroughError == null) { + _fallThroughError = new BackendImpact( + staticUses: [ + helpers.fallThroughError]); + } + return _fallThroughError; + } + + BackendImpact _asCheck; + + BackendImpact get asCheck { + if (_asCheck == null) { + _asCheck = new BackendImpact( + staticUses: [ + helpers.throwRuntimeError]); + } + return _asCheck; + } + + BackendImpact _throwNoSuchMethod; + + BackendImpact get throwNoSuchMethod { + if (_throwNoSuchMethod == null) { + _throwNoSuchMethod = new BackendImpact( + staticUses: [ + helpers.throwNoSuchMethod], + otherImpacts: [ + // Also register the types of the arguments passed to this method. + _needsList( + 'Needed to encode the arguments for throw NoSuchMethodError.'), + _needsString( + 'Needed to encode the name for throw NoSuchMethodError.')]); + } + return _throwNoSuchMethod; + } + + BackendImpact _throwRuntimeError; + + BackendImpact get throwRuntimeError { + if (_throwRuntimeError == null) { + _throwRuntimeError = new BackendImpact( + staticUses: [ + helpers.throwRuntimeError], + // Also register the types of the arguments passed to this method. + instantiatedClasses: [ + coreClasses.stringClass]); + } + return _throwRuntimeError; + } + + BackendImpact _superNoSuchMethod; + + BackendImpact get superNoSuchMethod { + if (_superNoSuchMethod == null) { + _superNoSuchMethod = new BackendImpact( + staticUses: [ + helpers.createInvocationMirror, + coreClasses.objectClass.lookupLocalMember( + Identifiers.noSuchMethod_)], + otherImpacts: [ + _needsInt( + 'Needed to encode the invocation kind of super.noSuchMethod.'), + _needsList( + 'Needed to encode the arguments of super.noSuchMethod.'), + _needsString( + 'Needed to encode the name of super.noSuchMethod.')]); + } + return _superNoSuchMethod; + } + + BackendImpact _constantMapLiteral; + + BackendImpact get constantMapLiteral { + if (_constantMapLiteral == null) { + + ClassElement find(String name) { + return helpers.find(helpers.jsHelperLibrary, name); + } + + _constantMapLiteral = new BackendImpact( + instantiatedClasses: [ + find(JavaScriptMapConstant.DART_CLASS), + find(JavaScriptMapConstant.DART_PROTO_CLASS), + find(JavaScriptMapConstant.DART_STRING_CLASS), + find(JavaScriptMapConstant.DART_GENERAL_CLASS)]); + } + return _constantMapLiteral; + } + + BackendImpact _symbolConstructor; + + BackendImpact get symbolConstructor { + if (_symbolConstructor == null) { + _symbolConstructor = new BackendImpact( + staticUses: [ + helpers.compiler.symbolValidatedConstructor]); + } + return _symbolConstructor; + } + + BackendImpact _constSymbol; + + BackendImpact get constSymbol { + if (_constSymbol == null) { + _constSymbol = new BackendImpact( + instantiatedClasses: [ + coreClasses.symbolClass], + staticUses: [ + compiler.symbolConstructor.declaration]); + } + return _constSymbol; + } + + BackendImpact _incDecOperation; + + BackendImpact get incDecOperation { + if (_incDecOperation == null) { + _incDecOperation = + _needsInt('Needed for the `+ 1` or `- 1` operation of ++/--.'); + } + return _incDecOperation; + } /// Helper for registering that `int` is needed. - BackendImpact needsInt(String reason) { + BackendImpact _needsInt(String reason) { // TODO(johnniwinther): Register [reason] for use in dump-info. return new BackendImpact( instantiatedClasses: [coreClasses.intClass]); } /// Helper for registering that `List` is needed. - BackendImpact needsList(String reason) { + BackendImpact _needsList(String reason) { // TODO(johnniwinther): Register [reason] for use in dump-info. return new BackendImpact( instantiatedClasses: [coreClasses.listClass]); } /// Helper for registering that `String` is needed. - BackendImpact needsString(String reason) { + BackendImpact _needsString(String reason) { // TODO(johnniwinther): Register [reason] for use in dump-info. return new BackendImpact( instantiatedClasses: [ coreClasses.stringClass]); } - BackendImpact get assertWithoutMessage => new BackendImpact( - staticUses: [ - helpers.assertHelper]); + BackendImpact _assertWithoutMessage; - BackendImpact get assertWithMessage => new BackendImpact( - staticUses: [ - helpers.assertTest, - helpers.assertThrow]); + BackendImpact get assertWithoutMessage { + if (_assertWithoutMessage == null) { + _assertWithoutMessage = new BackendImpact( + staticUses: [ + helpers.assertHelper]); + } + return _assertWithoutMessage; + } - BackendImpact get asyncForIn => new BackendImpact( - staticUses: [ - helpers.streamIteratorConstructor]); + BackendImpact _assertWithMessage; - BackendImpact get stringInterpolation => new BackendImpact( - staticUses: [ - helpers.stringInterpolationHelper], - otherImpacts: [ - needsString('Strings are created.')]); + BackendImpact get assertWithMessage { + if (_assertWithMessage == null) { + _assertWithMessage = new BackendImpact( + staticUses: [ + helpers.assertTest, + helpers.assertThrow]); + } + return _assertWithMessage; + } + + BackendImpact _asyncForIn; + + BackendImpact get asyncForIn { + if (_asyncForIn == null) { + _asyncForIn = new BackendImpact( + staticUses: [ + helpers.streamIteratorConstructor]); + } + return _asyncForIn; + } + + BackendImpact _stringInterpolation; + + BackendImpact get stringInterpolation { + if (_stringInterpolation == null) { + _stringInterpolation = new BackendImpact( + staticUses: [ + helpers.stringInterpolationHelper], + otherImpacts: [ + _needsString('Strings are created.')]); + } + return _stringInterpolation; + } + + BackendImpact _stringJuxtaposition; BackendImpact get stringJuxtaposition { - return needsString('String.concat is used.'); + if (_stringJuxtaposition == null) { + _stringJuxtaposition = _needsString('String.concat is used.'); + } + return _stringJuxtaposition; } // TODO(johnniwinther): Point to to the JavaScript classes instead of the Dart // classes in these impacts. - BackendImpact get nullLiteral => new BackendImpact( - instantiatedClasses: [ - coreClasses.nullClass]); + BackendImpact _nullLiteral; - BackendImpact get boolLiteral => new BackendImpact( - instantiatedClasses: [ - coreClasses.boolClass]); + BackendImpact get nullLiteral { + if (_nullLiteral == null) { + _nullLiteral = new BackendImpact( + instantiatedClasses: [ + coreClasses.nullClass]); + } + return _nullLiteral; + } - BackendImpact get intLiteral => new BackendImpact( - instantiatedClasses: [ - coreClasses.intClass]); + BackendImpact _boolLiteral; - BackendImpact get doubleLiteral => new BackendImpact( - instantiatedClasses: [ - coreClasses.doubleClass]); + BackendImpact get boolLiteral { + if (_boolLiteral == null) { + _boolLiteral = new BackendImpact( + instantiatedClasses: [ + coreClasses.boolClass]); + } + return _boolLiteral; + } - BackendImpact get stringLiteral => new BackendImpact( - instantiatedClasses: [ - coreClasses.stringClass]); + BackendImpact _intLiteral; - BackendImpact get catchStatement => new BackendImpact( - staticUses: [ - helpers.exceptionUnwrapper], - instantiatedClasses: [ - helpers.jsPlainJavaScriptObjectClass, - helpers.jsUnknownJavaScriptObjectClass]); + BackendImpact get intLiteral { + if (_intLiteral == null) { + _intLiteral = new BackendImpact( + instantiatedClasses: [ + coreClasses.intClass]); + } + return _intLiteral; + } - BackendImpact get throwExpression => new BackendImpact( - // We don't know ahead of time whether we will need the throw in a - // statement context or an expression context, so we register both - // here, even though we may not need the throwExpression helper. - staticUses: [ - helpers.wrapExceptionHelper, - helpers.throwExpressionHelper]); + BackendImpact _doubleLiteral; - BackendImpact get lazyField => new BackendImpact( - staticUses: [ - helpers.cyclicThrowHelper]); + BackendImpact get doubleLiteral { + if (_doubleLiteral == null) { + _doubleLiteral = new BackendImpact( + instantiatedClasses: [ + coreClasses.doubleClass]); + } + return _doubleLiteral; + } - BackendImpact get typeLiteral => new BackendImpact( - instantiatedClasses: [ - backend.typeImplementation], - staticUses: [ - helpers.createRuntimeType]); + BackendImpact _stringLiteral; - BackendImpact get stackTraceInCatch => new BackendImpact( - instantiatedClasses: [ - coreClasses.stackTraceClass], - staticUses: [ - helpers.traceFromException]); + BackendImpact get stringLiteral { + if (_stringLiteral == null) { + _stringLiteral = new BackendImpact( + instantiatedClasses: [ + coreClasses.stringClass]); + } + return _stringLiteral; + } - BackendImpact get syncForIn => new BackendImpact( - // The SSA builder recognizes certain for-in loops and can generate calls - // to throwConcurrentModificationError. - staticUses: [ - helpers.checkConcurrentModificationError]); + BackendImpact _catchStatement; - BackendImpact get typeVariableExpression => new BackendImpact( - staticUses: [ - helpers.setRuntimeTypeInfo, - helpers.getRuntimeTypeInfo, - helpers.runtimeTypeToString, - helpers.createRuntimeType], - instantiatedClasses: [ - coreClasses.listClass], - otherImpacts: [ - getRuntimeTypeArgument, - needsInt('Needed for accessing a type variable literal on this.')]); + BackendImpact get catchStatement { + if (_catchStatement == null) { + _catchStatement = new BackendImpact( + staticUses: [ + helpers.exceptionUnwrapper], + instantiatedClasses: [ + helpers.jsPlainJavaScriptObjectClass, + helpers.jsUnknownJavaScriptObjectClass]); + } + return _catchStatement; + } - BackendImpact get typeCheck => new BackendImpact( - instantiatedClasses: [ - coreClasses.boolClass]); + BackendImpact _throwExpression; - BackendImpact get checkedModeTypeCheck => new BackendImpact( - staticUses: [ - helpers.throwRuntimeError]); + BackendImpact get throwExpression { + if (_throwExpression == null) { + _throwExpression = new BackendImpact( + // We don't know ahead of time whether we will need the throw in a + // statement context or an expression context, so we register both + // here, even though we may not need the throwExpression helper. + staticUses: [ + helpers.wrapExceptionHelper, + helpers.throwExpressionHelper]); + } + return _throwExpression; + } - BackendImpact get malformedTypeCheck => new BackendImpact( - staticUses: [ - helpers.throwTypeError]); + BackendImpact _lazyField; - BackendImpact get genericTypeCheck => new BackendImpact( - staticUses: [ - helpers.checkSubtype, - // TODO(johnniwinther): Investigate why this is needed. - helpers.setRuntimeTypeInfo, - helpers.getRuntimeTypeInfo], - instantiatedClasses: [ - coreClasses.listClass], - otherImpacts: [ - getRuntimeTypeArgument]); + BackendImpact get lazyField { + if (_lazyField == null) { + _lazyField = new BackendImpact( + staticUses: [ + helpers.cyclicThrowHelper]); + } + return _lazyField; + } - BackendImpact get genericIsCheck => new BackendImpact( - instantiatedClasses: [ - coreClasses.listClass]); + BackendImpact _typeLiteral; - BackendImpact get genericCheckedModeTypeCheck => new BackendImpact( - staticUses: [ - helpers.assertSubtype]); + BackendImpact get typeLiteral { + if (_typeLiteral == null) { + _typeLiteral = new BackendImpact( + instantiatedClasses: [ + backend.typeImplementation], + staticUses: [ + helpers.createRuntimeType]); + } + return _typeLiteral; + } - BackendImpact get typeVariableTypeCheck => new BackendImpact( - staticUses: [ - helpers.checkSubtypeOfRuntimeType]); + BackendImpact _stackTraceInCatch; - BackendImpact get typeVariableCheckedModeTypeCheck => new BackendImpact( - staticUses: [ - helpers.assertSubtypeOfRuntimeType]); + BackendImpact get stackTraceInCatch { + if (_stackTraceInCatch == null) { + _stackTraceInCatch = new BackendImpact( + instantiatedClasses: [ + coreClasses.stackTraceClass], + staticUses: [ + helpers.traceFromException]); + } + return _stackTraceInCatch; + } - BackendImpact get functionTypeCheck => new BackendImpact( - staticUses: [ - helpers.functionTypeTestMetaHelper]); + BackendImpact _syncForIn; - BackendImpact get nativeTypeCheck => new BackendImpact( - staticUses: [ - // We will neeed to add the "$is" and "$as" properties on the - // JavaScript object prototype, so we make sure - // [:defineProperty:] is compiled. - helpers.defineProperty]); + BackendImpact get syncForIn { + if (_syncForIn == null) { + _syncForIn = new BackendImpact( + // The SSA builder recognizes certain for-in loops and can generate + // calls to throwConcurrentModificationError. + staticUses: [ + helpers.checkConcurrentModificationError]); + } + return _syncForIn; + } - BackendImpact get closure => new BackendImpact( - instantiatedClasses: [ - coreClasses.functionClass]); + BackendImpact _typeVariableExpression; + + BackendImpact get typeVariableExpression { + if (_typeVariableExpression == null) { + _typeVariableExpression = new BackendImpact( + staticUses: [ + helpers.setRuntimeTypeInfo, + helpers.getRuntimeTypeInfo, + helpers.runtimeTypeToString, + helpers.createRuntimeType], + instantiatedClasses: [ + coreClasses.listClass], + otherImpacts: [ + getRuntimeTypeArgument, + _needsInt('Needed for accessing a type variable literal on this.') + ]); + } + return _typeVariableExpression; + } + + BackendImpact _typeCheck; + + BackendImpact get typeCheck { + if (_typeCheck == null) { + _typeCheck = new BackendImpact( + instantiatedClasses: [ + coreClasses.boolClass]); + } + return _typeCheck; + } + + BackendImpact _checkedModeTypeCheck; + + BackendImpact get checkedModeTypeCheck { + if (_checkedModeTypeCheck == null) { + _checkedModeTypeCheck = new BackendImpact( + staticUses: [ + helpers.throwRuntimeError]); + } + return _checkedModeTypeCheck; + } + + BackendImpact _malformedTypeCheck; + + BackendImpact get malformedTypeCheck { + if (_malformedTypeCheck == null) { + _malformedTypeCheck = new BackendImpact( + staticUses: [ + helpers.throwTypeError]); + } + return _malformedTypeCheck; + } + + BackendImpact _genericTypeCheck; + + BackendImpact get genericTypeCheck { + if (_genericTypeCheck == null) { + _genericTypeCheck = new BackendImpact( + staticUses: [ + helpers.checkSubtype, + // TODO(johnniwinther): Investigate why this is needed. + helpers.setRuntimeTypeInfo, + helpers.getRuntimeTypeInfo], + instantiatedClasses: [ + coreClasses.listClass], + otherImpacts: [ + getRuntimeTypeArgument]); + } + return _genericTypeCheck; + } + + BackendImpact _genericIsCheck; + + BackendImpact get genericIsCheck { + if (_genericIsCheck == null) { + _genericIsCheck = new BackendImpact( + instantiatedClasses: [ + coreClasses.listClass]); + } + return _genericIsCheck; + } + + BackendImpact _genericCheckedModeTypeCheck; + + BackendImpact get genericCheckedModeTypeCheck { + if (_genericCheckedModeTypeCheck == null) { + _genericCheckedModeTypeCheck = new BackendImpact( + staticUses: [ + helpers.assertSubtype]); + } + return _genericCheckedModeTypeCheck; + } + + BackendImpact _typeVariableTypeCheck; + + BackendImpact get typeVariableTypeCheck { + if (_typeVariableTypeCheck == null) { + _typeVariableTypeCheck = new BackendImpact( + staticUses: [ + helpers.checkSubtypeOfRuntimeType]); + } + return _typeVariableTypeCheck; + } + + BackendImpact _typeVariableCheckedModeTypeCheck; + + BackendImpact get typeVariableCheckedModeTypeCheck { + if (_typeVariableCheckedModeTypeCheck == null) { + _typeVariableCheckedModeTypeCheck = new BackendImpact( + staticUses: [ + helpers.assertSubtypeOfRuntimeType]); + } + return _typeVariableCheckedModeTypeCheck; + } + + BackendImpact _functionTypeCheck; + + BackendImpact get functionTypeCheck { + if (_functionTypeCheck == null) { + _functionTypeCheck = new BackendImpact( + staticUses: [ + helpers.functionTypeTestMetaHelper]); + } + return _functionTypeCheck; + } + + BackendImpact _nativeTypeCheck; + + BackendImpact get nativeTypeCheck { + if (_nativeTypeCheck == null) { + _nativeTypeCheck = new BackendImpact( + staticUses: [ + // We will neeed to add the "$is" and "$as" properties on the + // JavaScript object prototype, so we make sure + // [:defineProperty:] is compiled. + helpers.defineProperty]); + } + return _nativeTypeCheck; + } + + BackendImpact _closure; + + BackendImpact get closure { + if (_closure == null) { + _closure = new BackendImpact( + instantiatedClasses: [ + coreClasses.functionClass]); + } + return _closure; + } } \ No newline at end of file