@@ -2486,132 +2486,164 @@ namespace Js
2486
2486
return SetProperty_Internal<false >(instance, instance, true , propertyId, newValue, info, requestContext, propertyOperationFlags);
2487
2487
}
2488
2488
2489
- template <bool unscopables>
2490
- BOOL JavascriptOperators::SetProperty_Internal (Var receiver, RecyclableObject* object, const bool isRoot, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
2491
- {
2492
- if (receiver)
2489
+ // Returns true if a result was written.
2490
+ bool JavascriptOperators::SetAccessorOrNonWritableProperty (
2491
+ Var receiver,
2492
+ RecyclableObject* object,
2493
+ PropertyId propertyId,
2494
+ Var newValue,
2495
+ PropertyValueInfo * info,
2496
+ ScriptContext* requestContext,
2497
+ PropertyOperationFlags propertyOperationFlags,
2498
+ bool isRoot,
2499
+ bool allowUndecInConsoleScope,
2500
+ BOOL *result)
2501
+ {
2502
+ *result = FALSE ;
2503
+ Var setterValueOrProxy = nullptr ;
2504
+ DescriptorFlags flags = None;
2505
+ if ((isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableRootProperty (object, propertyId, &setterValueOrProxy, &flags, info, requestContext)) ||
2506
+ (!isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty (object, propertyId, &setterValueOrProxy, &flags, info, requestContext)))
2493
2507
{
2494
- Assert (!TaggedNumber::Is (receiver));
2495
- Var setterValueOrProxy = nullptr ;
2496
- DescriptorFlags flags = None;
2497
- if ((isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableRootProperty (object, propertyId, &setterValueOrProxy, &flags, info, requestContext)) ||
2498
- (!isRoot && JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty (object, propertyId, &setterValueOrProxy, &flags, info, requestContext)))
2508
+ if ((flags & Accessor) == Accessor)
2499
2509
{
2500
- if ((flags & Accessor) == Accessor)
2510
+ if (JavascriptError::ThrowIfStrictModeUndefinedSetter (propertyOperationFlags, setterValueOrProxy, requestContext) ||
2511
+ JavascriptError::ThrowIfNotExtensibleUndefinedSetter (propertyOperationFlags, setterValueOrProxy, requestContext))
2512
+ {
2513
+ *result = TRUE ;
2514
+ return true ;
2515
+ }
2516
+ if (setterValueOrProxy)
2501
2517
{
2502
- if (JavascriptError::ThrowIfStrictModeUndefinedSetter (propertyOperationFlags, setterValueOrProxy, requestContext) ||
2503
- JavascriptError::ThrowIfNotExtensibleUndefinedSetter (propertyOperationFlags, setterValueOrProxy, requestContext))
2518
+ RecyclableObject* func = RecyclableObject::FromVar (setterValueOrProxy);
2519
+ Assert (!info || info->GetFlags () == InlineCacheSetterFlag || info->GetPropertyIndex () == Constants::NoSlot);
2520
+
2521
+ if (WithScopeObject::Is (receiver))
2504
2522
{
2505
- return TRUE ;
2523
+ receiver = ( RecyclableObject::FromVar (receiver))-> GetThisObjectOrUnWrap () ;
2506
2524
}
2507
- if (setterValueOrProxy)
2525
+ else
2508
2526
{
2509
- RecyclableObject* func = RecyclableObject::FromVar (setterValueOrProxy);
2510
- Assert (!info || info->GetFlags () == InlineCacheSetterFlag || info->GetPropertyIndex () == Constants::NoSlot);
2511
-
2512
- if (WithScopeObject::Is (receiver))
2513
- {
2514
- receiver = (RecyclableObject::FromVar (receiver))->GetThisObjectOrUnWrap ();
2515
- }
2516
- else
2517
- {
2518
- CacheOperators::CachePropertyWrite (RecyclableObject::FromVar (receiver), isRoot, object->GetType (), propertyId, info, requestContext);
2519
- }
2527
+ CacheOperators::CachePropertyWrite (RecyclableObject::FromVar (receiver), isRoot, object->GetType (), propertyId, info, requestContext);
2528
+ }
2520
2529
#ifdef ENABLE_MUTATION_BREAKPOINT
2521
- if (MutationBreakpoint::IsFeatureEnabled (requestContext))
2522
- {
2523
- MutationBreakpoint::HandleSetProperty (requestContext, object, propertyId, newValue);
2524
- }
2525
- #endif
2526
- JavascriptOperators::CallSetter (func, receiver, newValue, requestContext);
2530
+ if (MutationBreakpoint::IsFeatureEnabled (requestContext))
2531
+ {
2532
+ MutationBreakpoint::HandleSetProperty (requestContext, object, propertyId, newValue);
2527
2533
}
2528
- return TRUE ;
2534
+ #endif
2535
+ JavascriptOperators::CallSetter (func, receiver, newValue, requestContext);
2529
2536
}
2530
- else if ((flags & Proxy) == Proxy)
2531
- {
2532
- Assert (JavascriptProxy::Is (setterValueOrProxy));
2533
- JavascriptProxy* proxy = JavascriptProxy::FromVar (setterValueOrProxy);
2534
- // We can't cache the property at this time. both target and handler can be changed outside of the proxy, so the inline cache needs to be
2535
- // invalidate when target, handler, or handler prototype has changed. We don't have a way to achieve this yet.
2536
- PropertyValueInfo::SetNoCache (info, proxy);
2537
- PropertyValueInfo::DisablePrototypeCache (info, proxy); // We can't cache prototype property either
2537
+ *result = TRUE ;
2538
+ return true ;
2539
+ }
2540
+ else if ((flags & Proxy) == Proxy)
2541
+ {
2542
+ Assert (JavascriptProxy::Is (setterValueOrProxy));
2543
+ JavascriptProxy* proxy = JavascriptProxy::FromVar (setterValueOrProxy);
2544
+ // We can't cache the property at this time. both target and handler can be changed outside of the proxy, so the inline cache needs to be
2545
+ // invalidate when target, handler, or handler prototype has changed. We don't have a way to achieve this yet.
2546
+ PropertyValueInfo::SetNoCache (info, proxy);
2547
+ PropertyValueInfo::DisablePrototypeCache (info, proxy); // We can't cache prototype property either
2538
2548
2539
- return proxy->SetPropertyTrap (receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, requestContext);
2540
- }
2541
- else
2549
+ *result = proxy->SetPropertyTrap (receiver, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, requestContext);
2550
+ return true ;
2551
+ }
2552
+ else
2553
+ {
2554
+ Assert ((flags & Data) == Data && (flags & Writable) == None);
2555
+ if (!allowUndecInConsoleScope)
2542
2556
{
2543
- Assert ((flags & Data) == Data && (flags & Writable) == None);
2544
2557
if (flags & Const)
2545
2558
{
2546
2559
JavascriptError::ThrowTypeError (requestContext, ERRAssignmentToConst);
2547
2560
}
2548
2561
2549
2562
JavascriptError::ThrowCantAssign (propertyOperationFlags, requestContext, propertyId);
2550
2563
JavascriptError::ThrowCantAssignIfStrictMode (propertyOperationFlags, requestContext);
2551
- return FALSE ;
2564
+
2565
+ *result = FALSE ;
2566
+ return true ;
2552
2567
}
2553
2568
}
2554
- else if (!JavascriptOperators::IsObject (receiver))
2555
- {
2556
- JavascriptError::ThrowCantAssignIfStrictMode (propertyOperationFlags, requestContext);
2557
- return FALSE ;
2558
- }
2569
+ }
2570
+ return false ;
2571
+ }
2572
+
2573
+ template <bool unscopables>
2574
+ BOOL JavascriptOperators::SetProperty_Internal (Var receiver, RecyclableObject* object, const bool isRoot, PropertyId propertyId, Var newValue, PropertyValueInfo * info, ScriptContext* requestContext, PropertyOperationFlags propertyOperationFlags)
2575
+ {
2576
+ if (receiver == nullptr )
2577
+ {
2578
+ return FALSE ;
2579
+ }
2580
+
2581
+ Assert (!TaggedNumber::Is (receiver));
2582
+ BOOL setAccessorResult = FALSE ;
2583
+ if (SetAccessorOrNonWritableProperty (receiver, object, propertyId, newValue, info, requestContext, propertyOperationFlags, isRoot, false , &setAccessorResult))
2584
+ {
2585
+ return setAccessorResult;
2586
+ }
2587
+ else if (!JavascriptOperators::IsObject (receiver))
2588
+ {
2589
+ JavascriptError::ThrowCantAssignIfStrictMode (propertyOperationFlags, requestContext);
2590
+ return FALSE ;
2591
+ }
2559
2592
2560
2593
#ifdef ENABLE_MUTATION_BREAKPOINT
2561
- // Break on mutation if needed
2562
- bool doNotUpdateCacheForMbp = MutationBreakpoint::IsFeatureEnabled (requestContext) ?
2563
- MutationBreakpoint::HandleSetProperty (requestContext, object, propertyId, newValue) : false ;
2594
+ // Break on mutation if needed
2595
+ bool doNotUpdateCacheForMbp = MutationBreakpoint::IsFeatureEnabled (requestContext) ?
2596
+ MutationBreakpoint::HandleSetProperty (requestContext, object, propertyId, newValue) : false ;
2564
2597
#endif
2565
2598
2566
- // Get the original type before setting the property
2567
- Type *typeWithoutProperty = object->GetType ();
2568
- BOOL didSetProperty = false ;
2569
- if (isRoot)
2570
- {
2571
- AssertMsg (JavascriptOperators::GetTypeId (receiver) == TypeIds_GlobalObject
2572
- || JavascriptOperators::GetTypeId (receiver) == TypeIds_ModuleRoot,
2573
- " Root must be a global object!" );
2599
+ // Get the original type before setting the property
2600
+ Type *typeWithoutProperty = object->GetType ();
2601
+ BOOL didSetProperty = false ;
2602
+ if (isRoot)
2603
+ {
2604
+ AssertMsg (JavascriptOperators::GetTypeId (receiver) == TypeIds_GlobalObject
2605
+ || JavascriptOperators::GetTypeId (receiver) == TypeIds_ModuleRoot,
2606
+ " Root must be a global object!" );
2574
2607
2575
- RootObjectBase* rootObject = static_cast <RootObjectBase*>(receiver);
2576
- didSetProperty = rootObject->SetRootProperty (propertyId, newValue, propertyOperationFlags, info);
2577
- }
2578
- else
2608
+ RootObjectBase* rootObject = static_cast <RootObjectBase*>(receiver);
2609
+ didSetProperty = rootObject->SetRootProperty (propertyId, newValue, propertyOperationFlags, info);
2610
+ }
2611
+ else
2612
+ {
2613
+ RecyclableObject* instanceObject = RecyclableObject::FromVar (receiver);
2614
+ while (!JavascriptOperators::IsNull (instanceObject))
2579
2615
{
2580
- RecyclableObject* instanceObject = RecyclableObject::FromVar (receiver);
2581
- while (!JavascriptOperators::IsNull (instanceObject))
2616
+ if (unscopables && JavascriptOperators::IsPropertyUnscopable (instanceObject, propertyId))
2582
2617
{
2583
- if (unscopables && JavascriptOperators::IsPropertyUnscopable (instanceObject, propertyId))
2618
+ break ;
2619
+ }
2620
+ else
2621
+ {
2622
+ didSetProperty = instanceObject->SetProperty (propertyId, newValue, propertyOperationFlags, info);
2623
+ if (didSetProperty || !unscopables)
2584
2624
{
2585
2625
break ;
2586
2626
}
2587
- else
2588
- {
2589
- didSetProperty = instanceObject->SetProperty (propertyId, newValue, propertyOperationFlags, info);
2590
- if (didSetProperty || !unscopables)
2591
- {
2592
- break ;
2593
- }
2594
- }
2595
- instanceObject = JavascriptOperators::GetPrototypeNoTrap (instanceObject);
2596
2627
}
2628
+ instanceObject = JavascriptOperators::GetPrototypeNoTrap (instanceObject);
2597
2629
}
2630
+ }
2598
2631
2599
- if (didSetProperty)
2600
- {
2601
- bool updateCache = true ;
2632
+ if (didSetProperty)
2633
+ {
2634
+ bool updateCache = true ;
2602
2635
#ifdef ENABLE_MUTATION_BREAKPOINT
2603
- updateCache = updateCache && !doNotUpdateCacheForMbp;
2636
+ updateCache = updateCache && !doNotUpdateCacheForMbp;
2604
2637
#endif
2605
2638
2606
- if (updateCache)
2639
+ if (updateCache)
2640
+ {
2641
+ if (!JavascriptProxy::Is (receiver))
2607
2642
{
2608
- if (!JavascriptProxy::Is (receiver))
2609
- {
2610
- CacheOperators::CachePropertyWrite (RecyclableObject::FromVar (receiver), isRoot, typeWithoutProperty, propertyId, info, requestContext);
2611
- }
2643
+ CacheOperators::CachePropertyWrite (RecyclableObject::FromVar (receiver), isRoot, typeWithoutProperty, propertyId, info, requestContext);
2612
2644
}
2613
- return TRUE ;
2614
2645
}
2646
+ return TRUE ;
2615
2647
}
2616
2648
2617
2649
return FALSE ;
@@ -2939,50 +2971,10 @@ namespace Js
2939
2971
// is true, this must be a normal property.
2940
2972
// TODO: merge OP_HasProperty and GetSetter in one pass if there is perf problem. In fastDOM we have quite
2941
2973
// a lot of setters so separating the two might be actually faster.
2942
- Var setterValueOrProxy = nullptr ;
2943
- DescriptorFlags flags = None;
2944
- if (JavascriptOperators::CheckPrototypesForAccessorOrNonWritableProperty (object, propertyId, &setterValueOrProxy, &flags, &info, scriptContext))
2974
+ BOOL setAccessorResult = FALSE ;
2975
+ if (SetAccessorOrNonWritableProperty (object, object, propertyId, newValue, &info, scriptContext, propertyOperationFlags, false , allowUndecInConsoleScope, &setAccessorResult))
2945
2976
{
2946
- if ((flags & Accessor) == Accessor)
2947
- {
2948
- if (setterValueOrProxy)
2949
- {
2950
- JavascriptFunction* func = (JavascriptFunction*)setterValueOrProxy;
2951
- Assert (info.GetFlags () == InlineCacheSetterFlag || info.GetPropertyIndex () == Constants::NoSlot);
2952
- CacheOperators::CachePropertyWrite (object, false , type, propertyId, &info, scriptContext);
2953
- JavascriptOperators::CallSetter (func, object, newValue, scriptContext);
2954
- }
2955
-
2956
- Assert (!isLexicalThisSlotSymbol);
2957
- return ;
2958
- }
2959
- else if ((flags & Proxy) == Proxy)
2960
- {
2961
- Assert (JavascriptProxy::Is (setterValueOrProxy));
2962
- JavascriptProxy* proxy = JavascriptProxy::FromVar (setterValueOrProxy);
2963
- auto fn = [&](RecyclableObject* target) -> BOOL {
2964
- return JavascriptOperators::SetProperty (object, target, propertyId, newValue, scriptContext, propertyOperationFlags);
2965
- };
2966
- // We can't cache the property at this time. both target and handler can be changed outside of the proxy, so the inline cache needs to be
2967
- // invalidate when target, handler, or handler prototype has changed. We don't have a way to achieve this yet.
2968
- PropertyValueInfo::SetNoCache (&info, proxy);
2969
- PropertyValueInfo::DisablePrototypeCache (&info, proxy); // We can't cache prototype property either
2970
- proxy->SetPropertyTrap (object, JavascriptProxy::SetPropertyTrapKind::SetPropertyKind, propertyId, newValue, scriptContext);
2971
- }
2972
- else
2973
- {
2974
- Assert ((flags & Data) == Data && (flags & Writable) == None);
2975
- if (!allowUndecInConsoleScope)
2976
- {
2977
- if (flags & Const)
2978
- {
2979
- JavascriptError::ThrowTypeError (scriptContext, ERRAssignmentToConst);
2980
- }
2981
-
2982
- Assert (!isLexicalThisSlotSymbol);
2983
- return ;
2984
- }
2985
- }
2977
+ return ;
2986
2978
}
2987
2979
else if (!JavascriptOperators::IsObject (object))
2988
2980
{
0 commit comments