archives

« Bugzilla Issues Index

#3694 — 22.2.3.22.2%TypedArray%.prototype.set: Special case same element to allow memmove?


22.2.3.22.2%TypedArray%.prototype.set(typedArray [, offset ] )

Implementors like their memmoves, but the loop in step 28 makes it impossible to use memmove for Float32/64 because of NaN canonicalization in GetValueFromBuffer.


Looking at ArrayBuffer SetValueInBuffer, it seems that the only things that prevents using memmove is that fact the SetValueInBuffer says that NaNs must be stored as non-signaling value. So, if somebody had placed placed signaling NaN bit patterns into the source buffer, the current language requires that an implementation transform them.

I'm think I probably originally inserted the "non-signaling" language into the spec and now it isn't clear to me that it has any value given that any possible bit value can be placed into an ArrayBuffer by attaching an appropiate view to it.
I'm inclined to simply delete the words "non-signaling" from the SetValueInBuffer spec.

To you think this is reasonable and sufficient?

I'm also inclined to put a statement somewhere in the TypedArray section that says that a bit level transfer must occur anytime an algorithm retrieves a value from a typed array using [[Get]] and immediately stores it back into a typed array, of the same type, using [[Set]]. It seem this would have to be stated as a mandatory requirement, in order to avoid interop hazards.


> anytime an algorithm retrieves a value from a typed array using [[Get]] and
> immediately stores it back into a typed array, of the same type, using [[Set]].

I don't think this is viable. How would you define "immediately"? When doing a [[Set]] of a NaN, I agree we don't need to say "non-signaling", but we still need to allow any NaN bit pattern.


(In reply to Mark Miller from comment #2)
> > anytime an algorithm retrieves a value from a typed array using [[Get]] and
> > immediately stores it back into a typed array, of the same type, using [[Set]].
>
> I don't think this is viable. How would you define "immediately"? When doing
> a [[Set]] of a NaN, I agree we don't need to say "non-signaling", but we
> still need to allow any NaN bit pattern.

By immediately I mean equivalently to doing a [[Get]] immediately followed by a [[Set]] with no interesting operations between them. The language can be tweaked, as necessary to make that precise enough.

I'm not sure what you're trying to say in your last sentence. Are you saying that it is important that an implementation is allowed (but not required) to change NaN patterns on any such [[Get]]/[[Set]] sequence. If so, then there may be observable difference between implementations and it might even revealing of implementation details such as its preferred.

finally, I assume that implementations already do memmove where ever they think they can. What we are trying to do here is make sure that we don't unintentionally have spec. languages that says they can't do that.


(In reply to Allen Wirfs-Brock from comment #3)
> (In reply to Mark Miller from comment #2)
> > > anytime an algorithm retrieves a value from a typed array using [[Get]] and
> > > immediately stores it back into a typed array, of the same type, using [[Set]].
> >
> > I don't think this is viable. How would you define "immediately"? When doing
> > a [[Set]] of a NaN, I agree we don't need to say "non-signaling", but we
> > still need to allow any NaN bit pattern.
>
> By immediately I mean equivalently to doing a [[Get]] immediately followed
> by a [[Set]] with no interesting operations between them. The language can
> be tweaked, as necessary to make that precise enough.

Perhaps, depending on what you mean by "interesting". But I don't understand what you'd be accomplishing. It seems weird to me that

const x = ta[i];
ta[j] = x;

means something different than

const x = ta[i];
noop();
ta[j] = x;

This non-equivalence breaks what are otherwise algebraic properties of the language that code transformation tools (including transpilers) depend on. This non-equivalence would, AFAICT, be an unprecedented special case in the language semantics.


> I'm not sure what you're trying to say in your last sentence. Are you saying
> that it is important that an implementation is allowed (but not required)
> to change NaN patterns on any such [[Get]]/[[Set]] sequence.

When they are being gotten as floating point numbers, yes.


> If so, then
> there may be observable difference between implementations and it might even
> revealing of implementation details such as its preferred.

In for a penny....

We already paid this cost when we allowed storing a NaN to store any NaN bit pattern. Since we only have one abstract NaN value at the JavaScript level, and we decided we can't afford to canonicalize the bit pattern, I don't see that we have any other choice.


> finally, I assume that implementations already do memmove where ever they
> think they can. What we are trying to do here is make sure that we don't
> unintentionally have spec. languages that says they can't do that.

Having the spec allow the implementation more freedom does not threaten this.


(In reply to Mark Miller from comment #4)
>
> Perhaps, depending on what you mean by "interesting". But I don't understand
> what you'd be accomplishing. It seems weird to me that
>
> const x = ta[i];
> ta[j] = x;
>
> means something different than
>
> const x = ta[i];
> noop();
> ta[j] = x;
>

I'm not talking about JS level code. I'm talking about spec. algorithms like the substeps on step 28 of http://people.mozilla.org/~jorendorff/es6-draft.html#sec-%typedarray%.prototype.set-typedarray-offset which looks like:

28. Repeat, while targetByteIndex < limit
a. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType).
b. Let status be SetValueInBuffer (targetBuffer, targetByteIndex, targetType, value).
c. Set srcByteIndex to srcByteIndex + srcElementSize.
d. Set targetByteIndex to targetByteIndex + targetElementSize.

These aren't even actual [[Get]] or [[Set]] mop operations but the direct buffer access that are used to implemented [[Get]] and [[Set]].









> This non-equivalence breaks what are otherwise algebraic properties of the
> language that code transformation tools (including transpilers) depend on.
> This non-equivalence would, AFAICT, be an unprecedented special case in the
> language semantics.
>
>
> > I'm not sure what you're trying to say in your last sentence. Are you saying
> > that it is important that an implementation is allowed (but not required)
> > to change NaN patterns on any such [[Get]]/[[Set]] sequence.
>
> When they are being gotten as floating point numbers, yes.
>
>
> > If so, then
> > there may be observable difference between implementations and it might even
> > revealing of implementation details such as its preferred.
>
> In for a penny....
>
> We already paid this cost when we allowed storing a NaN to store any NaN bit
> pattern. Since we only have one abstract NaN value at the JavaScript level,
> and we decided we can't afford to canonicalize the bit pattern, I don't see
> that we have any other choice.
>
>
> > finally, I assume that implementations already do memmove where ever they
> > think they can. What we are trying to do here is make sure that we don't
> > unintentionally have spec. languages that says they can't do that.
>
> Having the spec allow the implementation more freedom does not threaten this.


I see. I misunderstood. I withdraw the objection. Looks fine to me.


fixed in rev34 editor's draft

In the end, I decided that the best thing to do was to explicitly specify encoding preserving data transfers in the situations where that makes sense.

the three places are TypedType copyWithin, slice, and set(TypedArray)


fixed in rev34