Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@

# Reset this number to 0 on major V8 upgrades.
# Increment by one for each non-official patch applied to deps/v8.
'v8_embedder_string': '-node.36',
'v8_embedder_string': '-node.37',

##### V8 defaults for Node.js #####

Expand Down
75 changes: 52 additions & 23 deletions deps/v8/src/builtins/typed-array-set.tq
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,61 @@ transitioning javascript builtin TypedArrayPrototypeSet(
}

try {
// 5. Let targetOffset be ? ToInteger(offset).
// 6. If targetOffset < 0, throw a RangeError exception.
let targetOffsetOverflowed: bool = false;
let attachedTargetAndLength: ValidJSTypedArrayAndLength;
let targetOffset: uintptr = 0;
if (arguments.length > 1) {
const offsetArg = arguments[1];
try {
targetOffset = ToUintPtr(offsetArg)
// On values less than zero throw RangeError immediately.
otherwise OffsetOutOfBounds,
// On UintPtr or SafeInteger range overflow throw RangeError after
// performing observable steps to follow the spec.
OffsetOverflow, OffsetOverflow;
} label OffsetOverflow {
targetOffsetOverflowed = true;
let targetOffsetOverflowed: bool = false;

// If the offset argument is not provided then the targetOffset is 0.
const offsetArg: JSAny =
arguments.length > 1 ? arguments[1] : SmiConstant(0);
typeswitch (offsetArg) {
case (offsetSmi: Smi): {
// 5. Let targetOffset be ? ToInteger(offset).
// 6. If targetOffset < 0, throw a RangeError exception.
if (offsetSmi < 0) goto OffsetOutOfBounds;
targetOffset = Unsigned(SmiUntag(offsetSmi));

// For Smi offsets, integer conversion has no side effects, so step 4
// (IsImmutableBuffer check) can be deferred and combined with steps 7-9
// in EnsureValidAndReadLength without observable differences.
// 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
// a TypeError exception.
// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
// exception.
// 9. Let targetLength be target.[[ArrayLength]].
attachedTargetAndLength = EnsureValidAndReadLength(
target, TypedArrayAccessMode::kWrite) otherwise Fail;
}
case (offsetOther: JSAny): {
// 4. If IsImmutableBuffer(target.[[ViewedArrayBuffer]]) is true, throw
// a TypeError exception.
if (IsImmutableArrayBuffer(target.buffer)) deferred {
goto Fail;
}

// 5. Let targetOffset be ? ToInteger(offset).
// 6. If targetOffset < 0, throw a RangeError exception.
try {
targetOffset = ToUintPtr(offsetOther)
// On values less than zero throw RangeError immediately.
otherwise OffsetOutOfBounds,
// On UintPtr or SafeInteger range overflow throw RangeError after
// performing observable steps to follow the spec.
OffsetOverflow, OffsetOverflow;
} label OffsetOverflow {
targetOffsetOverflowed = true;
}

// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
// exception.
// 9. Let targetLength be target.[[ArrayLength]].
attachedTargetAndLength = EnsureValidAndReadLength(
target, TypedArrayAccessMode::kWrite) otherwise Fail;
}
} else {
// If the offset argument is not provided then the targetOffset is 0.
}

// 7. Let targetBuffer be target.[[ViewedArrayBuffer]].
// 8. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError
// exception.
const attachedTargetAndLength = EnsureValidAndReadLength(
target, TypedArrayAccessMode::kWrite) otherwise Fail;

const overloadedArg = arguments[0];
try {
// 1. Choose SetTypedArrayFromTypedArray or SetTypedArrayFromArrayLike
Expand All @@ -86,7 +115,7 @@ transitioning javascript builtin TypedArrayPrototypeSet(
// 5. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError
// exception.
const attachedSourceAndLength =
EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kWrite)
EnsureValidAndReadLength(typedArray, TypedArrayAccessMode::kRead)
otherwise Fail;
TypedArrayPrototypeSetTypedArray(
attachedTargetAndLength, attachedSourceAndLength, targetOffset,
Expand Down
44 changes: 44 additions & 0 deletions deps/v8/test/mjsunit/immutable-arraybuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,3 +564,47 @@ if (this.Worker) {
assertEquals('OK', w.getMessage());
w.terminate();
}

(function testTypedArraySetOrder() {
const ab = new ArrayBuffer(8);
const imm = ab.transferToImmutable();
const immTA = new Uint8Array(imm);

let offsetEvaluated = false;
const offset = {
valueOf() {
offsetEvaluated = true;
return 0;
}
};

let sourceRead = false;
const source = {
get length() {
sourceRead = true;
return 1;
},
get 0() {
sourceRead = true;
return 42;
}
};

// 1. Immutable target throws before offset conversion or source reading
assertThrows(() => immTA.set(source, offset), TypeError);
assertFalse(offsetEvaluated, "offset should not be evaluated for immutable target");
assertFalse(sourceRead, "source should not be read for immutable target");

// 2. Mutable target can read from immutable TypedArray source
const mutableTA = new Uint8Array(8);
assertDoesNotThrow(() => mutableTA.set(immTA));

// 3. Detached target evaluates offset before throwing TypeError
const detachedAb = new ArrayBuffer(8);
const detachedTA = new Uint8Array(detachedAb);
%ArrayBufferDetach(detachedAb);

offsetEvaluated = false;
assertThrows(() => detachedTA.set([1], offset), TypeError);
assertTrue(offsetEvaluated, "offset should be evaluated for detached target");
})();
Loading