Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmarks/dart/lib/src/workloads.dart
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ buildBenchmarkDefinitions() {
}

Fory newBenchmarkFory() {
final fory = Fory(config: const Config(compatible: true));
final fory = Fory(compatible: true);
registerBenchmarkTypes(fory);
return fory;
}
90 changes: 71 additions & 19 deletions dart/packages/fory/lib/src/codegen/fory_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,14 @@ final class ForyGenerator extends Generator {
output.writeln(
' value.${field.name} = ${_directGeneratedTypedContainerReadExpression(structSpec.name, field, 'fields[$index]')};',
);
} else if (_usesDirectGeneratedStructFieldFastPath(field)) {
output.writeln(
' value.${field.name} = $readerFunctionName(readGeneratedStructDirectValue(context, fields[$index]), value.${field.name});',
);
} else if (_usesDirectGeneratedDeclaredReadFastPath(field)) {
output.writeln(
' value.${field.name} = $readerFunctionName(readGeneratedStructDeclaredValue(context, fields[$index]), value.${field.name});',
);
} else {
output.writeln(
' value.${field.name} = $readerFunctionName(readGeneratedStructFieldInfoValue(context, fields[$index], value.${field.name}), value.${field.name});',
Expand Down Expand Up @@ -531,12 +539,6 @@ final class ForyGenerator extends Generator {
output.writeln(' return value;');
case _ConstructorMode.constructor:
output.writeln(' final slots = generatedStructReadSlots(context);');
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
output.writeln(
' late final ${field.displayType} ${field.localName};',
);
}
output.writeln(' if (slots == null) {');
if (hasDirectPrimitiveFastPath || directCursorRuns.isNotEmpty) {
output.writeln(' final buffer = context.buffer;');
Expand All @@ -555,48 +557,73 @@ final class ForyGenerator extends Generator {
}
if (_usesReservedGeneratedFastPath(field)) {
output.writeln(
' ${field.localName} = ${_directGeneratedCursorReadExpression(field, 'cursor${directCursorStartByIndex[index]}')};',
' final ${field.displayType} ${field.localName} = ${_directGeneratedCursorReadExpression(field, 'cursor${directCursorStartByIndex[index]}')};',
);
} else if (_usesDirectGeneratedBasicFastPath(field)) {
output.writeln(
' ${field.localName} = ${_directGeneratedReadExpression(field)};',
' final ${field.displayType} ${field.localName} = ${_directGeneratedReadExpression(field)};',
);
} else if (_usesDirectGeneratedTypedContainerReadFastPath(field)) {
output.writeln(
' ${field.localName} = ${_directGeneratedTypedContainerReadExpression(structSpec.name, field, 'fields[$index]')};',
' final ${field.displayType} ${field.localName} = ${_directGeneratedTypedContainerReadExpression(structSpec.name, field, 'fields[$index]')};',
);
} else if (_usesDirectGeneratedStructFieldFastPath(field)) {
output.writeln(
' final ${field.displayType} ${field.localName} = $readerFunctionName(readGeneratedStructDirectValue(context, fields[$index]));',
);
} else if (_usesDirectGeneratedDeclaredReadFastPath(field)) {
output.writeln(
' final ${field.displayType} ${field.localName} = $readerFunctionName(readGeneratedStructDeclaredValue(context, fields[$index]));',
);
} else {
output.writeln(
' ${field.localName} = $readerFunctionName(readGeneratedStructFieldInfoValue(context, fields[$index]));',
' final ${field.displayType} ${field.localName} = $readerFunctionName(readGeneratedStructFieldInfoValue(context, fields[$index]));',
);
}
final directCursorEndRun = directCursorRunByEnd[index];
if (directCursorEndRun != null) {
output.writeln(' cursor${directCursorEndRun.start}.finish();');
}
}
output.writeln(' } else {');
final constructorInvocation = _constructorInvocation(structSpec);
output
..writeln(' final value = $constructorInvocation;')
..writeln(' context.reference(value);');
for (final fieldName
in structSpec.constructorPlan.postConstructionFieldNames) {
final field =
structSpec.fields.firstWhere((item) => item.name == fieldName);
output.writeln(' value.${field.name} = ${field.localName};');
}
output.writeln(' return value;');
// Slow path: schema-evolution slots present. Use `late final` so each
// field can be conditionally assigned from its slot or read fresh.
output.writeln(' }');
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
output.writeln(
' late final ${field.displayType} ${field.localName};',
);
}
for (var index = 0; index < structSpec.fields.length; index += 1) {
final field = structSpec.fields[index];
final readerFunctionName = field.readerFunctionName(structSpec.name);
final rawValueName = 'raw${structSpec.name}$index';
output.writeln(
' if (slots.containsSlot($index)) {',
' if (slots.containsSlot($index)) {',
);
output.writeln(
' final $rawValueName = slots.valueForSlot($index);',
' final $rawValueName = slots.valueForSlot($index);',
);
output.writeln(
' ${field.localName} = $readerFunctionName(${_slotResolvedRawExpression(rawValueName)});',
' ${field.localName} = $readerFunctionName(${_slotResolvedRawExpression(rawValueName)});',
);
output.writeln(' } else {');
output.writeln(' } else {');
output.writeln(
' ${field.localName} = $readerFunctionName(null);',
' ${field.localName} = $readerFunctionName(null);',
);
output.writeln(' }');
output.writeln(' }');
}
output.writeln(' }');
final constructorInvocation = _constructorInvocation(structSpec);
output
..writeln(' final value = $constructorInvocation;')
..writeln(' context.reference(value);');
Expand Down Expand Up @@ -939,6 +966,31 @@ GeneratedFieldType(
field.fieldType.typeId == TypeIds.enumById;
}

bool _usesDirectGeneratedDeclaredReadFastPath(
_GeneratedFieldSpec field,
) {
if (field.fieldType.nullable ||
field.fieldType.ref ||
field.fieldType.dynamic == true) {
return false;
}
final typeId = field.fieldType.typeId;
return typeId == TypeIds.ext || typeId == TypeIds.namedExt;
}

bool _usesDirectGeneratedStructFieldFastPath(_GeneratedFieldSpec field) {
if (field.fieldType.nullable ||
field.fieldType.ref ||
field.fieldType.dynamic == true) {
return false;
}
final typeId = field.fieldType.typeId;
return typeId == TypeIds.struct ||
typeId == TypeIds.compatibleStruct ||
typeId == TypeIds.namedStruct ||
typeId == TypeIds.namedCompatibleStruct;
}

bool _usesDirectGeneratedTypedContainerReadFastPath(
_GeneratedFieldSpec field,
) {
Expand Down
42 changes: 36 additions & 6 deletions dart/packages/fory/lib/src/codegen/generated_support.dart
Original file line number Diff line number Diff line change
Expand Up @@ -559,16 +559,12 @@ void registerGeneratedStruct<T>(

@internal
StructWriteSlots? generatedStructWriteSlots(WriteContext context) {
return context.getContextObject<StructWriteSlots>(
structWriteSlotsKey,
);
return context.structWriteSlots;
}

@internal
StructReadSlots? generatedStructReadSlots(ReadContext context) {
return context.getContextObject<StructReadSlots>(
structReadSlotsKey,
);
return context.structReadSlots;
}

@internal
Expand Down Expand Up @@ -687,6 +683,40 @@ Object? readGeneratedStructFieldInfoValue(
return readFieldValue(context, field, fallback);
}

@internal
Object? readGeneratedStructDeclaredValue(
ReadContext context,
GeneratedStructFieldInfo field,
) {
final resolved = fieldDeclaredTypeInfo(context.typeResolver, field)!;
if (fieldUsesDeclaredType(context.typeResolver, field)) {
return context.readResolvedValue(resolved, field.fieldType);
}
final actualResolved = context.readTypeMetaValue(
resolved.isNamed ? resolved : null,
);
return context.readResolvedValue(actualResolved, field.fieldType);
}

@internal
Object readGeneratedStructDirectValue(
ReadContext context,
GeneratedStructFieldInfo field,
) {
final declared = fieldDeclaredTypeInfo(context.typeResolver, field)!;
final resolver.TypeInfo resolved;
if (fieldUsesDeclaredType(context.typeResolver, field)) {
resolved = declared;
} else {
resolved =
context.readTypeMetaValue(declared.isNamed ? declared : null);
}
context.increaseDepth();
final value = resolved.structSerializer!.readValue(context, resolved);
context.decreaseDepth();
return value;
}

@internal
List<T> readGeneratedDirectListValue<T>(
ReadContext context,
Expand Down
33 changes: 6 additions & 27 deletions dart/packages/fory/lib/src/context/read_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:fory/src/serializer/map_serializers.dart';
import 'package:fory/src/serializer/primitive_serializers.dart';
import 'package:fory/src/serializer/scalar_serializers.dart';
import 'package:fory/src/serializer/serializer.dart';
import 'package:fory/src/serializer/struct_slots.dart';
import 'package:fory/src/serializer/typed_array_serializers.dart';
import 'package:fory/src/types/float16.dart';

Expand All @@ -29,7 +30,7 @@ final class ReadContext {

late Buffer _buffer;
final List<TypeInfo> _sharedTypes = <TypeInfo>[];
final Map<Object, Object?> _contextObjects = <Object, Object?>{};
StructReadSlots? _structReadSlots;
int _depth = 0;

@internal
Expand All @@ -50,7 +51,7 @@ final class ReadContext {
_sharedTypes.clear();
_refReader.reset();
_metaStringReader.reset();
_contextObjects.clear();
_structReadSlots = null;
_depth = 0;
}

Expand All @@ -64,33 +65,11 @@ final class ReadContext {
RefReader get refReader => _refReader;

@internal
bool hasContextObject(Object key) {
return _contextObjects.containsKey(key);
}

@internal
T? getContextObject<T>(Object key) {
return _contextObjects[key] as T?;
}
StructReadSlots? get structReadSlots => _structReadSlots;

@internal
Object? replaceContextObject(Object key, Object? next) {
final previous = _contextObjects[key];
if (next == null) {
_contextObjects.remove(key);
} else {
_contextObjects[key] = next;
}
return previous;
}

@internal
void restoreContextObject(Object key, Object? previous) {
if (previous == null) {
_contextObjects.remove(key);
} else {
_contextObjects[key] = previous;
}
set structReadSlots(StructReadSlots? value) {
_structReadSlots = value;
}

@internal
Expand Down
34 changes: 6 additions & 28 deletions dart/packages/fory/lib/src/context/write_context.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import 'package:fory/src/serializer/collection_serializers.dart';
import 'package:fory/src/serializer/map_serializers.dart';
import 'package:fory/src/serializer/primitive_serializers.dart';
import 'package:fory/src/serializer/scalar_serializers.dart';
import 'package:fory/src/serializer/struct_slots.dart';
import 'package:fory/src/serializer/typed_array_serializers.dart';
import 'package:fory/src/types/float16.dart';
import 'package:fory/src/types/local_date.dart';
Expand All @@ -35,8 +36,7 @@ final class WriteContext {
late Buffer _buffer;
final LinkedHashMap<TypeDef, int> _typeDefIds =
LinkedHashMap<TypeDef, int>.identity();
final LinkedHashMap<Object, Object?> _contextObjects =
LinkedHashMap<Object, Object?>.identity();
StructWriteSlots? _structWriteSlots;
bool _rootTrackRef = false;
int _depth = 0;

Expand All @@ -59,7 +59,7 @@ final class WriteContext {
_typeDefIds.clear();
_refWriter.reset();
_metaStringWriter.reset();
_contextObjects.clear();
_structWriteSlots = null;
_rootTrackRef = false;
_depth = 0;
}
Expand All @@ -77,33 +77,11 @@ final class WriteContext {
bool get rootTrackRef => _rootTrackRef;

@internal
bool hasContextObject(Object key) {
return _contextObjects.containsKey(key);
}
StructWriteSlots? get structWriteSlots => _structWriteSlots;

@internal
T? getContextObject<T>(Object key) {
return _contextObjects[key] as T?;
}

@internal
Object? replaceContextObject(Object key, Object? next) {
final previous = _contextObjects[key];
if (next == null) {
_contextObjects.remove(key);
} else {
_contextObjects[key] = next;
}
return previous;
}

@internal
void restoreContextObject(Object key, Object? previous) {
if (previous == null) {
_contextObjects.remove(key);
} else {
_contextObjects[key] = previous;
}
set structWriteSlots(StructWriteSlots? value) {
_structWriteSlots = value;
}

/// Records entry into one more nested write frame.
Expand Down
Loading
Loading