Commit 192984ea authored by mvstanton's avatar mvstanton Committed by Commit bot

Array.prototype.map write error.

More care must be taken to remain on the fast path in the face of
@@species constructors.

BUG=chromium:716044

Review-Url: https://codereview.chromium.org/2846963003
Cr-Commit-Position: refs/heads/master@{#45065}
parent 40d01184
......@@ -15,13 +15,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
: CodeStubAssembler(state),
k_(this, MachineRepresentation::kTagged),
a_(this, MachineRepresentation::kTagged),
to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {}
typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)>
BuiltinResultGenerator;
to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
BuiltinResultIndexInitializer;
BuiltinResultGenerator;
typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm,
Node* k_value, Node* k)>
......@@ -30,7 +28,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
PostLoopAction;
Node* ForEachResultGenerator() { return UndefinedConstant(); }
void ForEachResultGenerator() { a_.Bind(UndefinedConstant()); }
Node* ForEachProcessor(Node* k_value, Node* k) {
CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
......@@ -38,7 +36,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a();
}
Node* SomeResultGenerator() { return FalseConstant(); }
void SomeResultGenerator() { a_.Bind(FalseConstant()); }
Node* SomeProcessor(Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
......@@ -51,7 +49,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a();
}
Node* EveryResultGenerator() { return TrueConstant(); }
void EveryResultGenerator() { a_.Bind(TrueConstant()); }
Node* EveryProcessor(Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
......@@ -64,7 +62,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a();
}
Node* ReduceResultGenerator() { return this_arg(); }
void ReduceResultGenerator() { return a_.Bind(this_arg()); }
Node* ReduceProcessor(Node* k_value, Node* k) {
VARIABLE(result, MachineRepresentation::kTagged);
......@@ -91,9 +89,9 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
BIND(&ok);
}
Node* FilterResultGenerator() {
void FilterResultGenerator() {
// 7. Let A be ArraySpeciesCreate(O, 0).
return ArraySpeciesCreate(context(), o(), SmiConstant(0));
a_.Bind(ArraySpeciesCreate(context(), o(), SmiConstant(0)));
}
Node* FilterProcessor(Node* k_value, Node* k) {
......@@ -162,13 +160,53 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a();
}
Node* MapResultGenerator() {
// 5. Let A be ? ArraySpeciesCreate(O, len).
return ArraySpeciesCreate(context(), o(), len_);
void MapResultGenerator() {
Label runtime(this), done(this, {&a_});
GotoIf(DoesntHaveInstanceType(o(), JS_ARRAY_TYPE), &runtime);
Node* o_map = LoadMap(o());
Node* const initial_array_prototype = LoadContextElement(
LoadNativeContext(context()), Context::INITIAL_ARRAY_PROTOTYPE_INDEX);
Node* proto = LoadMapPrototype(o_map);
GotoIf(WordNotEqual(proto, initial_array_prototype), &runtime);
Node* species_protector = SpeciesProtectorConstant();
Node* value = LoadObjectField(species_protector, Cell::kValueOffset);
Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
GotoIf(WordEqual(value, protector_invalid), &runtime);
Node* const initial_array_constructor = LoadContextElement(
LoadNativeContext(context()), Context::ARRAY_FUNCTION_INDEX);
a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
initial_array_constructor, len_));
Goto(&done);
BIND(&runtime);
{
// 5. Let A be ? ArraySpeciesCreate(O, len).
Node* constructor =
CallRuntime(Runtime::kArraySpeciesConstructor, context(), o());
a_.Bind(ConstructJS(CodeFactory::Construct(isolate()), context(),
constructor, len_));
Goto(&fully_spec_compliant_);
}
BIND(&done);
}
Node* SpecCompliantMapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of
// SpecCompliantMapProcessor.
// ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O).
Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
// iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue);
return a();
}
Node* MapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor.
Node* FastMapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of
// FastMapProcessor.
// ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O).
Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o());
......@@ -268,8 +306,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
const CallResultProcessor& processor, const PostLoopAction& action,
const Callable& slow_case_continuation,
ForEachDirection direction = ForEachDirection::kForward) {
Label non_array(this), slow(this, {&k_, &a_, &to_}),
array_changes(this, {&k_, &a_, &to_});
Label non_array(this), array_changes(this, {&k_, &a_, &to_});
// TODO(danno): Seriously? Do we really need to throw the exact error
// message on null and undefined so that the webkit tests pass?
......@@ -336,11 +373,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
k_.Bind(NumberDec(len()));
}
a_.Bind(generator(this));
generator(this);
HandleFastElements(processor, action, &slow, direction);
HandleFastElements(processor, action, &fully_spec_compliant_, direction);
BIND(&slow);
BIND(&fully_spec_compliant_);
Node* result =
CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
......@@ -440,7 +477,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
} else {
k_.Bind(NumberDec(len()));
}
a_.Bind(generator(this));
generator(this);
Node* elements_type = LoadInstanceType(LoadElements(o_));
Switch(elements_type, &unexpected_instance_type, instance_types.data(),
label_ptrs.data(), labels.size());
......@@ -690,6 +727,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Variable k_;
Variable a_;
Variable to_;
Label fully_spec_compliant_;
};
TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
......@@ -1168,7 +1206,7 @@ TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) {
len, to);
GenerateIteratingArrayBuiltinLoopContinuation(
&ArrayBuiltinCodeStubAssembler::MapProcessor,
&ArrayBuiltinCodeStubAssembler::SpecCompliantMapProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
}
......@@ -1187,7 +1225,7 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinBody(
"Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator,
&ArrayBuiltinCodeStubAssembler::MapProcessor,
&ArrayBuiltinCodeStubAssembler::FastMapProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
}
......
......@@ -51,7 +51,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(Tuple2Map, Tuple2Map) \
V(Tuple3Map, Tuple3Map) \
V(UndefinedValue, Undefined) \
V(WeakCellMap, WeakCellMap)
V(WeakCellMap, WeakCellMap) \
V(SpeciesProtector, SpeciesProtector)
// Provides JavaScript-specific "macro-assembler" functionality on top of the
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
......
......@@ -65,6 +65,7 @@
# Too slow in debug mode for validation of elements.
'regress/regress-430201': [PASS, ['mode == debug', SKIP]],
'regress/regress-430201b': [PASS, ['mode == debug', SKIP]],
'regress/regress-716044': [PASS, ['mode == debug', SKIP]],
##############################################################################
# Too slow in debug mode for GC stress mode.
......
// 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: --verify-heap
class Array1 extends Array {
constructor(len) {
super(1);
}
};
class MyArray extends Array {
static get [Symbol.species]() {
return Array1;
}
}
a = new MyArray();
for (var i = 0; i < 100000; i++) {
a.push(1);
}
a.map(function(x) { return 42; });
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