-
-
Notifications
You must be signed in to change notification settings - Fork 609
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 22306 - scope array variable should be stack allocated #14562
Conversation
Thanks for your pull request and interest in making D better, @dkorpel! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla references
Testing this PR locallyIf you don't have a local development environment setup, you can use Digger to test this PR: dub run digger -- build "master + dmd#14562" |
Hum, the real MVP here would be to support |
I know two kinds of MVP, do you refer to "Minimum viable" or "Most valuable"? Because the run time value makes it a lot harder. You need to decide on a good size cap to prevent stack overflow, and dynamically switch at runtime. It can't statically be |
static arrays already have a limit, how about re-using that ?
That's the whole point. Instead of dynamically switching at runtime, you just give a hard error. It's easy enough to check beforehand.
Actually I was thinking "Most Valuable Player" but not sure my usage was right 🙃 |
That limit is far above a typical stack size. I'm basically asking for stack overflow if I write this: void main() {
ubyte[32*1024*1024] x; // Initializes 32 Mb of stack memory
} But here, I don't want the compiler to irresponsibly move this GC allocation to the stack: void main() {
scope ubyte[] x = new ubyte[](32*1024*1024);
}
When I use the
I think it's right, I'm just not used to hearing it in a software context where "Minimum Viable Product" is more prevalent. |
A general framework for moving gc allocations either onto the stack or malloc and free or whatever would be good but requires a level of trust in the rest of the frontend that I don't really have |
A test involving a scope array and a closure would be good, i.e. to make sure it ends up on the correct "stack" |
If you want GC promotions to the stack, use LDC |
Exactly my thought aswell. Such an optimization could have unforeseen (big) benefits to performance of allocation-heavy code. Moreover if the compiler could track uniqueness of array references it could do even more awesome optimizations like understanding that Cases such as void f()
{
class C { int x; }
scope c = new C(); // c is freed at the end of f()
} already uses |
No it doesn't. It's stack allocated, not
It's an optimization, which is great, but has the major downsides of all optimizations: It cannot be enforced (easily & statically).
What's a typical stack size ? There are a myriad of ways to control stack size (ulimit, fibers) and thus there's no "Right default".
Out of memory happens when an allocation can't be performed. Where the allocation is, that's an implementation detail. Remember we have different types of GC. Also you can do this currently: class Foobar
{
int[32*1024*1024 - 1] loads;
}
void main () @nogc
{
scope f = new Foobar;
} And yes it SEGV. |
Ok, sorry. My mistake. I've overstriked it.
Would be worthwhile looking into if GCC/Clang statically diagnoses corresponding C++ code as an error: Clang allows class C { int data[1*1024*1024*1024]; }; whereas disallows class C { int data[2*1024*1024*1024]; }; with output
. |
Co-authored-by: Max Haughton <[email protected]>
It doesn't disallow it. It just overflows the integer constant, leading to a negative size, and |
1 Mb on Windows, 8 Mb on linux.
In any case, you generally want to keep a function's stack frame under 4 Kb. Even if you don't overflow, large allocations can degrade cache performance, so it's not always better to move from the heap to the stack.
Here's a compliant implementation of void* malloc(size_t sz) { return null; } That it actually attempts to allocate memory that the system has is also an implementation detail, but one that's very important to users.
That's still a static size, so the compiler can (and should) diagnose that. I don't think it's a pressing issue though, classes usually don't have a huge instance size. |
@dkorpel could you please follow this up with a spec PR? |
Oops. Thanks. |
|
class Foobar
{
int[32*1024*1024 - 1] loads;
}
void main () @nogc
{
scope f = new Foobar;
}
@Geod24 interesting, is this filed in bugzilla? |
This includes a backend change @kinke @ibuclaw. I tried to make it a rewrite like in #11039, but didn't find a way to declare a temporary static array in the parent scope so it wouldn't immediately be destructed after the array literal assignment. So currently, I'm mirroring the way it's done with
scope Object o = new Object()
and keep anonstack
variable.