Skip to content
This repository was archived by the owner on Oct 24, 2023. It is now read-only.

Account for resize-in-the-middle in TA methods #74

Closed
wants to merge 6 commits into from

Conversation

syg
Copy link
Collaborator

@syg syg commented Sep 10, 2021

Closes #73

At a high-level:

  • Lengths are cached at the beginning of methods.
  • Any element copy where all bytes of the element are within bounds are,
    the copy is performed with GetValueFromBuffer and SetValueInBuffer to
    preserve byte-level encoding.
  • If the length changed due to a resize-in-the-middle, then an element
    copy can be partially out of bounds either in source or in target. In
    that case, the copy is done with Get and Set.

syg added 2 commits September 10, 2021 12:20
Closes #73

At a high-level:

- Lengths are cached at the beginning of methods.
- Any element copy where all bytes of the element are within bounds are,
  the copy is performed with GetValueFromBuffer and SetValueInBuffer to
  preserve byte-level encoding.
- If the length changed due to a resize-in-the-middle, then an element
  copy can be partially out of bounds either in source or in target. In
  that case, the copy is done with Get and Set.
@syg syg requested a review from marjakh September 10, 2021 21:13
@syg
Copy link
Collaborator Author

syg commented Sep 10, 2021

@marjakh It might be easier to review this by downloading the fork and viewing docs/index.html locally.

1. If _count_ > 0, then
1. NOTE: The copying must be performed in a manner that preserves the bit-level encoding of the source data.
1. Let _buffer_ be _O_.[[ViewedArrayBuffer]].
1. <ins>Let _regetBufferByteLength_ to MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).</ins>
Copy link
Contributor

Choose a reason for hiding this comment

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

Small typo here and in "slice":

-1. <ins>Let _regetBufferByteLength_ to MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).</ins>
+1. <ins>Let _regetBufferByteLength_ be MakeIdempotentArrayBufferByteLengthGetter(~SeqCst~).</ins>

...though I wonder what you think about re-assigning "getBufferByteLength" instead. While a distinct variable highlights the consideration we're making, it also insinuates that there's further need for the original closure. As I understand it, we do not need or want the original value of "getBufferByteLength" at this point, so over-writing it would be more clear from that perspective. We could use an informative note to underscore the consideration and also explain it a bit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It is a bit confusing, but the original closure could still be used. The reason this idempotent getter exists is to avoid multiple shared memory loads of the length, because each such load is always observable. So the getter loads it once and caches it. Once cached, you could re-use the getter. It's... not a great solution, and probably warrants a bigger refactor when we're getting ready for Stage 4. I'd like to discuss with the other editors what's a clearer way here.

Copy link
Contributor

Choose a reason for hiding this comment

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

My suggestion is editorially-motivated. While the original closure could still be used, I can't think of a case where the cached value would be pertinent. By storing the new closure in a new variable, the text suggests that such a case exists, and it presents a hazard for future editors who may mistakenly use "getBufferByteLength" instead of "regetBufferByteLength".

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fair enough, but I think the bigger problem is that the idempotent getter thing is just not a very clear mechanism to begin with. Happy to change it here to setting.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, if you expect this will be refactored, then I agree that this isn't so important. Though we still ought to correct the grammar ("to" to "be").

Copy link

@marjakh marjakh left a comment

Choose a reason for hiding this comment

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

lgtm (didn't review every line, but the overall thing looks correct)

(Re: whether to reuse the same variable as jugglingmike suggests, I don't have an opinion. Either way is fine by me.)

@marjakh
Copy link

marjakh commented Sep 13, 2021

(Now I actually ended up reading every line :) )

@marjakh
Copy link

marjakh commented Sep 15, 2021

Q: don't we need to reload the length also in ArrayBuffer.prototype.slice?

@syg
Copy link
Collaborator Author

syg commented Sep 15, 2021

Q: don't we need to reload the length also in ArrayBuffer.prototype.slice?

This PR does that in step 16.i, here in the source. Did I miss it somewhere else?

@@ -596,7 +671,9 @@ <h1>%TypedArray%.prototype.slice ( _start_, _end_ )</h1>
<emu-alg>
1. Let _O_ be the *this* value.
1. Perform ? ValidateTypedArray(_O_).
1. Let _len_ be _O_.[[ArrayLength]].

This comment was marked as off-topic.

This comment was marked as off-topic.

@marjakh
Copy link

marjakh commented Sep 16, 2021

Q: don't we need to reload the length also in ArrayBuffer.prototype.slice?

This PR does that in step 16.i, here in the source. Did I miss it somewhere else?

That line is in %TypedArray%.prototype.slice, no? I'm talking about ArrayBuffer.prototype.slice.

@syg
Copy link
Collaborator Author

syg commented Sep 16, 2021

Quite right, I missed the AB and SAB methods. Will fix.

syg added a commit that referenced this pull request Sep 17, 2021
Closes #73

At a high-level:

- Lengths are cached at the beginning of methods.
- Only in-bounds elements are copied.

Together, this means that the result TAs have the snapshotted length at
the beginning of the method. If the source TA's buffer shrunk due to
the species constructor, the elements between [newShrunkLen,
originalLen) in the result TA remain 0.

This is an alternative solution to #74. In #74, elements between
[newShrunkLen, originalLen) are set to the result of OOB [[Get]]s on the
source TA.  While doing so is maximally consistent with the Array
versions of these methods, it turns out to be really weird for
floating-point TAs. For OOB [[Get]]s on TAs returns `undefined`, and
setting `undefined` in Float32Arrays and Float64Arrays coerces to NaN.
This means extra complexity and code implementations have to do for an
edge case (resize-in-the-middle) that's bad practice anyway.
@syg
Copy link
Collaborator Author

syg commented Nov 1, 2021

Closing this in favor of #75

@syg syg closed this Nov 1, 2021
syg added a commit that referenced this pull request Nov 1, 2021
Closes #73

At a high-level:

- Lengths are cached at the beginning of methods.
- Only in-bounds elements are copied.

Together, this means that the result TAs have the snapshotted length at
the beginning of the method. If the source TA's buffer shrunk due to
the species constructor, the elements between [newShrunkLen,
originalLen) in the result TA remain 0.

This is an alternative solution to #74. In #74, elements between
[newShrunkLen, originalLen) are set to the result of OOB [[Get]]s on the
source TA.  While doing so is maximally consistent with the Array
versions of these methods, it turns out to be really weird for
floating-point TAs. For OOB [[Get]]s on TAs returns `undefined`, and
setting `undefined` in Float32Arrays and Float64Arrays coerces to NaN.
This means extra complexity and code implementations have to do for an
edge case (resize-in-the-middle) that's bad practice anyway.
syg added a commit that referenced this pull request Nov 1, 2021
Closes #73

At a high-level:

- Lengths are cached at the beginning of methods.
- Only in-bounds elements are copied.

Together, this means that the result TAs have the snapshotted length at
the beginning of the method. If the source TA's buffer shrunk due to
the species constructor, the elements between [newShrunkLen,
originalLen) in the result TA remain 0.

This is an alternative solution to #74. In #74, elements between
[newShrunkLen, originalLen) are set to the result of OOB [[Get]]s on the
source TA.  While doing so is maximally consistent with the Array
versions of these methods, it turns out to be really weird for
floating-point TAs. For OOB [[Get]]s on TAs returns `undefined`, and
setting `undefined` in Float32Arrays and Float64Arrays coerces to NaN.
This means extra complexity and code implementations have to do for an
edge case (resize-in-the-middle) that's bad practice anyway.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

slice & other TypedArray.prototype funcs: shouldn't we reload the length?
3 participants