Commit 5c6e79e1 authored by caitp's avatar caitp Committed by Commit bot

[builtins] throw if TypedArray buffer is detached during iteration

Per spec change in https://github.com/tc39/ecma262/pull/724, this adds
the exception thrown when a TypedArray's array buffer is detached at
some point during iteration, after the iterator has already been
created.

BUG=v8:5388
R=littledan@chromium.org, bmeurer@chromium.org, petermarshall@chromium.org

Review-Url: https://codereview.chromium.org/2609913002
Cr-Commit-Position: refs/heads/master@{#42048}
parent db7f0169
......@@ -2277,6 +2277,9 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
typedef CodeStubAssembler::Variable Variable;
CodeStubAssembler assembler(state);
Handle<String> operation = assembler.factory()->NewStringFromAsciiChecked(
"Array Iterator.prototype.next", TENURED);
Node* iterator = assembler.Parameter(0);
Node* context = assembler.Parameter(3);
......@@ -2318,7 +2321,8 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
iterator, JSArrayIterator::kIteratedObjectMapOffset);
Node* array_map = assembler.LoadMap(array);
Label if_isfastarray(&assembler), if_isnotfastarray(&assembler);
Label if_isfastarray(&assembler), if_isnotfastarray(&assembler),
if_isdetached(&assembler, Label::kDeferred);
assembler.Branch(assembler.WordEqual(orig_map, array_map), &if_isfastarray,
&if_isnotfastarray);
......@@ -2529,35 +2533,13 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
assembler.Bind(&if_istypedarray);
{
Node* length = nullptr;
{
Variable var_length(&assembler, MachineRepresentation::kTagged);
Label if_isdetached(&assembler, Label::kDeferred),
if_isnotdetached(&assembler), done(&assembler);
Node* buffer =
assembler.LoadObjectField(array, JSTypedArray::kBufferOffset);
assembler.Branch(assembler.IsDetachedBuffer(buffer), &if_isdetached,
&if_isnotdetached);
assembler.Bind(&if_isnotdetached);
{
var_length.Bind(
assembler.LoadObjectField(array, JSTypedArray::kLengthOffset));
assembler.Goto(&done);
}
Node* buffer =
assembler.LoadObjectField(array, JSTypedArray::kBufferOffset);
assembler.GotoIf(assembler.IsDetachedBuffer(buffer), &if_isdetached);
assembler.Bind(&if_isdetached);
{
// TODO(caitp): If IsDetached(buffer) is true, throw a TypeError, per
// https://github.com/tc39/ecma262/issues/713
var_length.Bind(assembler.SmiConstant(Smi::kZero));
assembler.Goto(&done);
}
Node* length =
assembler.LoadObjectField(array, JSTypedArray::kLengthOffset);
assembler.Bind(&done);
length = var_length.value();
}
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(length));
CSA_ASSERT(&assembler, assembler.TaggedIsSmi(index));
......@@ -2755,9 +2737,16 @@ void Builtins::Generate_ArrayIteratorPrototypeNext(
// The {receiver} is not a valid JSArrayIterator.
Node* result = assembler.CallRuntime(
Runtime::kThrowIncompatibleMethodReceiver, context,
assembler.HeapConstant(assembler.factory()->NewStringFromAsciiChecked(
"Array Iterator.prototype.next", TENURED)),
iterator);
assembler.HeapConstant(operation), iterator);
assembler.Return(result);
}
assembler.Bind(&if_isdetached);
{
Node* message = assembler.SmiConstant(MessageTemplate::kDetachedOperation);
Node* result =
assembler.CallRuntime(Runtime::kThrowTypeError, context, message,
assembler.HeapConstant(operation));
assembler.Return(result);
}
}
......
......@@ -557,7 +557,7 @@ Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
dependencies()->AssumePropertyCell(
factory()->array_buffer_neutering_protector());
} else {
// Deoptimize if the array byuffer was neutered.
// Deoptimize if the array buffer was neutered.
Node* check1 = efalse0 = graph()->NewNode(
simplified()->ArrayBufferWasNeutered(), buffer, efalse0, if_false0);
check1 = graph()->NewNode(simplified()->BooleanNot(), check1);
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
function Baseline() {
let array = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let it = array[Symbol.iterator]();
assertEquals(0, it.next().value);
assertEquals(1, it.next().value);
assertEquals(2, it.next().value);
%ArrayBufferNeuter(array.buffer);
it.next();
};
%NeverOptimizeFunction(Baseline);
assertThrows(Baseline, TypeError,
"Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer");
function Turbo(count = 10000) {
let array = Array(10000);
for (let i = 0; i < 10000; ++i) {
array[i] = 254;
}
array[5000] = 255;
array = new Uint8Array(array);
let sum = 0;
let it = array[Symbol.iterator]();
for (let i = 0; i < count; ++i) {
let result = it.next();
if (result.value === 255) {
%ArrayBufferNeuter(array.buffer);
}
sum += result.value;
}
return sum;
}
Turbo(10);
Turbo(10);
%OptimizeFunctionOnNextCall(Turbo);
assertThrows(Turbo, TypeError,
"Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment