@@ -2997,7 +2997,9 @@ namespace Js
2997
2997
}
2998
2998
2999
2999
template <typename T>
3000
- void JavascriptArray::ConcatArgs (RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start, BigIndex startIdxDest, BOOL FirstPromotedItemIsSpreadable, BigIndex FirstPromotedItemLength)
3000
+ void JavascriptArray::ConcatArgs (RecyclableObject* pDestObj, TypeId* remoteTypeIds,
3001
+ Js::Arguments& args, ScriptContext* scriptContext, uint start, BigIndex startIdxDest,
3002
+ BOOL FirstPromotedItemIsSpreadable, BigIndex FirstPromotedItemLength, bool spreadableCheckedAndTrue)
3001
3003
{
3002
3004
// This never gets called.
3003
3005
Throw::InternalError ();
@@ -3006,7 +3008,9 @@ namespace Js
3006
3008
// Helper for EntryConcat. Concat args or elements of arg arrays into dest array.
3007
3009
//
3008
3010
template <typename T>
3009
- void JavascriptArray::ConcatArgs (RecyclableObject* pDestObj, TypeId* remoteTypeIds, Js::Arguments& args, ScriptContext* scriptContext, uint start, uint startIdxDest, BOOL firstPromotedItemIsSpreadable, BigIndex firstPromotedItemLength)
3011
+ void JavascriptArray::ConcatArgs (RecyclableObject* pDestObj, TypeId* remoteTypeIds,
3012
+ Js::Arguments& args, ScriptContext* scriptContext, uint start, uint startIdxDest,
3013
+ BOOL firstPromotedItemIsSpreadable, BigIndex firstPromotedItemLength, bool spreadableCheckedAndTrue)
3010
3014
{
3011
3015
JavascriptArray* pDestArray = nullptr ;
3012
3016
@@ -3019,8 +3023,8 @@ namespace Js
3019
3023
for (uint idxArg = start; idxArg < args.Info .Count ; idxArg++)
3020
3024
{
3021
3025
Var aItem = args[idxArg];
3022
- BOOL spreadable = false ;
3023
- if (scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled ())
3026
+ bool spreadable = spreadableCheckedAndTrue ;
3027
+ if (!spreadable && scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled ())
3024
3028
{
3025
3029
// firstPromotedItemIsSpreadable is ONLY used to resume after a type promotion from uint32 to uint64
3026
3030
// we do this because calls to IsConcatSpreadable are observable (a big deal for proxies) and we don't
@@ -3034,6 +3038,10 @@ namespace Js
3034
3038
continue ;
3035
3039
}
3036
3040
}
3041
+ else
3042
+ {
3043
+ spreadableCheckedAndTrue = false ; // if it was `true`, reset after the first use
3044
+ }
3037
3045
3038
3046
if (pDestArray && JavascriptArray::IsDirectAccessArray (aItem) && JavascriptArray::IsDirectAccessArray (pDestArray)
3039
3047
&& BigIndex (idxDest + JavascriptArray::FromVar (aItem)->length ).IsSmallIndex ()) // Fast path
@@ -3151,6 +3159,7 @@ namespace Js
3151
3159
pDestArray->SetLength (ConvertToIndex<T, uint32>(idxDest, scriptContext));
3152
3160
}
3153
3161
}
3162
+
3154
3163
bool JavascriptArray::PromoteToBigIndex (BigIndex lhs, BigIndex rhs)
3155
3164
{
3156
3165
return false ; // already a big index
@@ -3173,17 +3182,25 @@ namespace Js
3173
3182
for (uint idxArg = 0 ; idxArg < args.Info .Count ; idxArg++)
3174
3183
{
3175
3184
Var aItem = args[idxArg];
3185
+ bool spreadableCheckedAndTrue = false ;
3176
3186
3177
- if (scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled () && ! JavascriptOperators::IsConcatSpreadable (aItem) )
3187
+ if (scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled ())
3178
3188
{
3179
- pDestArray->SetItem (idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
3180
- idxDest = idxDest + 1 ;
3181
- if (!JavascriptNativeIntArray::Is (pDestArray)) // SetItem could convert pDestArray to a var array if aItem is not an integer if so fall back
3189
+ if (JavascriptOperators::IsConcatSpreadable (aItem))
3182
3190
{
3183
- ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg + 1 , idxDest);
3184
- return pDestArray;
3191
+ spreadableCheckedAndTrue = true ;
3192
+ }
3193
+ else
3194
+ {
3195
+ pDestArray->SetItem (idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
3196
+ idxDest = idxDest + 1 ;
3197
+ if (!JavascriptNativeIntArray::Is (pDestArray)) // SetItem could convert pDestArray to a var array if aItem is not an integer if so fall back
3198
+ {
3199
+ ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg + 1 , idxDest);
3200
+ return pDestArray;
3201
+ }
3202
+ continue ;
3185
3203
}
3186
- continue ;
3187
3204
}
3188
3205
3189
3206
if (JavascriptNativeIntArray::Is (aItem)) // Fast path
@@ -3220,7 +3237,7 @@ namespace Js
3220
3237
else
3221
3238
{
3222
3239
JavascriptArray *pVarDestArray = JavascriptNativeIntArray::ConvertToVarArray (pDestArray);
3223
- ConcatArgs<uint>(pVarDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest);
3240
+ ConcatArgs<uint>(pVarDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest, spreadableCheckedAndTrue );
3224
3241
return pVarDestArray;
3225
3242
}
3226
3243
}
@@ -3238,18 +3255,26 @@ namespace Js
3238
3255
{
3239
3256
Var aItem = args[idxArg];
3240
3257
3241
- if (scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled () && !JavascriptOperators::IsConcatSpreadable (aItem))
3242
- {
3243
-
3244
- pDestArray->SetItem (idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
3258
+ bool spreadableCheckedAndTrue = false ;
3245
3259
3246
- idxDest = idxDest + 1 ;
3247
- if (!JavascriptNativeFloatArray::Is (pDestArray)) // SetItem could convert pDestArray to a var array if aItem is not an integer if so fall back
3260
+ if (scriptContext->GetConfig ()->IsES6IsConcatSpreadableEnabled ())
3261
+ {
3262
+ if (JavascriptOperators::IsConcatSpreadable (aItem))
3248
3263
{
3249
- ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg + 1 , idxDest);
3250
- return pDestArray;
3264
+ spreadableCheckedAndTrue = true ;
3265
+ }
3266
+ else
3267
+ {
3268
+ pDestArray->SetItem (idxDest, aItem, PropertyOperation_ThrowIfNotExtensible);
3269
+
3270
+ idxDest = idxDest + 1 ;
3271
+ if (!JavascriptNativeFloatArray::Is (pDestArray)) // SetItem could convert pDestArray to a var array if aItem is not an integer if so fall back
3272
+ {
3273
+ ConcatArgs<uint>(pDestArray, remoteTypeIds, args, scriptContext, idxArg + 1 , idxDest);
3274
+ return pDestArray;
3275
+ }
3276
+ continue ;
3251
3277
}
3252
- continue ;
3253
3278
}
3254
3279
3255
3280
bool converted;
@@ -3270,9 +3295,10 @@ namespace Js
3270
3295
else
3271
3296
{
3272
3297
JavascriptArray *pVarDestArray = JavascriptNativeFloatArray::ConvertToVarArray (pDestArray);
3273
- ConcatArgs<uint>(pVarDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest);
3298
+ ConcatArgs<uint>(pVarDestArray, remoteTypeIds, args, scriptContext, idxArg, idxDest, spreadableCheckedAndTrue );
3274
3299
return pVarDestArray;
3275
3300
}
3301
+
3276
3302
if (converted)
3277
3303
{
3278
3304
// Copying the last array forced a conversion, so switch over to the var version
0 commit comments