Skip to content

Commit

Permalink
Use less static types, just check names and library URIs of declarati…
Browse files Browse the repository at this point in the history
…ons.

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: <scheduler>, 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: <scheduler>, 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 <[email protected]>
Auto-Submit: Jake Macdonald <[email protected]>
Reviewed-by: Konstantin Shcheglov <[email protected]>
  • Loading branch information
jakemac53 authored and Commit Queue committed Apr 9, 2024
1 parent c2f3418 commit ddca3d2
Showing 1 changed file with 84 additions and 126 deletions.
210 changes: 84 additions & 126 deletions tests/language/macros/json/json_serializable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<String, Object?> 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<String, Object?> json)` constructor.',
target: superclass.asDiagnosticTarget),
Severity.error));
}
}

var fields = await builder.fieldsOf(clazz);
var jsonParam = constructor.positionalParameters.single.identifier;
var initializers = <Code>[];
for (var field in fields) {
var config = await field.readConfig(builder);

Future<Code> _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) ...[
Expand All @@ -139,8 +142,9 @@ macro class FromJson implements ConstructorDefinitionMacro {
' : ',
defaultValue,
],
]));
]);
}
var initializers = await Future.wait(fields.map(_initializerForField));

if (superclassHasFromJson) {
initializers.add(RawCode.fromParts([
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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,
);
}
}
Expand All @@ -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<String, Object?> 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<String, Object?> toJson()` method.',
target: superclass.asDiagnosticTarget),
Severity.error));
return;
}
}
}

Expand All @@ -466,8 +440,12 @@ macro class ToJson implements MethodDefinitionMacro {
],
';\n '
];
for (var field in fields) {
var config = await field.readConfig(builder);

Future<Code> _addEntryForField(FieldDeclaration field) async {
var parts = <Object>[];
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`.
Expand All @@ -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));
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
);
}
Expand Down Expand Up @@ -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;
}

0 comments on commit ddca3d2

Please sign in to comment.