-
-
Notifications
You must be signed in to change notification settings - Fork 405
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
Introduce NonMaxU32 for array index #2131
Conversation
Codecov Report
@@ Coverage Diff @@
## main #2131 +/- ##
==========================================
- Coverage 43.48% 43.43% -0.06%
==========================================
Files 220 221 +1
Lines 19983 20009 +26
==========================================
+ Hits 8689 8690 +1
- Misses 11294 11319 +25
Continue to review full report at Codecov.
|
da9d764
to
6559c96
Compare
Based on the definition in spec, [array index][] is only valid from zero to u32::MAX - 1. It would be helpful to use the NonMaxU32 type to define it as the property key instead so that contributors won't forget to check the validity. [array index]: https://tc39.es/ecma262/#array-index
6559c96
to
f18bf35
Compare
Test262 conformance changesVM implementation
Fixed tests (2):
|
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.
Looks very good! Thanks for the fix. I added some comments regarding some potential enhancements. I would like to also get inputs from the rest of the team, since some of the options might just be too much, or might not make sense.
Oh, and tests seem to be failing in MacOS and Windows, so these need to be fixed.
// Safety: `NonMaxU32` does not contain any objects which needs to be traced, | ||
// so this is safe. | ||
unsafe impl Trace for NonMaxU32 { | ||
unsafe_empty_trace!(); | ||
} |
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 would suggest to just not implement this, and use #[unsafe_ignore_trace]
in the enum
(if that's allowed). It should be more performant.
/// ``` | ||
#[derive(Copy, Clone, Eq, Finalize, PartialEq, Ord, PartialOrd, Hash)] | ||
#[repr(transparent)] | ||
pub struct NonMaxU32(u32); |
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 would suggest the internal type to be not an enum type and be a structure type:
pub struct NonMaxU32 {
inner: u32,
}
This would disallow direct editing of the internal structure (having to use getters and setters), and changing the internal type would be API compatible.
Talking about changing the internal type, it might be useful to use a NonZeroU32
, which is better optimized for space. On the other hand, this would require using a +1
when storing, and a -1
when retrieving, which could cause a small performance penalty. We should test both options.
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.
Sorry for late reply 🙏 Thank you for your suggestion! I will try to work on a fix.
On the other hand, this would require using a +1 when storing, and a -1 when retrieving, which could cause a small performance penalty.
This sounds a good idea to me. I experimented a bit using XOR to save with NonZeroU32
like the nonmax crate does last week but I realized we would need to rev()
the iterator because the xor'ed value would be in reversed order. So, I wonder just +1 and -1 would be easier.
I will try it more and share more information here or on Discord 🙏 Thank you!
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 I'm ok with either approach (-1/+1 or XOR).
pub const fn get(self) -> u32 { | ||
self.0 | ||
} |
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.
Should we also include setters? And operations such as add, sub, mul and so on?
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'm good with adding these methods though, I wonder it also depends on how we want to use it. Do we want to always do calculation with NonMaxU32
directly?
On the other hand, I wonder it might be good to at least add methods like checked_add
or saturating_add
on NonZeroU32
.
WDYT?
impl fmt::Debug for NonMaxU32 { | ||
#[inline] | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
self.get().fmt(f) | ||
} | ||
} |
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.
This might be a good implementation for Display
, but I would say the Debug
implementation shouldn't hide the internal structure. I'm open to suggestions, though.
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 tried to follow NonZeroU32
debug though, it sounds fine to me to format it like NonMaxU32 { inner: 42 }
.
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.
Agree with Razican
impl BitOr for NonMaxU32 { | ||
type Output = Self; | ||
#[inline] | ||
fn bitor(self, rhs: Self) -> Self::Output { | ||
// Safety: since `self` and `rhs` are both nonzero, the | ||
// result of the bitwise-or will be nonzero. | ||
unsafe { NonMaxU32::new_unchecked(self.get() | rhs.get()) } | ||
} | ||
} | ||
|
||
impl BitOr<u32> for NonMaxU32 { | ||
type Output = Self; | ||
|
||
#[inline] | ||
fn bitor(self, rhs: u32) -> Self::Output { | ||
// Safety: since `self` is nonzero, the result of the | ||
// bitwise-or will be nonzero regardless of the value of | ||
// `rhs`. | ||
unsafe { NonMaxU32::new_unchecked(self.get() | rhs) } | ||
} | ||
} | ||
|
||
impl BitOr<NonMaxU32> for u32 { | ||
type Output = NonMaxU32; | ||
|
||
#[inline] | ||
fn bitor(self, rhs: NonMaxU32) -> Self::Output { | ||
// Safety: since `rhs` is nonzero, the result of the | ||
// bitwise-or will be nonzero regardless of the value of | ||
// `self`. | ||
unsafe { NonMaxU32::new_unchecked(self | rhs.get()) } | ||
} | ||
} |
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.
The "Safety" argument and code seems to be copied from the nonzero implementaion and is not correct. (At least the comment is wrong)
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.
Need to introduce +1/-1 or XOR on accesses. fix the safety comments and correct the safety comments.
Hey @CYBAI how is this going do you need any help? |
Sorry for very late reply 🙏 I'll try to find some time to address the comments and update the PR after mid-Jan 🙇 |
Added in #3321 |
It changes the following:
NonMaxU32
typeNonMaxU32
for index property key instead ofu32
While looking into the failed
built-ins/Reflect/ownKeys/return-on-corresponding-order-large-index.js
in test262, I found that the root cause is related toarray index
for property keys.The root cause of the failure is, the test uses
u32::MAX
as key and we're ordering it wrong because we seeu32::MAX
as a array index instead of an integer index. Based on the spec, array index's range is from 0 <= n < u32::MAX so the max number is exclusive.We can avoid transforming
u32::MAX
into property key in some functions likeFrom<T>
traits though, it might be forgettable and error-prone. So, I wonder it might be good to introduce theNonMaxU32
type which is similar toNonZeroU32
in std but excluding max instead.Then, we can use it for the index property key
With doing so, we can always guarantee the integer hold by Index property key is valid.
WDYT?
(On the other hand, I'm not sure where is the best place for such types. Please feel free to let me know if I should move it to other places 🙏)