[esnext] Implement Array.prototype.{flatten,flatMap} 🥙
Proposal repo: https://tc39.github.io/proposal-flatMap/ Bug: v8:7220 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng Change-Id: I61661fc6d5c39d084ce5c96a9e150e5c26799e2d Also-By: bmeurer@chromium.org Reviewed-on: https://chromium-review.googlesource.com/957043 Commit-Queue: Mathias Bynens <mathias@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#51967}
This commit is contained in:
parent
f8fb4a5c74
commit
697d39abff
@ -4251,6 +4251,17 @@ void Genesis::InitializeGlobal_harmony_array_prototype_values() {
|
||||
NONE);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_array_flatten() {
|
||||
if (!FLAG_harmony_array_flatten) return;
|
||||
Handle<JSFunction> array_constructor(native_context()->array_function());
|
||||
Handle<JSObject> array_prototype(
|
||||
JSObject::cast(array_constructor->instance_prototype()));
|
||||
SimpleInstallFunction(array_prototype, "flatten",
|
||||
Builtins::kArrayPrototypeFlatten, 0, false, DONT_ENUM);
|
||||
SimpleInstallFunction(array_prototype, "flatMap",
|
||||
Builtins::kArrayPrototypeFlatMap, 1, false, DONT_ENUM);
|
||||
}
|
||||
|
||||
void Genesis::InitializeGlobal_harmony_promise_finally() {
|
||||
if (!FLAG_harmony_promise_finally) return;
|
||||
|
||||
|
@ -3845,5 +3845,260 @@ TF_BUILTIN(ArrayIteratorPrototypeNext, CodeStubAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class ArrayFlattenAssembler : public CodeStubAssembler {
|
||||
public:
|
||||
explicit ArrayFlattenAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
|
||||
Node* FlattenIntoArray(Node* context, Node* target, Node* source,
|
||||
Node* source_length, Node* start, Node* depth,
|
||||
Node* mapper_function = nullptr,
|
||||
Node* this_arg = nullptr) {
|
||||
CSA_ASSERT(this, IsJSReceiver(target));
|
||||
CSA_ASSERT(this, IsJSReceiver(source));
|
||||
CSA_ASSERT(this, IsNumberPositive(source_length));
|
||||
CSA_ASSERT(this, IsNumberPositive(start));
|
||||
CSA_ASSERT(this, IsNumber(depth));
|
||||
|
||||
// 1. Let targetIndex be start.
|
||||
VARIABLE(var_target_index, MachineRepresentation::kTagged, start);
|
||||
|
||||
// 2. Let sourceIndex be 0.
|
||||
VARIABLE(var_source_index, MachineRepresentation::kTagged, SmiConstant(0));
|
||||
|
||||
// 3. Repeat...
|
||||
Label loop(this, {&var_target_index, &var_source_index}), done_loop(this);
|
||||
Goto(&loop);
|
||||
BIND(&loop);
|
||||
{
|
||||
Node* const source_index = var_source_index.value();
|
||||
Node* const target_index = var_target_index.value();
|
||||
|
||||
// ...while sourceIndex < sourceLen
|
||||
GotoIfNumberGreaterThanOrEqual(source_index, source_length, &done_loop);
|
||||
|
||||
// a. Let P be ! ToString(sourceIndex).
|
||||
// b. Let exists be ? HasProperty(source, P).
|
||||
CSA_ASSERT(this, SmiGreaterThanOrEqual(source_index, SmiConstant(0)));
|
||||
Node* const exists =
|
||||
HasProperty(source, source_index, context, kHasProperty);
|
||||
|
||||
// c. If exists is true, then
|
||||
Label next(this);
|
||||
GotoIfNot(IsTrue(exists), &next);
|
||||
{
|
||||
// i. Let element be ? Get(source, P).
|
||||
Node* element = GetProperty(context, source, source_index);
|
||||
|
||||
// ii. If mapperFunction is present, then
|
||||
if (mapper_function != nullptr) {
|
||||
CSA_ASSERT(this, Word32Or(IsUndefined(mapper_function),
|
||||
IsCallable(mapper_function)));
|
||||
DCHECK_NOT_NULL(this_arg);
|
||||
|
||||
// 1. Set element to ? Call(mapperFunction, thisArg , « element,
|
||||
// sourceIndex, source »).
|
||||
element =
|
||||
CallJS(CodeFactory::Call(isolate()), context, mapper_function,
|
||||
this_arg, element, source_index, source);
|
||||
}
|
||||
|
||||
// iii. Let shouldFlatten be false.
|
||||
Label if_flatten_array(this), if_flatten_proxy(this, Label::kDeferred),
|
||||
if_noflatten(this);
|
||||
// iv. If depth > 0, then
|
||||
GotoIfNumberGreaterThanOrEqual(SmiConstant(0), depth, &if_noflatten);
|
||||
// 1. Set shouldFlatten to ? IsArray(element).
|
||||
GotoIf(TaggedIsSmi(element), &if_noflatten);
|
||||
GotoIf(IsJSArray(element), &if_flatten_array);
|
||||
GotoIfNot(IsJSProxy(element), &if_noflatten);
|
||||
Branch(IsTrue(CallRuntime(Runtime::kArrayIsArray, context, element)),
|
||||
&if_flatten_proxy, &if_noflatten);
|
||||
|
||||
BIND(&if_flatten_array);
|
||||
{
|
||||
CSA_ASSERT(this, IsJSArray(element));
|
||||
|
||||
// 1. Let elementLen be ? ToLength(? Get(element, "length")).
|
||||
Node* const element_length =
|
||||
LoadObjectField(element, JSArray::kLengthOffset);
|
||||
|
||||
// 2. Set targetIndex to ? FlattenIntoArray(target, element,
|
||||
// elementLen, targetIndex,
|
||||
// depth - 1).
|
||||
var_target_index.Bind(
|
||||
CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
|
||||
element_length, target_index, NumberDec(depth)));
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
BIND(&if_flatten_proxy);
|
||||
{
|
||||
CSA_ASSERT(this, IsJSProxy(element));
|
||||
|
||||
// 1. Let elementLen be ? ToLength(? Get(element, "length")).
|
||||
Node* const element_length = ToLength_Inline(
|
||||
context, GetProperty(context, element, LengthStringConstant()));
|
||||
|
||||
// 2. Set targetIndex to ? FlattenIntoArray(target, element,
|
||||
// elementLen, targetIndex,
|
||||
// depth - 1).
|
||||
var_target_index.Bind(
|
||||
CallBuiltin(Builtins::kFlattenIntoArray, context, target, element,
|
||||
element_length, target_index, NumberDec(depth)));
|
||||
Goto(&next);
|
||||
}
|
||||
|
||||
BIND(&if_noflatten);
|
||||
{
|
||||
// 1. If targetIndex >= 2^53-1, throw a TypeError exception.
|
||||
Label throw_error(this, Label::kDeferred);
|
||||
GotoIfNumberGreaterThanOrEqual(
|
||||
target_index, NumberConstant(kMaxSafeInteger), &throw_error);
|
||||
|
||||
// 2. Perform ? CreateDataPropertyOrThrow(target,
|
||||
// ! ToString(targetIndex),
|
||||
// element).
|
||||
CallRuntime(Runtime::kCreateDataProperty, context, target,
|
||||
target_index, element);
|
||||
|
||||
// 3. Increase targetIndex by 1.
|
||||
var_target_index.Bind(NumberInc(target_index));
|
||||
Goto(&next);
|
||||
|
||||
BIND(&throw_error);
|
||||
ThrowTypeError(context, MessageTemplate::kFlattenPastSafeLength,
|
||||
source_length, target_index);
|
||||
}
|
||||
}
|
||||
BIND(&next);
|
||||
|
||||
// d. Increase sourceIndex by 1.
|
||||
var_source_index.Bind(NumberInc(source_index));
|
||||
Goto(&loop);
|
||||
}
|
||||
|
||||
BIND(&done_loop);
|
||||
return var_target_index.value();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
|
||||
TF_BUILTIN(FlattenIntoArray, ArrayFlattenAssembler) {
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
Node* const target = Parameter(Descriptor::kTarget);
|
||||
Node* const source = Parameter(Descriptor::kSource);
|
||||
Node* const source_length = Parameter(Descriptor::kSourceLength);
|
||||
Node* const start = Parameter(Descriptor::kStart);
|
||||
Node* const depth = Parameter(Descriptor::kDepth);
|
||||
|
||||
Return(
|
||||
FlattenIntoArray(context, target, source, source_length, start, depth));
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray
|
||||
TF_BUILTIN(FlatMapIntoArray, ArrayFlattenAssembler) {
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
Node* const target = Parameter(Descriptor::kTarget);
|
||||
Node* const source = Parameter(Descriptor::kSource);
|
||||
Node* const source_length = Parameter(Descriptor::kSourceLength);
|
||||
Node* const start = Parameter(Descriptor::kStart);
|
||||
Node* const depth = Parameter(Descriptor::kDepth);
|
||||
Node* const mapper_function = Parameter(Descriptor::kMapperFunction);
|
||||
Node* const this_arg = Parameter(Descriptor::kThisArg);
|
||||
|
||||
Return(FlattenIntoArray(context, target, source, source_length, start, depth,
|
||||
mapper_function, this_arg));
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatten
|
||||
TF_BUILTIN(ArrayPrototypeFlatten, CodeStubAssembler) {
|
||||
Node* const argc =
|
||||
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
Node* const context = Parameter(BuiltinDescriptor::kContext);
|
||||
Node* const receiver = args.GetReceiver();
|
||||
Node* const depth = args.GetOptionalArgumentValue(0);
|
||||
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
Node* const o = ToObject(context, receiver);
|
||||
|
||||
// 2. Let sourceLen be ? ToLength(? Get(O, "length")).
|
||||
Node* const source_length =
|
||||
ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
|
||||
|
||||
// 3. Let depthNum be 1.
|
||||
VARIABLE(var_depth_num, MachineRepresentation::kTagged, SmiConstant(1));
|
||||
|
||||
// 4. If depth is not undefined, then
|
||||
Label done(this);
|
||||
GotoIf(IsUndefined(depth), &done);
|
||||
{
|
||||
// a. Set depthNum to ? ToInteger(depth).
|
||||
var_depth_num.Bind(ToInteger_Inline(context, depth));
|
||||
Goto(&done);
|
||||
}
|
||||
BIND(&done);
|
||||
|
||||
// 5. Let A be ? ArraySpeciesCreate(O, 0).
|
||||
Node* const constructor =
|
||||
CallRuntime(Runtime::kArraySpeciesConstructor, context, o);
|
||||
Node* const a = ConstructJS(CodeFactory::Construct(isolate()), context,
|
||||
constructor, SmiConstant(0));
|
||||
|
||||
// 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
|
||||
CallBuiltin(Builtins::kFlattenIntoArray, context, a, o, source_length,
|
||||
SmiConstant(0), var_depth_num.value());
|
||||
|
||||
// 7. Return A.
|
||||
args.PopAndReturn(a);
|
||||
}
|
||||
|
||||
// https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap
|
||||
TF_BUILTIN(ArrayPrototypeFlatMap, CodeStubAssembler) {
|
||||
Node* const argc =
|
||||
ChangeInt32ToIntPtr(Parameter(BuiltinDescriptor::kArgumentsCount));
|
||||
CodeStubArguments args(this, argc);
|
||||
Node* const context = Parameter(BuiltinDescriptor::kContext);
|
||||
Node* const receiver = args.GetReceiver();
|
||||
Node* const mapper_function = args.GetOptionalArgumentValue(0);
|
||||
|
||||
// 1. Let O be ? ToObject(this value).
|
||||
Node* const o = ToObject(context, receiver);
|
||||
|
||||
// 2. Let sourceLen be ? ToLength(? Get(O, "length")).
|
||||
Node* const source_length =
|
||||
ToLength_Inline(context, GetProperty(context, o, LengthStringConstant()));
|
||||
|
||||
// 3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
|
||||
Label if_not_callable(this, Label::kDeferred);
|
||||
GotoIf(TaggedIsSmi(mapper_function), &if_not_callable);
|
||||
GotoIfNot(IsCallable(mapper_function), &if_not_callable);
|
||||
|
||||
// 4. If thisArg is present, let T be thisArg; else let T be undefined.
|
||||
Node* const t = args.GetOptionalArgumentValue(1);
|
||||
|
||||
// 5. Let A be ? ArraySpeciesCreate(O, 0).
|
||||
Node* const constructor =
|
||||
CallRuntime(Runtime::kArraySpeciesConstructor, context, o);
|
||||
Node* const a = ConstructJS(CodeFactory::Construct(isolate()), context,
|
||||
constructor, SmiConstant(0));
|
||||
|
||||
// 6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
|
||||
CallBuiltin(Builtins::kFlatMapIntoArray, context, a, o, source_length,
|
||||
SmiConstant(0), SmiConstant(1), mapper_function, t);
|
||||
|
||||
// 7. Return A.
|
||||
args.PopAndReturn(a);
|
||||
|
||||
BIND(&if_not_callable);
|
||||
{ ThrowTypeError(context, MessageTemplate::kMapperFunctionNonCallable); }
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -367,6 +367,14 @@ namespace internal {
|
||||
TFJ(ArrayPrototypeValues, 0) \
|
||||
/* ES6 #sec-%arrayiteratorprototype%.next */ \
|
||||
TFJ(ArrayIteratorPrototypeNext, 0) \
|
||||
/* https://tc39.github.io/proposal-flatMap/#sec-FlattenIntoArray */ \
|
||||
TFS(FlattenIntoArray, kTarget, kSource, kSourceLength, kStart, kDepth) \
|
||||
TFS(FlatMapIntoArray, kTarget, kSource, kSourceLength, kStart, kDepth, \
|
||||
kMapperFunction, kThisArg) \
|
||||
/* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatten */ \
|
||||
TFJ(ArrayPrototypeFlatten, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* https://tc39.github.io/proposal-flatMap/#sec-Array.prototype.flatMap */ \
|
||||
TFJ(ArrayPrototypeFlatMap, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
\
|
||||
/* ArrayBuffer */ \
|
||||
/* ES #sec-arraybuffer-constructor */ \
|
||||
|
@ -6174,7 +6174,8 @@ TNode<Number> CodeStubAssembler::ToLength_Inline(SloppyTNode<Context> context,
|
||||
}
|
||||
|
||||
TNode<Number> CodeStubAssembler::ToInteger_Inline(
|
||||
TNode<Context> context, TNode<Object> input, ToIntegerTruncationMode mode) {
|
||||
SloppyTNode<Context> context, SloppyTNode<Object> input,
|
||||
ToIntegerTruncationMode mode) {
|
||||
Builtins::Name builtin = (mode == kNoTruncation)
|
||||
? Builtins::kToInteger
|
||||
: Builtins::kToInteger_TruncateMinusZero;
|
||||
@ -10022,7 +10023,7 @@ void CodeStubAssembler::BranchIfSameValue(Node* lhs, Node* rhs, Label* if_true,
|
||||
}
|
||||
|
||||
TNode<Oddball> CodeStubAssembler::HasProperty(SloppyTNode<HeapObject> object,
|
||||
SloppyTNode<Name> key,
|
||||
SloppyTNode<Object> key,
|
||||
SloppyTNode<Context> context,
|
||||
HasPropertyLookupMode mode) {
|
||||
Label call_runtime(this, Label::kDeferred), return_true(this),
|
||||
|
@ -1315,7 +1315,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
SloppyTNode<Object> input);
|
||||
|
||||
// ES6 7.1.4 ToInteger ( argument )
|
||||
TNode<Number> ToInteger_Inline(TNode<Context> context, TNode<Object> input,
|
||||
TNode<Number> ToInteger_Inline(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input,
|
||||
ToIntegerTruncationMode mode = kNoTruncation);
|
||||
TNode<Number> ToInteger(SloppyTNode<Context> context,
|
||||
SloppyTNode<Object> input,
|
||||
@ -1910,7 +1911,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
enum HasPropertyLookupMode { kHasProperty, kForInHasProperty };
|
||||
|
||||
TNode<Oddball> HasProperty(SloppyTNode<HeapObject> object,
|
||||
SloppyTNode<Name> key,
|
||||
SloppyTNode<Object> key,
|
||||
SloppyTNode<Context> context,
|
||||
HasPropertyLookupMode mode);
|
||||
|
||||
|
@ -212,7 +212,8 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields)
|
||||
V(harmony_array_prototype_values, "harmony Array.prototype.values") \
|
||||
V(harmony_do_expressions, "harmony do-expressions") \
|
||||
V(harmony_class_fields, "harmony fields in class literals") \
|
||||
V(harmony_static_fields, "harmony static fields in class literals")
|
||||
V(harmony_static_fields, "harmony static fields in class literals") \
|
||||
V(harmony_array_flatten, "harmony Array.prototype.flat{ten,Map}")
|
||||
|
||||
// Features that are complete (but still behind --harmony/es-staging flag).
|
||||
#define HARMONY_STAGED(V) \
|
||||
|
@ -343,6 +343,7 @@ class ErrorUtils : public AllStatic {
|
||||
T(IteratorSymbolNonCallable, "Found non-callable @@iterator") \
|
||||
T(IteratorValueNotAnObject, "Iterator value % is not an entry object") \
|
||||
T(LanguageID, "Language ID should be string or object.") \
|
||||
T(MapperFunctionNonCallable, "flatMap mapper function is not callable") \
|
||||
T(MethodCalledOnWrongObject, \
|
||||
"Method % called on a non-object or on a wrong type of object.") \
|
||||
T(MethodInvokedOnNullOrUndefined, \
|
||||
@ -643,6 +644,9 @@ class ErrorUtils : public AllStatic {
|
||||
T(NoCatchOrFinally, "Missing catch or finally after try") \
|
||||
T(NotIsvar, "builtin %%IS_VAR: not a variable") \
|
||||
T(ParamAfterRest, "Rest parameter must be last formal parameter") \
|
||||
T(FlattenPastSafeLength, \
|
||||
"Flattening % elements on an array-like of length % " \
|
||||
"is disallowed, as the total surpasses 2**53-1") \
|
||||
T(PushPastSafeLength, \
|
||||
"Pushing % elements on an array-like of length % " \
|
||||
"is disallowed, as the total surpasses 2**53-1") \
|
||||
|
@ -367,7 +367,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(18),
|
||||
B(LdaConstant), U8(15),
|
||||
B(Star), R(19),
|
||||
|
@ -124,7 +124,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(19),
|
||||
B(LdaConstant), U8(12),
|
||||
B(Star), R(20),
|
||||
@ -378,7 +378,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(19),
|
||||
B(LdaConstant), U8(12),
|
||||
B(Star), R(20),
|
||||
@ -654,7 +654,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(19),
|
||||
B(LdaConstant), U8(12),
|
||||
B(Star), R(20),
|
||||
@ -886,7 +886,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(17),
|
||||
B(LdaConstant), U8(10),
|
||||
B(Star), R(18),
|
||||
|
@ -86,7 +86,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(12),
|
||||
B(LdaConstant), U8(8),
|
||||
B(Star), R(13),
|
||||
@ -220,7 +220,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(13),
|
||||
B(LdaConstant), U8(8),
|
||||
B(Star), R(14),
|
||||
@ -366,7 +366,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(12),
|
||||
B(LdaConstant), U8(8),
|
||||
B(Star), R(13),
|
||||
@ -502,7 +502,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(11),
|
||||
B(LdaConstant), U8(10),
|
||||
B(Star), R(12),
|
||||
|
@ -90,7 +90,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(14),
|
||||
B(LdaConstant), U8(7),
|
||||
B(Star), R(15),
|
||||
@ -261,7 +261,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(14),
|
||||
B(LdaConstant), U8(11),
|
||||
B(Star), R(15),
|
||||
@ -408,7 +408,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(12),
|
||||
B(LdaConstant), U8(9),
|
||||
B(Star), R(13),
|
||||
@ -503,7 +503,7 @@ bytecodes: [
|
||||
B(JumpIfUndefined), U8(6),
|
||||
B(Ldar), R(6),
|
||||
B(JumpIfNotNull), U8(16),
|
||||
B(LdaSmi), I8(76),
|
||||
B(LdaSmi), I8(77),
|
||||
B(Star), R(18),
|
||||
B(LdaConstant), U8(4),
|
||||
B(Star), R(19),
|
||||
@ -559,7 +559,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(17),
|
||||
B(LdaConstant), U8(9),
|
||||
B(Star), R(18),
|
||||
@ -713,7 +713,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(16),
|
||||
B(LdaConstant), U8(10),
|
||||
B(Star), R(17),
|
||||
@ -882,7 +882,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(15),
|
||||
B(LdaConstant), U8(13),
|
||||
B(Star), R(16),
|
||||
@ -1037,7 +1037,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(21),
|
||||
B(LdaConstant), U8(7),
|
||||
B(Star), R(22),
|
||||
@ -1253,7 +1253,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(20),
|
||||
B(LdaConstant), U8(8),
|
||||
B(Star), R(21),
|
||||
|
@ -204,7 +204,7 @@ bytecodes: [
|
||||
B(TestTypeOf), U8(6),
|
||||
B(JumpIfFalse), U8(4),
|
||||
B(Jump), U8(18),
|
||||
B(Wide), B(LdaSmi), I16(146),
|
||||
B(Wide), B(LdaSmi), I16(147),
|
||||
B(Star), R(14),
|
||||
B(LdaConstant), U8(14),
|
||||
B(Star), R(15),
|
||||
|
@ -231,7 +231,7 @@ bytecodes: [
|
||||
B(JumpIfUndefined), U8(6),
|
||||
B(Ldar), R(3),
|
||||
B(JumpIfNotNull), U8(16),
|
||||
B(LdaSmi), I8(76),
|
||||
B(LdaSmi), I8(77),
|
||||
B(Star), R(4),
|
||||
B(LdaConstant), U8(1),
|
||||
B(Star), R(5),
|
||||
|
120
test/mjsunit/harmony/array-flatMap.js
Normal file
120
test/mjsunit/harmony/array-flatMap.js
Normal file
@ -0,0 +1,120 @@
|
||||
// Copyright 2018 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: --harmony-array-flatten --allow-natives-syntax
|
||||
|
||||
assertEquals(Array.prototype.flatMap.length, 1);
|
||||
assertEquals(Array.prototype.flatMap.name, 'flatMap');
|
||||
|
||||
assertEquals(
|
||||
[1, 2, 3, 4].flatMap((element) => [element, element ** 2]),
|
||||
[1, 1, 2, 4, 3, 9, 4, 16]
|
||||
);
|
||||
assertEquals(
|
||||
[1, 2, 3, 4].flatMap((element) => [[element, element ** 2]]),
|
||||
[[1, 1], [2, 4], [3, 9], [4, 16]]
|
||||
);
|
||||
|
||||
const elements = new Set([
|
||||
-Infinity,
|
||||
-1,
|
||||
-0,
|
||||
+0,
|
||||
+1,
|
||||
Infinity,
|
||||
null,
|
||||
undefined,
|
||||
true,
|
||||
false,
|
||||
'',
|
||||
'foo',
|
||||
/./,
|
||||
[],
|
||||
{},
|
||||
Object.create(null),
|
||||
new Proxy({}, {}),
|
||||
Symbol(),
|
||||
x => x ** 2,
|
||||
String
|
||||
]);
|
||||
|
||||
for (const value of elements) {
|
||||
assertEquals(
|
||||
[value].flatMap((element) => [element, element]),
|
||||
[value, value]
|
||||
);
|
||||
}
|
||||
|
||||
const array = [42];
|
||||
assertEquals(
|
||||
[array].flatMap((element) => [element, element]),
|
||||
[array, array]
|
||||
);
|
||||
|
||||
const nonCallables = new Set([
|
||||
-Infinity,
|
||||
-1,
|
||||
-0,
|
||||
+0,
|
||||
+1,
|
||||
Infinity,
|
||||
null,
|
||||
undefined,
|
||||
true,
|
||||
false,
|
||||
'',
|
||||
'foo',
|
||||
/./,
|
||||
[],
|
||||
{},
|
||||
Object.create(null),
|
||||
new Proxy({}, {}),
|
||||
Symbol(),
|
||||
]);
|
||||
for (const nonCallable of nonCallables) {
|
||||
assertThrows(() => {
|
||||
[].flatMap(nonCallable);
|
||||
}, TypeError);
|
||||
}
|
||||
|
||||
const object = {
|
||||
foo: 42,
|
||||
get length() {
|
||||
object.foo = 0;
|
||||
}
|
||||
};
|
||||
const result = [object].flatMap((element) => [element, element]);
|
||||
%HeapObjectVerify(result);
|
||||
assertEquals(result, [object, object]);
|
||||
assertEquals(result[0].foo, 42);
|
||||
|
||||
assertThrows(() => {
|
||||
Array.prototype.flatMap.call(null, (element) => element);
|
||||
}, TypeError);
|
||||
assertThrows(() => {
|
||||
Array.prototype.flatMap.call(undefined, (element) => element);
|
||||
}, TypeError);
|
||||
|
||||
assertEquals(
|
||||
Array.prototype.flatMap.call(
|
||||
{
|
||||
length: 1,
|
||||
0: 'a',
|
||||
1: 'b',
|
||||
},
|
||||
(element) => element
|
||||
),
|
||||
['a']
|
||||
);
|
||||
assertEquals(
|
||||
Array.prototype.flatMap.call(
|
||||
{
|
||||
length: 2,
|
||||
0: 'a',
|
||||
1: 'b',
|
||||
},
|
||||
(element) => element
|
||||
),
|
||||
['a', 'b']
|
||||
);
|
38
test/mjsunit/harmony/array-flatten.js
Normal file
38
test/mjsunit/harmony/array-flatten.js
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018 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: --harmony-array-flatten
|
||||
|
||||
assertEquals(Array.prototype.flatten.length, 0);
|
||||
assertEquals(Array.prototype.flatten.name, 'flatten');
|
||||
|
||||
const input = [1, [2], [[3]]];
|
||||
|
||||
assertEquals(input.flatten(), [1, 2, [3]]);
|
||||
assertEquals(input.flatten(1), [1, 2, [3]]);
|
||||
assertEquals(input.flatten(true), [1, 2, [3]]);
|
||||
assertEquals(input.flatten(undefined), [1, 2, [3]]);
|
||||
|
||||
assertEquals(input.flatten(-Infinity), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(-1), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(-0), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(0), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(false), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(null), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(''), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten('foo'), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten(/./), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten([]), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten({}), [1, [2], [[3]]]);
|
||||
assertEquals(
|
||||
input.flatten(new Proxy({}, {})), [1, [2], [[3]]]);
|
||||
assertEquals(input.flatten((x) => x), [1, [2], [[3]]]);
|
||||
assertEquals(
|
||||
input.flatten(String), [1, [2], [[3]]]);
|
||||
|
||||
assertEquals(input.flatten(2), [1, 2, 3]);
|
||||
assertEquals(input.flatten(Infinity), [1, 2, 3]);
|
||||
|
||||
assertThrows(() => { input.flatten(Symbol()); }, TypeError);
|
||||
assertThrows(() => { input.flatten(Object.create(null)); }, TypeError);
|
@ -50,11 +50,12 @@ FEATURE_FLAGS = {
|
||||
'class-fields-public': '--harmony-public-fields',
|
||||
'optional-catch-binding': '--harmony-optional-catch-binding',
|
||||
'class-fields-private': '--harmony-private-fields',
|
||||
'Array.prototype.flatten': '--harmony-array-flatten',
|
||||
'Array.prototype.flatMap': '--harmony-array-flatten',
|
||||
'numeric-separator-literal': '--harmony-numeric-separator',
|
||||
}
|
||||
|
||||
SKIPPED_FEATURES = set(['Array.prototype.flatten',
|
||||
'Array.prototype.flatMap'])
|
||||
SKIPPED_FEATURES = set([])
|
||||
|
||||
DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
|
||||
ARCHIVE = DATA + ".tar"
|
||||
|
@ -60,7 +60,9 @@ LINT_RULES = """
|
||||
-build/header_guard
|
||||
-build/include_what_you_use
|
||||
-readability/fn_size
|
||||
-readability/multiline_comment
|
||||
-runtime/references
|
||||
-whitespace/comments
|
||||
""".split()
|
||||
|
||||
LINT_OUTPUT_PATTERN = re.compile(r'^.+[:(]\d+[:)]|^Done processing')
|
||||
|
Loading…
Reference in New Issue
Block a user