Procházet zdrojové kódy

swb: misc fixes from unit test verification

Fix a few swb annotation issues.

Opnd::IsWriteBarrierTriggerableValue(): Skip some optimization in
verification mode.

SimpleDictionaryTypeHandler: reorder fields and add a tag bit to avoid
GC false positive.
Jianchun Xu před 9 roky
rodič
revize
4e73253011

+ 20 - 5
lib/Backend/Opnd.cpp

@@ -96,13 +96,28 @@ bool
 Opnd::IsWriteBarrierTriggerableValue()
 {
     // Determines whether if an operand is used as a source in a store instruction, whether the store needs a write barrier
-    //
-    // If it's not a tagged value, and one of the two following conditions are true, then a write barrier is needed
+
+    // If it's a tagged value, we don't need a write barrier
+    if (!this->IsNotTaggedValue()) // SWB-TODO: change to: this->IsTaggedValue()
+    {
+        return false;
+    }
+
     // If this operand is known address, then it doesn't need a write barrier, the address is either not a GC address or is pinned
+    if (this->IsAddrOpnd() && static_cast<AddrOpndKind>(this->AsAddrOpnd()->GetKind()) == AddrOpndKindDynamicVar)
+    {
+        return false;
+    }
+
+#if DBG
+    if (CONFIG_FLAG(ForceSoftwareWriteBarrier) && CONFIG_FLAG(RecyclerVerifyMark))
+    {
+        return true; // No further optimization if we are in verification
+    }
+#endif
+
     // If its null/boolean/undefined, we don't need a write barrier since the javascript library will keep those guys alive
-    return this->IsNotTaggedValue() &&
-        !((this->IsAddrOpnd() && static_cast<AddrOpndKind>(this->AsAddrOpnd()->GetKind()) == AddrOpndKindDynamicVar) ||
-          (this->GetValueType().IsBoolean() || this->GetValueType().IsNull() || this->GetValueType().IsUndefined()));
+    return !(this->GetValueType().IsBoolean() || this->GetValueType().IsNull() || this->GetValueType().IsUndefined());
 }
 
 /*

+ 4 - 0
lib/Common/DataStructures/KeyValuePair.h

@@ -23,6 +23,10 @@ namespace JsUtil
             this->value = value;
         }
 
+        KeyValuePair(const KeyValuePair& other)
+            : key(other.key), value(other.value)
+        {}
+
         TKey Key() { return key; }
         const TKey Key() const { return key; }
 

+ 4 - 1
lib/Runtime/Language/DynamicProfileInfo.cpp

@@ -1921,7 +1921,10 @@ namespace Js
 
             if (callSiteInfoCount != 0)
             {
-                callSiteInfo = RecyclerNewArray(recycler, CallSiteInfo, callSiteInfoCount);
+                // CallSiteInfo contains pointer "polymorphicCallSiteInfo", but
+                // we explicitly save that pointer in FunctionBody. Safe to
+                // allocate CallSiteInfo[] as Leaf here.
+                callSiteInfo = RecyclerNewArrayLeaf(recycler, CallSiteInfo, callSiteInfoCount);
                 if (!reader->ReadArray(callSiteInfo, callSiteInfoCount))
                 {
                     goto Error;

+ 5 - 4
lib/Runtime/Library/ConcatString.h

@@ -153,12 +153,12 @@ namespace Js
         virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed
         {
             const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
-            __super::CopyImpl(buffer, _countof(m_slots), m_slots, nestedStringTreeCopyInfos, recursionDepth);
+            __super::CopyImpl(buffer, _countof(m_slots), AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
         }
         virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const override sealed
         {
             const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
-            items = m_slots;
+            items = AddressOf(m_slots[0]);
             return _countof(m_slots);
         }
     public:
@@ -171,10 +171,11 @@ namespace Js
             m_slots[1] = m_inner;
             m_slots[2] = this->GetLastItem();
         }
-        JavascriptString * m_inner;
+
+        Field(JavascriptString *) m_inner;
 
         // Use the padding space for the concat
-        JavascriptString * m_slots[3];
+        Field(JavascriptString *) m_slots[3];
     };
 
     // Make sure the padding doesn't add tot he size of ConcatStringWrapping

+ 1 - 1
lib/Runtime/Library/ConcatString.inl

@@ -114,7 +114,7 @@ namespace Js
     {
         const char16 * sz = GetSzImpl<ConcatStringWrapping>();
         m_inner = nullptr;
-        memset(m_slots, 0, sizeof(m_slots));
+        ClearArray(m_slots);
         return sz;
     }
 

+ 1 - 1
lib/Runtime/Library/JavascriptArray.h

@@ -81,7 +81,7 @@ namespace Js
         void Add(Recycler* recycler, SparseArraySegmentBase* newSeg);
         void Find(uint itemIndex, SparseArraySegmentBase*& prevOrMatch, SparseArraySegmentBase*& matchOrNext);
 
-        FieldNoBarrier(SparseArraySegmentBase *) lastUsedSegment;
+        Field(SparseArraySegmentBase *) lastUsedSegment;
     };
 
     class JavascriptArray : public ArrayObject

+ 1 - 1
lib/Runtime/Library/JavascriptMap.h

@@ -9,7 +9,7 @@ namespace Js
     class JavascriptMap : public DynamicObject
     {
     public:
-        typedef JsUtil::KeyValuePair<Var, Var> MapDataKeyValuePair;
+        typedef JsUtil::KeyValuePair<Field(Var), Field(Var)> MapDataKeyValuePair;
         typedef MapOrSetDataNode<MapDataKeyValuePair> MapDataNode;
         typedef MapOrSetDataList<MapDataKeyValuePair> MapDataList;
         typedef JsUtil::BaseDictionary<Var, MapDataNode*, Recycler, PowerOf2SizePolicy, SameValueZeroComparer> MapDataMap;

+ 4 - 4
lib/Runtime/Library/MapOrSetDataList.h

@@ -28,13 +28,13 @@ namespace Js
         template <typename TData>
         friend class MapOrSetDataList;
 
-        MapOrSetDataNode<TData>* next;
-        MapOrSetDataNode<TData>* prev;
+        Field(MapOrSetDataNode<TData>*) next;
+        Field(MapOrSetDataNode<TData>*) prev;
 
         MapOrSetDataNode(TData& data) : data(data), next(nullptr), prev(nullptr) { }
 
     public:
-        TData data;
+        Field(TData) data;
     };
 
     template <typename TData>
@@ -120,7 +120,7 @@ namespace Js
                 return false;
             }
 
-            TData& Current()
+            const TData& Current() const
             {
                 return current->data;
             }

+ 15 - 10
lib/Runtime/Types/SimpleDictionaryTypeHandler.cpp

@@ -262,7 +262,9 @@ namespace Js
         DynamicTypeHandler(1),
         nextPropertyIndex(0),
         singletonInstance(nullptr),
+        _gc_tag(true),
         isUnordered(false),
+        hasNamelessPropertyId(false),
         numDeletedProperties(0)
     {
         SetIsInlineSlotCapacityLocked();
@@ -275,6 +277,7 @@ namespace Js
         DynamicTypeHandler(slotCapacity, inlineSlotCapacity, offsetOfInlineSlots, DefaultFlags | (isLocked ? IsLockedFlag : 0) | (isShared ? (MayBecomeSharedFlag | IsSharedFlag) : 0)),
         nextPropertyIndex(0),
         singletonInstance(nullptr),
+        _gc_tag(true),
         isUnordered(false),
         hasNamelessPropertyId(false),
         numDeletedProperties(0)
@@ -295,6 +298,7 @@ namespace Js
         DynamicTypeHandler(slotCapacity, inlineSlotCapacity, offsetOfInlineSlots, DefaultFlags | (isLocked ? IsLockedFlag : 0) | (isShared ? (MayBecomeSharedFlag | IsSharedFlag) : 0)),
         nextPropertyIndex(0),
         singletonInstance(nullptr),
+        _gc_tag(true),
         isUnordered(false),
         hasNamelessPropertyId(false),
         numDeletedProperties(0)
@@ -310,6 +314,7 @@ namespace Js
         DynamicTypeHandler(slotCapacity, inlineSlotCapacity, offsetOfInlineSlots, DefaultFlags | (isLocked ? IsLockedFlag : 0) | (isShared ? (MayBecomeSharedFlag | IsSharedFlag) : 0)),
         nextPropertyIndex(0),
         singletonInstance(nullptr),
+        _gc_tag(true),
         isUnordered(false),
         hasNamelessPropertyId(false),
         numDeletedProperties(0)
@@ -1559,7 +1564,7 @@ namespace Js
     {
         AssertMsg(!PropertyRecord::IsPropertyNameNumeric(propertyNameString->GetString(), propertyNameString->GetLength()),
             "Numeric property names should have been converted to uint or PropertyRecord* ");
-    
+
         if (!GetIsLocked())
         {
 #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
@@ -1571,9 +1576,9 @@ namespace Js
                     ->DeleteProperty(instance, propertyNameString, propertyOperationFlags);
             }
 #endif
-    
+
             ScriptContext* scriptContext = instance->GetScriptContext();
-    
+
             JsUtil::CharacterBuffer<WCHAR> propertyName(propertyNameString->GetString(), propertyNameString->GetLength());
             SimpleDictionaryPropertyDescriptor<TPropertyIndex>* descriptor;
             if (propertyMap->TryGetReference(propertyName, &descriptor))
@@ -1590,7 +1595,7 @@ namespace Js
                 else if (!(descriptor->Attributes & PropertyConfigurable))
                 {
                     JavascriptError::ThrowCantDelete(propertyOperationFlags, scriptContext, propertyNameString->GetString()); // or propertyName->GetBuffer
-    
+
                     return false;
                 }
                 Assert(!(descriptor->Attributes & PropertyLetConstGlobal));
@@ -1606,7 +1611,7 @@ namespace Js
                             // property IDs. After this, enumeration order is nondeterministic.
                             // Also use JavascriptString* as the property map key so that PropertyRecords can be avoided
                             // entirely where possible.
-    
+
                             // Check if prototype chain has enumerable properties, according to logic used in
                             // ForInObjectEnumerator::Initialize().  If there are enumerable properties in the
                             // prototype chain, then enumerating this object's properties will require keeping
@@ -1618,7 +1623,7 @@ namespace Js
                             bool fConvertToStringKeyedHandler =
                                 !hasNamelessPropertyId &&
                                 ForInObjectEnumerator::GetFirstPrototypeWithEnumerableProperties(instance) == nullptr;
-    
+
                             if (fConvertToStringKeyedHandler)
                             {
                                 PHASE_PRINT_TESTTRACE1(Js::TypeHandlerTransitionPhase, _u("Transitioning to string keyed SimpleDictionaryUnorderedTypeHandler\n"));
@@ -1635,15 +1640,15 @@ namespace Js
                             }
                         }
                     }
-    
+
                     Assert(this->singletonInstance == nullptr || instance == this->singletonInstance->Get());
                     InvalidateFixedField(propertyNameString, descriptor, instance->GetScriptContext());
-    
+
                     if (this->GetFlags() & IsPrototypeFlag)
                     {
                         scriptContext->InvalidateProtoCaches(scriptContext->GetOrAddPropertyIdTracked(propertyNameString->GetSz(), propertyNameString->GetLength()));
                     }
-    
+
                     // If this is an unordered type handler, register the deleted property index so that it can be reused for
                     // other property IDs added later
                     if (!isUnordered ||
@@ -1653,7 +1658,7 @@ namespace Js
                     }
                 }
                 descriptor->Attributes = PropertyDeletedDefaults;
-    
+
                 // Change the type so as we can invalidate the cache in fast path jit
                 if (instance->GetType()->HasBeenCached())
                 {

+ 2 - 2
lib/Runtime/Types/SimpleDictionaryTypeHandler.h

@@ -67,17 +67,17 @@ namespace Js
 
     private:
         Field(RecyclerWeakReference<DynamicObject>*) singletonInstance;
-        Field(TPropertyIndex) nextPropertyIndex;
 
     protected:
+        Field(bool) _gc_tag : 1;  // Tag the low bit to prevent possible GC false references
         // Determines whether this instance is actually a SimpleDictionaryUnorderedTypeHandler
         Field(bool) isUnordered : 1;
         // Tracks if an InternalPropertyRecord or symbol has been added to this type; will prevent conversion to string-keyed type handler
         Field(bool) hasNamelessPropertyId : 1;
-
     private:
         // Number of deleted properties in the property map
         Field(byte) numDeletedProperties;
+        Field(TPropertyIndex) nextPropertyIndex;
 
     public:
         DEFINE_GETCPPNAME();