Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Freespace and finalization support in extent, using new metadata scheme #311

Closed
wants to merge 27 commits into from

Conversation

dsm9000
Copy link
Contributor

@dsm9000 dsm9000 commented Oct 12, 2023

Supercedes #307 .

Resolves #268 .

deadalnix pushed a commit that referenced this pull request Oct 13, 2023
Note: the extent side support split into #311
auto base = nativeToBigEndian(native);
auto mask = -isLarge | nativeToBigEndian!ushort(ushort(0xff));

auto current = *ptr;
auto delta = (current ^ base) & mask;
auto value = current ^ delta;
auto value = (current ^ delta) | (current & finalizerBit);
Copy link
Contributor

Choose a reason for hiding this comment

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

Change the mask instead of fetching the finalizer bit and you'll do this for free.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point, thank you.

@deadalnix
Copy link
Contributor

Let's split the packign/unpackig of the metadata in its own MR. We can use the new format even if we never using finalization.

@@ -322,6 +322,13 @@ public:
return _metadata.slabData.freeSpaceData.freeSpaceFlags;
}

bool hasFreeSpaceField(uint index) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The whole point of this diff is that this isn't a free space field anymore.

return 0;
}

// Decode freespace, found in the final byte (or two bytes) of the alloc:
return readPackedFreeSpace(freeSpacePtr(index));
}

size_t getTotalSpace(uint index) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Capacity.

"freeSpace must be set before finalizer!");

if (finalizer is null) {
*(finalizerPtr(index)) &= ~FinalizerBit;
Copy link
Contributor

Choose a reason for hiding this comment

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

you are callign that functon in all branches and sometime several times.

*/

@property
bool supportsFreeSpace() const {
bool supportsSlabMetaData() const {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this API used outside of contracts here? I have a hard time imagining it would in a way that's not a bug as the pd also has the size class.

If that's the case, it's probably preferable to inline isAppendableSizeClass in the contract themselves.

It would also be nice to rename this, because it's not just appenable anymore.

Comment on lines 405 to 408
auto finalizerFieldPtr = finalizerPtr(index);
if (!(*finalizerFieldPtr & FinalizerBit)) {
return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You may want to check that first, so you avoid the atomic check.

}

auto finalizerFieldPtr = finalizerPtr(index);
if (!(*finalizerFieldPtr & FinalizerBit)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Well int hat case you'd be better off with a == 0 instead of a bang.

assert(isSlab(), "setFinalizer accessed on non slab!");
assert(index < slotCount, "index is out of range!");
assert(hasSlabMetaData(index),
"No metadata! (must set freespace before finalizer)");
Copy link
Contributor

Choose a reason for hiding this comment

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

You want to check that finalizer & Addressmask == finalizer.

}

auto newMetaData = (*finalizerFieldPtr & ~AddressMask) | FinalizerBit;
*finalizerFieldPtr = newMetaData | cast(ulong) cast(void*) finalizer;
Copy link
Contributor

Choose a reason for hiding this comment

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

All the various longs all over the place should be size_t, the size of a pointer.

sdlib/d/gc/extent.d Outdated Show resolved Hide resolved
return 0;
}

// Decode freespace, found in the final byte (or two bytes) of the alloc:
return readPackedFreeSpace(freeSpacePtr(index));
}

size_t getTotalCapacity(uint index) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure why the capacity has to be total. What else could it be? If you insist on qualifying, then maybe getSlotCapacity, but getCapacity is probably fine, the index kinda gives it away that it's about a specific slot.

assert(index < slotCount, "index is out of range!");

return hasSlabMetaData(index)
&& (*(finalizerPtr(index)) & FinalizerBit);
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd say you want to do the checks int he opposite order, this way you can avoid snooping in the metadata when you don't have to.

Copy link
Contributor

Choose a reason for hiding this comment

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

In fact, this is likely to be false, consider that:

  • If the slot is not full, then this is probably going to be zero.
  • If it has metadata, in most cases, it won't have a finalizer: 0.
  • If there is a pointer in there, it'll the MSB, which are going to be zero.
  • If there is a number there, once again, MSB, and most numbers are small, so it's likely to be zero.
  • If there is something else in there that don't heavily bias toward zero (float, random/compressed data) we are still at 50/50.

We should expect to find a zero in there the VAST majority of the time.

Copy link
Contributor

Choose a reason for hiding this comment

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

BTW, this probably warrant a comment :P

sdlib/d/gc/extent.d Outdated Show resolved Hide resolved
return PointerSize;
}

enum FinalizerBit = nativeToBigEndian!size_t(size_t(0x2));
Copy link
Contributor

Choose a reason for hiding this comment

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

You always use a constructor here because somehow VRP doesn't kick in when calling the function, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct for the one in the test, but it seems to default to size_t in fact. This one can be cut

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.

Add support for finalizer in the GC
2 participants