@@ -45,12 +45,12 @@ private uint hashSeed
4545 }
4646 private bool ownsKeys
4747 {
48- readonly get => ( flags >> 30 ) != 0 ;
48+ readonly get => ( ( flags >> 30 ) & 1 ) != 0 ;
4949 set => flags = ( flags & ~ ( 1u << 30 ) ) | ( ( uint ) BoolToInt ( value ) << 30 ) ;
5050 }
5151 private bool ownsValues
5252 {
53- readonly get => ( flags >> 31 ) != 0 ;
53+ readonly get => ( ( flags >> 31 ) & 1 ) != 0 ;
5454 set => flags = ( flags & ~ ( 1u << 31 ) ) | ( ( uint ) BoolToInt ( value ) << 31 ) ;
5555 }
5656
@@ -260,6 +260,7 @@ public void Set(DotvvmPropertyId p, object? value)
260260 else
261261 {
262262 Debug . Assert ( values is Dictionary < DotvvmPropertyId , object ? > ) ;
263+ OwnValues ( ) ;
263264 valuesAsDictionary [ p ] = value ;
264265 }
265266 }
@@ -320,10 +321,12 @@ public bool TryAdd(DotvvmPropertyId p, object? value)
320321 return Object . ReferenceEquals ( existingValue , value ) ;
321322 else
322323 {
324+ OwnValues ( ) ;
323325 valuesAsDictionary . Add ( p , value ) ;
324326 return true ;
325327 }
326328#else
329+ OwnValues ( ) ;
327330 return valuesAsDictionary . TryAdd ( p , value ) || Object . ReferenceEquals ( valuesAsDictionary [ p ] , value ) ;
328331#endif
329332 }
@@ -408,23 +411,40 @@ internal void CloneInto(ref DotvvmControlProperties newDict)
408411 else if ( this . keys == null )
409412 {
410413 var dictionary = this . valuesAsDictionary ;
411- if ( dictionary . Count > 30 )
414+ if ( dictionary . Count > 8 )
412415 {
413416 newDict = this ;
414417 newDict . keys = null ;
415- newDict . valuesAsDictionary = new Dictionary < DotvvmPropertyId , object ? > ( dictionary ) ;
418+ Dictionary < DotvvmPropertyId , object ? > ? newValues = null ;
416419 foreach ( var ( key , value ) in dictionary )
417420 if ( CloneValue ( value ) is { } newValue )
421+ {
422+ if ( newValues is null )
423+ // ok, we have to copy it
424+ newValues = new Dictionary < DotvvmPropertyId , object ? > ( dictionary ) ;
418425 newDict . valuesAsDictionary [ key ] = newValue ;
426+ }
427+
428+ if ( newValues is null )
429+ {
430+ newDict . valuesAsDictionary = dictionary ;
431+ newDict . ownsValues = false ;
432+ this . ownsValues = false ;
433+ }
434+ else
435+ {
436+ newDict . valuesAsDictionary = newValues ;
437+ newDict . ownsValues = true ;
438+ }
419439 return ;
420440 }
421- // move to immutable version if it's reasonably small. It will be probably cloned multiple times again
441+ // move to immutable version if it's small. It will be probably cloned multiple times again
422442 SwitchToPerfectHashing ( ) ;
423443 }
424444
425445 newDict = this ;
426446 newDict . ownsKeys = false ;
427- newDict . ownsValues = false ;
447+ this . ownsKeys = false ;
428448 for ( int i = 0 ; i < newDict . valuesAsArray . Length ; i ++ )
429449 {
430450 if ( CloneValue ( newDict . valuesAsArray [ i ] ) is { } newValue )
@@ -439,6 +459,12 @@ internal void CloneInto(ref DotvvmControlProperties newDict)
439459 newDict . valuesAsArray [ i ] = newValue ;
440460 }
441461 }
462+
463+ if ( newDict . values == this . values )
464+ {
465+ this . ownsValues = false ;
466+ newDict . ownsValues = false ;
467+ }
442468 }
443469
444470 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
0 commit comments