-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
all: automatically move (some) referenced objects to heap #9873
Conversation
@@ -80,7 +80,7 @@ pub fn (mut ctx CancelContext) err() IError { | |||
|
|||
pub fn (ctx CancelContext) value(key string) ?voidptr { | |||
if key == cancel_context_key { | |||
return voidptr(&ctx) | |||
return voidptr(unsafe { &ctx }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, that is very likely a bug 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, too. I've just added what was needed to make it compile. This case needs further investigation - at least the compiler now flags such cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ulises-jeremias could you please have a look at this? Here the address of a (stack allocated) value parameter is returned. You can get an error message with the very latest version of V when you remove the unsafe
wrapper (that I've added just to make it compile).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'll change that implementation asap to prevent bugs. For now the unsafe is good until I figure out a better way to solve that 👌🏻
vlib/v/checker/checker.v
Outdated
c.error('`$node.name` cannot be referenced since it might be on stack', | ||
node.pos) | ||
} else if c.table.get_type_symbol(obj.typ).kind == .array_fixed { | ||
c.error('cannot reference fixed array `$node.name` as it might be on stack', | ||
node.pos) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For many this might be a bit surprising in a "high-level" lang which claims to do memory management on it's own. Maybe we could ease the mental shift for them by extending the error messages with ... Wrap with unsafe{} if you're sure else use the [heap] attribute..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Taking the address of something is not a high level operation imho.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've improved the error message a bit. I think it should be clear now.
Cool idea - thanks for putting thorough thoughts in it! |
is_tmp bool // for tmp for loop vars, so that autofree can skip them | ||
is_auto_heap bool // value whoes address goes out of scope | ||
is_heap_ref bool // *known* to be pointer to heap memory (ptr to [heap] struct) | ||
is_stack_obj bool // may be pointer to stack value (`mut` or `&` arg and not [heap] struct) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, can there be a situation where .is_heap_ref = true and .is_stack_obj = true at the same time?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, but there can be a situation where both are false
(the default).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps an enum with 3 states will be a less error prone representation instead of 2 bools that can get out of sync?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I don't know. Then comparisons would be needed where now a simple meaningful bool is used. I think this would make the code a tiny little bit more clumsy. 🤔
And bool
is just 1 byte whereas an enum
is 4 bytes in size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I'm thinking about resurrecting #8802. There the flag is_auto_heap
(maybe renamed to is_auto_ref
) could also be used for mut
function arguments / loop variables. So it's better to keep it separate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent work.
Great job! |
Creating references of stack objects is problematic. Example:
Here the first assertion passes and second assertion fails, because
x
points to a stack object that is overwritten by the call tog()
. (The exact behaviour depends on the compiler and the optimization being used.)There are several possible approaches to handle this problem:
pr()
in Example 2 be allowed? Or, what happens if a reference is stored in astruct
that is returned by value. Or if a function returns the address of amut
or&
argument.unsafe
). A called function assumes that a(n) argument/receiver passed asmut
or&
might be stack allocated (unless the object type has been declared as[heap]
). Thus, the function is not allowed to use this reference (outsideunsafe
) for other purposes than accessing the object. This is the approach that is implemented by this PR.With this (solution 4.) both assertions pass in Example 1 and
x
remains on stack in Example 2.