Reland "Optimize TypedArraySpeciesCreate using SpeciesProtector of Array"
If there is no constructor or species updates on Array or TypedArrays, then skip lookups of constructor and species so that we can create a new typed array quickly. This path makes TA.p.slice() 2x faster in fast cases. Bug: chromium:800356, v8:7161 Change-Id: Ied8c90e23ca6708f4a3cec077c1fd733e4a6609e Reviewed-on: https://chromium-review.googlesource.com/859397 Reviewed-by: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#50617}
This commit is contained in:
parent
1a0cc926ba
commit
3a4f3b73e2
@ -237,22 +237,45 @@ void LookupIterator::ReloadPropertyInformation() {
|
||||
DCHECK(IsFound() || !holder_->HasFastProperties());
|
||||
}
|
||||
|
||||
namespace {
|
||||
bool IsTypedArrayFunctionInAnyContext(Isolate* isolate, JSReceiver* holder) {
|
||||
static uint32_t context_slots[] = {
|
||||
#define TYPED_ARRAY_CONTEXT_SLOTS(Type, type, TYPE, ctype, size) \
|
||||
Context::TYPE##_ARRAY_FUN_INDEX,
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CONTEXT_SLOTS)
|
||||
#undef TYPED_ARRAY_CONTEXT_SLOTS
|
||||
};
|
||||
|
||||
if (!holder->IsJSFunction()) return false;
|
||||
|
||||
return std::any_of(
|
||||
std::begin(context_slots), std::end(context_slots),
|
||||
[=](uint32_t slot) { return isolate->IsInAnyContext(holder, slot); });
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void LookupIterator::InternalUpdateProtector() {
|
||||
if (isolate_->bootstrapper()->IsActive()) return;
|
||||
|
||||
if (*name_ == heap()->constructor_string()) {
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
// Setting the constructor property could change an instance's @@species
|
||||
if (holder_->IsJSArray()) {
|
||||
if (holder_->IsJSArray() || holder_->IsJSTypedArray()) {
|
||||
isolate_->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
} else if (holder_->map()->is_prototype_map()) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
// Setting the constructor of Array.prototype of any realm also needs
|
||||
// to invalidate the species protector
|
||||
// Setting the constructor of Array.prototype or %TypedArray%.prototype of
|
||||
// any realm also needs to invalidate the species protector.
|
||||
// For typed arrays, we check a prototype of this holder since TypedArrays
|
||||
// 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)) {
|
||||
Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
|
||||
isolate_->IsInAnyContext(holder_->map()->prototype(),
|
||||
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
|
||||
isolate_->CountUsage(v8::Isolate::UseCounterFeature::
|
||||
kArrayPrototypeConstructorModified);
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
@ -260,9 +283,10 @@ void LookupIterator::InternalUpdateProtector() {
|
||||
}
|
||||
} else if (*name_ == heap()->species_symbol()) {
|
||||
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
|
||||
// Setting the Symbol.species property of any Array constructor invalidates
|
||||
// the species protector
|
||||
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
|
||||
// Setting the Symbol.species property of any Array or TypedArray
|
||||
// constructor invalidates the species protector
|
||||
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX) ||
|
||||
IsTypedArrayFunctionInAnyContext(isolate_, *holder_)) {
|
||||
isolate_->CountUsage(
|
||||
v8::Isolate::UseCounterFeature::kArraySpeciesModified);
|
||||
isolate_->InvalidateArraySpeciesProtector();
|
||||
|
@ -16703,26 +16703,18 @@ MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
|
||||
|
||||
// 2. Let defaultConstructor be the intrinsic object listed in column one of
|
||||
// Table 51 for exemplar.[[TypedArrayName]].
|
||||
Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
|
||||
switch (exemplar->type()) {
|
||||
#define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: { \
|
||||
default_ctor = isolate->type##_array_fun(); \
|
||||
break; \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CTOR)
|
||||
#undef TYPED_ARRAY_CTOR
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
Handle<JSFunction> default_ctor =
|
||||
JSTypedArray::DefaultConstructor(isolate, exemplar);
|
||||
|
||||
// 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
|
||||
Handle<Object> ctor;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, ctor,
|
||||
Object::SpeciesConstructor(isolate, exemplar, default_ctor),
|
||||
JSTypedArray);
|
||||
Handle<Object> ctor = default_ctor;
|
||||
if (!exemplar->HasJSTypedArrayPrototype(isolate) ||
|
||||
!isolate->IsArraySpeciesLookupChainIntact()) {
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
isolate, ctor,
|
||||
Object::SpeciesConstructor(isolate, exemplar, default_ctor),
|
||||
JSTypedArray);
|
||||
}
|
||||
|
||||
// 4. Return ? TypedArrayCreate(constructor, argumentList).
|
||||
return Create(isolate, ctor, argc, argv, method_name);
|
||||
|
@ -204,6 +204,15 @@ void JSTypedArray::set_length(Object* value, WriteBarrierMode mode) {
|
||||
CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kLengthOffset, value, mode);
|
||||
}
|
||||
|
||||
bool JSTypedArray::HasJSTypedArrayPrototype(Isolate* isolate) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
Object* proto = map()->prototype();
|
||||
if (!proto->IsJSObject()) return false;
|
||||
|
||||
JSObject* proto_obj = JSObject::cast(proto);
|
||||
return proto_obj->map()->prototype() == *isolate->typed_array_prototype();
|
||||
}
|
||||
|
||||
// static
|
||||
MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
|
||||
Handle<Object> receiver,
|
||||
@ -227,6 +236,26 @@ MaybeHandle<JSTypedArray> JSTypedArray::Validate(Isolate* isolate,
|
||||
return array;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<JSFunction> JSTypedArray::DefaultConstructor(
|
||||
Isolate* isolate, Handle<JSTypedArray> exemplar) {
|
||||
Handle<JSFunction> default_ctor = isolate->uint8_array_fun();
|
||||
switch (exemplar->type()) {
|
||||
#define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) \
|
||||
case kExternal##Type##Array: { \
|
||||
default_ctor = isolate->type##_array_fun(); \
|
||||
break; \
|
||||
}
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CTOR)
|
||||
#undef TYPED_ARRAY_CTOR
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return default_ctor;
|
||||
}
|
||||
|
||||
#ifdef VERIFY_HEAP
|
||||
ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset)
|
||||
#endif
|
||||
|
@ -299,9 +299,12 @@ class JSTypedArray : public JSArrayBufferView {
|
||||
|
||||
Handle<JSArrayBuffer> GetBuffer();
|
||||
|
||||
inline bool HasJSTypedArrayPrototype(Isolate* isolate);
|
||||
static inline MaybeHandle<JSTypedArray> Validate(Isolate* isolate,
|
||||
Handle<Object> receiver,
|
||||
const char* method_name);
|
||||
static inline Handle<JSFunction> DefaultConstructor(
|
||||
Isolate* isolate, Handle<JSTypedArray> exemplar);
|
||||
// ES7 section 22.2.4.6 Create ( constructor, argumentList )
|
||||
static MaybeHandle<JSTypedArray> Create(Isolate* isolate,
|
||||
Handle<Object> default_ctor, int argc,
|
||||
|
@ -85,5 +85,79 @@ TEST(AllocateNotExternal) {
|
||||
CHECK_EQ(memory, buffer->GetContents().Data());
|
||||
}
|
||||
|
||||
void TestSpeciesProtector(char* code,
|
||||
bool invalidates_species_protector = true) {
|
||||
v8::Isolate::CreateParams create_params;
|
||||
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
|
||||
std::string typed_array_constructors[] = {
|
||||
#define TYPED_ARRAY_CTOR(Type, type, TYPE, ctype, size) #Type "Array",
|
||||
|
||||
TYPED_ARRAYS(TYPED_ARRAY_CTOR)
|
||||
#undef TYPED_ARRAY_CTOR
|
||||
};
|
||||
|
||||
for (auto& constructor : typed_array_constructors) {
|
||||
v8::Isolate* isolate = v8::Isolate::New(create_params);
|
||||
isolate->Enter();
|
||||
{
|
||||
LocalContext context(isolate);
|
||||
v8::HandleScope scope(isolate);
|
||||
v8::TryCatch try_catch(isolate);
|
||||
|
||||
CompileRun(("let x = new " + constructor + "();").c_str());
|
||||
CompileRun(("let constructor = " + constructor + ";").c_str());
|
||||
v8::Local<v8::Value> constructor_obj = CompileRun(constructor.c_str());
|
||||
CHECK_EQ(constructor_obj, CompileRun("x.slice().constructor"));
|
||||
CHECK_EQ(constructor_obj, CompileRun("x.map(()=>{}).constructor"));
|
||||
std::string decl = "class MyTypedArray extends " + constructor + " { }";
|
||||
CompileRun(decl.c_str());
|
||||
|
||||
v8::internal::Isolate* i_isolate =
|
||||
reinterpret_cast<v8::internal::Isolate*>(isolate);
|
||||
CHECK(i_isolate->IsArraySpeciesLookupChainIntact());
|
||||
CompileRun(code);
|
||||
if (invalidates_species_protector) {
|
||||
CHECK(!i_isolate->IsArraySpeciesLookupChainIntact());
|
||||
} else {
|
||||
CHECK(i_isolate->IsArraySpeciesLookupChainIntact());
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> my_typed_array = CompileRun("MyTypedArray");
|
||||
CHECK_EQ(my_typed_array, CompileRun("x.slice().constructor"));
|
||||
CHECK_EQ(my_typed_array, CompileRun("x.map(()=>{}).constructor"));
|
||||
}
|
||||
isolate->Exit();
|
||||
isolate->Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(SpeciesConstructor) {
|
||||
char code[] = "x.constructor = MyTypedArray";
|
||||
TestSpeciesProtector(code);
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(SpeciesConstructorAccessor) {
|
||||
char code[] =
|
||||
"Object.defineProperty(x, 'constructor',{get() {return MyTypedArray;}})";
|
||||
TestSpeciesProtector(code);
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(SpeciesModified) {
|
||||
char code[] =
|
||||
"Object.defineProperty(constructor, Symbol.species, "
|
||||
"{value:MyTypedArray})";
|
||||
TestSpeciesProtector(code);
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(SpeciesParentConstructor) {
|
||||
char code[] = "constructor.prototype.constructor = MyTypedArray";
|
||||
TestSpeciesProtector(code);
|
||||
}
|
||||
|
||||
UNINITIALIZED_TEST(SpeciesProto) {
|
||||
char code[] = "x.__proto__ = MyTypedArray.prototype";
|
||||
TestSpeciesProtector(code, false);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user