Skip to content

Commit

Permalink
Minor deserialization perf improvements for collections (dotnet#40889)
Browse files Browse the repository at this point in the history
  • Loading branch information
steveharter committed Oct 14, 2019
1 parent 046a95e commit e71bb5c
Show file tree
Hide file tree
Showing 18 changed files with 67 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public override object CreateFromDictionary(ref ReadStack state, IDictionary sou
{
JsonPropertyInfo collectionPropertyInfo = state.Current.JsonPropertyInfo;
JsonPropertyInfo elementPropertyInfo = options.GetJsonPropertyInfoFromClassInfo(collectionPropertyInfo.ElementType, options);
return elementPropertyInfo.CreateDerivedDictionaryInstance(collectionPropertyInfo, sourceDictionary, state.JsonPath, options);
return elementPropertyInfo.CreateDerivedDictionaryInstance(ref state, collectionPropertyInfo, sourceDictionary);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList
{
JsonPropertyInfo collectionPropertyInfo = state.Current.JsonPropertyInfo;
JsonPropertyInfo elementPropertyInfo = options.GetJsonPropertyInfoFromClassInfo(collectionPropertyInfo.ElementType, options);
return elementPropertyInfo.CreateDerivedEnumerableInstance(collectionPropertyInfo, sourceList, state.JsonPath, options);
return elementPropertyInfo.CreateDerivedEnumerableInstance(ref state, collectionPropertyInfo, sourceList);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList
Type enumerableType = state.Current.JsonPropertyInfo.RuntimePropertyType;
Type elementType = state.Current.JsonPropertyInfo.ElementType;
JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
return propertyInfo.CreateIEnumerableInstance(enumerableType, sourceList, state.JsonPath, options);
return propertyInfo.CreateIEnumerableInstance(ref state, enumerableType, sourceList);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public override object CreateFromDictionary(ref ReadStack state, IDictionary sou
Type dictionaryType = state.Current.JsonPropertyInfo.RuntimePropertyType;
Type elementType = state.Current.JsonPropertyInfo.ElementType;
JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
return propertyInfo.CreateIDictionaryInstance(dictionaryType, sourceDictionary, state.JsonPath, options);
return propertyInfo.CreateIDictionaryInstance(ref state, dictionaryType, sourceDictionary);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public override object CreateFromDictionary(ref ReadStack state, IDictionary sou
string delegateKey = DefaultImmutableEnumerableConverter.GetDelegateKey(immutableCollectionType, elementType, out _, out _);

JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
return propertyInfo.CreateImmutableDictionaryInstance(immutableCollectionType, delegateKey, sourceDictionary, state.JsonPath, options);
return propertyInfo.CreateImmutableDictionaryInstance(ref state, immutableCollectionType, delegateKey, sourceDictionary, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList
string delegateKey = GetDelegateKey(immutableCollectionType, elementType, out _, out _);

JsonPropertyInfo propertyInfo = options.GetJsonPropertyInfoFromClassInfo(elementType, options);
return propertyInfo.CreateImmutableCollectionInstance(immutableCollectionType, delegateKey, sourceList, state.JsonPath, options);
return propertyInfo.CreateImmutableCollectionInstance(ref state, immutableCollectionType, delegateKey, sourceList, options);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ public void CopyRuntimeSettingsTo(JsonPropertyInfo other)

public abstract IList CreateConverterList();

public abstract IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options);
public abstract IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList);

public abstract object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options);
public abstract object CreateDerivedDictionaryInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary);

public abstract IEnumerable CreateIEnumerableInstance(Type parentType, IList sourceList, string jsonPath, JsonSerializerOptions options);
public abstract IEnumerable CreateIEnumerableInstance(ref ReadStack state, Type parentType, IList sourceList);

public abstract IDictionary CreateIDictionaryInstance(Type parentType, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options);
public abstract IDictionary CreateIDictionaryInstance(ref ReadStack state, Type parentType, IDictionary sourceDictionary);

public abstract IEnumerable CreateImmutableCollectionInstance(Type collectionType, string delegateKey, IList sourceList, string propertyPath, JsonSerializerOptions options);
public abstract IEnumerable CreateImmutableCollectionInstance(ref ReadStack state, Type collectionType, string delegateKey, IList sourceList, JsonSerializerOptions options);

public abstract IDictionary CreateImmutableDictionaryInstance(Type collectionType, string delegateKey, IDictionary sourceDictionary, string propertyPath, JsonSerializerOptions options);
public abstract IDictionary CreateImmutableDictionaryInstance(ref ReadStack state, Type collectionType, string delegateKey, IDictionary sourceDictionary, JsonSerializerOptions options);

// Create a property that is ignored at run-time. It uses the same type (typeof(sbyte)) to help
// prevent issues with unsupported types and helps ensure we don't accidently (de)serialize it.
Expand Down Expand Up @@ -409,11 +409,11 @@ private void VerifyRead(JsonTokenType tokenType, int depth, long bytesConsumed,
case JsonTokenType.StartArray:
if (reader.TokenType != JsonTokenType.EndArray)
{
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath(), ConverterBase.ToString());
}
else if (depth != reader.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath(), ConverterBase.ToString());
}

// Should not be possible to have not read anything.
Expand All @@ -423,11 +423,11 @@ private void VerifyRead(JsonTokenType tokenType, int depth, long bytesConsumed,
case JsonTokenType.StartObject:
if (reader.TokenType != JsonTokenType.EndObject)
{
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath(), ConverterBase.ToString());
}
else if (depth != reader.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath(), ConverterBase.ToString());
}

// Should not be possible to have not read anything.
Expand All @@ -438,7 +438,7 @@ private void VerifyRead(JsonTokenType tokenType, int depth, long bytesConsumed,
// Reading a single property value.
if (reader.BytesConsumed != bytesConsumed)
{
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterRead(reader, state.JsonPath(), ConverterBase.ToString());
}

// Should not be possible to change token type.
Expand Down Expand Up @@ -466,7 +466,7 @@ public void Write(ref WriteStack state, Utf8JsonWriter writer)

if (originalDepth != writer.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath(), ConverterBase.ToString());
}
}
}
Expand All @@ -480,7 +480,7 @@ public void WriteDictionary(ref WriteStack state, Utf8JsonWriter writer)

if (originalDepth != writer.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath(), ConverterBase.ToString());
}
}

Expand All @@ -493,7 +493,7 @@ public void WriteEnumerable(ref WriteStack state, Utf8JsonWriter writer)

if (originalDepth != writer.CurrentDepth)
{
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath, ConverterBase.ToString());
ThrowHelper.ThrowJsonException_SerializationConverterWrite(state.PropertyPath(), ConverterBase.ToString());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public override Type GetConcreteType(Type parentType)
return parentType;
}

public override IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo collectionPropertyInfo, IList sourceList, string jsonPath, JsonSerializerOptions options)
public override IEnumerable CreateDerivedEnumerableInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IList sourceList)
{
// Implementing types that don't have default constructors are not supported for deserialization.
if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
Expand Down Expand Up @@ -174,7 +174,7 @@ public override IEnumerable CreateDerivedEnumerableInstance(JsonPropertyInfo col
collectionPropertyInfo.PropertyInfo);
}

public override object CreateDerivedDictionaryInstance(JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options)
public override object CreateDerivedDictionaryInstance(ref ReadStack state, JsonPropertyInfo collectionPropertyInfo, IDictionary sourceDictionary)
{
// Implementing types that don't have default constructors are not supported for deserialization.
if (collectionPropertyInfo.DeclaredTypeClassInfo.CreateObject == null)
Expand Down Expand Up @@ -216,7 +216,7 @@ public override object CreateDerivedDictionaryInstance(JsonPropertyInfo collecti
collectionPropertyInfo.PropertyInfo);
}

public override IEnumerable CreateIEnumerableInstance(Type parentType, IList sourceList, string jsonPath, JsonSerializerOptions options)
public override IEnumerable CreateIEnumerableInstance(ref ReadStack state, Type parentType, IList sourceList)
{
if (parentType.IsGenericType)
{
Expand Down Expand Up @@ -260,7 +260,7 @@ public override IEnumerable CreateIEnumerableInstance(Type parentType, IList sou
}
}

public override IDictionary CreateIDictionaryInstance(Type parentType, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options)
public override IDictionary CreateIDictionaryInstance(ref ReadStack state, Type parentType, IDictionary sourceDictionary)
{
if (parentType.FullName == JsonClassInfo.HashtableTypeName)
{
Expand All @@ -275,31 +275,31 @@ public override IDictionary CreateIDictionaryInstance(Type parentType, IDictiona

// Creates an IEnumerable<TDeclaredPropertyType> and populates it with the items in the
// sourceList argument then uses the delegateKey argument to identify the appropriate cached
// CreateRange<TDeclaredPropertyType> method to create and return the desired immutable collection type.
public override IEnumerable CreateImmutableCollectionInstance(Type collectionType, string delegateKey, IList sourceList, string jsonPath, JsonSerializerOptions options)
// CreateRange<TRuntimePropertyType> method to create and return the desired immutable collection type.
public override IEnumerable CreateImmutableCollectionInstance(ref ReadStack state, Type collectionType, string delegateKey, IList sourceList, JsonSerializerOptions options)
{
IEnumerable collection = null;

if (!options.TryGetCreateRangeDelegate(delegateKey, out ImmutableCollectionCreator creator) ||
!creator.CreateImmutableEnumerable(sourceList, out collection))
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(collectionType, jsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(collectionType, state.JsonPath());
}

return collection;
}

// Creates an IEnumerable<TDeclaredPropertyType> and populates it with the items in the
// sourceList argument then uses the delegateKey argument to identify the appropriate cached
// CreateRange<TDeclaredPropertyType> method to create and return the desired immutable collection type.
public override IDictionary CreateImmutableDictionaryInstance(Type collectionType, string delegateKey, IDictionary sourceDictionary, string jsonPath, JsonSerializerOptions options)
// CreateRange<TRuntimePropertyType> method to create and return the desired immutable collection type.
public override IDictionary CreateImmutableDictionaryInstance(ref ReadStack state, Type collectionType, string delegateKey, IDictionary sourceDictionary, JsonSerializerOptions options)
{
IDictionary collection = null;

if (!options.TryGetCreateRangeDelegate(delegateKey, out ImmutableCollectionCreator creator) ||
!creator.CreateImmutableDictionary(sourceDictionary, out collection))
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(collectionType, jsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(collectionType, state.JsonPath());
}

return collection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ protected override void OnRead(JsonTokenType tokenType, ref ReadStack state, ref
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

TConverter value = Converter.Read(ref reader, RuntimePropertyType, Options);
Expand All @@ -38,19 +38,19 @@ protected override void OnReadEnumerable(JsonTokenType tokenType, ref ReadStack
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

if (state.Current.KeyName == null && (state.Current.IsProcessingDictionary || state.Current.IsProcessingIDictionaryConstructible))
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
return;
}

// We need an initialized array in order to store the values.
if (state.Current.IsProcessingEnumerable && state.Current.TempEnumerableValues == null && state.Current.ReturnValue == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ protected override void OnRead(JsonTokenType tokenType, ref ReadStack state, ref
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

TConverter value = Converter.Read(ref reader, RuntimePropertyType, Options);
Expand All @@ -39,19 +39,19 @@ protected override void OnReadEnumerable(JsonTokenType tokenType, ref ReadStack
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

if (state.Current.KeyName == null && (state.Current.IsProcessingDictionary || state.Current.IsProcessingIDictionaryConstructible))
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
return;
}

// We need an initialized array in order to store the values.
if (state.Current.IsProcessingEnumerable && state.Current.TempEnumerableValues == null && state.Current.ReturnValue == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ protected override void OnRead(JsonTokenType tokenType, ref ReadStack state, ref
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

TProperty value = Converter.Read(ref reader, s_underlyingType, Options);
Expand All @@ -41,7 +41,7 @@ protected override void OnReadEnumerable(JsonTokenType tokenType, ref ReadStack
{
if (Converter == null)
{
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath);
ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(RuntimePropertyType, reader, state.JsonPath());
}

TProperty value = Converter.Read(ref reader, s_underlyingType, Options);
Expand Down
Loading

0 comments on commit e71bb5c

Please sign in to comment.