[builtins] Separate species protectors for Array, TypedArray, Promise
Previously, there was one species protector for Array, TypedArray and Promise. This CL splits the protector in three separate ones. This means that invalidating one of them does not have negative performance implications for the other ones. Bug: chromium:835347, v8:7340 Change-Id: Id84aa0071f17096192965264eb60ddadd1e8e73f Reviewed-on: https://chromium-review.googlesource.com/1023408 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#52733}
This commit is contained in:
parent
c823ca959e
commit
5728b3fbc5
@ -20,7 +20,7 @@ module array {
|
|||||||
let map: Map = a.map;
|
let map: Map = a.map;
|
||||||
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Bailout;
|
if (!IsPrototypeInitialArrayPrototype(context, map)) goto Bailout;
|
||||||
if (IsNoElementsProtectorCellInvalid()) goto Bailout;
|
if (IsNoElementsProtectorCellInvalid()) goto Bailout;
|
||||||
if (IsSpeciesProtectorCellInvalid()) goto Bailout;
|
if (IsArraySpeciesProtectorCellInvalid()) goto Bailout;
|
||||||
|
|
||||||
// Fast path only works on fast elements kind and with writable length.
|
// Fast path only works on fast elements kind and with writable length.
|
||||||
let elementsKind: int32 = EnsureArrayPushable(map) otherwise Bailout;
|
let elementsKind: int32 = EnsureArrayPushable(map) otherwise Bailout;
|
||||||
|
@ -199,7 +199,9 @@ extern macro BranchIfNotFastJSArray(Object, Context): never labels True, False;
|
|||||||
|
|
||||||
extern macro IsPrototypeInitialArrayPrototype(Context, Map): bit;
|
extern macro IsPrototypeInitialArrayPrototype(Context, Map): bit;
|
||||||
extern macro IsNoElementsProtectorCellInvalid(): bit;
|
extern macro IsNoElementsProtectorCellInvalid(): bit;
|
||||||
extern macro IsSpeciesProtectorCellInvalid(): bit;
|
extern macro IsArraySpeciesProtectorCellInvalid(): bit;
|
||||||
|
extern macro IsTypedArraySpeciesProtectorCellInvalid(): bit;
|
||||||
|
extern macro IsPromiseSpeciesProtectorCellInvalid(): bit;
|
||||||
|
|
||||||
extern operator '.elements_kind' macro LoadMapElementsKind(Map): int32;
|
extern operator '.elements_kind' macro LoadMapElementsKind(Map): int32;
|
||||||
|
|
||||||
|
@ -817,7 +817,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
|
|||||||
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
||||||
&runtime);
|
&runtime);
|
||||||
|
|
||||||
Node* species_protector = SpeciesProtectorConstant();
|
Node* species_protector = ArraySpeciesProtectorConstant();
|
||||||
Node* value =
|
Node* value =
|
||||||
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
||||||
TNode<Smi> const protector_invalid =
|
TNode<Smi> const protector_invalid =
|
||||||
@ -862,7 +862,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
|
|||||||
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
||||||
&runtime);
|
&runtime);
|
||||||
|
|
||||||
Node* species_protector = SpeciesProtectorConstant();
|
Node* species_protector = ArraySpeciesProtectorConstant();
|
||||||
Node* value =
|
Node* value =
|
||||||
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
||||||
Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
|
Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||||
@ -1155,7 +1155,7 @@ class ArrayPrototypeSliceCodeStubAssembler : public CodeStubAssembler {
|
|||||||
|
|
||||||
GotoIf(IsNoElementsProtectorCellInvalid(), slow);
|
GotoIf(IsNoElementsProtectorCellInvalid(), slow);
|
||||||
|
|
||||||
GotoIf(IsSpeciesProtectorCellInvalid(), slow);
|
GotoIf(IsArraySpeciesProtectorCellInvalid(), slow);
|
||||||
|
|
||||||
// Bailout if receiver has slow elements.
|
// Bailout if receiver has slow elements.
|
||||||
Node* elements_kind = LoadMapElementsKind(map);
|
Node* elements_kind = LoadMapElementsKind(map);
|
||||||
|
@ -247,7 +247,7 @@ BUILTIN(ArraySplice) {
|
|||||||
// If this is a subclass of Array, then call out to JS.
|
// If this is a subclass of Array, then call out to JS.
|
||||||
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
|
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
|
||||||
// If anything with @@species has been messed with, call out to JS.
|
// If anything with @@species has been messed with, call out to JS.
|
||||||
!isolate->IsSpeciesLookupChainIntact())) {
|
!isolate->IsArraySpeciesLookupChainIntact())) {
|
||||||
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
|
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
|
||||||
}
|
}
|
||||||
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
|
Handle<JSArray> array = Handle<JSArray>::cast(receiver);
|
||||||
@ -1123,7 +1123,7 @@ BUILTIN(ArrayConcat) {
|
|||||||
// Avoid a real species read to avoid extra lookups to the array constructor
|
// Avoid a real species read to avoid extra lookups to the array constructor
|
||||||
if (V8_LIKELY(receiver->IsJSArray() &&
|
if (V8_LIKELY(receiver->IsJSArray() &&
|
||||||
Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
|
Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
|
||||||
isolate->IsSpeciesLookupChainIntact())) {
|
isolate->IsArraySpeciesLookupChainIntact())) {
|
||||||
if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
|
if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
|
||||||
return *result_array;
|
return *result_array;
|
||||||
}
|
}
|
||||||
|
@ -635,7 +635,7 @@ void PromiseBuiltinsAssembler::BranchIfPromiseSpeciesLookupChainIntact(
|
|||||||
GotoIfForceSlowPath(if_slow);
|
GotoIfForceSlowPath(if_slow);
|
||||||
GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
|
GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
|
||||||
if_slow);
|
if_slow);
|
||||||
Branch(IsSpeciesProtectorCellInvalid(), if_slow, if_fast);
|
Branch(IsPromiseSpeciesProtectorCellInvalid(), if_slow, if_fast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
|
void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
|
||||||
@ -1285,7 +1285,7 @@ TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
|
|||||||
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
|
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
|
||||||
GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
|
GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
|
||||||
&if_slow_constructor);
|
&if_slow_constructor);
|
||||||
GotoIf(IsSpeciesProtectorCellInvalid(), &if_slow_constructor);
|
GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
|
||||||
|
|
||||||
// If the {constructor} is the Promise function, we just immediately
|
// If the {constructor} is the Promise function, we just immediately
|
||||||
// return the {value} here and don't bother wrapping it into a
|
// return the {value} here and don't bother wrapping it into a
|
||||||
|
@ -883,7 +883,7 @@ TNode<Object> TypedArrayBuiltinsAssembler::TypedArraySpeciesConstructor(
|
|||||||
var_constructor = default_constructor;
|
var_constructor = default_constructor;
|
||||||
Node* map = LoadMap(exemplar);
|
Node* map = LoadMap(exemplar);
|
||||||
GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
|
GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
|
||||||
Branch(IsSpeciesProtectorCellInvalid(), &slow, &done);
|
Branch(IsTypedArraySpeciesProtectorCellInvalid(), &slow, &done);
|
||||||
|
|
||||||
BIND(&slow);
|
BIND(&slow);
|
||||||
var_constructor = SpeciesConstructor(context, exemplar, default_constructor);
|
var_constructor = SpeciesConstructor(context, exemplar, default_constructor);
|
||||||
|
@ -991,7 +991,7 @@ void CodeStubAssembler::BranchIfFastJSArray(Node* object, Node* context,
|
|||||||
void CodeStubAssembler::BranchIfFastJSArrayForCopy(Node* object, Node* context,
|
void CodeStubAssembler::BranchIfFastJSArrayForCopy(Node* object, Node* context,
|
||||||
Label* if_true,
|
Label* if_true,
|
||||||
Label* if_false) {
|
Label* if_false) {
|
||||||
GotoIf(IsSpeciesProtectorCellInvalid(), if_false);
|
GotoIf(IsArraySpeciesProtectorCellInvalid(), if_false);
|
||||||
BranchIfFastJSArray(object, context, if_true, if_false);
|
BranchIfFastJSArray(object, context, if_true, if_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4545,9 +4545,23 @@ Node* CodeStubAssembler::IsPromiseThenProtectorCellInvalid() {
|
|||||||
return WordEqual(cell_value, invalid);
|
return WordEqual(cell_value, invalid);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* CodeStubAssembler::IsSpeciesProtectorCellInvalid() {
|
Node* CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() {
|
||||||
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||||
Node* cell = LoadRoot(Heap::kSpeciesProtectorRootIndex);
|
Node* cell = LoadRoot(Heap::kArraySpeciesProtectorRootIndex);
|
||||||
|
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||||
|
return WordEqual(cell_value, invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* CodeStubAssembler::IsTypedArraySpeciesProtectorCellInvalid() {
|
||||||
|
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||||
|
Node* cell = LoadRoot(Heap::kTypedArraySpeciesProtectorRootIndex);
|
||||||
|
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||||
|
return WordEqual(cell_value, invalid);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* CodeStubAssembler::IsPromiseSpeciesProtectorCellInvalid() {
|
||||||
|
Node* invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||||
|
Node* cell = LoadRoot(Heap::kPromiseSpeciesProtectorRootIndex);
|
||||||
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
Node* cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
|
||||||
return WordEqual(cell_value, invalid);
|
return WordEqual(cell_value, invalid);
|
||||||
}
|
}
|
||||||
|
@ -22,50 +22,54 @@ class StubCache;
|
|||||||
|
|
||||||
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||||
|
|
||||||
#define HEAP_CONSTANT_LIST(V) \
|
#define HEAP_CONSTANT_LIST(V) \
|
||||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||||
V(BooleanMap, boolean_map, BooleanMap) \
|
V(BooleanMap, boolean_map, BooleanMap) \
|
||||||
V(CodeMap, code_map, CodeMap) \
|
V(CodeMap, code_map, CodeMap) \
|
||||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||||
EmptyPropertyDictionary) \
|
EmptyPropertyDictionary) \
|
||||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||||
EmptySlowElementDictionary) \
|
EmptySlowElementDictionary) \
|
||||||
V(empty_string, empty_string, EmptyString) \
|
V(empty_string, empty_string, EmptyString) \
|
||||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||||
V(FalseValue, false_value, False) \
|
V(FalseValue, false_value, False) \
|
||||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||||
FunctionTemplateInfoMap) \
|
FunctionTemplateInfoMap) \
|
||||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||||
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
|
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
|
||||||
V(length_string, length_string, LengthString) \
|
V(length_string, length_string, LengthString) \
|
||||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||||
V(MetaMap, meta_map, MetaMap) \
|
V(MetaMap, meta_map, MetaMap) \
|
||||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||||
V(NanValue, nan_value, Nan) \
|
V(NanValue, nan_value, Nan) \
|
||||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||||
V(NullValue, null_value, Null) \
|
V(NullValue, null_value, Null) \
|
||||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||||
V(prototype_string, prototype_string, PrototypeString) \
|
V(prototype_string, prototype_string, PrototypeString) \
|
||||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \
|
||||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
V(TypedArraySpeciesProtector, typed_array_species_protector, \
|
||||||
V(SymbolMap, symbol_map, SymbolMap) \
|
TypedArraySpeciesProtector) \
|
||||||
V(TheHoleValue, the_hole_value, TheHole) \
|
V(PromiseSpeciesProtector, promise_species_protector, \
|
||||||
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
|
PromiseSpeciesProtector) \
|
||||||
V(TrueValue, true_value, True) \
|
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||||
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
V(SymbolMap, symbol_map, SymbolMap) \
|
||||||
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
V(TheHoleValue, the_hole_value, TheHole) \
|
||||||
V(UndefinedValue, undefined_value, Undefined) \
|
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
|
||||||
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
V(TrueValue, true_value, True) \
|
||||||
|
V(Tuple2Map, tuple2_map, Tuple2Map) \
|
||||||
|
V(Tuple3Map, tuple3_map, Tuple3Map) \
|
||||||
|
V(UndefinedValue, undefined_value, Undefined) \
|
||||||
|
V(WeakCellMap, weak_cell_map, WeakCellMap) \
|
||||||
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
|
V(SharedFunctionInfoMap, shared_function_info_map, SharedFunctionInfoMap)
|
||||||
|
|
||||||
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
|
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
|
||||||
@ -1383,7 +1387,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
|
|
||||||
Node* IsPromiseResolveProtectorCellInvalid();
|
Node* IsPromiseResolveProtectorCellInvalid();
|
||||||
Node* IsPromiseThenProtectorCellInvalid();
|
Node* IsPromiseThenProtectorCellInvalid();
|
||||||
Node* IsSpeciesProtectorCellInvalid();
|
Node* IsArraySpeciesProtectorCellInvalid();
|
||||||
|
Node* IsTypedArraySpeciesProtectorCellInvalid();
|
||||||
|
Node* IsPromiseSpeciesProtectorCellInvalid();
|
||||||
|
|
||||||
// True iff |object| is a Smi or a HeapNumber.
|
// True iff |object| is a Smi or a HeapNumber.
|
||||||
TNode<BoolT> IsNumber(SloppyTNode<Object> object);
|
TNode<BoolT> IsNumber(SloppyTNode<Object> object);
|
||||||
|
@ -1481,7 +1481,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
|||||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||||
|
|
||||||
// Ensure that any changes to the Array species constructor cause deopt.
|
// Ensure that any changes to the Array species constructor cause deopt.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
||||||
|
|
||||||
@ -1492,7 +1492,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
|||||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||||
|
|
||||||
Handle<JSFunction> handle_constructor(
|
Handle<JSFunction> handle_constructor(
|
||||||
JSFunction::cast(
|
JSFunction::cast(
|
||||||
@ -1681,7 +1681,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
|
|||||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||||
|
|
||||||
// And ensure that any changes to the Array species constructor cause deopt.
|
// And ensure that any changes to the Array species constructor cause deopt.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
||||||
// The output array is packed (filter doesn't visit holes).
|
// The output array is packed (filter doesn't visit holes).
|
||||||
@ -1696,7 +1696,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
|
|||||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||||
|
|
||||||
Handle<Map> initial_map(
|
Handle<Map> initial_map(
|
||||||
Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)));
|
Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)));
|
||||||
@ -2274,7 +2274,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
|||||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||||
|
|
||||||
// And ensure that any changes to the Array species constructor cause deopt.
|
// And ensure that any changes to the Array species constructor cause deopt.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
const ElementsKind kind = receiver_maps[0]->elements_kind();
|
||||||
|
|
||||||
@ -2285,7 +2285,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
|||||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||||
|
|
||||||
// If we have unreliable maps, we need a map check.
|
// If we have unreliable maps, we need a map check.
|
||||||
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
if (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||||
@ -2597,7 +2597,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
|||||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||||
|
|
||||||
// And ensure that any changes to the Array species constructor cause deopt.
|
// And ensure that any changes to the Array species constructor cause deopt.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsArraySpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
if (receiver_maps.size() == 0) return NoChange();
|
if (receiver_maps.size() == 0) return NoChange();
|
||||||
|
|
||||||
@ -2610,7 +2610,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
|||||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||||
|
|
||||||
Node* k = jsgraph()->ZeroConstant();
|
Node* k = jsgraph()->ZeroConstant();
|
||||||
|
|
||||||
@ -5730,7 +5730,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
|||||||
// lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is
|
// lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is
|
||||||
// the initial %PromisePrototype%, and the Symbol.species lookup on the
|
// the initial %PromisePrototype%, and the Symbol.species lookup on the
|
||||||
// %PromisePrototype%.
|
// %PromisePrototype%.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
// Check if we know something about {receiver} already.
|
// Check if we know something about {receiver} already.
|
||||||
ZoneHandleSet<Map> receiver_maps;
|
ZoneHandleSet<Map> receiver_maps;
|
||||||
@ -5751,7 +5751,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
|||||||
// Add a code dependency on the necessary protectors.
|
// Add a code dependency on the necessary protectors.
|
||||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||||
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
dependencies()->AssumePropertyCell(factory()->promise_then_protector());
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->promise_species_protector());
|
||||||
|
|
||||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||||
// map check here, guarded by the CALL_IC.
|
// map check here, guarded by the CALL_IC.
|
||||||
@ -5878,7 +5878,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
|
|||||||
// guards the "constructor" lookup on all JSPromise instances and the
|
// guards the "constructor" lookup on all JSPromise instances and the
|
||||||
// initial Promise.prototype, as well as the Symbol.species lookup on
|
// initial Promise.prototype, as well as the Symbol.species lookup on
|
||||||
// the Promise constructor.
|
// the Promise constructor.
|
||||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
|
||||||
|
|
||||||
// Check if we know something about {receiver} already.
|
// Check if we know something about {receiver} already.
|
||||||
ZoneHandleSet<Map> receiver_maps;
|
ZoneHandleSet<Map> receiver_maps;
|
||||||
@ -5900,7 +5900,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
|
|||||||
|
|
||||||
// Add a code dependency on the necessary protectors.
|
// Add a code dependency on the necessary protectors.
|
||||||
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
dependencies()->AssumePropertyCell(factory()->promise_hook_protector());
|
||||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
dependencies()->AssumePropertyCell(factory()->promise_species_protector());
|
||||||
|
|
||||||
// If the {receiver_maps} aren't reliable, we need to repeat the
|
// If the {receiver_maps} aren't reliable, we need to repeat the
|
||||||
// map check here, guarded by the CALL_IC.
|
// map check here, guarded by the CALL_IC.
|
||||||
|
@ -228,7 +228,9 @@ using v8::MemoryPressureLevel;
|
|||||||
V(Cell, array_constructor_protector, ArrayConstructorProtector) \
|
V(Cell, array_constructor_protector, ArrayConstructorProtector) \
|
||||||
V(PropertyCell, no_elements_protector, NoElementsProtector) \
|
V(PropertyCell, no_elements_protector, NoElementsProtector) \
|
||||||
V(Cell, is_concat_spreadable_protector, IsConcatSpreadableProtector) \
|
V(Cell, is_concat_spreadable_protector, IsConcatSpreadableProtector) \
|
||||||
V(PropertyCell, species_protector, SpeciesProtector) \
|
V(PropertyCell, array_species_protector, ArraySpeciesProtector) \
|
||||||
|
V(PropertyCell, typed_array_species_protector, TypedArraySpeciesProtector) \
|
||||||
|
V(PropertyCell, promise_species_protector, PromiseSpeciesProtector) \
|
||||||
V(Cell, string_length_protector, StringLengthProtector) \
|
V(Cell, string_length_protector, StringLengthProtector) \
|
||||||
V(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \
|
V(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \
|
||||||
V(PropertyCell, array_buffer_neutering_protector, \
|
V(PropertyCell, array_buffer_neutering_protector, \
|
||||||
@ -389,7 +391,9 @@ using v8::MemoryPressureLevel;
|
|||||||
V(SloppyArgumentsElementsMap) \
|
V(SloppyArgumentsElementsMap) \
|
||||||
V(SmallOrderedHashMapMap) \
|
V(SmallOrderedHashMapMap) \
|
||||||
V(SmallOrderedHashSetMap) \
|
V(SmallOrderedHashSetMap) \
|
||||||
V(SpeciesProtector) \
|
V(ArraySpeciesProtector) \
|
||||||
|
V(TypedArraySpeciesProtector) \
|
||||||
|
V(PromiseSpeciesProtector) \
|
||||||
V(StaleRegister) \
|
V(StaleRegister) \
|
||||||
V(StringLengthProtector) \
|
V(StringLengthProtector) \
|
||||||
V(StringTableMap) \
|
V(StringTableMap) \
|
||||||
|
@ -787,7 +787,15 @@ void Heap::CreateInitialObjects() {
|
|||||||
|
|
||||||
cell = factory->NewPropertyCell(factory->empty_string());
|
cell = factory->NewPropertyCell(factory->empty_string());
|
||||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||||
set_species_protector(*cell);
|
set_array_species_protector(*cell);
|
||||||
|
|
||||||
|
cell = factory->NewPropertyCell(factory->empty_string());
|
||||||
|
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||||
|
set_typed_array_species_protector(*cell);
|
||||||
|
|
||||||
|
cell = factory->NewPropertyCell(factory->empty_string());
|
||||||
|
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||||
|
set_promise_species_protector(*cell);
|
||||||
|
|
||||||
Handle<Cell> string_length_overflow_cell = factory->NewCell(
|
Handle<Cell> string_length_overflow_cell = factory->NewCell(
|
||||||
handle(Smi::FromInt(Isolate::kProtectorValid), isolate()));
|
handle(Smi::FromInt(Isolate::kProtectorValid), isolate()));
|
||||||
|
@ -133,7 +133,7 @@ bool Isolate::IsArrayConstructorIntact() {
|
|||||||
return array_constructor_cell->value() == Smi::FromInt(kProtectorValid);
|
return array_constructor_cell->value() == Smi::FromInt(kProtectorValid);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Isolate::IsSpeciesLookupChainIntact() {
|
bool Isolate::IsArraySpeciesLookupChainIntact() {
|
||||||
// Note: It would be nice to have debug checks to make sure that the
|
// Note: It would be nice to have debug checks to make sure that the
|
||||||
// species protector is accurate, but this would be hard to do for most of
|
// species protector is accurate, but this would be hard to do for most of
|
||||||
// what the protector stands for:
|
// what the protector stands for:
|
||||||
@ -146,7 +146,19 @@ bool Isolate::IsSpeciesLookupChainIntact() {
|
|||||||
// done here. In place, there are mjsunit tests harmony/array-species* which
|
// done here. In place, there are mjsunit tests harmony/array-species* which
|
||||||
// ensure that behavior is correct in various invalid protector cases.
|
// ensure that behavior is correct in various invalid protector cases.
|
||||||
|
|
||||||
PropertyCell* species_cell = heap()->species_protector();
|
PropertyCell* species_cell = heap()->array_species_protector();
|
||||||
|
return species_cell->value()->IsSmi() &&
|
||||||
|
Smi::ToInt(species_cell->value()) == kProtectorValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Isolate::IsTypedArraySpeciesLookupChainIntact() {
|
||||||
|
PropertyCell* species_cell = heap()->typed_array_species_protector();
|
||||||
|
return species_cell->value()->IsSmi() &&
|
||||||
|
Smi::ToInt(species_cell->value()) == kProtectorValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Isolate::IsPromiseSpeciesLookupChainIntact() {
|
||||||
|
PropertyCell* species_cell = heap()->promise_species_protector();
|
||||||
return species_cell->value()->IsSmi() &&
|
return species_cell->value()->IsSmi() &&
|
||||||
Smi::ToInt(species_cell->value()) == kProtectorValid;
|
Smi::ToInt(species_cell->value()) == kProtectorValid;
|
||||||
}
|
}
|
||||||
|
@ -3573,11 +3573,28 @@ void Isolate::InvalidateArrayConstructorProtector() {
|
|||||||
DCHECK(!IsArrayConstructorIntact());
|
DCHECK(!IsArrayConstructorIntact());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Isolate::InvalidateSpeciesProtector() {
|
void Isolate::InvalidateArraySpeciesProtector() {
|
||||||
DCHECK(factory()->species_protector()->value()->IsSmi());
|
DCHECK(factory()->array_species_protector()->value()->IsSmi());
|
||||||
DCHECK(IsSpeciesLookupChainIntact());
|
DCHECK(IsArraySpeciesLookupChainIntact());
|
||||||
factory()->species_protector()->set_value(Smi::FromInt(kProtectorInvalid));
|
factory()->array_species_protector()->set_value(
|
||||||
DCHECK(!IsSpeciesLookupChainIntact());
|
Smi::FromInt(kProtectorInvalid));
|
||||||
|
DCHECK(!IsArraySpeciesLookupChainIntact());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Isolate::InvalidateTypedArraySpeciesProtector() {
|
||||||
|
DCHECK(factory()->typed_array_species_protector()->value()->IsSmi());
|
||||||
|
DCHECK(IsTypedArraySpeciesLookupChainIntact());
|
||||||
|
factory()->typed_array_species_protector()->set_value(
|
||||||
|
Smi::FromInt(kProtectorInvalid));
|
||||||
|
DCHECK(!IsTypedArraySpeciesLookupChainIntact());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Isolate::InvalidatePromiseSpeciesProtector() {
|
||||||
|
DCHECK(factory()->promise_species_protector()->value()->IsSmi());
|
||||||
|
DCHECK(IsPromiseSpeciesLookupChainIntact());
|
||||||
|
factory()->promise_species_protector()->set_value(
|
||||||
|
Smi::FromInt(kProtectorInvalid));
|
||||||
|
DCHECK(!IsPromiseSpeciesLookupChainIntact());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Isolate::InvalidateStringLengthOverflowProtector() {
|
void Isolate::InvalidateStringLengthOverflowProtector() {
|
||||||
|
@ -1080,7 +1080,9 @@ class Isolate : private HiddenFactory {
|
|||||||
bool IsNoElementsProtectorIntact(Context* context);
|
bool IsNoElementsProtectorIntact(Context* context);
|
||||||
bool IsNoElementsProtectorIntact();
|
bool IsNoElementsProtectorIntact();
|
||||||
|
|
||||||
inline bool IsSpeciesLookupChainIntact();
|
inline bool IsArraySpeciesLookupChainIntact();
|
||||||
|
inline bool IsTypedArraySpeciesLookupChainIntact();
|
||||||
|
inline bool IsPromiseSpeciesLookupChainIntact();
|
||||||
bool IsIsConcatSpreadableLookupChainIntact();
|
bool IsIsConcatSpreadableLookupChainIntact();
|
||||||
bool IsIsConcatSpreadableLookupChainIntact(JSReceiver* receiver);
|
bool IsIsConcatSpreadableLookupChainIntact(JSReceiver* receiver);
|
||||||
inline bool IsStringLengthOverflowIntact();
|
inline bool IsStringLengthOverflowIntact();
|
||||||
@ -1120,7 +1122,9 @@ class Isolate : private HiddenFactory {
|
|||||||
UpdateNoElementsProtectorOnSetElement(object);
|
UpdateNoElementsProtectorOnSetElement(object);
|
||||||
}
|
}
|
||||||
void InvalidateArrayConstructorProtector();
|
void InvalidateArrayConstructorProtector();
|
||||||
void InvalidateSpeciesProtector();
|
void InvalidateArraySpeciesProtector();
|
||||||
|
void InvalidateTypedArraySpeciesProtector();
|
||||||
|
void InvalidatePromiseSpeciesProtector();
|
||||||
void InvalidateIsConcatSpreadableProtector();
|
void InvalidateIsConcatSpreadableProtector();
|
||||||
void InvalidateStringLengthOverflowProtector();
|
void InvalidateStringLengthOverflowProtector();
|
||||||
void InvalidateArrayIteratorProtector();
|
void InvalidateArrayIteratorProtector();
|
||||||
|
@ -272,14 +272,27 @@ void LookupIterator::InternalUpdateProtector() {
|
|||||||
if (isolate_->bootstrapper()->IsActive()) return;
|
if (isolate_->bootstrapper()->IsActive()) return;
|
||||||
|
|
||||||
if (*name_ == heap()->constructor_string()) {
|
if (*name_ == heap()->constructor_string()) {
|
||||||
if (!isolate_->IsSpeciesLookupChainIntact()) return;
|
if (!isolate_->IsArraySpeciesLookupChainIntact() &&
|
||||||
|
!isolate_->IsTypedArraySpeciesLookupChainIntact() &&
|
||||||
|
!isolate_->IsPromiseSpeciesLookupChainIntact())
|
||||||
|
return;
|
||||||
// Setting the constructor property could change an instance's @@species
|
// Setting the constructor property could change an instance's @@species
|
||||||
if (holder_->IsJSArray() || holder_->IsJSPromise() ||
|
if (holder_->IsJSArray()) {
|
||||||
holder_->IsJSTypedArray()) {
|
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||||
isolate_->CountUsage(
|
isolate_->CountUsage(
|
||||||
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
|
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
|
||||||
isolate_->InvalidateSpeciesProtector();
|
isolate_->InvalidateArraySpeciesProtector();
|
||||||
} else if (holder_->map()->is_prototype_map()) {
|
return;
|
||||||
|
} else if (holder_->IsJSPromise()) {
|
||||||
|
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidatePromiseSpeciesProtector();
|
||||||
|
return;
|
||||||
|
} else if (holder_->IsJSTypedArray()) {
|
||||||
|
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidateTypedArraySpeciesProtector();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (holder_->map()->is_prototype_map()) {
|
||||||
DisallowHeapAllocation no_gc;
|
DisallowHeapAllocation no_gc;
|
||||||
// Setting the constructor of Array.prototype, Promise.prototype or
|
// Setting the constructor of Array.prototype, Promise.prototype or
|
||||||
// %TypedArray%.prototype of any realm also needs to invalidate the
|
// %TypedArray%.prototype of any realm also needs to invalidate the
|
||||||
@ -288,14 +301,20 @@ void LookupIterator::InternalUpdateProtector() {
|
|||||||
// have different prototypes for each type, and their parent prototype is
|
// have different prototypes for each type, and their parent prototype is
|
||||||
// pointing the same TYPED_ARRAY_PROTOTYPE.
|
// pointing the same TYPED_ARRAY_PROTOTYPE.
|
||||||
if (isolate_->IsInAnyContext(*holder_,
|
if (isolate_->IsInAnyContext(*holder_,
|
||||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
|
Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
|
||||||
isolate_->IsInAnyContext(*holder_,
|
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||||
Context::PROMISE_PROTOTYPE_INDEX) ||
|
isolate_->CountUsage(
|
||||||
isolate_->IsInAnyContext(holder_->map()->prototype(),
|
v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
|
||||||
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
|
isolate_->InvalidateArraySpeciesProtector();
|
||||||
isolate_->CountUsage(v8::Isolate::UseCounterFeature::
|
} else if (isolate_->IsInAnyContext(*holder_,
|
||||||
kArrayPrototypeConstructorModified);
|
Context::PROMISE_PROTOTYPE_INDEX)) {
|
||||||
isolate_->InvalidateSpeciesProtector();
|
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidatePromiseSpeciesProtector();
|
||||||
|
} else if (isolate_->IsInAnyContext(
|
||||||
|
holder_->map()->prototype(),
|
||||||
|
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
|
||||||
|
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidateTypedArraySpeciesProtector();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (*name_ == heap()->next_string()) {
|
} else if (*name_ == heap()->next_string()) {
|
||||||
@ -307,15 +326,24 @@ void LookupIterator::InternalUpdateProtector() {
|
|||||||
isolate_->InvalidateArrayIteratorProtector();
|
isolate_->InvalidateArrayIteratorProtector();
|
||||||
}
|
}
|
||||||
} else if (*name_ == heap()->species_symbol()) {
|
} else if (*name_ == heap()->species_symbol()) {
|
||||||
if (!isolate_->IsSpeciesLookupChainIntact()) return;
|
if (!isolate_->IsArraySpeciesLookupChainIntact() &&
|
||||||
|
!isolate_->IsTypedArraySpeciesLookupChainIntact() &&
|
||||||
|
!isolate_->IsPromiseSpeciesLookupChainIntact())
|
||||||
|
return;
|
||||||
// Setting the Symbol.species property of any Array, Promise or TypedArray
|
// Setting the Symbol.species property of any Array, Promise or TypedArray
|
||||||
// constructor invalidates the @@species protector
|
// constructor invalidates the @@species protector
|
||||||
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX) ||
|
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
|
||||||
isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX) ||
|
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||||
IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
|
|
||||||
isolate_->CountUsage(
|
isolate_->CountUsage(
|
||||||
v8::Isolate::UseCounterFeature::kArraySpeciesModified);
|
v8::Isolate::UseCounterFeature::kArraySpeciesModified);
|
||||||
isolate_->InvalidateSpeciesProtector();
|
isolate_->InvalidateArraySpeciesProtector();
|
||||||
|
} else if (isolate_->IsInAnyContext(*holder_,
|
||||||
|
Context::PROMISE_FUNCTION_INDEX)) {
|
||||||
|
if (!isolate_->IsPromiseSpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidatePromiseSpeciesProtector();
|
||||||
|
} else if (IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
|
||||||
|
if (!isolate_->IsTypedArraySpeciesLookupChainIntact()) return;
|
||||||
|
isolate_->InvalidateTypedArraySpeciesProtector();
|
||||||
}
|
}
|
||||||
} else if (*name_ == heap()->is_concat_spreadable_symbol()) {
|
} else if (*name_ == heap()->is_concat_spreadable_symbol()) {
|
||||||
if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
|
if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
|
||||||
|
@ -2370,7 +2370,7 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
|
|||||||
Handle<Object> default_species = isolate->array_function();
|
Handle<Object> default_species = isolate->array_function();
|
||||||
if (original_array->IsJSArray() &&
|
if (original_array->IsJSArray() &&
|
||||||
Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
|
Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
|
||||||
isolate->IsSpeciesLookupChainIntact()) {
|
isolate->IsArraySpeciesLookupChainIntact()) {
|
||||||
return default_species;
|
return default_species;
|
||||||
}
|
}
|
||||||
Handle<Object> constructor = isolate->factory()->undefined_value();
|
Handle<Object> constructor = isolate->factory()->undefined_value();
|
||||||
|
@ -396,7 +396,7 @@ RUNTIME_FUNCTION(Runtime_TrySliceSimpleNonFastElements) {
|
|||||||
// implementation.
|
// implementation.
|
||||||
if (receiver->IsJSArray()) {
|
if (receiver->IsJSArray()) {
|
||||||
// This "fastish" path must make sure the destination array is a JSArray.
|
// This "fastish" path must make sure the destination array is a JSArray.
|
||||||
if (!isolate->IsSpeciesLookupChainIntact() ||
|
if (!isolate->IsArraySpeciesLookupChainIntact() ||
|
||||||
!JSArray::cast(*receiver)->HasArrayPrototype(isolate)) {
|
!JSArray::cast(*receiver)->HasArrayPrototype(isolate)) {
|
||||||
return Smi::FromInt(0);
|
return Smi::FromInt(0);
|
||||||
}
|
}
|
||||||
|
@ -841,11 +841,24 @@ TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
|||||||
|
|
||||||
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
|
||||||
RUNTIME_FUNCTION(Runtime_SpeciesProtector) {
|
|
||||||
SealHandleScope shs(isolate);
|
SealHandleScope shs(isolate);
|
||||||
DCHECK_EQ(0, args.length());
|
DCHECK_EQ(0, args.length());
|
||||||
return isolate->heap()->ToBoolean(isolate->IsSpeciesLookupChainIntact());
|
return isolate->heap()->ToBoolean(isolate->IsArraySpeciesLookupChainIntact());
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_TypedArraySpeciesProtector) {
|
||||||
|
SealHandleScope shs(isolate);
|
||||||
|
DCHECK_EQ(0, args.length());
|
||||||
|
return isolate->heap()->ToBoolean(
|
||||||
|
isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||||
|
}
|
||||||
|
|
||||||
|
RUNTIME_FUNCTION(Runtime_PromiseSpeciesProtector) {
|
||||||
|
SealHandleScope shs(isolate);
|
||||||
|
DCHECK_EQ(0, args.length());
|
||||||
|
return isolate->heap()->ToBoolean(
|
||||||
|
isolate->IsPromiseSpeciesLookupChainIntact());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take a compiled wasm module, serialize it and copy the buffer into an array
|
// Take a compiled wasm module, serialize it and copy the buffer into an array
|
||||||
|
@ -588,7 +588,9 @@ namespace internal {
|
|||||||
F(SetForceSlowPath, 1, 1) \
|
F(SetForceSlowPath, 1, 1) \
|
||||||
F(SetWasmCompileControls, 2, 1) \
|
F(SetWasmCompileControls, 2, 1) \
|
||||||
F(SetWasmInstantiateControls, 0, 1) \
|
F(SetWasmInstantiateControls, 0, 1) \
|
||||||
F(SpeciesProtector, 0, 1) \
|
F(ArraySpeciesProtector, 0, 1) \
|
||||||
|
F(TypedArraySpeciesProtector, 0, 1) \
|
||||||
|
F(PromiseSpeciesProtector, 0, 1) \
|
||||||
F(SystemBreak, 0, 1) \
|
F(SystemBreak, 0, 1) \
|
||||||
F(TraceEnter, 0, 1) \
|
F(TraceEnter, 0, 1) \
|
||||||
F(TraceExit, 1, 1) \
|
F(TraceExit, 1, 1) \
|
||||||
|
@ -117,12 +117,12 @@ void TestSpeciesProtector(char* code,
|
|||||||
|
|
||||||
v8::internal::Isolate* i_isolate =
|
v8::internal::Isolate* i_isolate =
|
||||||
reinterpret_cast<v8::internal::Isolate*>(isolate);
|
reinterpret_cast<v8::internal::Isolate*>(isolate);
|
||||||
CHECK(i_isolate->IsSpeciesLookupChainIntact());
|
CHECK(i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||||
CompileRun(code);
|
CompileRun(code);
|
||||||
if (invalidates_species_protector) {
|
if (invalidates_species_protector) {
|
||||||
CHECK(!i_isolate->IsSpeciesLookupChainIntact());
|
CHECK(!i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||||
} else {
|
} else {
|
||||||
CHECK(i_isolate->IsSpeciesLookupChainIntact());
|
CHECK(i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> my_typed_array = CompileRun("MyTypedArray");
|
v8::Local<v8::Value> my_typed_array = CompileRun("MyTypedArray");
|
||||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
|||||||
class MyArray extends Array { }
|
class MyArray extends Array { }
|
||||||
|
|
||||||
Object.defineProperty(x, 'constructor', {get() { return MyArray; }});
|
Object.defineProperty(x, 'constructor', {get() { return MyArray; }});
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -19,7 +19,7 @@ class MyArray extends Array { }
|
|||||||
|
|
||||||
Object.prototype.constructor = MyArray;
|
Object.prototype.constructor = MyArray;
|
||||||
delete Array.prototype.constructor;
|
delete Array.prototype.constructor;
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
|||||||
class MyArray extends Array { }
|
class MyArray extends Array { }
|
||||||
|
|
||||||
x.constructor = MyArray;
|
x.constructor = MyArray;
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -19,7 +19,7 @@ class MyArray extends Array { }
|
|||||||
|
|
||||||
Object.prototype[Symbol.species] = MyArray;
|
Object.prototype[Symbol.species] = MyArray;
|
||||||
delete Array[Symbol.species];
|
delete Array[Symbol.species];
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
|||||||
class MyArray extends Array { }
|
class MyArray extends Array { }
|
||||||
|
|
||||||
Object.defineProperty(Array, Symbol.species, {value: MyArray});
|
Object.defineProperty(Array, Symbol.species, {value: MyArray});
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
|||||||
class MyArray extends Array { }
|
class MyArray extends Array { }
|
||||||
|
|
||||||
Array.prototype.constructor = MyArray;
|
Array.prototype.constructor = MyArray;
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
|||||||
class MyArray extends Array { }
|
class MyArray extends Array { }
|
||||||
|
|
||||||
x.__proto__ = MyArray.prototype;
|
x.__proto__ = MyArray.prototype;
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
|
|
||||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||||
|
@ -425,7 +425,7 @@ function toSlowMode(re) {
|
|||||||
{
|
{
|
||||||
const re = /./;
|
const re = /./;
|
||||||
const result = re.exec("a");
|
const result = re.exec("a");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertTrue(result.hasOwnProperty('groups'));
|
assertTrue(result.hasOwnProperty('groups'));
|
||||||
assertArrayEquals(["a"], result);
|
assertArrayEquals(["a"], result);
|
||||||
@ -433,7 +433,7 @@ function toSlowMode(re) {
|
|||||||
assertEquals(undefined, result.groups);
|
assertEquals(undefined, result.groups);
|
||||||
|
|
||||||
Array.prototype.groups = { a: "b" };
|
Array.prototype.groups = { a: "b" };
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
||||||
Array.prototype.groups = undefined;
|
Array.prototype.groups = undefined;
|
||||||
}
|
}
|
||||||
@ -441,7 +441,7 @@ function toSlowMode(re) {
|
|||||||
{
|
{
|
||||||
const re = toSlowMode(/./);
|
const re = toSlowMode(/./);
|
||||||
const result = re.exec("a");
|
const result = re.exec("a");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertTrue(result.hasOwnProperty('groups'));
|
assertTrue(result.hasOwnProperty('groups'));
|
||||||
assertArrayEquals(["a"], result);
|
assertArrayEquals(["a"], result);
|
||||||
@ -449,7 +449,7 @@ function toSlowMode(re) {
|
|||||||
assertEquals(undefined, result.groups);
|
assertEquals(undefined, result.groups);
|
||||||
|
|
||||||
Array.prototype.groups = { a: "b" };
|
Array.prototype.groups = { a: "b" };
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
||||||
Array.prototype.groups = undefined;
|
Array.prototype.groups = undefined;
|
||||||
}
|
}
|
||||||
@ -457,7 +457,7 @@ function toSlowMode(re) {
|
|||||||
{
|
{
|
||||||
const re = /(?<a>a).|(?<x>x)/;
|
const re = /(?<a>a).|(?<x>x)/;
|
||||||
const result = re.exec("ab");
|
const result = re.exec("ab");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertTrue(result.hasOwnProperty('groups'));
|
assertTrue(result.hasOwnProperty('groups'));
|
||||||
assertArrayEquals(["ab", "a", undefined], result);
|
assertArrayEquals(["ab", "a", undefined], result);
|
||||||
@ -467,7 +467,7 @@ function toSlowMode(re) {
|
|||||||
// a is a matched named capture, b is an unmatched named capture, and z
|
// a is a matched named capture, b is an unmatched named capture, and z
|
||||||
// is not a named capture.
|
// is not a named capture.
|
||||||
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals("a", "ab".replace(re, "$<a>"));
|
assertEquals("a", "ab".replace(re, "$<a>"));
|
||||||
assertEquals("", "ab".replace(re, "$<x>"));
|
assertEquals("", "ab".replace(re, "$<x>"));
|
||||||
assertEquals("", "ab".replace(re, "$<z>"));
|
assertEquals("", "ab".replace(re, "$<z>"));
|
||||||
@ -477,7 +477,7 @@ function toSlowMode(re) {
|
|||||||
{
|
{
|
||||||
const re = toSlowMode(/(?<a>a).|(?<x>x)/);
|
const re = toSlowMode(/(?<a>a).|(?<x>x)/);
|
||||||
const result = re.exec("ab");
|
const result = re.exec("ab");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertTrue(result.hasOwnProperty('groups'));
|
assertTrue(result.hasOwnProperty('groups'));
|
||||||
assertArrayEquals(["ab", "a", undefined], result);
|
assertArrayEquals(["ab", "a", undefined], result);
|
||||||
@ -487,7 +487,7 @@ function toSlowMode(re) {
|
|||||||
// a is a matched named capture, b is an unmatched named capture, and z
|
// a is a matched named capture, b is an unmatched named capture, and z
|
||||||
// is not a named capture.
|
// is not a named capture.
|
||||||
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals("a", "ab".replace(re, "$<a>"));
|
assertEquals("a", "ab".replace(re, "$<a>"));
|
||||||
assertEquals("", "ab".replace(re, "$<x>"));
|
assertEquals("", "ab".replace(re, "$<x>"));
|
||||||
assertEquals("", "ab".replace(re, "$<z>"));
|
assertEquals("", "ab".replace(re, "$<z>"));
|
||||||
@ -506,13 +506,13 @@ function toSlowMode(re) {
|
|||||||
|
|
||||||
const re = new FakeRegExp();
|
const re = new FakeRegExp();
|
||||||
const result = re.exec("ab");
|
const result = re.exec("ab");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertFalse(result.hasOwnProperty('groups'));
|
assertFalse(result.hasOwnProperty('groups'));
|
||||||
|
|
||||||
Array.prototype.groups = { a: "b" };
|
Array.prototype.groups = { a: "b" };
|
||||||
Array.prototype.groups.__proto__.b = "c";
|
Array.prototype.groups.__proto__.b = "c";
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals("b", "ab".replace(re, "$<a>"));
|
assertEquals("b", "ab".replace(re, "$<a>"));
|
||||||
assertEquals("c", "ab".replace(re, "$<b>"));
|
assertEquals("c", "ab".replace(re, "$<b>"));
|
||||||
Array.prototype.groups = undefined;
|
Array.prototype.groups = undefined;
|
||||||
@ -531,7 +531,7 @@ function toSlowMode(re) {
|
|||||||
|
|
||||||
const re = new FakeRegExp();
|
const re = new FakeRegExp();
|
||||||
const result = re.exec("ab");
|
const result = re.exec("ab");
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
assertEquals(result.__proto__, Array.prototype);
|
assertEquals(result.__proto__, Array.prototype);
|
||||||
assertTrue(result.hasOwnProperty('groups'));
|
assertTrue(result.hasOwnProperty('groups'));
|
||||||
assertEquals({ a: "b" }, result.groups);
|
assertEquals({ a: "b" }, result.groups);
|
||||||
|
@ -16,7 +16,7 @@ f("make it generic", 0, 0);
|
|||||||
|
|
||||||
(function TestSpeciesProtector() {
|
(function TestSpeciesProtector() {
|
||||||
function MyArray() {}
|
function MyArray() {}
|
||||||
assertTrue(%SpeciesProtector());
|
assertTrue(%ArraySpeciesProtector());
|
||||||
f(Array.prototype, "constructor", MyArray);
|
f(Array.prototype, "constructor", MyArray);
|
||||||
assertFalse(%SpeciesProtector());
|
assertFalse(%ArraySpeciesProtector());
|
||||||
})();
|
})();
|
||||||
|
@ -333,13 +333,15 @@ KNOWN_OBJECTS = {
|
|||||||
("OLD_SPACE", 0x02659): "EmptyWeakCell",
|
("OLD_SPACE", 0x02659): "EmptyWeakCell",
|
||||||
("OLD_SPACE", 0x026e1): "NoElementsProtector",
|
("OLD_SPACE", 0x026e1): "NoElementsProtector",
|
||||||
("OLD_SPACE", 0x02709): "IsConcatSpreadableProtector",
|
("OLD_SPACE", 0x02709): "IsConcatSpreadableProtector",
|
||||||
("OLD_SPACE", 0x02719): "SpeciesProtector",
|
("OLD_SPACE", 0x02719): "ArraySpeciesProtector",
|
||||||
("OLD_SPACE", 0x02741): "StringLengthProtector",
|
("OLD_SPACE", 0x02741): "TypedArraySpeciesProtector",
|
||||||
("OLD_SPACE", 0x02751): "ArrayIteratorProtector",
|
("OLD_SPACE", 0x02769): "PromiseSpeciesProtector",
|
||||||
("OLD_SPACE", 0x02779): "ArrayBufferNeuteringProtector",
|
("OLD_SPACE", 0x02791): "StringLengthProtector",
|
||||||
("OLD_SPACE", 0x02801): "InfinityValue",
|
("OLD_SPACE", 0x027a1): "ArrayIteratorProtector",
|
||||||
("OLD_SPACE", 0x02811): "MinusZeroValue",
|
("OLD_SPACE", 0x027c9): "ArrayBufferNeuteringProtector",
|
||||||
("OLD_SPACE", 0x02821): "MinusInfinityValue",
|
("OLD_SPACE", 0x02851): "InfinityValue",
|
||||||
|
("OLD_SPACE", 0x02861): "MinusZeroValue",
|
||||||
|
("OLD_SPACE", 0x02871): "MinusInfinityValue",
|
||||||
}
|
}
|
||||||
|
|
||||||
# List of known V8 Frame Markers.
|
# List of known V8 Frame Markers.
|
||||||
|
Loading…
Reference in New Issue
Block a user