Skip to content

Commit 87cecd6

Browse files
author
Jianchun Xu
committed
[MERGE #1819 @jianchun] swb: annotate BaseDictionary entry items
Merge pull request #1819 from jianchun:wbdict BaseDictionary Key or Value can be of GC pointer type, potentially needs write barrier on each entry item. Use macro and template type traits to replace underlying entry Key/Value type with WriteBarrierPtr when Key or Value is pointer type and used with recycler allocators. BaseDictionary methods still use original Key/Value types. Only the underlying EntryType may contain swapped type. Most methods are not affected. However, when WriteBarrierPtr is used, only immutable TryGetReference should be used. (We cannot get a mutable reference and possibly change the pointer underneath WriteBarrierPtr.) Allow WriteBarrierPtr to take immutable address to support TryGetReference (used a lot). Fixed a bunch of incorrect `const` usage. Update: Apply template traits to field types to simplify write barrier field annotations. Now most annotations are Field or FieldNoBarrier (for pointers known not needing write barrier).
2 parents e22ec43 + 3a170fb commit 87cecd6

File tree

10 files changed

+88
-74
lines changed

10 files changed

+88
-74
lines changed

lib/Common/DataStructures/BaseDictionary.h

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ namespace JsUtil
8080
typedef TValue ValueType;
8181
typedef typename AllocatorInfo<TAllocator, TValue>::AllocatorType AllocatorType;
8282
typedef SizePolicy CurrentSizePolicy;
83-
typedef Entry<TKey, TValue> EntryType;
83+
typedef Entry<
84+
Field(TKey, TAllocator),
85+
Field(TValue, TAllocator)> EntryType;
8486

8587
template<class TDictionary> class EntryIterator;
8688
template<class TDictionary> class BucketEntryIterator;
@@ -90,17 +92,17 @@ namespace JsUtil
9092
friend class Js::RemoteDictionary<BaseDictionary>;
9193
template <typename ValueOrKey> struct ComparerType { typedef Comparer<ValueOrKey> Type; }; // Used by diagnostics to access Comparer type
9294

93-
Pointer(int, TAllocator) buckets;
94-
Pointer(EntryType, TAllocator) entries;
95-
PointerNoBarrier(AllocatorType) alloc;
95+
Field(int*, TAllocator) buckets;
96+
Field(EntryType*, TAllocator) entries;
97+
FieldNoBarrier(AllocatorType*) alloc;
9698
Field(int) size;
9799
Field(uint) bucketCount;
98100
Field(int) count;
99101
Field(int) freeList;
100102
Field(int) freeCount;
101103

102104
#if PROFILE_DICTIONARY
103-
PointerNoBarrier(DictionaryStats) stats;
105+
FieldNoBarrier(DictionaryStats*) stats;
104106
#endif
105107
enum InsertOperations
106108
{
@@ -370,7 +372,8 @@ namespace JsUtil
370372
template <typename TLookup>
371373
bool TryGetReference(const TLookup& key, TValue** value) const
372374
{
373-
return TryGetReference(key, const_cast<const TValue **>(value));
375+
int i;
376+
return TryGetReference(key, value, &i);
374377
}
375378

376379
template <typename TLookup>
@@ -389,7 +392,14 @@ namespace JsUtil
389392
template <typename TLookup>
390393
bool TryGetReference(const TLookup& key, TValue** value, int* index) const
391394
{
392-
return TryGetReference(key, const_cast<const TValue **>(value), index);
395+
int i = FindEntryWithKey(key);
396+
if (i >= 0)
397+
{
398+
*value = &entries[i].Value();
399+
*index = i;
400+
return true;
401+
}
402+
return false;
393403
}
394404

395405
const TValue& GetValueAt(const int index) const
@@ -1385,7 +1395,7 @@ namespace JsUtil
13851395
class BaseHashSet : protected BaseDictionary<TKey, TElement, TAllocator, SizePolicy, Comparer, Entry, Lock>
13861396
{
13871397
typedef BaseDictionary<TKey, TElement, TAllocator, SizePolicy, Comparer, Entry, Lock> Base;
1388-
typedef Entry<TKey, TElement> EntryType;
1398+
typedef typename Base::EntryType EntryType;
13891399
typedef typename Base::AllocatorType AllocatorType;
13901400
friend struct JsDiag::RemoteDictionary<BaseHashSet<TElement, TAllocator, SizePolicy, TKey, Comparer, Entry, Lock>>;
13911401

@@ -1559,7 +1569,7 @@ namespace JsUtil
15591569
class SynchronizedDictionary: protected BaseDictionary<TKey, TValue, TAllocator, SizePolicy, Comparer, Entry>
15601570
{
15611571
private:
1562-
PointerNoBarrier(SyncObject) syncObj;
1572+
FieldNoBarrier(SyncObject*) syncObj;
15631573

15641574
typedef BaseDictionary<TKey, TValue, TAllocator, SizePolicy, Comparer, Entry> Base;
15651575
public:

lib/Common/DataStructures/Cache.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ namespace JsUtil
184184
return cacheStore->TryGetValue(key, value);
185185
}
186186

187-
bool TryGetReference(const TKey& key, TValue** value, int* index)
187+
bool TryGetReference(const TKey& key, const TValue** value, int* index)
188188
{
189189
return cacheStore->TryGetReference(key, value, index);
190190
}

lib/Common/Memory/RecyclerPointers.h

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,19 +63,17 @@ struct AllocatorWriteBarrierPolicy<RecyclerNonLeafAllocator, T> { typedef _write
6363
template <>
6464
struct AllocatorWriteBarrierPolicy<RecyclerNonLeafAllocator, int> { typedef _no_write_barrier_policy Policy; };
6565

66-
// Choose WriteBarrierPtr or NoWriteBarrierPtr based on Policy
66+
// Choose write barrier Field type: T unchanged, or WriteBarrierPtr based on Policy.
6767
//
6868
template <class T, class Policy>
69-
struct _WriteBarrierPtrPolicy { typedef NoWriteBarrierPtr<T> Ptr; };
69+
struct _WriteBarrierFieldType { typedef T Type; };
7070
template <class T>
71-
struct _WriteBarrierPtrPolicy<T, _write_barrier_policy> { typedef WriteBarrierPtr<T> Ptr; };
71+
struct _WriteBarrierFieldType<T*, _write_barrier_policy> { typedef WriteBarrierPtr<T> Type; };
7272

73-
// Choose WriteBarrierPtr or NoWriteBarrierPtr based on Allocator and T* type
74-
//
7573
template <class T,
7674
class Allocator = Recycler,
77-
class Policy = typename AllocatorWriteBarrierPolicy<Allocator, T*>::Policy>
78-
struct WriteBarrierPtrTraits { typedef typename _WriteBarrierPtrPolicy<T, Policy>::Ptr Ptr; };
75+
class Policy = typename AllocatorWriteBarrierPolicy<Allocator, T>::Policy>
76+
struct WriteBarrierFieldTypeTraits { typedef typename _WriteBarrierFieldType<T, Policy>::Type Type; };
7977

8078
// ArrayWriteBarrier behavior
8179
//
@@ -163,9 +161,9 @@ class NoWriteBarrierPtr
163161

164162
// Getters
165163
T * operator->() const { return this->value; }
166-
operator T*() const { return this->value; }
164+
operator T* const & () const { return this->value; }
167165

168-
T const** operator&() const { return &value; }
166+
T* const * operator&() const { return &value; }
169167
T** operator&() { return &value; }
170168

171169
// Setters
@@ -216,21 +214,24 @@ class WriteBarrierPtr
216214

217215
// Getters
218216
T * operator->() const { return ptr; }
219-
operator T*() const { return ptr; }
217+
operator T* const & () const { return ptr; }
220218

221-
T const** AddressOf() const { return &ptr; }
219+
T* const * AddressOf() const { return &ptr; }
222220
T** AddressOf() { return &ptr; }
223221

224-
T const** operator&() const
225-
{
226-
static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead.");
227-
return &ptr;
228-
}
229-
T** operator&()
222+
// Taking immutable address is ok
223+
//
224+
T* const * operator&() const
230225
{
231-
static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead.");
232226
return &ptr;
233227
}
228+
// Taking mutable address is not allowed
229+
//
230+
// T** operator&()
231+
// {
232+
// static_assert(false, "Might need to set barrier for this operation, and use AddressOf instead.");
233+
// return &ptr;
234+
// }
234235

235236
// Setters
236237
WriteBarrierPtr& operator=(T * ptr)

lib/Common/Memory/WriteBarrierMacros.h

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,33 +28,30 @@
2828

2929
#define SAVE_WRITE_BARRIER_MACROS() \
3030
PushMacro("Field") \
31-
PushMacro("PointerNoBarrier") \
32-
PushMacro("Pointer")
31+
PushMacro("FieldNoBarrier")
3332

3433
#define RESTORE_WRITE_BARRIER_MACROS() \
3534
PopMacro("Field") \
36-
PopMacro("PointerNoBarrier") \
37-
PopMacro("Pointer")
35+
PopMacro("FieldNoBarrier")
3836

3937
#endif
4038

4139
#ifdef FORCE_USE_WRITE_BARRIER
4240
SAVE_WRITE_BARRIER_MACROS()
4341
#undef Field
44-
#undef PointerNoBarrier
45-
#undef Pointer
42+
#undef FieldNoBarrier
4643
#endif
4744

4845
// TODO: Turn off these annotations on Win32
4946
#if defined(__clang__) || defined(FORCE_USE_WRITE_BARRIER)
5047
// Various macros for defining field attributes
51-
#define Field(type) NoWriteBarrierField<type>
52-
#define PointerNoBarrier(type) NoWriteBarrierPtr<type>
53-
#define Pointer(type, ...) typename WriteBarrierPtrTraits<type, ##__VA_ARGS__>::Ptr
48+
#define Field(type, ...) \
49+
typename WriteBarrierFieldTypeTraits<type, ##__VA_ARGS__>::Type
50+
#define FieldNoBarrier(type) \
51+
typename WriteBarrierFieldTypeTraits<type, _no_write_barrier_policy, _no_write_barrier_policy>::Type
5452
#else
55-
#define Field(type) type
56-
#define PointerNoBarrier(type) type*
57-
#define Pointer(type, ...) type*
53+
#define Field(type, ...) type
54+
#define FieldNoBarrier(type) type
5855
#endif
5956

6057
#undef FORCE_USE_WRITE_BARRIER

lib/Runtime/Base/AuxPtrs.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace Js
2828
static const uint8 MaxCount;
2929
Field(uint8) count; // always saving maxCount
3030
Field(FieldsEnum) type[_MaxCount]; // save instantiated pointer enum
31-
Pointer(void) ptr[_MaxCount]; // save instantiated pointer address
31+
Field(void*) ptr[_MaxCount]; // save instantiated pointer address
3232
AuxPtrsFix();
3333
AuxPtrsFix(AuxPtrsFix<FieldsEnum, 16>* ptr16); // called when promoting from AuxPtrs16 to AuxPtrs32
3434
void* Get(FieldsEnum e);
@@ -53,7 +53,7 @@ namespace Js
5353
Field(uint8) count; // save instantiated pointers count
5454
Field(uint8) capacity; // save number of pointers can be hold in current instance of AuxPtrs
5555
Field(uint8) offsets[static_cast<int>(FieldsEnum::Max)]; // save position of each instantiated pointers, if not instantiate, it's invalid
56-
Pointer(void) ptrs[1]; // instantiated pointer addresses
56+
Field(void*) ptrs[1]; // instantiated pointer addresses
5757
AuxPtrs(uint8 capacity, AuxPtrs32* ptr32); // called when promoting from AuxPtrs32 to AuxPtrs
5858
AuxPtrs(uint8 capacity, AuxPtrs* ptr); // called when expanding (i.e. promoting from AuxPtrs to bigger AuxPtrs)
5959
void* Get(FieldsEnum e);

lib/Runtime/Base/CompactCounters.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ namespace Js
3737
mutable Field(bool) bgThreadCallStarted;
3838
Field(bool) isCleaningUp;
3939
#endif
40-
Pointer(Fields) fields;
40+
Field(Fields*) fields;
4141

4242
CompactCounters() { }
4343
CompactCounters(T* host)

lib/Runtime/Base/FunctionBody.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,7 @@ namespace Js
17311731
!this->GetSourceContextInfo()->IsDynamic() &&
17321732
this->m_scriptContext->DoUndeferGlobalFunctions())
17331733
{
1734-
this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](JsUtil::SimpleDictionaryEntry<Js::LocalFunctionId, Js::ParseableFunctionInfo*> func)
1734+
this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](const Utf8SourceInfo::DeferredFunctionsDictionary::EntryType& func)
17351735
{
17361736
Js::ParseableFunctionInfo *nextFunc = func.Value();
17371737
JavascriptExceptionObject* pExceptionObject = nullptr;

lib/Runtime/Base/FunctionBody.h

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,7 +1351,7 @@ namespace Js
13511351

13521352
typedef AuxPtrs<FunctionProxy, AuxPointerType> AuxPtrsT;
13531353
friend AuxPtrsT;
1354-
Pointer(AuxPtrsT) auxPtrs;
1354+
Field(AuxPtrsT*) auxPtrs;
13551355
void* GetAuxPtr(AuxPointerType e) const;
13561356
void* GetAuxPtrWithLock(AuxPointerType e) const;
13571357
void SetAuxPtr(AuxPointerType e, void* ptr);
@@ -1451,17 +1451,17 @@ namespace Js
14511451

14521452
protected:
14531453
// Static method(s)
1454-
static void SetDisplayName(const char16* srcName, Pointer(const char16)* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone);
1454+
static void SetDisplayName(const char16* srcName, Field(const char16*)* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone);
14551455
static bool SetDisplayName(const char16* srcName, const char16** destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags = SetDisplayNameFlagsNone);
14561456
static bool IsConstantFunctionName(const char16* srcName);
14571457

14581458
protected:
1459-
PointerNoBarrier(ScriptContext) m_scriptContext; // Memory context for this function body
1460-
Pointer(Utf8SourceInfo) m_utf8SourceInfo;
1459+
FieldNoBarrier(ScriptContext*) m_scriptContext; // Memory context for this function body
1460+
Field(Utf8SourceInfo*) m_utf8SourceInfo;
14611461
// WriteBarrier-TODO: Consider changing this to NoWriteBarrierPtr, and skip tagging- also, tagging is likely unnecessary since that pointer in question is likely not resolvable
1462-
PointerNoBarrier(FunctionProxyPtr) m_referenceInParentFunction; // Reference to nested function reference to this function in the parent function body (tagged to not be actual reference)
1463-
Pointer(ScriptFunctionType) deferredPrototypeType;
1464-
Pointer(ProxyEntryPointInfo) m_defaultEntryPointInfo; // The default entry point info for the function proxy
1462+
FieldNoBarrier(FunctionProxyPtr*) m_referenceInParentFunction; // Reference to nested function reference to this function in the parent function body (tagged to not be actual reference)
1463+
Field(ScriptFunctionType*) deferredPrototypeType;
1464+
Field(ProxyEntryPointInfo*) m_defaultEntryPointInfo; // The default entry point info for the function proxy
14651465

14661466
Field(uint) m_functionNumber; // Per thread global function number
14671467

@@ -1771,7 +1771,7 @@ namespace Js
17711771
Field(bool) m_utf8SourceHasBeenSet; // start of UTF8-encoded source
17721772
Field(uint) m_sourceIndex; // index into the scriptContext's list of saved sources
17731773
#if DYNAMIC_INTERPRETER_THUNK
1774-
PointerNoBarrier(void) m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding.
1774+
FieldNoBarrier(void*) m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding.
17751775
#endif
17761776
Field(uint) m_cbStartOffset; // pUtf8Source is this many bytes from the start of the scriptContext's source buffer.
17771777

@@ -1783,10 +1783,10 @@ namespace Js
17831783

17841784
ULONG m_lineNumber;
17851785
ULONG m_columnNumber;
1786-
Pointer(const char16) m_displayName; // Optional name
1786+
Field(const char16*) m_displayName; // Optional name
17871787
uint m_displayNameLength;
1788-
Pointer(PropertyRecordList) m_boundPropertyRecords;
1789-
Pointer(NestedArray) nestedArray;
1788+
Field(PropertyRecordList*) m_boundPropertyRecords;
1789+
Field(NestedArray*) nestedArray;
17901790

17911791
public:
17921792
#if DBG
@@ -1988,16 +1988,16 @@ namespace Js
19881988
friend class ByteCodeBufferBuilder;
19891989

19901990
public:
1991-
PointerNoBarrier(SmallSpanSequence) pSpanSequence;
1991+
FieldNoBarrier(SmallSpanSequence*) pSpanSequence;
19921992

19931993
RegSlot frameDisplayRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid
19941994
RegSlot objectRegister; // this register slot cannot be 0 so we use that sentinel value to indicate invalid
1995-
Pointer(ScopeObjectChain) pScopeObjectChain;
1996-
Pointer(ByteBlock) m_probeBackingBlock; // NULL if no Probes, otherwise a copy of the unmodified the byte-codeblock //Delay
1995+
Field(ScopeObjectChain*) pScopeObjectChain;
1996+
Field(ByteBlock*) m_probeBackingBlock; // NULL if no Probes, otherwise a copy of the unmodified the byte-codeblock //Delay
19971997
int32 m_probeCount; // The number of installed probes (such as breakpoints).
19981998

19991999
// List of bytecode offset for the Branch bytecode.
2000-
Pointer(AuxStatementData) m_auxStatementData;
2000+
Field(AuxStatementData*) m_auxStatementData;
20012001

20022002
SourceInfo():
20032003
frameDisplayRegister(0),
@@ -2012,18 +2012,18 @@ namespace Js
20122012
};
20132013

20142014
private:
2015-
Pointer(ByteBlock) byteCodeBlock; // Function byte-code for script functions
2016-
Pointer(FunctionEntryPointList) entryPoints;
2017-
Pointer(Var) m_constTable;
2018-
Pointer(void*) inlineCaches;
2015+
Field(ByteBlock*) byteCodeBlock; // Function byte-code for script functions
2016+
Field(FunctionEntryPointList*) entryPoints;
2017+
Field(Var*) m_constTable;
2018+
Field(void**) inlineCaches;
20192019
InlineCachePointerArray<PolymorphicInlineCache> polymorphicInlineCaches; // Contains the latest polymorphic inline caches
2020-
Pointer(PropertyId) cacheIdToPropertyIdMap;
2020+
Field(PropertyId*) cacheIdToPropertyIdMap;
20212021

20222022
#if DBG
20232023
#define InlineCacheTypeNone 0x00
20242024
#define InlineCacheTypeInlineCache 0x01
20252025
#define InlineCacheTypeIsInst 0x02
2026-
Pointer(byte) m_inlineCacheTypes;
2026+
Field(byte*) m_inlineCacheTypes;
20272027
#endif
20282028
public:
20292029
PropertyId * GetCacheIdToPropertyIdMap()
@@ -2149,7 +2149,7 @@ namespace Js
21492149
#ifdef IR_VIEWER
21502150
// whether IR Dump is enabled for this function (used by parseIR)
21512151
bool m_isIRDumpEnabled : 1;
2152-
Pointer(Js::DynamicObject) m_irDumpBaseObject;
2152+
Field(Js::DynamicObject*) m_irDumpBaseObject;
21532153
#endif /* IR_VIEWER */
21542154

21552155
Field(uint8) bailOnMisingProfileCount;
@@ -2181,14 +2181,14 @@ namespace Js
21812181
// copied in FunctionBody::Clone
21822182
//
21832183

2184-
PointerNoBarrier(Js::ByteCodeCache) byteCodeCache; // Not GC allocated so naked pointer
2184+
FieldNoBarrier(Js::ByteCodeCache*) byteCodeCache; // Not GC allocated so naked pointer
21852185
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
21862186
static bool shareInlineCaches;
21872187
#endif
2188-
Pointer(FunctionEntryPointInfo) defaultFunctionEntryPointInfo;
2188+
Field(FunctionEntryPointInfo*) defaultFunctionEntryPointInfo;
21892189

21902190
#if ENABLE_PROFILE_INFO
2191-
Pointer(DynamicProfileInfo) dynamicProfileInfo;
2191+
Field(DynamicProfileInfo*) dynamicProfileInfo;
21922192
#endif
21932193

21942194

@@ -2642,7 +2642,7 @@ namespace Js
26422642
bool IsSimpleJitOriginalEntryPoint() const;
26432643

26442644
#if DYNAMIC_INTERPRETER_THUNK
2645-
static BYTE GetOffsetOfDynamicInterpreterThunk() { return offsetof(FunctionBody, m_dynamicInterpreterThunk); }
2645+
static BYTE GetOffsetOfDynamicInterpreterThunk() { return static_cast<BYTE>(offsetof(FunctionBody, m_dynamicInterpreterThunk)); }
26462646
void* GetDynamicInterpreterEntryPoint() const
26472647
{
26482648
return m_dynamicInterpreterThunk;

lib/Runtime/Language/EvalMapRecord.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ namespace Js
131131

132132
bool TryGetValue(const Key& key, Value* value)
133133
{
134-
EntryRecord** entryRecord;
134+
EntryRecord* const * entryRecord;
135135
Key cachedKey;
136136
int index;
137137
bool success = dictionary->TryGetReference(key, &entryRecord, &index);
@@ -168,7 +168,7 @@ namespace Js
168168

169169
void Add(const Key& key, Value value)
170170
{
171-
EntryRecord** entryRecord;
171+
EntryRecord* const * entryRecord;
172172
int index;
173173
bool success = dictionary->TryGetReference(key, &entryRecord, &index);
174174
if (success && ((*entryRecord) != nullptr))

0 commit comments

Comments
 (0)