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 { ...@@ -15,13 +15,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
: CodeStubAssembler(state), : CodeStubAssembler(state),
k_(this, MachineRepresentation::kTagged), k_(this, MachineRepresentation::kTagged),
a_(this, MachineRepresentation::kTagged), a_(this, MachineRepresentation::kTagged),
to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} to_(this, MachineRepresentation::kTagged, SmiConstant(0)),
fully_spec_compliant_(this, {&k_, &a_, &to_}) {}
typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)>
BuiltinResultGenerator;
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
BuiltinResultIndexInitializer; BuiltinResultGenerator;
typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm,
Node* k_value, Node* k)> Node* k_value, Node* k)>
...@@ -30,7 +28,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -30,7 +28,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)>
PostLoopAction; PostLoopAction;
Node* ForEachResultGenerator() { return UndefinedConstant(); } void ForEachResultGenerator() { a_.Bind(UndefinedConstant()); }
Node* ForEachProcessor(Node* k_value, Node* k) { Node* ForEachProcessor(Node* k_value, Node* k) {
CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(),
...@@ -38,7 +36,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -38,7 +36,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a(); return a();
} }
Node* SomeResultGenerator() { return FalseConstant(); } void SomeResultGenerator() { a_.Bind(FalseConstant()); }
Node* SomeProcessor(Node* k_value, Node* k) { Node* SomeProcessor(Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
...@@ -51,7 +49,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -51,7 +49,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a(); return a();
} }
Node* EveryResultGenerator() { return TrueConstant(); } void EveryResultGenerator() { a_.Bind(TrueConstant()); }
Node* EveryProcessor(Node* k_value, Node* k) { Node* EveryProcessor(Node* k_value, Node* k) {
Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(),
...@@ -64,7 +62,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -64,7 +62,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a(); return a();
} }
Node* ReduceResultGenerator() { return this_arg(); } void ReduceResultGenerator() { return a_.Bind(this_arg()); }
Node* ReduceProcessor(Node* k_value, Node* k) { Node* ReduceProcessor(Node* k_value, Node* k) {
VARIABLE(result, MachineRepresentation::kTagged); VARIABLE(result, MachineRepresentation::kTagged);
...@@ -91,9 +89,9 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -91,9 +89,9 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
BIND(&ok); BIND(&ok);
} }
Node* FilterResultGenerator() { void FilterResultGenerator() {
// 7. Let A be ArraySpeciesCreate(O, 0). // 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) { Node* FilterProcessor(Node* k_value, Node* k) {
...@@ -162,13 +160,53 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -162,13 +160,53 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
return a(); return a();
} }
Node* MapResultGenerator() { void MapResultGenerator() {
// 5. Let A be ? ArraySpeciesCreate(O, len). Label runtime(this), done(this, {&a_});
return ArraySpeciesCreate(context(), o(), len_); 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) { Node* FastMapProcessor(Node* k_value, Node* k) {
// i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. // i. Let kValue be ? Get(O, Pk). Performed by the caller of
// FastMapProcessor.
// ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O).
Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(),
callbackfn(), this_arg(), k_value, k, o()); callbackfn(), this_arg(), k_value, k, o());
...@@ -268,8 +306,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -268,8 +306,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
const CallResultProcessor& processor, const PostLoopAction& action, const CallResultProcessor& processor, const PostLoopAction& action,
const Callable& slow_case_continuation, const Callable& slow_case_continuation,
ForEachDirection direction = ForEachDirection::kForward) { ForEachDirection direction = ForEachDirection::kForward) {
Label non_array(this), slow(this, {&k_, &a_, &to_}), Label non_array(this), array_changes(this, {&k_, &a_, &to_});
array_changes(this, {&k_, &a_, &to_});
// TODO(danno): Seriously? Do we really need to throw the exact error // TODO(danno): Seriously? Do we really need to throw the exact error
// message on null and undefined so that the webkit tests pass? // message on null and undefined so that the webkit tests pass?
...@@ -336,11 +373,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -336,11 +373,11 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
k_.Bind(NumberDec(len())); 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 = Node* result =
CallStub(slow_case_continuation, context(), receiver(), callbackfn(), CallStub(slow_case_continuation, context(), receiver(), callbackfn(),
...@@ -440,7 +477,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -440,7 +477,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
} else { } else {
k_.Bind(NumberDec(len())); k_.Bind(NumberDec(len()));
} }
a_.Bind(generator(this)); generator(this);
Node* elements_type = LoadInstanceType(LoadElements(o_)); Node* elements_type = LoadInstanceType(LoadElements(o_));
Switch(elements_type, &unexpected_instance_type, instance_types.data(), Switch(elements_type, &unexpected_instance_type, instance_types.data(),
label_ptrs.data(), labels.size()); label_ptrs.data(), labels.size());
...@@ -690,6 +727,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { ...@@ -690,6 +727,7 @@ class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler {
Variable k_; Variable k_;
Variable a_; Variable a_;
Variable to_; Variable to_;
Label fully_spec_compliant_;
}; };
TF_BUILTIN(FastArrayPush, CodeStubAssembler) { TF_BUILTIN(FastArrayPush, CodeStubAssembler) {
...@@ -1168,7 +1206,7 @@ TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) { ...@@ -1168,7 +1206,7 @@ TF_BUILTIN(ArrayMapLoopContinuation, ArrayBuiltinCodeStubAssembler) {
len, to); len, to);
GenerateIteratingArrayBuiltinLoopContinuation( GenerateIteratingArrayBuiltinLoopContinuation(
&ArrayBuiltinCodeStubAssembler::MapProcessor, &ArrayBuiltinCodeStubAssembler::SpecCompliantMapProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction); &ArrayBuiltinCodeStubAssembler::NullPostLoopAction);
} }
...@@ -1187,7 +1225,7 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) { ...@@ -1187,7 +1225,7 @@ TF_BUILTIN(ArrayMap, ArrayBuiltinCodeStubAssembler) {
GenerateIteratingArrayBuiltinBody( GenerateIteratingArrayBuiltinBody(
"Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator, "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator,
&ArrayBuiltinCodeStubAssembler::MapProcessor, &ArrayBuiltinCodeStubAssembler::FastMapProcessor,
&ArrayBuiltinCodeStubAssembler::NullPostLoopAction, &ArrayBuiltinCodeStubAssembler::NullPostLoopAction,
Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation)); Builtins::CallableFor(isolate(), Builtins::kArrayMapLoopContinuation));
} }
......
...@@ -51,7 +51,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol }; ...@@ -51,7 +51,8 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(Tuple2Map, Tuple2Map) \ V(Tuple2Map, Tuple2Map) \
V(Tuple3Map, Tuple3Map) \ V(Tuple3Map, Tuple3Map) \
V(UndefinedValue, Undefined) \ V(UndefinedValue, Undefined) \
V(WeakCellMap, WeakCellMap) V(WeakCellMap, WeakCellMap) \
V(SpeciesProtector, SpeciesProtector)
// Provides JavaScript-specific "macro-assembler" functionality on top of the // Provides JavaScript-specific "macro-assembler" functionality on top of the
// CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler, // CodeAssembler. By factoring the JavaScript-isms out of the CodeAssembler,
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
# Too slow in debug mode for validation of elements. # Too slow in debug mode for validation of elements.
'regress/regress-430201': [PASS, ['mode == debug', SKIP]], 'regress/regress-430201': [PASS, ['mode == debug', SKIP]],
'regress/regress-430201b': [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. # 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