[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;
|
||||
if (!IsPrototypeInitialArrayPrototype(context, map)) 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.
|
||||
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 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;
|
||||
|
||||
|
@ -817,7 +817,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
|
||||
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
||||
&runtime);
|
||||
|
||||
Node* species_protector = SpeciesProtectorConstant();
|
||||
Node* species_protector = ArraySpeciesProtectorConstant();
|
||||
Node* value =
|
||||
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
||||
TNode<Smi> const protector_invalid =
|
||||
@ -862,7 +862,7 @@ Node* ArrayBuiltinsAssembler::FindProcessor(Node* k_value, Node* k) {
|
||||
GotoIfNot(IsPrototypeInitialArrayPrototype(context(), original_map),
|
||||
&runtime);
|
||||
|
||||
Node* species_protector = SpeciesProtectorConstant();
|
||||
Node* species_protector = ArraySpeciesProtectorConstant();
|
||||
Node* value =
|
||||
LoadObjectField(species_protector, PropertyCell::kValueOffset);
|
||||
Node* const protector_invalid = SmiConstant(Isolate::kProtectorInvalid);
|
||||
@ -1155,7 +1155,7 @@ class ArrayPrototypeSliceCodeStubAssembler : public CodeStubAssembler {
|
||||
|
||||
GotoIf(IsNoElementsProtectorCellInvalid(), slow);
|
||||
|
||||
GotoIf(IsSpeciesProtectorCellInvalid(), slow);
|
||||
GotoIf(IsArraySpeciesProtectorCellInvalid(), slow);
|
||||
|
||||
// Bailout if receiver has slow elements.
|
||||
Node* elements_kind = LoadMapElementsKind(map);
|
||||
|
@ -247,7 +247,7 @@ BUILTIN(ArraySplice) {
|
||||
// If this is a subclass of Array, then call out to JS.
|
||||
!Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) ||
|
||||
// If anything with @@species has been messed with, call out to JS.
|
||||
!isolate->IsSpeciesLookupChainIntact())) {
|
||||
!isolate->IsArraySpeciesLookupChainIntact())) {
|
||||
return CallJsIntrinsic(isolate, isolate->array_splice(), args);
|
||||
}
|
||||
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
|
||||
if (V8_LIKELY(receiver->IsJSArray() &&
|
||||
Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) &&
|
||||
isolate->IsSpeciesLookupChainIntact())) {
|
||||
isolate->IsArraySpeciesLookupChainIntact())) {
|
||||
if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) {
|
||||
return *result_array;
|
||||
}
|
||||
|
@ -635,7 +635,7 @@ void PromiseBuiltinsAssembler::BranchIfPromiseSpeciesLookupChainIntact(
|
||||
GotoIfForceSlowPath(if_slow);
|
||||
GotoIfNot(WordEqual(LoadMapPrototype(promise_map), promise_prototype),
|
||||
if_slow);
|
||||
Branch(IsSpeciesProtectorCellInvalid(), if_slow, if_fast);
|
||||
Branch(IsPromiseSpeciesProtectorCellInvalid(), if_slow, if_fast);
|
||||
}
|
||||
|
||||
void PromiseBuiltinsAssembler::BranchIfPromiseThenLookupChainIntact(
|
||||
@ -1285,7 +1285,7 @@ TF_BUILTIN(PromiseResolve, PromiseBuiltinsAssembler) {
|
||||
LoadContextElement(native_context, Context::PROMISE_PROTOTYPE_INDEX);
|
||||
GotoIfNot(WordEqual(LoadMapPrototype(value_map), promise_prototype),
|
||||
&if_slow_constructor);
|
||||
GotoIf(IsSpeciesProtectorCellInvalid(), &if_slow_constructor);
|
||||
GotoIf(IsPromiseSpeciesProtectorCellInvalid(), &if_slow_constructor);
|
||||
|
||||
// If the {constructor} is the Promise function, we just immediately
|
||||
// return the {value} here and don't bother wrapping it into a
|
||||
|
@ -883,7 +883,7 @@ TNode<Object> TypedArrayBuiltinsAssembler::TypedArraySpeciesConstructor(
|
||||
var_constructor = default_constructor;
|
||||
Node* map = LoadMap(exemplar);
|
||||
GotoIfNot(IsPrototypeTypedArrayPrototype(context, map), &slow);
|
||||
Branch(IsSpeciesProtectorCellInvalid(), &slow, &done);
|
||||
Branch(IsTypedArraySpeciesProtectorCellInvalid(), &slow, &done);
|
||||
|
||||
BIND(&slow);
|
||||
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,
|
||||
Label* if_true,
|
||||
Label* if_false) {
|
||||
GotoIf(IsSpeciesProtectorCellInvalid(), if_false);
|
||||
GotoIf(IsArraySpeciesProtectorCellInvalid(), if_false);
|
||||
BranchIfFastJSArray(object, context, if_true, if_false);
|
||||
}
|
||||
|
||||
@ -4545,9 +4545,23 @@ Node* CodeStubAssembler::IsPromiseThenProtectorCellInvalid() {
|
||||
return WordEqual(cell_value, invalid);
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::IsSpeciesProtectorCellInvalid() {
|
||||
Node* CodeStubAssembler::IsArraySpeciesProtectorCellInvalid() {
|
||||
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);
|
||||
return WordEqual(cell_value, invalid);
|
||||
}
|
||||
|
@ -22,50 +22,54 @@ class StubCache;
|
||||
|
||||
enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
|
||||
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(SpeciesProtector, species_protector, SpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
|
||||
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) \
|
||||
#define HEAP_CONSTANT_LIST(V) \
|
||||
V(AccessorInfoMap, accessor_info_map, AccessorInfoMap) \
|
||||
V(AccessorPairMap, accessor_pair_map, AccessorPairMap) \
|
||||
V(AllocationSiteMap, allocation_site_map, AllocationSiteMap) \
|
||||
V(BooleanMap, boolean_map, BooleanMap) \
|
||||
V(CodeMap, code_map, CodeMap) \
|
||||
V(EmptyPropertyDictionary, empty_property_dictionary, \
|
||||
EmptyPropertyDictionary) \
|
||||
V(EmptyFixedArray, empty_fixed_array, EmptyFixedArray) \
|
||||
V(EmptySlowElementDictionary, empty_slow_element_dictionary, \
|
||||
EmptySlowElementDictionary) \
|
||||
V(empty_string, empty_string, EmptyString) \
|
||||
V(EmptyWeakCell, empty_weak_cell, EmptyWeakCell) \
|
||||
V(FalseValue, false_value, False) \
|
||||
V(FeedbackVectorMap, feedback_vector_map, FeedbackVectorMap) \
|
||||
V(FixedArrayMap, fixed_array_map, FixedArrayMap) \
|
||||
V(FixedCOWArrayMap, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(FixedDoubleArrayMap, fixed_double_array_map, FixedDoubleArrayMap) \
|
||||
V(FunctionTemplateInfoMap, function_template_info_map, \
|
||||
FunctionTemplateInfoMap) \
|
||||
V(GlobalPropertyCellMap, global_property_cell_map, PropertyCellMap) \
|
||||
V(has_instance_symbol, has_instance_symbol, HasInstanceSymbol) \
|
||||
V(HeapNumberMap, heap_number_map, HeapNumberMap) \
|
||||
V(iterator_symbol, iterator_symbol, IteratorSymbol) \
|
||||
V(length_string, length_string, LengthString) \
|
||||
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
|
||||
V(MetaMap, meta_map, MetaMap) \
|
||||
V(MinusZeroValue, minus_zero_value, MinusZero) \
|
||||
V(MutableHeapNumberMap, mutable_heap_number_map, MutableHeapNumberMap) \
|
||||
V(NanValue, nan_value, Nan) \
|
||||
V(NoClosuresCellMap, no_closures_cell_map, NoClosuresCellMap) \
|
||||
V(NullValue, null_value, Null) \
|
||||
V(OneClosureCellMap, one_closure_cell_map, OneClosureCellMap) \
|
||||
V(prototype_string, prototype_string, PrototypeString) \
|
||||
V(ArraySpeciesProtector, array_species_protector, ArraySpeciesProtector) \
|
||||
V(TypedArraySpeciesProtector, typed_array_species_protector, \
|
||||
TypedArraySpeciesProtector) \
|
||||
V(PromiseSpeciesProtector, promise_species_protector, \
|
||||
PromiseSpeciesProtector) \
|
||||
V(StoreHandler0Map, store_handler0_map, StoreHandler0Map) \
|
||||
V(SymbolMap, symbol_map, SymbolMap) \
|
||||
V(TheHoleValue, the_hole_value, TheHole) \
|
||||
V(TransitionArrayMap, transition_array_map, TransitionArrayMap) \
|
||||
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)
|
||||
|
||||
// Returned from IteratorBuiltinsAssembler::GetIterator(). Struct is declared
|
||||
@ -1383,7 +1387,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
|
||||
Node* IsPromiseResolveProtectorCellInvalid();
|
||||
Node* IsPromiseThenProtectorCellInvalid();
|
||||
Node* IsSpeciesProtectorCellInvalid();
|
||||
Node* IsArraySpeciesProtectorCellInvalid();
|
||||
Node* IsTypedArraySpeciesProtectorCellInvalid();
|
||||
Node* IsPromiseSpeciesProtectorCellInvalid();
|
||||
|
||||
// True iff |object| is a Smi or a HeapNumber.
|
||||
TNode<BoolT> IsNumber(SloppyTNode<Object> object);
|
||||
|
@ -1481,7 +1481,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
|
||||
// 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();
|
||||
|
||||
@ -1492,7 +1492,7 @@ Reduction JSCallReducer::ReduceArrayMap(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Handle<JSFunction> handle_constructor(
|
||||
JSFunction::cast(
|
||||
@ -1681,7 +1681,7 @@ Reduction JSCallReducer::ReduceArrayFilter(Node* node,
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
|
||||
// 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();
|
||||
// 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();
|
||||
}
|
||||
|
||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Handle<Map> initial_map(
|
||||
Map::cast(native_context()->GetInitialJSArrayMap(packed_kind)));
|
||||
@ -2274,7 +2274,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
|
||||
// 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();
|
||||
|
||||
@ -2285,7 +2285,7 @@ Reduction JSCallReducer::ReduceArrayEvery(Node* node,
|
||||
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 (result == NodeProperties::kUnreliableReceiverMaps) {
|
||||
@ -2597,7 +2597,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
||||
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
|
||||
|
||||
// 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();
|
||||
|
||||
@ -2610,7 +2610,7 @@ Reduction JSCallReducer::ReduceArraySome(Node* node,
|
||||
if (receiver_map->elements_kind() != kind) return NoChange();
|
||||
}
|
||||
|
||||
dependencies()->AssumePropertyCell(factory()->species_protector());
|
||||
dependencies()->AssumePropertyCell(factory()->array_species_protector());
|
||||
|
||||
Node* k = jsgraph()->ZeroConstant();
|
||||
|
||||
@ -5730,7 +5730,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
||||
// lookup of "constructor" on JSPromise instances, whoch [[Prototype]] is
|
||||
// the initial %PromisePrototype%, and the Symbol.species lookup on the
|
||||
// %PromisePrototype%.
|
||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
||||
if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
|
||||
|
||||
// Check if we know something about {receiver} already.
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
@ -5751,7 +5751,7 @@ Reduction JSCallReducer::ReducePromisePrototypeFinally(Node* node) {
|
||||
// Add a code dependency on the necessary protectors.
|
||||
dependencies()->AssumePropertyCell(factory()->promise_hook_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
|
||||
// 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
|
||||
// initial Promise.prototype, as well as the Symbol.species lookup on
|
||||
// the Promise constructor.
|
||||
if (!isolate()->IsSpeciesLookupChainIntact()) return NoChange();
|
||||
if (!isolate()->IsPromiseSpeciesLookupChainIntact()) return NoChange();
|
||||
|
||||
// Check if we know something about {receiver} already.
|
||||
ZoneHandleSet<Map> receiver_maps;
|
||||
@ -5900,7 +5900,7 @@ Reduction JSCallReducer::ReducePromisePrototypeThen(Node* node) {
|
||||
|
||||
// Add a code dependency on the necessary protectors.
|
||||
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
|
||||
// map check here, guarded by the CALL_IC.
|
||||
|
@ -228,7 +228,9 @@ using v8::MemoryPressureLevel;
|
||||
V(Cell, array_constructor_protector, ArrayConstructorProtector) \
|
||||
V(PropertyCell, no_elements_protector, NoElementsProtector) \
|
||||
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(PropertyCell, array_iterator_protector, ArrayIteratorProtector) \
|
||||
V(PropertyCell, array_buffer_neutering_protector, \
|
||||
@ -389,7 +391,9 @@ using v8::MemoryPressureLevel;
|
||||
V(SloppyArgumentsElementsMap) \
|
||||
V(SmallOrderedHashMapMap) \
|
||||
V(SmallOrderedHashSetMap) \
|
||||
V(SpeciesProtector) \
|
||||
V(ArraySpeciesProtector) \
|
||||
V(TypedArraySpeciesProtector) \
|
||||
V(PromiseSpeciesProtector) \
|
||||
V(StaleRegister) \
|
||||
V(StringLengthProtector) \
|
||||
V(StringTableMap) \
|
||||
|
@ -787,7 +787,15 @@ void Heap::CreateInitialObjects() {
|
||||
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
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(Smi::FromInt(Isolate::kProtectorValid), isolate()));
|
||||
|
@ -133,7 +133,7 @@ bool Isolate::IsArrayConstructorIntact() {
|
||||
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
|
||||
// species protector is accurate, but this would be hard to do for most of
|
||||
// what the protector stands for:
|
||||
@ -146,7 +146,19 @@ bool Isolate::IsSpeciesLookupChainIntact() {
|
||||
// done here. In place, there are mjsunit tests harmony/array-species* which
|
||||
// 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() &&
|
||||
Smi::ToInt(species_cell->value()) == kProtectorValid;
|
||||
}
|
||||
|
@ -3573,11 +3573,28 @@ void Isolate::InvalidateArrayConstructorProtector() {
|
||||
DCHECK(!IsArrayConstructorIntact());
|
||||
}
|
||||
|
||||
void Isolate::InvalidateSpeciesProtector() {
|
||||
DCHECK(factory()->species_protector()->value()->IsSmi());
|
||||
DCHECK(IsSpeciesLookupChainIntact());
|
||||
factory()->species_protector()->set_value(Smi::FromInt(kProtectorInvalid));
|
||||
DCHECK(!IsSpeciesLookupChainIntact());
|
||||
void Isolate::InvalidateArraySpeciesProtector() {
|
||||
DCHECK(factory()->array_species_protector()->value()->IsSmi());
|
||||
DCHECK(IsArraySpeciesLookupChainIntact());
|
||||
factory()->array_species_protector()->set_value(
|
||||
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() {
|
||||
|
@ -1080,7 +1080,9 @@ class Isolate : private HiddenFactory {
|
||||
bool IsNoElementsProtectorIntact(Context* context);
|
||||
bool IsNoElementsProtectorIntact();
|
||||
|
||||
inline bool IsSpeciesLookupChainIntact();
|
||||
inline bool IsArraySpeciesLookupChainIntact();
|
||||
inline bool IsTypedArraySpeciesLookupChainIntact();
|
||||
inline bool IsPromiseSpeciesLookupChainIntact();
|
||||
bool IsIsConcatSpreadableLookupChainIntact();
|
||||
bool IsIsConcatSpreadableLookupChainIntact(JSReceiver* receiver);
|
||||
inline bool IsStringLengthOverflowIntact();
|
||||
@ -1120,7 +1122,9 @@ class Isolate : private HiddenFactory {
|
||||
UpdateNoElementsProtectorOnSetElement(object);
|
||||
}
|
||||
void InvalidateArrayConstructorProtector();
|
||||
void InvalidateSpeciesProtector();
|
||||
void InvalidateArraySpeciesProtector();
|
||||
void InvalidateTypedArraySpeciesProtector();
|
||||
void InvalidatePromiseSpeciesProtector();
|
||||
void InvalidateIsConcatSpreadableProtector();
|
||||
void InvalidateStringLengthOverflowProtector();
|
||||
void InvalidateArrayIteratorProtector();
|
||||
|
@ -272,14 +272,27 @@ void LookupIterator::InternalUpdateProtector() {
|
||||
if (isolate_->bootstrapper()->IsActive()) return;
|
||||
|
||||
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
|
||||
if (holder_->IsJSArray() || holder_->IsJSPromise() ||
|
||||
holder_->IsJSTypedArray()) {
|
||||
if (holder_->IsJSArray()) {
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
isolate_->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
|
||||
isolate_->InvalidateSpeciesProtector();
|
||||
} else if (holder_->map()->is_prototype_map()) {
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
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;
|
||||
// Setting the constructor of Array.prototype, Promise.prototype or
|
||||
// %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
|
||||
// pointing the same TYPED_ARRAY_PROTOTYPE.
|
||||
if (isolate_->IsInAnyContext(*holder_,
|
||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
|
||||
isolate_->IsInAnyContext(*holder_,
|
||||
Context::PROMISE_PROTOTYPE_INDEX) ||
|
||||
isolate_->IsInAnyContext(holder_->map()->prototype(),
|
||||
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
|
||||
isolate_->CountUsage(v8::Isolate::UseCounterFeature::
|
||||
kArrayPrototypeConstructorModified);
|
||||
isolate_->InvalidateSpeciesProtector();
|
||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
isolate_->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kArrayPrototypeConstructorModified);
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
} else if (isolate_->IsInAnyContext(*holder_,
|
||||
Context::PROMISE_PROTOTYPE_INDEX)) {
|
||||
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()) {
|
||||
@ -307,15 +326,24 @@ void LookupIterator::InternalUpdateProtector() {
|
||||
isolate_->InvalidateArrayIteratorProtector();
|
||||
}
|
||||
} 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
|
||||
// constructor invalidates the @@species protector
|
||||
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX) ||
|
||||
isolate_->IsInAnyContext(*holder_, Context::PROMISE_FUNCTION_INDEX) ||
|
||||
IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
|
||||
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
isolate_->CountUsage(
|
||||
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()) {
|
||||
if (!isolate_->IsIsConcatSpreadableLookupChainIntact()) return;
|
||||
|
@ -2370,7 +2370,7 @@ MaybeHandle<Object> Object::ArraySpeciesConstructor(
|
||||
Handle<Object> default_species = isolate->array_function();
|
||||
if (original_array->IsJSArray() &&
|
||||
Handle<JSArray>::cast(original_array)->HasArrayPrototype(isolate) &&
|
||||
isolate->IsSpeciesLookupChainIntact()) {
|
||||
isolate->IsArraySpeciesLookupChainIntact()) {
|
||||
return default_species;
|
||||
}
|
||||
Handle<Object> constructor = isolate->factory()->undefined_value();
|
||||
|
@ -396,7 +396,7 @@ RUNTIME_FUNCTION(Runtime_TrySliceSimpleNonFastElements) {
|
||||
// implementation.
|
||||
if (receiver->IsJSArray()) {
|
||||
// This "fastish" path must make sure the destination array is a JSArray.
|
||||
if (!isolate->IsSpeciesLookupChainIntact() ||
|
||||
if (!isolate->IsArraySpeciesLookupChainIntact() ||
|
||||
!JSArray::cast(*receiver)->HasArrayPrototype(isolate)) {
|
||||
return Smi::FromInt(0);
|
||||
}
|
||||
|
@ -841,11 +841,24 @@ TYPED_ARRAYS(FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION)
|
||||
|
||||
#undef FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_SpeciesProtector) {
|
||||
RUNTIME_FUNCTION(Runtime_ArraySpeciesProtector) {
|
||||
SealHandleScope shs(isolate);
|
||||
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
|
||||
|
@ -588,7 +588,9 @@ namespace internal {
|
||||
F(SetForceSlowPath, 1, 1) \
|
||||
F(SetWasmCompileControls, 2, 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(TraceEnter, 0, 1) \
|
||||
F(TraceExit, 1, 1) \
|
||||
|
@ -117,12 +117,12 @@ void TestSpeciesProtector(char* code,
|
||||
|
||||
v8::internal::Isolate* i_isolate =
|
||||
reinterpret_cast<v8::internal::Isolate*>(isolate);
|
||||
CHECK(i_isolate->IsSpeciesLookupChainIntact());
|
||||
CHECK(i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||
CompileRun(code);
|
||||
if (invalidates_species_protector) {
|
||||
CHECK(!i_isolate->IsSpeciesLookupChainIntact());
|
||||
CHECK(!i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||
} else {
|
||||
CHECK(i_isolate->IsSpeciesLookupChainIntact());
|
||||
CHECK(i_isolate->IsTypedArraySpeciesLookupChainIntact());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> my_typed_array = CompileRun("MyTypedArray");
|
||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
||||
class MyArray extends Array { }
|
||||
|
||||
Object.defineProperty(x, 'constructor', {get() { return MyArray; }});
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -19,7 +19,7 @@ class MyArray extends Array { }
|
||||
|
||||
Object.prototype.constructor = MyArray;
|
||||
delete Array.prototype.constructor;
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
||||
class MyArray extends Array { }
|
||||
|
||||
x.constructor = MyArray;
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -19,7 +19,7 @@ class MyArray extends Array { }
|
||||
|
||||
Object.prototype[Symbol.species] = MyArray;
|
||||
delete Array[Symbol.species];
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
||||
class MyArray extends Array { }
|
||||
|
||||
Object.defineProperty(Array, Symbol.species, {value: MyArray});
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
||||
class MyArray extends Array { }
|
||||
|
||||
Array.prototype.constructor = MyArray;
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -18,7 +18,7 @@ assertEquals(1, x.concat([1])[0]);
|
||||
class MyArray extends Array { }
|
||||
|
||||
x.__proto__ = MyArray.prototype;
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
|
||||
assertEquals(MyArray, x.map(()=>{}).constructor);
|
||||
assertEquals(MyArray, x.filter(()=>{}).constructor);
|
||||
|
@ -425,7 +425,7 @@ function toSlowMode(re) {
|
||||
{
|
||||
const re = /./;
|
||||
const result = re.exec("a");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertTrue(result.hasOwnProperty('groups'));
|
||||
assertArrayEquals(["a"], result);
|
||||
@ -433,7 +433,7 @@ function toSlowMode(re) {
|
||||
assertEquals(undefined, result.groups);
|
||||
|
||||
Array.prototype.groups = { a: "b" };
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
||||
Array.prototype.groups = undefined;
|
||||
}
|
||||
@ -441,7 +441,7 @@ function toSlowMode(re) {
|
||||
{
|
||||
const re = toSlowMode(/./);
|
||||
const result = re.exec("a");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertTrue(result.hasOwnProperty('groups'));
|
||||
assertArrayEquals(["a"], result);
|
||||
@ -449,7 +449,7 @@ function toSlowMode(re) {
|
||||
assertEquals(undefined, result.groups);
|
||||
|
||||
Array.prototype.groups = { a: "b" };
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals("$<a>", "a".replace(re, "$<a>"));
|
||||
Array.prototype.groups = undefined;
|
||||
}
|
||||
@ -457,7 +457,7 @@ function toSlowMode(re) {
|
||||
{
|
||||
const re = /(?<a>a).|(?<x>x)/;
|
||||
const result = re.exec("ab");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertTrue(result.hasOwnProperty('groups'));
|
||||
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
|
||||
// is not a named capture.
|
||||
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals("a", "ab".replace(re, "$<a>"));
|
||||
assertEquals("", "ab".replace(re, "$<x>"));
|
||||
assertEquals("", "ab".replace(re, "$<z>"));
|
||||
@ -477,7 +477,7 @@ function toSlowMode(re) {
|
||||
{
|
||||
const re = toSlowMode(/(?<a>a).|(?<x>x)/);
|
||||
const result = re.exec("ab");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertTrue(result.hasOwnProperty('groups'));
|
||||
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
|
||||
// is not a named capture.
|
||||
Array.prototype.groups = { a: "b", x: "y", z: "z" };
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals("a", "ab".replace(re, "$<a>"));
|
||||
assertEquals("", "ab".replace(re, "$<x>"));
|
||||
assertEquals("", "ab".replace(re, "$<z>"));
|
||||
@ -506,13 +506,13 @@ function toSlowMode(re) {
|
||||
|
||||
const re = new FakeRegExp();
|
||||
const result = re.exec("ab");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertFalse(result.hasOwnProperty('groups'));
|
||||
|
||||
Array.prototype.groups = { a: "b" };
|
||||
Array.prototype.groups.__proto__.b = "c";
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals("b", "ab".replace(re, "$<a>"));
|
||||
assertEquals("c", "ab".replace(re, "$<b>"));
|
||||
Array.prototype.groups = undefined;
|
||||
@ -531,7 +531,7 @@ function toSlowMode(re) {
|
||||
|
||||
const re = new FakeRegExp();
|
||||
const result = re.exec("ab");
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
assertEquals(result.__proto__, Array.prototype);
|
||||
assertTrue(result.hasOwnProperty('groups'));
|
||||
assertEquals({ a: "b" }, result.groups);
|
||||
|
@ -16,7 +16,7 @@ f("make it generic", 0, 0);
|
||||
|
||||
(function TestSpeciesProtector() {
|
||||
function MyArray() {}
|
||||
assertTrue(%SpeciesProtector());
|
||||
assertTrue(%ArraySpeciesProtector());
|
||||
f(Array.prototype, "constructor", MyArray);
|
||||
assertFalse(%SpeciesProtector());
|
||||
assertFalse(%ArraySpeciesProtector());
|
||||
})();
|
||||
|
@ -333,13 +333,15 @@ KNOWN_OBJECTS = {
|
||||
("OLD_SPACE", 0x02659): "EmptyWeakCell",
|
||||
("OLD_SPACE", 0x026e1): "NoElementsProtector",
|
||||
("OLD_SPACE", 0x02709): "IsConcatSpreadableProtector",
|
||||
("OLD_SPACE", 0x02719): "SpeciesProtector",
|
||||
("OLD_SPACE", 0x02741): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x02751): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02779): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02801): "InfinityValue",
|
||||
("OLD_SPACE", 0x02811): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02821): "MinusInfinityValue",
|
||||
("OLD_SPACE", 0x02719): "ArraySpeciesProtector",
|
||||
("OLD_SPACE", 0x02741): "TypedArraySpeciesProtector",
|
||||
("OLD_SPACE", 0x02769): "PromiseSpeciesProtector",
|
||||
("OLD_SPACE", 0x02791): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x027a1): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x027c9): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02851): "InfinityValue",
|
||||
("OLD_SPACE", 0x02861): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02871): "MinusInfinityValue",
|
||||
}
|
||||
|
||||
# List of known V8 Frame Markers.
|
||||
|
Loading…
Reference in New Issue
Block a user