Skip to content

Conversation

@jianchun
Copy link

@jianchun jianchun commented Oct 21, 2016

Expand Pointer macro to choose WriteBarrierPtr/NoWriteBarrierPtr
based on optional Allocator type using WriteBarrierPtrTraits.
(E.g. pointer fields but using with Arena, choose NoWriteBarrierPtr.)

Add WriteBarrier function to trigger write barrier on array content
when needed.

Added CopyArray function to copy array data. Triggers write barrier
on the array content when needed.

By default only pointer types, WriteBarrierPtr wrapper, or explicit
_write_barrier_policy trigger write barrier (when using Recycler).
Users can also use template instantiation to alter custom allocator/type
write barrier policy.

This change does not handle individual Item write barrier yet.

@jianchun
Copy link
Author

Please hold on review -- Curtis suggested a better approach. Will update.

@jianchun
Copy link
Author

@dotnet-bot test Linux tests please

@jianchun
Copy link
Author

@leirocks @curtisman @digitalinfinity Please CR, thanks!

Pointer(int, TAllocator) buckets;
Pointer(EntryType, TAllocator) entries;
PointerNoBarrier(AllocatorType) alloc;
int size;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, it's better if we annotate all the fields (so annotate the non-pointer fields with Field)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, will do (paid too much attention to buckets and entries).

Allocate(&newBuckets, &newEntries, initBucketCount, initSize);

// Allocation can throw - assign only after allocation has succeeded.
SetArray<TAllocator>(this->buckets, newBuckets, initBucketCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little counterintuitive- you're setting a field in the dictionary, not the array itself, so you don't need to trigger the write barrier for every element in the array. You could argue that SetArray is getting called here because Allocate was writing to every element in the array but Allocate just does a memset without any pointers so it's probably fine to not trigger the barrier here. So in short- any reason why you can't just do this->buckets = newBuckets here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The write barrier on elements scenario is hard to understand (I'm still not too clear after asking Lei and Curtis.) this->buckets = newBuckets is fine here, but this->entries = newEntries is not. I was thinking of how we prevent accidental error. In the case of pointer field, the operator= function takes care of all scenarios, be it raw pointer, NoWriteBarrierPtr, or WriteBarrierPtr. So in comparison, I was thinking maybe we require all array assignment through this SetArray function. SetArray determines if we need write barrier or not. Possibly we can track that in clang plugin (not trivial...).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this->entries = newEntries not fine? this->entries and this->buckets are both pointer types- that is, setting them goes through the barrier on the Dictionary instance itself, not on the entries. If you assign this->entries = blah, you don't need to see all the bits corresponding to the range of memory symbolized by the entries array, you need to only set the bit corresponding to the dictionary itself, since that's the memory that has changed. That being said, you'll need to do what SetArray does when you do something like memcpy or set individual elements in the array.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this->entries = newEntries is fine when newEntries already takes care of write barrier on the array elements. So either I do it here with SetArray, or I do something similar ahead replacing js_memcpy_s with a version of CopyArray. Either approach has the concern that it is hard to know we missed one. Do you think CopyArray is safer in terms of write barrier correctness? e.g. is it possible GC collects in between js_memcpy_s and my current SetArray, and SetArray write barrier is too late?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making this change now. Revert SetArray, prefer earlier with CopyArray.

@digitalinfinity
Copy link
Contributor

        js_memcpy_s(newEntries, sizeof(EntryType) * newSize, entries, sizeof(EntryType) * count);

This probably needs the write barrier but I think you already noted that you haven't set barriers on the items themselves


Refers to: lib/Common/DataStructures/BaseDictionary.h:1020 in 9958e2f. [](commit_id = 9958e2f, deletion_comment = False)


void
RecyclerWriteBarrierManager::WriteBarrier(void * address, size_t ptrCount)
RecyclerWriteBarrierManager::WriteBarrier(void * address, size_t bytes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious- why this change?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dictionary's "entries" is an array of "EntryType" structs, not pointers.

class Recycler;
class RecyclerNonLeafAllocator;

// Dummy tag classes to mark yes/no write barrier policy
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clever- although has the potential to be a little confusing so it's worth clearly documenting this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, looks quite complex to myself...

@digitalinfinity
Copy link
Contributor

:shipit:

@jianchun
Copy link
Author

        js_memcpy_s(newEntries, sizeof(EntryType) * newSize, entries, sizeof(EntryType) * count);

I was hoping line 1046 below will take care of that. I was unsure if it would be a problem around line 1039 where we DeleteEntries(entries, ...). But line 1046 will write barrier the whole array content. Would it work?


In reply to: 255494454 [](ancestors = 255494454)


Refers to: lib/Common/DataStructures/BaseDictionary.h:1020 in 9958e2f. [](commit_id = 9958e2f, deletion_comment = False)

@digitalinfinity
Copy link
Contributor

LGTM

Expand `Pointer` macro to choose `WriteBarrierPtr/NoWriteBarrierPtr`
based on optional `Allocator` type using `WriteBarrierPtrTraits`.
(E.g. pointer fields but using with Arena, choose NoWriteBarrierPtr.)

Add `WriteBarrier` function to trigger write barrier on array content
when needed.

Added `CopyArray` function to copy array data. Triggers write barrier
on the array content when needed.

By default only pointer types, WriteBarrierPtr wrapper, or explicit
_write_barrier_policy trigger write barrier (when using Recycler).
Users can also use template instantiation to alter custom allocator/type
write barrier policy.

This change does not handle individual `Item` write barrier yet.
@jianchun
Copy link
Author

Thanks @digitalinfinity !

@jianchun jianchun merged commit e26f96b into chakra-core:swb Oct 25, 2016
jianchun pushed a commit that referenced this pull request Oct 25, 2016
Merge pull request #1797 from jianchun:wballoc

Expand `Pointer` macro to choose `WriteBarrierPtr/NoWriteBarrierPtr`
based on optional `Allocator` type using `WriteBarrierPtrTraits`.
(E.g. pointer fields but using with Arena, choose NoWriteBarrierPtr.)

Add `WriteBarrier` function to trigger write barrier on array content
when needed.

Added `CopyArray` function to copy array data. Triggers write barrier
on the array content when needed.

By default only pointer types, WriteBarrierPtr wrapper, or explicit
_write_barrier_policy trigger write barrier (when using Recycler).
Users can also use template instantiation to alter custom allocator/type
write barrier policy.

This change does not handle individual `Item` write barrier yet.
@jianchun jianchun deleted the wballoc branch October 25, 2016 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants