@@ -23,6 +23,8 @@ public class ArrayInstance : ObjectInstance, IEnumerable<JsValue>
23
23
24
24
private ObjectChangeFlags _objectChangeFlags ;
25
25
26
+ private ArrayConstructor ? _constructor ;
27
+
26
28
private protected ArrayInstance ( Engine engine , InternalTypes type ) : base ( engine , type : type )
27
29
{
28
30
_dense = System . Array . Empty < JsValue ? > ( ) ;
@@ -54,7 +56,8 @@ private protected ArrayInstance(Engine engine, JsValue[] items) : base(engine, t
54
56
55
57
private void InitializePrototypeAndValidateCapacity ( Engine engine , uint capacity )
56
58
{
57
- _prototype = engine . Realm . Intrinsics . Array . PrototypeObject ;
59
+ _constructor = engine . Realm . Intrinsics . Array ;
60
+ _prototype = _constructor . PrototypeObject ;
58
61
59
62
if ( capacity > 0 && capacity > engine . Options . Constraints . MaxArraySize )
60
63
{
@@ -67,7 +70,7 @@ private void InitializePrototypeAndValidateCapacity(Engine engine, uint capacity
67
70
public sealed override bool IsArray ( ) => true ;
68
71
69
72
internal sealed override bool HasOriginalIterator
70
- => ReferenceEquals ( Get ( GlobalSymbolRegistry . Iterator ) , _engine . Realm . Intrinsics . Array . PrototypeObject . _originalIteratorFunction ) ;
73
+ => ReferenceEquals ( Get ( GlobalSymbolRegistry . Iterator ) , _constructor ? . PrototypeObject . _originalIteratorFunction ) ;
71
74
72
75
/// <summary>
73
76
/// Checks whether there have been changes to object prototype chain which could render fast access patterns impossible.
@@ -83,7 +86,7 @@ internal bool CanUseFastAccess
83
86
}
84
87
85
88
if ( _prototype is not ArrayPrototype arrayPrototype
86
- || ! ReferenceEquals ( _prototype , _engine . Realm . Intrinsics . Array . PrototypeObject ) )
89
+ || ! ReferenceEquals ( _prototype , _constructor ? . PrototypeObject ) )
87
90
{
88
91
// somebody has switched prototype
89
92
return false ;
@@ -96,7 +99,7 @@ internal bool CanUseFastAccess
96
99
}
97
100
98
101
if ( arrayPrototype . Prototype is not ObjectPrototype arrayPrototypePrototype
99
- || ! ReferenceEquals ( arrayPrototypePrototype , _engine . Realm . Intrinsics . Array . PrototypeObject . Prototype ) )
102
+ || ! ReferenceEquals ( arrayPrototypePrototype , _constructor . PrototypeObject . Prototype ) )
100
103
{
101
104
return false ;
102
105
}
@@ -177,7 +180,7 @@ private bool DefineLength(PropertyDescriptor desc)
177
180
{
178
181
for ( uint keyIndex = 0 ; keyIndex < _dense . Length ; ++ keyIndex )
179
182
{
180
- if ( _dense [ keyIndex ] == null )
183
+ if ( _dense [ keyIndex ] is null )
181
184
{
182
185
continue ;
183
186
}
@@ -284,15 +287,10 @@ private bool DefineOwnProperty(uint index, PropertyDescriptor desc)
284
287
}
285
288
286
289
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
287
- internal uint GetLength ( )
288
- {
289
- if ( _length is null )
290
- {
291
- return 0 ;
292
- }
290
+ internal uint GetLength ( ) => ( uint ) GetJsNumberLength ( ) . _value ;
293
291
294
- return ( uint ) ( ( JsNumber ) _length . _value ! ) . _value ;
295
- }
292
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
293
+ private JsNumber GetJsNumberLength ( ) => _length is null ? JsNumber . PositiveZero : ( JsNumber ) _length . _value ! ;
296
294
297
295
protected sealed override void AddProperty ( JsValue property , PropertyDescriptor descriptor )
298
296
{
@@ -330,7 +328,7 @@ public sealed override List<JsValue> GetOwnPropertyKeys(Types types = Types.None
330
328
var length = System . Math . Min ( temp . Length , GetLength ( ) ) ;
331
329
for ( var i = 0 ; i < length ; i ++ )
332
330
{
333
- if ( temp [ i ] != null )
331
+ if ( temp [ i ] is not null )
334
332
{
335
333
properties . Add ( JsString . Create ( i ) ) ;
336
334
}
@@ -380,7 +378,7 @@ public sealed override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> Ge
380
378
for ( uint i = 0 ; i < length ; i ++ )
381
379
{
382
380
var value = temp [ i ] ;
383
- if ( value != null )
381
+ if ( value is not null )
384
382
{
385
383
if ( _sparse is null || ! _sparse . TryGetValue ( i , out var descriptor ) || descriptor is null )
386
384
{
@@ -633,17 +631,19 @@ private void EnsureCorrectLength(uint index)
633
631
}
634
632
635
633
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
636
- internal void SetLength ( ulong length )
634
+ internal void SetLength ( ulong length ) => SetLength ( JsNumber . Create ( length ) ) ;
635
+
636
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
637
+ internal void SetLength ( JsNumber length )
637
638
{
638
- var number = JsNumber . Create ( length ) ;
639
639
if ( Extensible && _length ! . _flags == PropertyFlag . OnlyWritable )
640
640
{
641
- _length ! . Value = number ;
641
+ _length ! . Value = length ;
642
642
}
643
643
else
644
644
{
645
645
// slow path
646
- Set ( CommonProperties . Length , number , true ) ;
646
+ Set ( CommonProperties . Length , length , true ) ;
647
647
}
648
648
}
649
649
@@ -677,33 +677,44 @@ internal bool DeletePropertyOrThrow(uint index)
677
677
return true ;
678
678
}
679
679
680
- internal bool Delete ( uint index )
680
+ private bool Delete ( uint index ) => Delete ( index , unwrapFromNonDataDescriptor : false , out _ ) ;
681
+
682
+ private bool Delete ( uint index , bool unwrapFromNonDataDescriptor , out JsValue ? deletedValue )
681
683
{
684
+ TryGetDescriptor ( index , createIfMissing : false , out var desc ) ;
685
+
682
686
// check fast path
683
687
var temp = _dense ;
684
688
if ( temp != null )
685
689
{
686
690
if ( index < ( uint ) temp . Length )
687
691
{
688
- if ( ! TryGetDescriptor ( index , createIfMissing : false , out var descriptor ) || descriptor . Configurable )
692
+ if ( desc is null || desc . Configurable )
689
693
{
694
+ deletedValue = temp [ index ] ;
690
695
temp [ index ] = null ;
691
696
return true ;
692
697
}
693
698
}
694
699
}
695
700
696
- if ( ! TryGetDescriptor ( index , createIfMissing : false , out var desc ) )
701
+ if ( desc is null )
697
702
{
703
+ deletedValue = null ;
698
704
return true ;
699
705
}
700
706
701
707
if ( desc . Configurable )
702
708
{
703
- DeleteAt ( index ) ;
709
+ _sparse ! . Remove ( index ) ;
710
+ deletedValue = desc . IsDataDescriptor ( ) || unwrapFromNonDataDescriptor
711
+ ? UnwrapJsValue ( desc )
712
+ : null ;
713
+
704
714
return true ;
705
715
}
706
716
717
+ deletedValue = null ;
707
718
return false ;
708
719
}
709
720
@@ -728,21 +739,23 @@ internal bool DeleteAt(uint index)
728
739
729
740
private bool TryGetDescriptor ( uint index , bool createIfMissing , [ NotNullWhen ( true ) ] out PropertyDescriptor ? descriptor )
730
741
{
742
+ if ( ! createIfMissing && _sparse is null )
743
+ {
744
+ descriptor = null ;
745
+ return false ;
746
+ }
747
+
731
748
descriptor = null ;
732
749
var temp = _dense ;
733
750
if ( temp != null )
734
751
{
735
752
if ( index < ( uint ) temp . Length )
736
753
{
737
754
var value = temp [ index ] ;
738
- if ( value != null )
755
+ if ( value is not null )
739
756
{
740
757
if ( _sparse is null || ! _sparse . TryGetValue ( index , out descriptor ) || descriptor is null )
741
758
{
742
- if ( ! createIfMissing )
743
- {
744
- return false ;
745
- }
746
759
_sparse ??= new Dictionary < uint , PropertyDescriptor ? > ( ) ;
747
760
_sparse [ index ] = descriptor = new PropertyDescriptor ( value , PropertyFlag . ConfigurableEnumerableWritable ) ;
748
761
}
@@ -913,7 +926,7 @@ private void ConvertToSparse()
913
926
for ( uint i = 0 ; i < ( uint ) temp . Length ; ++ i )
914
927
{
915
928
var value = temp [ i ] ;
916
- if ( value != null )
929
+ if ( value is not null )
917
930
{
918
931
_sparse . TryGetValue ( i , out var descriptor ) ;
919
932
descriptor ??= new PropertyDescriptor ( value , PropertyFlag . ConfigurableEnumerableWritable ) ;
@@ -1004,7 +1017,7 @@ private IEnumerable<IndexedEntry> Enumerate()
1004
1017
for ( var i = 0 ; i < length ; i ++ )
1005
1018
{
1006
1019
var value = temp [ i ] ;
1007
- if ( value != null )
1020
+ if ( value is not null )
1008
1021
{
1009
1022
yield return new IndexedEntry ( i , value ) ;
1010
1023
}
@@ -1107,6 +1120,27 @@ public uint Push(JsValue[] values)
1107
1120
return ( uint ) n ;
1108
1121
}
1109
1122
1123
+ public JsValue Pop ( )
1124
+ {
1125
+ var len = GetJsNumberLength ( ) ;
1126
+ if ( JsNumber . PositiveZero . Equals ( len ) )
1127
+ {
1128
+ SetLength ( len ) ;
1129
+ return Undefined ;
1130
+ }
1131
+
1132
+ var newLength = ( uint ) len . _value - 1 ;
1133
+
1134
+ if ( ! Delete ( newLength , unwrapFromNonDataDescriptor : true , out var element ) )
1135
+ {
1136
+ ExceptionHelper . ThrowTypeError ( _engine . Realm ) ;
1137
+ }
1138
+
1139
+ SetLength ( newLength ) ;
1140
+
1141
+ return element ?? Undefined ;
1142
+ }
1143
+
1110
1144
private bool CanSetLength ( )
1111
1145
{
1112
1146
if ( ! _length ! . IsAccessorDescriptor ( ) )
@@ -1138,7 +1172,7 @@ internal JsArray Map(JsValue[] arguments)
1138
1172
var len = GetLength ( ) ;
1139
1173
1140
1174
var callable = GetCallable ( callbackfn ) ;
1141
- var a = Engine . Realm . Intrinsics . Array . ArrayCreate ( len ) ;
1175
+ var a = _engine . Realm . Intrinsics . Array . ArrayCreate ( len ) ;
1142
1176
var args = _engine . _jsValueArrayPool . RentArray ( 3 ) ;
1143
1177
args [ 2 ] = this ;
1144
1178
for ( uint k = 0 ; k < len ; k ++ )
@@ -1306,7 +1340,7 @@ internal void CopyValues(JsArray source, uint sourceStartIndex, uint targetStart
1306
1340
for ( var i = sourceStartIndex ; i < sourceStartIndex + length ; ++ i , j ++ )
1307
1341
{
1308
1342
JsValue ? sourceValue ;
1309
- if ( i < ( uint ) sourceDense . Length && sourceDense [ i ] != null )
1343
+ if ( i < ( uint ) sourceDense . Length && sourceDense [ i ] is not null )
1310
1344
{
1311
1345
sourceValue = sourceDense [ i ] ;
1312
1346
}
0 commit comments