Commit cb903e31 authored by loorongjie's avatar loorongjie Committed by Commit bot

Migrate %TypedArray%.prototype.fill to C++

BUG=v8:5929
R=adamk@chromium.org,bmeurer@chromium.org

Review-Url: https://codereview.chromium.org/2735563002
Cr-Commit-Position: refs/heads/master@{#43934}
parent 51637465
......@@ -2598,6 +2598,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
// TODO(caitp): alphasort accessors/methods
SimpleInstallFunction(prototype, "copyWithin",
Builtins::kTypedArrayPrototypeCopyWithin, 2, false);
SimpleInstallFunction(prototype, "fill",
Builtins::kTypedArrayPrototypeFill, 1, false);
SimpleInstallFunction(prototype, "includes",
Builtins::kTypedArrayPrototypeIncludes, 1, false);
SimpleInstallFunction(prototype, "indexOf",
......
......@@ -108,6 +108,55 @@ BUILTIN(TypedArrayPrototypeCopyWithin) {
return *array;
}
BUILTIN(TypedArrayPrototypeFill) {
HandleScope scope(isolate);
Handle<JSTypedArray> array;
const char* method = "%TypedArray%.prototype.fill";
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, array, JSTypedArray::Validate(isolate, args.receiver(), method));
if (V8_UNLIKELY(array->WasNeutered())) return *array;
int64_t len = array->length_value();
int64_t start = 0;
int64_t end = len;
if (args.length() > 2) {
Handle<Object> num = args.atOrUndefined(isolate, 2);
if (!num->IsUndefined(isolate)) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num, Object::ToInteger(isolate, num));
start = CapRelativeIndex(num, 0, len);
num = args.atOrUndefined(isolate, 3);
if (!num->IsUndefined(isolate)) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, num, Object::ToInteger(isolate, num));
end = CapRelativeIndex(num, 0, len);
}
}
}
int64_t count = end - start;
if (count <= 0) return *array;
if (V8_UNLIKELY(array->WasNeutered())) return *array;
// Ensure processed indexes are within array bounds
DCHECK_GE(start, 0);
DCHECK_LT(start, len);
DCHECK_GE(end, 0);
DCHECK_LE(end, len);
DCHECK_LE(count, len);
Handle<Object> obj_value = args.atOrUndefined(isolate, 1);
return array->GetElementsAccessor()->Fill(isolate, array, obj_value,
static_cast<uint32_t>(start),
static_cast<uint32_t>(end));
}
BUILTIN(TypedArrayPrototypeIncludes) {
HandleScope scope(isolate);
......
......@@ -855,6 +855,8 @@ class Isolate;
TFJ(TypedArrayPrototypeValues, 0) \
/* ES6 #sec-%typedarray%.prototype.copywithin */ \
CPP(TypedArrayPrototypeCopyWithin) \
/* ES6 #sec-%typedarray%.prototype.fill */ \
CPP(TypedArrayPrototypeFill) \
/* ES7 #sec-%typedarray%.prototype.includes */ \
CPP(TypedArrayPrototypeIncludes) \
/* ES6 #sec-%typedarray%.prototype.indexof */ \
......
......@@ -470,6 +470,22 @@ static void SortIndices(
}
}
static Object* FillNumberSlowPath(Isolate* isolate, Handle<JSTypedArray> array,
Handle<Object> obj_value,
uint32_t start, uint32_t end) {
Handle<Object> cast_value;
ElementsAccessor* elements = array->GetElementsAccessor();
for (uint32_t k = start; k < end; ++k) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, cast_value, Object::ToNumber(obj_value));
// TODO(caitp,cbruni): throw on neutered array
if (V8_UNLIKELY(array->WasNeutered())) return *array;
elements->Set(array, k, *cast_value);
}
return *array;
}
static Maybe<bool> IncludesValueSlowPath(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
......@@ -1191,6 +1207,18 @@ class ElementsAccessorBase : public ElementsAccessor {
return Subclass::GetCapacityImpl(holder, backing_store);
}
static Object* FillImpl(Isolate* isolate, Handle<JSObject> receiver,
Handle<Object> obj_value, uint32_t start,
uint32_t end) {
UNREACHABLE();
return *receiver;
}
Object* Fill(Isolate* isolate, Handle<JSObject> receiver,
Handle<Object> obj_value, uint32_t start, uint32_t end) {
return Subclass::FillImpl(isolate, receiver, obj_value, start, end);
}
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
......@@ -2829,6 +2857,36 @@ class TypedElementsAccessor
return Just(true);
}
static Object* FillImpl(Isolate* isolate, Handle<JSObject> receiver,
Handle<Object> obj_value, uint32_t start,
uint32_t end) {
Handle<JSTypedArray> array = Handle<JSTypedArray>::cast(receiver);
DCHECK(!array->WasNeutered());
if (!obj_value->IsNumber()) {
return FillNumberSlowPath(isolate, array, obj_value, start, end);
}
ctype value = 0;
if (obj_value->IsSmi()) {
value = BackingStore::from_int(Smi::cast(*obj_value)->value());
} else {
DCHECK(obj_value->IsHeapNumber());
value = BackingStore::from_double(HeapNumber::cast(*obj_value)->value());
}
// Ensure indexes are within array bounds
DCHECK_LE(0, start);
DCHECK_LE(start, end);
DCHECK_LE(end, array->length_value());
DisallowHeapAllocation no_gc;
BackingStore* elements = BackingStore::cast(receiver->elements());
ctype* data = static_cast<ctype*>(elements->DataPtr());
std::fill(data + start, data + end, value);
return *array;
}
static Maybe<bool> IncludesValueImpl(Isolate* isolate,
Handle<JSObject> receiver,
Handle<Object> value,
......
......@@ -158,6 +158,10 @@ class ElementsAccessor {
virtual uint32_t GetCapacity(JSObject* holder,
FixedArrayBase* backing_store) = 0;
virtual Object* Fill(Isolate* isolate, Handle<JSObject> receiver,
Handle<Object> obj_value, uint32_t start,
uint32_t end) = 0;
// Check an Object's own elements for an element (using SameValueZero
// semantics)
virtual Maybe<bool> IncludesValue(Isolate* isolate, Handle<JSObject> receiver,
......
......@@ -1376,7 +1376,12 @@ function ArrayFindIndex(predicate, thisArg) {
// ES6, draft 04-05-14, section 22.1.3.6
function InnerArrayFill(value, start, end, array, length) {
function ArrayFill(value, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill");
var array = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
var i = IS_UNDEFINED(start) ? 0 : TO_INTEGER(start);
var end = IS_UNDEFINED(end) ? length : TO_INTEGER(end);
......@@ -1404,17 +1409,6 @@ function InnerArrayFill(value, start, end, array, length) {
}
// ES6, draft 04-05-14, section 22.1.3.6
function ArrayFill(value, start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.fill");
var array = TO_OBJECT(this);
var length = TO_LENGTH(array.length);
return InnerArrayFill(value, start, end, array, length);
}
// ES6, draft 10-14-14, section 22.1.2.1
function ArrayFrom(arrayLike, mapfn, receiver) {
var items = TO_OBJECT(arrayLike);
......@@ -1618,7 +1612,6 @@ utils.Export(function(to) {
to.ArrayToString = ArrayToString;
to.ArrayValues = IteratorFunctions.values,
to.InnerArrayEvery = InnerArrayEvery;
to.InnerArrayFill = InnerArrayFill;
to.InnerArrayFilter = InnerArrayFilter;
to.InnerArrayFind = InnerArrayFind;
to.InnerArrayFindIndex = InnerArrayFindIndex;
......
......@@ -21,7 +21,6 @@ var GlobalArrayBuffer = global.ArrayBuffer;
var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
var GlobalObject = global.Object;
var InnerArrayEvery;
var InnerArrayFill;
var InnerArrayFilter;
var InnerArrayFind;
var InnerArrayFindIndex;
......@@ -68,7 +67,6 @@ utils.Import(function(from) {
GetIterator = from.GetIterator;
GetMethod = from.GetMethod;
InnerArrayEvery = from.InnerArrayEvery;
InnerArrayFill = from.InnerArrayFill;
InnerArrayFilter = from.InnerArrayFilter;
InnerArrayFind = from.InnerArrayFind;
InnerArrayFindIndex = from.InnerArrayFindIndex;
......@@ -396,17 +394,6 @@ function TypedArrayForEach(f, receiver) {
%FunctionSetLength(TypedArrayForEach, 1);
// ES6 draft 04-05-14 section 22.2.3.8
function TypedArrayFill(value, start, end) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
var length = %_TypedArrayGetLength(this);
return InnerArrayFill(value, start, end, this, length);
}
%FunctionSetLength(TypedArrayFill, 1);
// ES6 draft 07-15-13, section 22.2.3.9
function TypedArrayFilter(f, thisArg) {
if (!IS_TYPEDARRAY(this)) throw %make_type_error(kNotTypedArray);
......@@ -658,7 +645,6 @@ utils.InstallFunctions(GlobalTypedArray.prototype, DONT_ENUM, [
"subarray", TypedArraySubArray,
"set", TypedArraySet,
"every", TypedArrayEvery,
"fill", TypedArrayFill,
"filter", TypedArrayFilter,
"find", TypedArrayFind,
"findIndex", TypedArrayFindIndex,
......
......@@ -16,30 +16,72 @@ var typedArrayConstructors = [
for (var constructor of typedArrayConstructors) {
assertEquals(1, constructor.prototype.fill.length);
assertArrayEquals(new constructor([]).fill(8), []);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8), [8, 8, 8, 8, 8]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1), [0, 8, 8, 8, 8]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 10), [0, 0, 0, 0, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -5), [8, 8, 8, 8, 8]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, 4), [0, 8, 8, 8, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, -1), [0, 8, 8, 8, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 1, 42), [0, 8, 8, 8, 8]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -3, 42), [0, 0, 8, 8, 8]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -3, 4), [0, 0, 8, 8, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -2, -1), [0, 0, 0, 8, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, -1, -3), [0, 0, 0, 0, 0]);
assertArrayEquals(new constructor([0, 0, 0, 0, 0]).fill(8, 0, 4), [8, 8, 8, 8, 0]);
assertArrayEquals([], new constructor([]).fill(8));
assertArrayEquals([8, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8));
assertArrayEquals([0, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, 1));
assertArrayEquals([0, 0, 0, 0, 0], new constructor([0, 0, 0, 0, 0]).fill(8, 10));
assertArrayEquals([8, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, -5));
assertArrayEquals([0, 8, 8, 8, 0], new constructor([0, 0, 0, 0, 0]).fill(8, 1, 4));
assertArrayEquals([0, 8, 8, 8, 0], new constructor([0, 0, 0, 0, 0]).fill(8, 1, -1));
assertArrayEquals([0, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, 1, 42));
assertArrayEquals([0, 0, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, -3, 42));
assertArrayEquals([0, 0, 8, 8, 0], new constructor([0, 0, 0, 0, 0]).fill(8, -3, 4));
assertArrayEquals([0, 0, 0, 8, 0], new constructor([0, 0, 0, 0, 0]).fill(8, -2, -1));
assertArrayEquals([0, 0, 0, 0, 0], new constructor([0, 0, 0, 0, 0]).fill(8, -1, -3));
assertArrayEquals([8, 8, 8, 8, 0], new constructor([0, 0, 0, 0, 0]).fill(8, 0, 4));
assertArrayEquals([0, 0, 0, 0, 0], new constructor([0, 0, 0, 0, 0]).fill(8, Infinity));
assertArrayEquals([8, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, -Infinity));
assertArrayEquals([8, 8, 8, 8, 8], new constructor([0, 0, 0, 0, 0]).fill(8, 0, Infinity));
assertArrayEquals([0, 0, 0, 0, 0], new constructor([0, 0, 0, 0, 0]).fill(8, 0, -Infinity));
// Test exceptions
assertThrows('constructor.prototype.fill.call(null)', TypeError);
assertThrows('constructor.prototype.fill.call(undefined)', TypeError);
assertThrows('constructor.prototype.fill.call([])', TypeError);
// Test ToNumber
var s = "";
var p = new Proxy({}, {get(t,k) { s += k.toString() + '\n'; return Reflect.get(t, k)}})
new constructor(3).fill(p);
assertEquals(s, `Symbol(Symbol.toPrimitive)
valueOf
toString
Symbol(Symbol.toStringTag)
Symbol(Symbol.toPrimitive)
valueOf
toString
Symbol(Symbol.toStringTag)
Symbol(Symbol.toPrimitive)
valueOf
toString
Symbol(Symbol.toStringTag)
`);
// Shadowing length doesn't affect fill, unlike Array.prototype.fill
var a = new constructor([2, 2]);
Object.defineProperty(a, 'length', {value: 1});
a.fill(3);
assertArrayEquals([a[0], a[1]], [3, 3]);
assertArrayEquals([3, 3], [a[0], a[1]]);
Array.prototype.fill.call(a, 4);
assertArrayEquals([a[0], a[1]], [4, 3]);
assertArrayEquals([4, 3], [a[0], a[1]]);
}
// Empty args
assertArrayEquals([0], new Uint8Array([0]).fill());
assertArrayEquals([NaN], new Float32Array([0]).fill());
// Clamping
assertArrayEquals([0, 0, 0, 0, 0], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(-10));
assertArrayEquals([255, 255, 255, 255, 255], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(1000));
assertArrayEquals([1, 1, 1, 1, 1], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(0.50001));
assertArrayEquals([0, 0, 0, 0, 0], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(0.50000));
assertArrayEquals([0, 0, 0, 0, 0], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(0.49999));
// Check round half to even
assertArrayEquals([2, 2, 2, 2, 2], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(1.50000));
assertArrayEquals([2, 2, 2, 2, 2], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(2.50000));
assertArrayEquals([3, 3, 3, 3, 3], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(2.50001));
// Check infinity clamping.
assertArrayEquals([0, 0, 0, 0, 0], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(-Infinity));
assertArrayEquals([255, 255, 255, 255, 255], new Uint8ClampedArray([0, 0, 0, 0, 0]).fill(Infinity));
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