From ddca3d2386880cf90f987589ce1388fc64064fc9 Mon Sep 17 00:00:00 2001 From: Jake Macdonald Date: Tue, 9 Apr 2024 19:56:01 +0000 Subject: [PATCH] Use less static types, just check names and library URIs of declarations. Also adds some additional "parallelizatoin" of async tasks. Overall speedup of >50%, definitions phase in particular is about 75% faster. Before: [time: 16043 ms] (name: , count: 0, elapsed: 0:00:00.000000, elapsedSelf: -0:00:15.823859) (name: analyzeFile, count: 104, elapsed: 0:00:15.823859, elapsedSelf: 0:00:01.428470) (name: libraryContext, count: 104, elapsed: 0:00:14.395389, elapsedSelf: 0:00:00.272344)(bytesPut: 5386317, cycleCount: 9, libraryCount: 115) (name: link, count: 9, elapsed: 0:00:11.027694, elapsedSelf: 0:00:00.529548) (name: computeLibraryScopes, count: 9, elapsed: 0:00:00.305524, elapsedSelf: 0:00:00.126633) (name: buildMacroApplier, count: 9, elapsed: 0:00:00.178642, elapsedSelf: 0:00:00.178642) (name: executeMacroTypesPhase, count: 9, elapsed: 0:00:00.000249, elapsedSelf: 0:00:00.000249) (name: executeMacroDeclarationsPhase, count: 9, elapsed: 0:00:00.367608, elapsedSelf: 0:00:00.367608)(constructorsOf: 100, methodsOf: 100) (name: executeMacroDefinitionsPhase, count: 9, elapsed: 0:00:09.226594, elapsedSelf: 0:00:00.002483) (name: executeDefinitionsPhase, count: 315, elapsed: 0:00:08.188795, elapsedSelf: 0:00:08.188795)(constructorsOf: 300, methodsOf: 300, resolve: 42000, typeDeclarationOf: 1200) (name: addMacroResults, count: 200, elapsed: 0:00:01.035316, elapsedSelf: 0:00:01.035316) (name: mergeMacroAugmentations, count: 9, elapsed: 0:00:00.598420, elapsedSelf: 0:00:00.598420) (name: macroCompileKernel, count: 1, elapsed: 0:00:03.095351, elapsedSelf: 0:00:03.095351) After: [time: 7774 ms] (name: , count: 0, elapsed: 0:00:00.000000, elapsedSelf: -0:00:07.582758) (name: analyzeFile, count: 104, elapsed: 0:00:07.582758, elapsedSelf: 0:00:01.049135) (name: libraryContext, count: 104, elapsed: 0:00:06.533623, elapsedSelf: 0:00:00.232088)(bytesPut: 5385998, cycleCount: 9, libraryCount: 115) (name: link, count: 9, elapsed: 0:00:03.198967, elapsedSelf: 0:00:00.309712) (name: computeLibraryScopes, count: 9, elapsed: 0:00:00.184852, elapsedSelf: 0:00:00.079394) (name: buildMacroApplier, count: 9, elapsed: 0:00:00.105297, elapsedSelf: 0:00:00.105297) (name: executeMacroTypesPhase, count: 9, elapsed: 0:00:00.000161, elapsedSelf: 0:00:00.000161) (name: executeMacroDeclarationsPhase, count: 9, elapsed: 0:00:00.301573, elapsedSelf: 0:00:00.301573)(constructorsOf: 100, methodsOf: 100) (name: executeMacroDefinitionsPhase, count: 9, elapsed: 0:00:01.823845, elapsedSelf: 0:00:00.001162) (name: executeDefinitionsPhase, count: 315, elapsed: 0:00:01.101564, elapsedSelf: 0:00:01.101564)(constructorsOf: 300, methodsOf: 300, resolve: 400, typeDeclarationOf: 41200) (name: addMacroResults, count: 200, elapsed: 0:00:00.721119, elapsedSelf: 0:00:00.721119) (name: mergeMacroAugmentations, count: 9, elapsed: 0:00:00.578985, elapsedSelf: 0:00:00.578985) (name: macroCompileKernel, count: 1, elapsed: 0:00:03.102568, elapsedSelf: 0:00:03.102568) Change-Id: I88f390ec01469e96ca8a43a49897e3e5b173b731 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/362041 Commit-Queue: Jake Macdonald Auto-Submit: Jake Macdonald Reviewed-by: Konstantin Shcheglov --- .../macros/json/json_serializable.dart | 210 +++++++----------- 1 file changed, 84 insertions(+), 126 deletions(-) diff --git a/tests/language/macros/json/json_serializable.dart b/tests/language/macros/json/json_serializable.dart index c89c78663129..550437cafe1e 100644 --- a/tests/language/macros/json/json_serializable.dart +++ b/tests/language/macros/json/json_serializable.dart @@ -38,13 +38,15 @@ macro class JsonSerializable implements ClassDeclarationsMacro { Severity.error)); } - var map = await builder.resolveIdentifier(_dartCore, 'Map'); - var string = NamedTypeAnnotationCode( - name: await builder.resolveIdentifier(_dartCore, 'String')); - var object = NamedTypeAnnotationCode( - name: await builder.resolveIdentifier(_dartCore, 'Object')); - var mapStringObject = NamedTypeAnnotationCode( - name: map, typeArguments: [string, object.asNullable]); + var [map, string, object] = await Future.wait([ + builder.resolveIdentifier(_dartCore, 'Map'), + builder.resolveIdentifier(_dartCore, 'String'), + builder.resolveIdentifier(_dartCore, 'Object'), + ]); + var mapStringObject = NamedTypeAnnotationCode(name: map, typeArguments: [ + NamedTypeAnnotationCode(name: string), + NamedTypeAnnotationCode(name: object).asNullable + ]); var jsonSerializableUri = clazz.jsonSerializableUri; @@ -84,39 +86,40 @@ macro class FromJson implements ConstructorDefinitionMacro { as ClassDeclaration; var superclass = clazz.superclass; var superclassHasFromJson = false; - if (superclass != null && - !await (await builder - .resolve(NamedTypeAnnotationCode(name: superclass.identifier))) - .isExactly(fromJsonData.objectType)) { + if (superclass != null) { var superclassDeclaration = await builder.typeDeclarationOf(superclass.identifier); - var superclassConstructors = - await builder.constructorsOf(superclassDeclaration); - for (var superConstructor in superclassConstructors) { - if (superConstructor.identifier.name == 'fromJson') { - await _checkValidFromJson(superConstructor, fromJsonData, builder); - superclassHasFromJson = true; - break; + if (!superclassDeclaration.isExactly('Object', _dartCore)) { + var superclassConstructors = + await builder.constructorsOf(superclassDeclaration); + for (var superConstructor in superclassConstructors) { + if (superConstructor.identifier.name == 'fromJson') { + await _checkValidFromJson(superConstructor, fromJsonData, builder); + superclassHasFromJson = true; + break; + } + } + if (!superclassHasFromJson) { + throw new DiagnosticException(Diagnostic( + DiagnosticMessage( + 'Serialization of classes that extend other classes is only ' + 'supported if those classes have a valid ' + '`fromJson(Map json)` constructor.', + target: superclass.asDiagnosticTarget), + Severity.error)); } - } - if (!superclassHasFromJson) { - throw new DiagnosticException(Diagnostic( - DiagnosticMessage( - 'Serialization of classes that extend other classes is only ' - 'supported if those classes have a valid ' - '`fromJson(Map json)` constructor.', - target: superclass.asDiagnosticTarget), - Severity.error)); } } var fields = await builder.fieldsOf(clazz); var jsonParam = constructor.positionalParameters.single.identifier; - var initializers = []; - for (var field in fields) { - var config = await field.readConfig(builder); + + Future _initializerForField(FieldDeclaration field) async { + var config = field.metadata.isEmpty + ? _FieldConfig(field, null) + : await field.readConfig(builder); var defaultValue = config.defaultValue; - initializers.add(RawCode.fromParts([ + return RawCode.fromParts([ field.identifier, ' = ', if (defaultValue != null) ...[ @@ -139,8 +142,9 @@ macro class FromJson implements ConstructorDefinitionMacro { ' : ', defaultValue, ], - ])); + ]); } + var initializers = await Future.wait(fields.map(_initializerForField)); if (superclassHasFromJson) { initializers.add(RawCode.fromParts([ @@ -205,13 +209,7 @@ macro class FromJson implements ConstructorDefinitionMacro { "throw 'Unable to deserialize type ${type.code.debugString}'"); } - // The static type of the expected type, without any type arguments. - var typeDeclType = await builder.resolve( - NamedTypeAnnotationCode(name: typeDecl.identifier, typeArguments: [ - for (var typeParam in typeDecl.typeParameters) - typeParam.bound?.code ?? fromJsonData.objectCode.asNullable, - ])); - if (await typeDeclType.isExactly(fromJsonData.listType)) { + if (typeDecl.isExactly('List', _dartCore)) { return RawCode.fromParts([ '[ for (var item in ', jsonReference, @@ -222,7 +220,7 @@ macro class FromJson implements ConstructorDefinitionMacro { RawCode.fromString('item'), builder, fromJsonData), ']', ]); - } else if (await typeDeclType.isExactly(fromJsonData.setType)) { + } else if (typeDecl.isExactly('Set', _dartCore)) { return RawCode.fromParts([ '{ for (var item in ', jsonReference, @@ -233,7 +231,7 @@ macro class FromJson implements ConstructorDefinitionMacro { RawCode.fromString('item'), builder, fromJsonData), '}', ]); - } else if (await typeDeclType.isExactly(fromJsonData.mapType)) { + } else if (typeDecl.isExactly('Map', _dartCore)) { return RawCode.fromParts([ '{ for (var entry in ', jsonReference, @@ -348,30 +346,21 @@ final class _FromJsonData { final NamedTypeAnnotationCode jsonListCode; final NamedTypeAnnotationCode jsonMapCode; final StaticType jsonMapType; - final StaticType listType; - final StaticType mapType; final NamedTypeAnnotationCode objectCode; - final StaticType objectType; - final StaticType setType; _FromJsonData({ required this.jsonListCode, required this.jsonMapCode, required this.jsonMapType, - required this.listType, - required this.mapType, required this.objectCode, - required this.objectType, - required this.setType, }); static Future<_FromJsonData> build( ConstructorDefinitionBuilder builder) async { - var [list, map, object, set, string] = await Future.wait([ + var [list, map, object, string] = await Future.wait([ builder.resolveIdentifier(_dartCore, 'List'), builder.resolveIdentifier(_dartCore, 'Map'), builder.resolveIdentifier(_dartCore, 'Object'), - builder.resolveIdentifier(_dartCore, 'Set'), builder.resolveIdentifier(_dartCore, 'String'), ]); var objectCode = NamedTypeAnnotationCode(name: object); @@ -383,27 +372,13 @@ final class _FromJsonData { NamedTypeAnnotationCode(name: string), nullableObjectCode, ]); - var [jsonMapType, listType, mapType, objectType, setType] = - await Future.wait([ - builder.resolve(jsonMapCode), - builder.resolve(NamedTypeAnnotationCode( - name: list, typeArguments: [nullableObjectCode])), - builder.resolve(NamedTypeAnnotationCode( - name: map, typeArguments: [nullableObjectCode, nullableObjectCode])), - builder.resolve(objectCode), - builder.resolve(NamedTypeAnnotationCode( - name: set, typeArguments: [nullableObjectCode])), - ]); + var jsonMapType = await builder.resolve(jsonMapCode); return _FromJsonData( jsonListCode: jsonListCode, jsonMapCode: jsonMapCode, jsonMapType: jsonMapType, - listType: listType, - mapType: mapType, objectCode: objectCode, - objectType: objectType, - setType: setType, ); } } @@ -424,31 +399,30 @@ macro class ToJson implements MethodDefinitionMacro { as ClassDeclaration; var superclass = clazz.superclass; var superclassHasToJson = false; - if (superclass != null && - !await (await builder - .resolve(NamedTypeAnnotationCode(name: superclass.identifier))) - .isExactly(toJsonData.objectType)) { + if (superclass != null) { var superclassDeclaration = await builder.typeDeclarationOf(superclass.identifier); - var superclassMethods = await builder.methodsOf(superclassDeclaration); - for (var superMethod in superclassMethods) { - if (superMethod.identifier.name == 'toJson') { - if (!(await _checkValidToJson(superMethod, toJsonData, builder))) { - return; + if (!superclassDeclaration.isExactly('Object', _dartCore)) { + var superclassMethods = await builder.methodsOf(superclassDeclaration); + for (var superMethod in superclassMethods) { + if (superMethod.identifier.name == 'toJson') { + if (!(await _checkValidToJson(superMethod, toJsonData, builder))) { + return; + } + superclassHasToJson = true; + break; } - superclassHasToJson = true; - break; } - } - if (!superclassHasToJson) { - builder.report(Diagnostic( - DiagnosticMessage( - 'Serialization of classes that extend other classes is only ' - 'supported if those classes have a valid ' - '`Map toJson()` method.', - target: superclass.asDiagnosticTarget), - Severity.error)); - return; + if (!superclassHasToJson) { + builder.report(Diagnostic( + DiagnosticMessage( + 'Serialization of classes that extend other classes is only ' + 'supported if those classes have a valid ' + '`Map toJson()` method.', + target: superclass.asDiagnosticTarget), + Severity.error)); + return; + } } } @@ -466,8 +440,12 @@ macro class ToJson implements MethodDefinitionMacro { ], ';\n ' ]; - for (var field in fields) { - var config = await field.readConfig(builder); + + Future _addEntryForField(FieldDeclaration field) async { + var parts = []; + var config = field.metadata.isEmpty + ? _FieldConfig(field, null) + : await field.readConfig(builder); var doNullCheck = !config.includeIfNull && field.type.isNullable; if (doNullCheck) { // TODO: Compare == `null` instead, once we can resolve `null`. @@ -490,7 +468,10 @@ macro class ToJson implements MethodDefinitionMacro { if (doNullCheck) { parts.add(' }\n'); } + return RawCode.fromParts(parts); } + parts.addAll(await Future.wait(fields.map(_addEntryForField))); + parts.add(' return json;\n }'); builder.augment(FunctionBodyCode.fromParts(parts)); @@ -547,14 +528,9 @@ macro class ToJson implements MethodDefinitionMacro { "throw 'Unable to serialize type ${type.code.debugString}'"); } - var typeDeclType = await builder.resolve( - NamedTypeAnnotationCode(name: typeDecl.identifier, typeArguments: [ - for (var typeParam in typeDecl.typeParameters) - typeParam.bound?.code ?? toJsonData.objectCode.asNullable, - ])); // If it is a List/Set type, serialize it as a JSON list. - if (await typeDeclType.isExactly(toJsonData.listType) || - await typeDeclType.isExactly(toJsonData.setType)) { + if (typeDecl.isExactly('List', _dartCore) || + typeDecl.isExactly('Set', _dartCore)) { return RawCode.fromParts([ '[ for (var item in ', valueReference, @@ -564,7 +540,7 @@ macro class ToJson implements MethodDefinitionMacro { ']', ]); // If it is a Map type, serialize it as a JSON map. - } else if (await typeDeclType.isExactly(toJsonData.mapType)) { + } else if (typeDecl.isExactly('Map', _dartCore)) { return RawCode.fromParts([ '{ for (var entry in ', valueReference, @@ -595,60 +571,37 @@ macro class ToJson implements MethodDefinitionMacro { final class _ToJsonData { final StaticType jsonMapType; - final StaticType listType; - final StaticType mapType; final Identifier nullIdentifier; final NamedTypeAnnotationCode objectCode; - final StaticType objectType; - final StaticType setType; final NamedTypeAnnotationCode stringCode; _ToJsonData({ required this.jsonMapType, - required this.listType, - required this.mapType, required this.nullIdentifier, required this.objectCode, - required this.objectType, - required this.setType, required this.stringCode, }); static Future<_ToJsonData> build(FunctionDefinitionBuilder builder) async { - var [list, map, nullIdentifier, object, set, string] = await Future.wait([ - builder.resolveIdentifier(_dartCore, 'List'), + var [map, nullIdentifier, object, string] = await Future.wait([ builder.resolveIdentifier(_dartCore, 'Map'), builder.resolveIdentifier(_dartCore, 'Null'), builder.resolveIdentifier(_dartCore, 'Object'), - builder.resolveIdentifier(_dartCore, 'Set'), builder.resolveIdentifier(_dartCore, 'String'), ]); var objectCode = NamedTypeAnnotationCode(name: object); var stringCode = NamedTypeAnnotationCode(name: string); var nullableObjectCode = objectCode.asNullable; - var [jsonMapType, listType, mapType, objectType, setType] = - await Future.wait([ - builder.resolve(NamedTypeAnnotationCode(name: map, typeArguments: [ - stringCode, - nullableObjectCode, - ])), - builder.resolve(NamedTypeAnnotationCode( - name: list, typeArguments: [nullableObjectCode])), - builder.resolve(NamedTypeAnnotationCode( - name: map, typeArguments: [nullableObjectCode, nullableObjectCode])), - builder.resolve(objectCode), - builder.resolve(NamedTypeAnnotationCode( - name: set, typeArguments: [nullableObjectCode])), - ]); + var jsonMapType = await builder + .resolve(NamedTypeAnnotationCode(name: map, typeArguments: [ + stringCode, + nullableObjectCode, + ])); return _ToJsonData( jsonMapType: jsonMapType, - listType: listType, - mapType: mapType, nullIdentifier: nullIdentifier, objectCode: objectCode, - objectType: objectType, - setType: setType, stringCode: stringCode, ); } @@ -693,3 +646,8 @@ extension _RelativeUris on Declaration { Uri get jsonSerializableUri => library.uri.resolve('json_serializable.dart'); } + +extension _IsExactly on TypeDeclaration { + bool isExactly(String name, Uri library) => + identifier.name == name && this.library.uri == library; +}