Revert of [typedarrays] move %TypedArray%.prototype.copyWithin to C++ (patchset #6 id:100001 of https://codereview.chromium.org/2671233002/ )

Reason for revert:
Due to security issue described in review thread.

Original issue's description:
> [typedarrays] move %TypedArray%.prototype.copyWithin to C++
>
> - Removes shared InnerArrayCopyWithin JS builtin from src/js/array.js
> - Implements %TypedArray%.prototype.copyWithin as a C++ builtin, which
> relies on std::memmove rather than accessing individual eleements.
> - Fixes the case where copyWithin is invoked on a TypedArray with a
> detached buffer.
> - Add tests to ensure that +/-Infinity (for all 3 parameters) is handled correctly by the
> algorithm
>
> The C++ version gets through the benchmark more than 25000 times as
> quickly as the JS implementation.
>
> BUG=v8:5925, v8:5929, v8:4648
> R=cbruni@chromium.org, adamk@chromium.org, littledan@chromium.org
>
> Review-Url: https://codereview.chromium.org/2671233002
> Cr-Commit-Position: refs/heads/master@{#42975}
> Committed: 0f1c626d55

TBR=cbruni@chromium.org,adamk@chromium.org,bmeurer@chromium.org,cwhan.tunz@gmail.com,caitp@igalia.com
# Not skipping CQ checks because original CL landed more than 1 days ago.
BUG=v8:5925, v8:5929, v8:4648

Review-Url: https://codereview.chromium.org/2693753002
Cr-Commit-Position: refs/heads/master@{#43132}
This commit is contained in:
littledan 2017-02-12 13:16:18 -08:00 committed by Commit bot
parent 32ed62911f
commit 4530f0dc0c
7 changed files with 29 additions and 158 deletions

View File

@ -2483,10 +2483,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
values->shared()->set_builtin_function_id(kTypedArrayValues);
JSObject::AddProperty(prototype, factory->iterator_symbol(), values,
DONT_ENUM);
// TODO(caitp): alphasort accessors/methods
SimpleInstallFunction(prototype, "copyWithin",
Builtins::kTypedArrayPrototypeCopyWithin, 2, false);
}
{ // -- T y p e d A r r a y s

View File

@ -167,95 +167,5 @@ void Builtins::Generate_TypedArrayPrototypeKeys(
state, "%TypedArray%.prototype.keys()");
}
namespace {
MaybeHandle<JSTypedArray> ValiadateTypedArray(Isolate* isolate,
Handle<Object> receiver,
const char* method_name) {
if (V8_UNLIKELY(!receiver->IsJSTypedArray())) {
const MessageTemplate::Template message = MessageTemplate::kNotTypedArray;
THROW_NEW_ERROR(isolate, NewTypeError(message), JSTypedArray);
}
Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(receiver);
if (V8_UNLIKELY(array->WasNeutered())) {
const MessageTemplate::Template message = MessageTemplate::kNotTypedArray;
Handle<String> operation =
isolate->factory()->NewStringFromAsciiChecked(method_name);
THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
}
return array;
}
int64_t CapRelativeIndex(Handle<Object> num, int64_t minimum, int64_t maximum) {
int64_t relative;
if (V8_LIKELY(num->IsSmi())) {
relative = Smi::cast(*num)->value();
} else {
DCHECK(num->IsHeapNumber());
double fp = HeapNumber::cast(*num)->value();
if (V8_UNLIKELY(!std::isfinite(fp))) {
// +Infinity / -Infinity
DCHECK(!std::isnan(fp));
return fp < 0 ? minimum : maximum;
}
relative = static_cast<int64_t>(fp);
}
return relative < 0 ? std::max<int64_t>(relative + maximum, minimum)
: std::min<int64_t>(relative, maximum);
}
} // namespace
BUILTIN(TypedArrayPrototypeCopyWithin) {
HandleScope scope(isolate);
Handle<JSTypedArray> array;
const char* method = "%TypedArray%.prototype.copyWithin";
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, array, ValiadateTypedArray(isolate, args.receiver(), method));
int64_t len = array->length_value();
int64_t to = 0;
int64_t from = 0;
int64_t final = len;
if (V8_LIKELY(args.length() > 1)) {
Handle<Object> num;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num, Object::ToInteger(isolate, args.at<Object>(1)));
to = CapRelativeIndex(num, 0, len);
if (args.length() > 2) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num, Object::ToInteger(isolate, args.at<Object>(2)));
from = CapRelativeIndex(num, 0, len);
Handle<Object> end = args.atOrUndefined(isolate, 3);
if (!end->IsUndefined(isolate)) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, num,
Object::ToInteger(isolate, end));
final = CapRelativeIndex(num, 0, len);
}
}
}
int64_t count = std::min<int64_t>(final - from, len - to);
if (count <= 0) return *array;
Handle<FixedTypedArrayBase> elements(
FixedTypedArrayBase::cast(array->elements()));
size_t element_size = array->element_size();
to = to * element_size;
from = from * element_size;
count = count * element_size;
uint8_t* data = static_cast<uint8_t*>(elements->DataPtr());
std::memmove(data + to, data + from, count);
return *array;
}
} // namespace internal
} // namespace v8

View File

@ -803,9 +803,7 @@ class Isolate;
/* ES6 #sec-%typedarray%.prototype.keys */ \
TFJ(TypedArrayPrototypeKeys, 0) \
/* ES6 #sec-%typedarray%.prototype.values */ \
TFJ(TypedArrayPrototypeValues, 0) \
/* ES6 #sec-%typedarray%.prototype.copywithin */ \
CPP(TypedArrayPrototypeCopyWithin)
TFJ(TypedArrayPrototypeValues, 0)
#define IGNORE_BUILTIN(...)

View File

@ -1270,13 +1270,7 @@ function ArrayReduceRight(callback, current) {
}
// ES6 draft 03-17-15, section 22.1.3.3
function ArrayCopyWithin(target, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
var array = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
function InnerArrayCopyWithin(target, start, end, array, length) {
target = TO_INTEGER(target);
var to;
if (target < 0) {
@ -1324,6 +1318,17 @@ function ArrayCopyWithin(target, start, end) {
}
// ES6 draft 03-17-15, section 22.1.3.3
function ArrayCopyWithin(target, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.copyWithin");
var array = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArrayCopyWithin(target, start, end, array, length);
}
function InnerArrayFind(predicate, thisArg, array, length) {
if (!IS_CALLABLE(predicate)) {
throw %make_type_error(kCalledNonCallable, predicate);
@ -1620,6 +1625,7 @@ utils.Export(function(to) {
to.ArrayPush = ArrayPush;
to.ArrayToString = ArrayToString;
to.ArrayValues = IteratorFunctions.values,
to.InnerArrayCopyWithin = InnerArrayCopyWithin;
to.InnerArrayEvery = InnerArrayEvery;
to.InnerArrayFill = InnerArrayFill;
to.InnerArrayFilter = InnerArrayFilter;

View File

@ -20,6 +20,7 @@ var GlobalArray = global.Array;
var GlobalArrayBuffer = global.ArrayBuffer;
var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
var GlobalObject = global.Object;
var InnerArrayCopyWithin;
var InnerArrayEvery;
var InnerArrayFill;
var InnerArrayFilter;
@ -67,6 +68,7 @@ utils.Import(function(from) {
ArrayValues = from.ArrayValues;
GetIterator = from.GetIterator;
GetMethod = from.GetMethod;
InnerArrayCopyWithin = from.InnerArrayCopyWithin;
InnerArrayEvery = from.InnerArrayEvery;
InnerArrayFill = from.InnerArrayFill;
InnerArrayFilter = from.InnerArrayFilter;
@ -436,6 +438,17 @@ function TypedArrayGetToStringTag() {
}
function TypedArrayCopyWithin(target, start, end) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
// TODO(littledan): Replace with a memcpy for better performance
return InnerArrayCopyWithin(target, start, end, this, length);
}
%FunctionSetLength(TypedArrayCopyWithin, 2);
// ES6 draft 05-05-15, section 22.2.3.7
function TypedArrayEvery(f, receiver) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
@ -845,6 +858,7 @@ utils.InstallGetter(GlobalTypedArray.prototype, toStringTagSymbol,
utils.InstallFunctions(GlobalTypedArray.prototype, DONT_ENUM, [
"subarray", TypedArraySubArray,
"set", TypedArraySet,
"copyWithin", TypedArrayCopyWithin,
"every", TypedArrayEvery,
"fill", TypedArrayFill,
"filter", TypedArrayFilter,

View File

@ -171,57 +171,3 @@ CheckEachTypedArray(function copyWithinNullEnd(constructor) {
assertArrayEquals([1, 2, 3, 4, 5],
new constructor([1, 2, 3, 4, 5]).copyWithin(0, 3, null));
});
CheckEachTypedArray(function copyWithinMinusInfinityTarget(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [6, 7, 8, 9, 10, 6, 7, 8, 9, 10];
assertArrayEquals(expected, arr.copyWithin(-Infinity, 5));
assertEquals(10, arr.length);
});
CheckEachTypedArray(function copyWithinPositiveInfinityTarget(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assertArrayEquals(expected, arr.copyWithin(+Infinity, 5));
assertEquals(10, arr.length);
});
CheckEachTypedArray(function copyWithinMinusInfinityStart(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
assertArrayEquals(expected, arr.copyWithin(5, -Infinity));
assertEquals(10, arr.length);
});
CheckEachTypedArray(function copyWithinPositiveInfinityStart(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assertArrayEquals(expected, arr.copyWithin(5, +Infinity));
assertEquals(10, arr.length);
});
CheckEachTypedArray(function copyWithinMinusInfinityEnd(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assertArrayEquals(expected, arr.copyWithin(5, 0, -Infinity));
assertEquals(10, arr.length);
});
CheckEachTypedArray(function copyWithinPositiveInfinityEnd(constructor) {
var arr = new constructor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
var expected = [1, 2, 3, 4, 5, 1, 2, 3, 4, 5];
assertArrayEquals(expected, arr.copyWithin(5, 0, +Infinity));
assertEquals(10, arr.length);
});

View File

@ -167,6 +167,7 @@
'built-ins/DataView/prototype/setUint8/detached-buffer-before-outofrange-byteoffset': [FAIL],
# https://bugs.chromium.org/p/v8/issues/detail?id=4648
'built-ins/TypedArray/prototype/copyWithin/detached-buffer': [FAIL],
'built-ins/TypedArray/prototype/every/detached-buffer': [FAIL],
'built-ins/TypedArray/prototype/fill/detached-buffer': [FAIL],
'built-ins/TypedArray/prototype/filter/detached-buffer': [FAIL],