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

Fix Issue 17153 – Make std.container.array @nogc #5036

Merged
merged 1 commit into from
Feb 20, 2017

Conversation

JackStouffer
Copy link
Member

Despite Array not using the GC for allocating its elements, it was still unusable for @nogc code because of its use of throw and enforce.

This PR turns those into asserts and makes the majority of the functions @nogc.

@JackStouffer
Copy link
Member Author

@andralex requesting your review because this is a breaking change.

@JackStouffer JackStouffer requested a review from andralex January 15, 2017 13:35
@JackStouffer JackStouffer changed the title Removed GC allocations from std.container.array Make std.container.array @nogc Jan 15, 2017
@@ -142,26 +142,26 @@ private struct RangeT(A)

E moveFront()
{
version (assert) if (empty || _a >= _outer.length) throw new RangeError();
assert(!empty || _a < _outer.length);
Copy link
Contributor

Choose a reason for hiding this comment

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

Unless I'm having a dumb moment, this should use &&. !(foo || bar) = !foo && !bar. Same mistake throughout.

@JackStouffer
Copy link
Member Author

@wilzbach The coverage report that DMD generates and the coverage that appears on codecov are different.

@JackStouffer JackStouffer changed the title Make std.container.array @nogc Fix Issue 17153 – Make std.container.array @nogc Feb 7, 2017
@JackStouffer JackStouffer added this to the 2.074.0 milestone Feb 8, 2017
Copy link
Member

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

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

LGTM, but I am not sure how far @andralex is on his journey to make it possible to use exceptions in @nogc?

@wilzbach
Copy link
Member

@wilzbach The coverage report that DMD generates and the coverage that appears on codecov are different.

That looks pretty weird and I am not sure how to fix this. Maybe @stevepeak (from CodeCov) knows the reason for this issue with CodeCov?

@JackStouffer
Copy link
Member Author

but I am not sure how far @andralex is on his journey to make it possible to use exceptions in @nogc?

Requires @safe RC which requires escape analysis which requires DIP1000 to be completed.

Copy link
Member

@PetarKirov PetarKirov left a comment

Choose a reason for hiding this comment

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

Some late review comments

auto newPayload =
enforce(cast(T*) malloc(sz))[0 .. oldLength];

auto newPayloadPtr = cast(T*) malloc(sz);
Copy link
Member

Choose a reason for hiding this comment

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

Consider using pureMalloc next time ;)

_outer[_b - 1] = value;
}
/// Ditto
T moveBack()
{
enforce(!empty);
assert(!empty, "Attempting to mpve the back of an empty Array");
Copy link
Member

Choose a reason for hiding this comment

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

move typo

@stevepeak
Copy link

Hey @wilzbach can you check if the webhook is setup and sending to Codecov? Status was waiting on a webhook. Thank you!

Copy link
Member

@andralex andralex left a comment

Choose a reason for hiding this comment

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

OK, there's a fair amount of stuff to discuss here.

First, there are a few version(assert) things that throw a different exception. These are safe to commit. Yes, there is a technical breakage, but a palatable one.

Second, there are a few memory allocations that have been changed from enforce to assert. That makes them UB. We don't want that. It should be okay to finish the application upon allocation failure, but not UB.

Third, the bulk is a change in philosophy. Currently, calling front against an empty container caused an exception, so it was defined behavior. This PR makes it undefined. This is definitely not OK for backwards compatibility.

Instead, I propose to make a small PR with the noncontroversial changes in it.

Second, change the remaining instances of enforce with throwing a statically-allocated exception similar to dlang/druntime#1710. That way we'd technically break code (what if someone collects an array of exceptions?) but the scope would be smaller.

The saving grace of this is the documentation doesn't specify current behavior, so we're free to do as we please :). Please accompany this and the following PRs with appropriate documentation changes.

Thanks!

enforce(cast(T*) malloc(sz))[0 .. oldLength];

auto newPayloadPtr = cast(T*) malloc(sz);
assert(newPayloadPtr, "std.container.Array.reserve failed to allocate memory");
Copy link
Member

Choose a reason for hiding this comment

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

Let's do this: newPayloadPtr || assert(false, "std.container.Array.reserve failed to allocate memory");

enforce(cast(T*) realloc(_payload.ptr, sz))[0 .. length];
auto newPayloadPtr = cast(T*) realloc(_payload.ptr, sz);
assert(newPayloadPtr, "std.container.Array.reserve failed to allocate memory");
auto newPayload = newPayloadPtr[0 .. length];
Copy link
Member

Choose a reason for hiding this comment

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

Same here, end the app if no memory.

@@ -547,7 +550,8 @@ Complexity: $(BIGOH 1)
bool overflow;
const sz = mulu(elements, T.sizeof, overflow);
if (overflow) assert(0);
auto p = enforce(malloc(sz));
auto p = malloc(sz);
assert(p);
Copy link
Member

Choose a reason for hiding this comment

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

Same here, end the app if no memory.

@@ -805,7 +809,7 @@ Complexity: $(BIGOH log(n)).
*/
void removeBack()
{
enforce(!empty);
assert(!empty);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

@@ -855,7 +859,7 @@ Complexity: $(BIGOH n + m), where $(D m) is the length of $(D stuff)
if (isImplicitlyConvertible!(Stuff, T))
{
import std.conv : emplace;
enforce(r._outer._data is _data && r._a <= length);
assert(r._outer._data is _data && r._a <= length);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

return cast(bool)(data.back & (cast(size_t)1 << ((_store._length - 1) % bitsPerWord)));
}

/// Ditto
@property void back(bool value)
{
enforce(!empty);
assert(!empty);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

@@ -1767,15 +1788,15 @@ if (is(Unqual!T == bool))
{
auto div = cast(size_t) (i / bitsPerWord);
auto rem = i % bitsPerWord;
enforce(div < data.length);
assert(div < data.length);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

return cast(bool)(data.ptr[div] & (cast(size_t)1 << rem));
}
/// ditto
void opIndexAssign(bool value, size_t i)
{
auto div = cast(size_t) (i / bitsPerWord);
auto rem = i % bitsPerWord;
enforce(div < data.length);
assert(div < data.length);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

@@ -1784,7 +1805,7 @@ if (is(Unqual!T == bool))
{
auto div = cast(size_t) (i / bitsPerWord);
auto rem = i % bitsPerWord;
enforce(div < data.length);
assert(div < data.length);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

@@ -2050,7 +2071,7 @@ if (is(Unqual!T == bool))
*/
void removeBack()
{
enforce(_store._length);
assert(_store._length);
Copy link
Member

Choose a reason for hiding this comment

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

Does not belong with this PR, it's a (breaking) change in philosophy.

@wilzbach
Copy link
Member

@wilzbach The coverage report that DMD generates and the coverage that appears on codecov are different.

The problem is that we merge the upstream branch into the PR and thus generate slightly different .lst files. This is also the reason why codecov/project appears to be fluctuating so often.
I opened a support issue at CodeCov: https://github.com/codecov/support/issues/360

@JackStouffer JackStouffer force-pushed the nogc-Array branch 2 times, most recently from b653798 to 5f5a444 Compare February 20, 2017 19:37
@JackStouffer
Copy link
Member Author

@andralex Removed controversial changes

@andralex
Copy link
Member

Auto-merge toggled on

@andralex andralex merged commit 2a97fb4 into dlang:master Feb 20, 2017
@JackStouffer JackStouffer deleted the nogc-Array branch May 22, 2017 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants