diff --git a/lib/Common/DataStructures/BaseDictionary.h b/lib/Common/DataStructures/BaseDictionary.h index 6ecca4c9c0f..08d08573a01 100644 --- a/lib/Common/DataStructures/BaseDictionary.h +++ b/lib/Common/DataStructures/BaseDictionary.h @@ -80,7 +80,9 @@ namespace JsUtil typedef TValue ValueType; typedef typename AllocatorInfo::AllocatorType AllocatorType; typedef SizePolicy CurrentSizePolicy; - typedef Entry EntryType; + typedef Entry< + Field(TKey, TAllocator), + Field(TValue, TAllocator)> EntryType; template class EntryIterator; template class BucketEntryIterator; @@ -90,9 +92,9 @@ namespace JsUtil friend class Js::RemoteDictionary; template struct ComparerType { typedef Comparer Type; }; // Used by diagnostics to access Comparer type - Pointer(int, TAllocator) buckets; - Pointer(EntryType, TAllocator) entries; - PointerNoBarrier(AllocatorType) alloc; + Field(int*, TAllocator) buckets; + Field(EntryType*, TAllocator) entries; + FieldNoBarrier(AllocatorType*) alloc; Field(int) size; Field(uint) bucketCount; Field(int) count; @@ -100,7 +102,7 @@ namespace JsUtil Field(int) freeCount; #if PROFILE_DICTIONARY - PointerNoBarrier(DictionaryStats) stats; + FieldNoBarrier(DictionaryStats*) stats; #endif enum InsertOperations { @@ -370,7 +372,8 @@ namespace JsUtil template bool TryGetReference(const TLookup& key, TValue** value) const { - return TryGetReference(key, const_cast(value)); + int i; + return TryGetReference(key, value, &i); } template @@ -389,7 +392,14 @@ namespace JsUtil template bool TryGetReference(const TLookup& key, TValue** value, int* index) const { - return TryGetReference(key, const_cast(value), index); + int i = FindEntryWithKey(key); + if (i >= 0) + { + *value = &entries[i].Value(); + *index = i; + return true; + } + return false; } const TValue& GetValueAt(const int index) const @@ -1385,7 +1395,7 @@ namespace JsUtil class BaseHashSet : protected BaseDictionary { typedef BaseDictionary Base; - typedef Entry EntryType; + typedef typename Base::EntryType EntryType; typedef typename Base::AllocatorType AllocatorType; friend struct JsDiag::RemoteDictionary>; @@ -1559,7 +1569,7 @@ namespace JsUtil class SynchronizedDictionary: protected BaseDictionary { private: - PointerNoBarrier(SyncObject) syncObj; + FieldNoBarrier(SyncObject*) syncObj; typedef BaseDictionary Base; public: diff --git a/lib/Common/DataStructures/Cache.h b/lib/Common/DataStructures/Cache.h index 32eb0c7e4a1..c316df2f2be 100644 --- a/lib/Common/DataStructures/Cache.h +++ b/lib/Common/DataStructures/Cache.h @@ -184,7 +184,7 @@ namespace JsUtil return cacheStore->TryGetValue(key, value); } - bool TryGetReference(const TKey& key, TValue** value, int* index) + bool TryGetReference(const TKey& key, const TValue** value, int* index) { return cacheStore->TryGetReference(key, value, index); } diff --git a/lib/Common/Memory/RecyclerPointers.h b/lib/Common/Memory/RecyclerPointers.h index b433378387c..99865aa2c51 100644 --- a/lib/Common/Memory/RecyclerPointers.h +++ b/lib/Common/Memory/RecyclerPointers.h @@ -63,19 +63,17 @@ struct AllocatorWriteBarrierPolicy { typedef _write template <> struct AllocatorWriteBarrierPolicy { typedef _no_write_barrier_policy Policy; }; -// Choose WriteBarrierPtr or NoWriteBarrierPtr based on Policy +// Choose write barrier Field type: T unchanged, or WriteBarrierPtr based on Policy. // template -struct _WriteBarrierPtrPolicy { typedef NoWriteBarrierPtr Ptr; }; +struct _WriteBarrierFieldType { typedef T Type; }; template -struct _WriteBarrierPtrPolicy { typedef WriteBarrierPtr Ptr; }; +struct _WriteBarrierFieldType { typedef WriteBarrierPtr Type; }; -// Choose WriteBarrierPtr or NoWriteBarrierPtr based on Allocator and T* type -// template ::Policy> -struct WriteBarrierPtrTraits { typedef typename _WriteBarrierPtrPolicy::Ptr Ptr; }; + class Policy = typename AllocatorWriteBarrierPolicy::Policy> +struct WriteBarrierFieldTypeTraits { typedef typename _WriteBarrierFieldType::Type Type; }; // ArrayWriteBarrier behavior // @@ -163,9 +161,9 @@ class NoWriteBarrierPtr // Getters T * operator->() const { return this->value; } - operator T*() const { return this->value; } + operator T* const & () const { return this->value; } - T const** operator&() const { return &value; } + T* const * operator&() const { return &value; } T** operator&() { return &value; } // Setters @@ -216,21 +214,24 @@ class WriteBarrierPtr // Getters T * operator->() const { return ptr; } - operator T*() const { return ptr; } + operator T* const & () const { return ptr; } - T const** AddressOf() const { return &ptr; } + T* const * AddressOf() const { return &ptr; } T** AddressOf() { return &ptr; } - T const** operator&() const - { - static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead."); - return &ptr; - } - T** operator&() + // Taking immutable address is ok + // + T* const * operator&() const { - static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead."); return &ptr; } + // Taking mutable address is not allowed + // + // T** operator&() + // { + // static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead."); + // return &ptr; + // } // Setters WriteBarrierPtr& operator=(T * ptr) diff --git a/lib/Common/Memory/WriteBarrierMacros.h b/lib/Common/Memory/WriteBarrierMacros.h index b4191e2a83a..eb0fe6afe2f 100644 --- a/lib/Common/Memory/WriteBarrierMacros.h +++ b/lib/Common/Memory/WriteBarrierMacros.h @@ -28,33 +28,30 @@ #define SAVE_WRITE_BARRIER_MACROS() \ PushMacro("Field") \ - PushMacro("PointerNoBarrier") \ - PushMacro("Pointer") + PushMacro("FieldNoBarrier") #define RESTORE_WRITE_BARRIER_MACROS() \ PopMacro("Field") \ - PopMacro("PointerNoBarrier") \ - PopMacro("Pointer") + PopMacro("FieldNoBarrier") #endif #ifdef FORCE_USE_WRITE_BARRIER SAVE_WRITE_BARRIER_MACROS() #undef Field -#undef PointerNoBarrier -#undef Pointer +#undef FieldNoBarrier #endif // TODO: Turn off these annotations on Win32 #if defined(__clang__) || defined(FORCE_USE_WRITE_BARRIER) // Various macros for defining field attributes -#define Field(type) NoWriteBarrierField -#define PointerNoBarrier(type) NoWriteBarrierPtr -#define Pointer(type, ...) typename WriteBarrierPtrTraits::Ptr +#define Field(type, ...) \ + typename WriteBarrierFieldTypeTraits::Type +#define FieldNoBarrier(type) \ + typename WriteBarrierFieldTypeTraits::Type #else -#define Field(type) type -#define PointerNoBarrier(type) type* -#define Pointer(type, ...) type* +#define Field(type, ...) type +#define FieldNoBarrier(type) type #endif #undef FORCE_USE_WRITE_BARRIER diff --git a/lib/Runtime/Base/AuxPtrs.h b/lib/Runtime/Base/AuxPtrs.h index e569627ae19..b849839ab72 100644 --- a/lib/Runtime/Base/AuxPtrs.h +++ b/lib/Runtime/Base/AuxPtrs.h @@ -28,7 +28,7 @@ namespace Js static const uint8 MaxCount; Field(uint8) count; // always saving maxCount Field(FieldsEnum) type[_MaxCount]; // save instantiated pointer enum - Pointer(void) ptr[_MaxCount]; // save instantiated pointer address + Field(void*) ptr[_MaxCount]; // save instantiated pointer address AuxPtrsFix(); AuxPtrsFix(AuxPtrsFix* ptr16); // called when promoting from AuxPtrs16 to AuxPtrs32 void* Get(FieldsEnum e); @@ -53,7 +53,7 @@ namespace Js Field(uint8) count; // save instantiated pointers count Field(uint8) capacity; // save number of pointers can be hold in current instance of AuxPtrs Field(uint8) offsets[static_cast(FieldsEnum::Max)]; // save position of each instantiated pointers, if not instantiate, it's invalid - Pointer(void) ptrs[1]; // instantiated pointer addresses + Field(void*) ptrs[1]; // instantiated pointer addresses AuxPtrs(uint8 capacity, AuxPtrs32* ptr32); // called when promoting from AuxPtrs32 to AuxPtrs AuxPtrs(uint8 capacity, AuxPtrs* ptr); // called when expanding (i.e. promoting from AuxPtrs to bigger AuxPtrs) void* Get(FieldsEnum e); diff --git a/lib/Runtime/Base/CompactCounters.h b/lib/Runtime/Base/CompactCounters.h index 3df7fed8164..7502d41a74c 100644 --- a/lib/Runtime/Base/CompactCounters.h +++ b/lib/Runtime/Base/CompactCounters.h @@ -37,7 +37,7 @@ namespace Js mutable Field(bool) bgThreadCallStarted; Field(bool) isCleaningUp; #endif - Pointer(Fields) fields; + Field(Fields*) fields; CompactCounters() { } CompactCounters(T* host) diff --git a/lib/Runtime/Base/FunctionBody.cpp b/lib/Runtime/Base/FunctionBody.cpp index bb2922780fc..5e55edfe5bf 100644 --- a/lib/Runtime/Base/FunctionBody.cpp +++ b/lib/Runtime/Base/FunctionBody.cpp @@ -1731,7 +1731,7 @@ namespace Js !this->GetSourceContextInfo()->IsDynamic() && this->m_scriptContext->DoUndeferGlobalFunctions()) { - this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](JsUtil::SimpleDictionaryEntry func) + this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](const Utf8SourceInfo::DeferredFunctionsDictionary::EntryType& func) { Js::ParseableFunctionInfo *nextFunc = func.Value(); JavascriptExceptionObject* pExceptionObject = nullptr; diff --git a/lib/Runtime/Base/FunctionBody.h b/lib/Runtime/Base/FunctionBody.h index a551003f40e..76ac7633091 100644 --- a/lib/Runtime/Base/FunctionBody.h +++ b/lib/Runtime/Base/FunctionBody.h @@ -1351,7 +1351,7 @@ namespace Js typedef AuxPtrs AuxPtrsT; friend AuxPtrsT; - Pointer(AuxPtrsT) auxPtrs; + Field(AuxPtrsT*) auxPtrs; void* GetAuxPtr(AuxPointerType e) const; void* GetAuxPtrWithLock(AuxPointerType e) const; void SetAuxPtr(AuxPointerType e, void* ptr); @@ -1451,17 +1451,17 @@ namespace Js protected: // Static method(s) - static void SetDisplayName(const char16* srcName, Pointer(const char16)* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone); + static void SetDisplayName(const char16* srcName, Field(const char16*)* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone); static bool SetDisplayName(const char16* srcName, const char16** destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone); static bool IsConstantFunctionName(const char16* srcName); protected: - PointerNoBarrier(ScriptContext) m_scriptContext; // Memory context for this function body - Pointer(Utf8SourceInfo) m_utf8SourceInfo; + FieldNoBarrier(ScriptContext*) m_scriptContext; // Memory context for this function body + Field(Utf8SourceInfo*) m_utf8SourceInfo; // WriteBarrier-TODO: Consider changing this to NoWriteBarrierPtr, and skip tagging- also, tagging is likely unnecessary since that pointer in question is likely not resolvable - PointerNoBarrier(FunctionProxyPtr) m_referenceInParentFunction; // Reference to nested function reference to this function in the parent function body (tagged to not be actual reference) - Pointer(ScriptFunctionType) deferredPrototypeType; - Pointer(ProxyEntryPointInfo) m_defaultEntryPointInfo; // The default entry point info for the function proxy + FieldNoBarrier(FunctionProxyPtr*) m_referenceInParentFunction; // Reference to nested function reference to this function in the parent function body (tagged to not be actual reference) + Field(ScriptFunctionType*) deferredPrototypeType; + Field(ProxyEntryPointInfo*) m_defaultEntryPointInfo; // The default entry point info for the function proxy Field(uint) m_functionNumber; // Per thread global function number @@ -1771,7 +1771,7 @@ namespace Js Field(bool) m_utf8SourceHasBeenSet; // start of UTF8-encoded source Field(uint) m_sourceIndex; // index into the scriptContext's list of saved sources #if DYNAMIC_INTERPRETER_THUNK - PointerNoBarrier(void) m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding. + FieldNoBarrier(void*) m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding. #endif Field(uint) m_cbStartOffset; // pUtf8Source is this many bytes from the start of the scriptContext's source buffer. @@ -1783,10 +1783,10 @@ namespace Js ULONG m_lineNumber; ULONG m_columnNumber; - Pointer(const char16) m_displayName; // Optional name + Field(const char16*) m_displayName; // Optional name uint m_displayNameLength; - Pointer(PropertyRecordList) m_boundPropertyRecords; - Pointer(NestedArray) nestedArray; + Field(PropertyRecordList*) m_boundPropertyRecords; + Field(NestedArray*) nestedArray; public: #if DBG @@ -1988,16 +1988,16 @@ namespace Js friend class ByteCodeBufferBuilder; public: - PointerNoBarrier(SmallSpanSequence) pSpanSequence; + FieldNoBarrier(SmallSpanSequence*) pSpanSequence; RegSlot frameDisplayRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid RegSlot objectRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid - Pointer(ScopeObjectChain) pScopeObjectChain; - Pointer(ByteBlock) m_probeBackingBlock; // NULL if no Probes, otherwise a copy of the unmodified the byte-codeblock //Delay + Field(ScopeObjectChain*) pScopeObjectChain; + Field(ByteBlock*) m_probeBackingBlock; // NULL if no Probes, otherwise a copy of the unmodified the byte-codeblock //Delay int32 m_probeCount; // The number of installed probes (such as breakpoints). // List of bytecode offset for the Branch bytecode. - Pointer(AuxStatementData) m_auxStatementData; + Field(AuxStatementData*) m_auxStatementData; SourceInfo(): frameDisplayRegister(0), @@ -2012,18 +2012,18 @@ namespace Js }; private: - Pointer(ByteBlock) byteCodeBlock; // Function byte-code for script functions - Pointer(FunctionEntryPointList) entryPoints; - Pointer(Var) m_constTable; - Pointer(void*) inlineCaches; + Field(ByteBlock*) byteCodeBlock; // Function byte-code for script functions + Field(FunctionEntryPointList*) entryPoints; + Field(Var*) m_constTable; + Field(void**) inlineCaches; InlineCachePointerArray polymorphicInlineCaches; // Contains the latest polymorphic inline caches - Pointer(PropertyId) cacheIdToPropertyIdMap; + Field(PropertyId*) cacheIdToPropertyIdMap; #if DBG #define InlineCacheTypeNone 0x00 #define InlineCacheTypeInlineCache 0x01 #define InlineCacheTypeIsInst 0x02 - Pointer(byte) m_inlineCacheTypes; + Field(byte*) m_inlineCacheTypes; #endif public: PropertyId * GetCacheIdToPropertyIdMap() @@ -2149,7 +2149,7 @@ namespace Js #ifdef IR_VIEWER // whether IR Dump is enabled for this function (used by parseIR) bool m_isIRDumpEnabled : 1; - Pointer(Js::DynamicObject) m_irDumpBaseObject; + Field(Js::DynamicObject*) m_irDumpBaseObject; #endif /* IR_VIEWER */ Field(uint8) bailOnMisingProfileCount; @@ -2181,14 +2181,14 @@ namespace Js // copied in FunctionBody::Clone // - PointerNoBarrier(Js::ByteCodeCache) byteCodeCache; // Not GC allocated so naked pointer + FieldNoBarrier(Js::ByteCodeCache*) byteCodeCache; // Not GC allocated so naked pointer #ifdef ENABLE_DEBUG_CONFIG_OPTIONS static bool shareInlineCaches; #endif - Pointer(FunctionEntryPointInfo) defaultFunctionEntryPointInfo; + Field(FunctionEntryPointInfo*) defaultFunctionEntryPointInfo; #if ENABLE_PROFILE_INFO - Pointer(DynamicProfileInfo) dynamicProfileInfo; + Field(DynamicProfileInfo*) dynamicProfileInfo; #endif @@ -2642,7 +2642,7 @@ namespace Js bool IsSimpleJitOriginalEntryPoint() const; #if DYNAMIC_INTERPRETER_THUNK - static BYTE GetOffsetOfDynamicInterpreterThunk() { return offsetof(FunctionBody, m_dynamicInterpreterThunk); } + static BYTE GetOffsetOfDynamicInterpreterThunk() { return static_cast(offsetof(FunctionBody, m_dynamicInterpreterThunk)); } void* GetDynamicInterpreterEntryPoint() const { return m_dynamicInterpreterThunk; diff --git a/lib/Runtime/Language/EvalMapRecord.h b/lib/Runtime/Language/EvalMapRecord.h index a6f43e70511..d42ee96e1fa 100644 --- a/lib/Runtime/Language/EvalMapRecord.h +++ b/lib/Runtime/Language/EvalMapRecord.h @@ -131,7 +131,7 @@ namespace Js bool TryGetValue(const Key& key, Value* value) { - EntryRecord** entryRecord; + EntryRecord* const * entryRecord; Key cachedKey; int index; bool success = dictionary->TryGetReference(key, &entryRecord, &index); @@ -168,7 +168,7 @@ namespace Js void Add(const Key& key, Value value) { - EntryRecord** entryRecord; + EntryRecord* const * entryRecord; int index; bool success = dictionary->TryGetReference(key, &entryRecord, &index); if (success && ((*entryRecord) != nullptr)) diff --git a/tools/RecyclerChecker/RecyclerChecker.cpp b/tools/RecyclerChecker/RecyclerChecker.cpp index 02c85c51c1f..875071f69e5 100644 --- a/tools/RecyclerChecker/RecyclerChecker.cpp +++ b/tools/RecyclerChecker/RecyclerChecker.cpp @@ -14,11 +14,16 @@ using namespace clang; using namespace std; +template +bool StartsWith(const string& s, const char (&prefix)[N]) +{ + return s.compare(0, string::npos, prefix, N - 1) == 0; +} namespace { - class MainVisitor; + class CheckAllocationsInFunctionVisitor : public RecursiveASTVisitor { @@ -80,8 +85,9 @@ class MainVisitor: else { auto fieldTypeName = qualType.getAsString(); - if (fieldTypeName.find("WriteBarrierPtr") == 0) // starts with + if (StartsWith(fieldTypeName, "typename WriteBarrierFieldTypeTraits")) { + // Note this only indicates the class is write-barrier annotated hasBarrieredField = true; } else if (type->isCompoundType())