Commit b131cc35 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

Revert "Optimize TypedArraySpeciesCreate using SpeciesProtector of Array"

This reverts commit 8fbc6a05.

Reason for revert: https://crbug.com/800356

Original change's description:
> 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() 4x faster in fast
> cases.
> 
> Bug: v8:7161
> Change-Id: Ib8d2a3f6b8b5ed356c5822a814164166d1285f64
> Reviewed-on: https://chromium-review.googlesource.com/828343
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Jakob Gruber <jgruber@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#50423}

TBR=jkummerow@chromium.org,jgruber@chromium.org,ishell@chromium.org,bmeurer@chromium.org,cwhan.tunz@gmail.com

Change-Id: Icca07564d2a83710852eb797bac25f1d5600696e
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7161
Reviewed-on: https://chromium-review.googlesource.com/859156Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50470}
parent f64605ea
......@@ -237,45 +237,22 @@ 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() || holder_->IsJSTypedArray()) {
if (holder_->IsJSArray()) {
isolate_->CountUsage(
v8::Isolate::UseCounterFeature::kArrayInstanceConstructorModified);
isolate_->InvalidateArraySpeciesProtector();
} else if (holder_->map()->is_prototype_map()) {
DisallowHeapAllocation no_gc;
// 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.
// Setting the constructor of Array.prototype of any realm also needs
// to invalidate the species protector
if (isolate_->IsInAnyContext(*holder_,
Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
isolate_->IsInAnyContext(holder_->map()->prototype(),
Context::TYPED_ARRAY_PROTOTYPE_INDEX)) {
Context::INITIAL_ARRAY_PROTOTYPE_INDEX)) {
isolate_->CountUsage(v8::Isolate::UseCounterFeature::
kArrayPrototypeConstructorModified);
isolate_->InvalidateArraySpeciesProtector();
......@@ -283,10 +260,9 @@ void LookupIterator::InternalUpdateProtector() {
}
} else if (*name_ == heap()->species_symbol()) {
if (!isolate_->IsArraySpeciesLookupChainIntact()) return;
// 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_)) {
// Setting the Symbol.species property of any Array constructor invalidates
// the species protector
if (isolate_->IsInAnyContext(*holder_, Context::ARRAY_FUNCTION_INDEX)) {
isolate_->CountUsage(
v8::Isolate::UseCounterFeature::kArraySpeciesModified);
isolate_->InvalidateArraySpeciesProtector();
......
......@@ -16682,47 +16682,6 @@ MaybeHandle<JSTypedArray> JSTypedArray::Create(Isolate* isolate,
return new_array;
}
// static
MaybeHandle<JSTypedArray> JSTypedArray::CreateFast(
Isolate* isolate, Handle<JSTypedArray> exemplar, int argc,
Handle<Object>* argv, const char* method_name) {
DCHECK_GT(argc, 0);
DCHECK_IMPLIES(argc == 1, argv[0]->IsNumber());
DCHECK_IMPLIES(argc == 3, argv[0]->IsJSArrayBuffer());
DCHECK_IMPLIES(argc == 3, argv[1]->IsNumber());
DCHECK_IMPLIES(argc == 3, argv[2]->IsNumber());
// 1. Let newTypedArray be ? Construct(constructor, argumentList).
Handle<JSTypedArray> new_array;
if (argc == 1) {
size_t length = NumberToSize(*argv[0]);
new_array = isolate->factory()->NewJSTypedArray(exemplar->GetElementsKind(),
length);
DCHECK_GE(new_array->length_value(), length);
// We don't need a validation step for one argument case since
// NewJSTypedArray always returns a non-neutered typed array.
} else if (argc == 3) {
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(*argv[0]));
size_t byte_offset = NumberToSize(*argv[1]);
size_t length = NumberToSize(*argv[2]);
new_array = isolate->factory()->NewJSTypedArray(exemplar->type(), buffer,
byte_offset, length);
if (V8_UNLIKELY(new_array->WasNeutered())) {
const MessageTemplate::Template message =
MessageTemplate::kDetachedOperation;
Handle<String> operation =
isolate->factory()->NewStringFromAsciiChecked(method_name);
THROW_NEW_ERROR(isolate, NewTypeError(message, operation), JSTypedArray);
}
} else {
UNREACHABLE();
}
DCHECK(!new_array->WasNeutered());
return new_array;
}
// static
MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
Isolate* isolate, Handle<JSTypedArray> exemplar, int argc,
......@@ -16731,15 +16690,21 @@ MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
// slot.
DCHECK(exemplar->IsJSTypedArray());
if (exemplar->HasJSTypedArrayPrototype(isolate) &&
isolate->IsArraySpeciesLookupChainIntact()) {
return CreateFast(isolate, exemplar, argc, argv, method_name);
}
// 2. Let defaultConstructor be the intrinsic object listed in column one of
// Table 51 for exemplar.[[TypedArrayName]].
Handle<JSFunction> default_ctor =
JSTypedArray::DefaultConstructor(isolate, 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();
}
// 3. Let constructor be ? SpeciesConstructor(exemplar, defaultConstructor).
Handle<Object> ctor;
......@@ -16748,10 +16713,6 @@ MaybeHandle<JSTypedArray> JSTypedArray::SpeciesCreate(
Object::SpeciesConstructor(isolate, exemplar, default_ctor),
JSTypedArray);
if (*default_ctor == *ctor) {
return CreateFast(isolate, exemplar, argc, argv, method_name);
}
// 4. Return ? TypedArrayCreate(constructor, argumentList).
return Create(isolate, ctor, argc, argv, method_name);
}
......
......@@ -204,15 +204,6 @@ 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,
......@@ -236,26 +227,6 @@ 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,24 +299,14 @@ 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,
Handle<Object>* argv,
const char* method_name);
// If there was no updates of constructors and species, SpeciesCreate invokes
// CreateFast instead of Create. This creates a typed array without lookup of
// species.
static MaybeHandle<JSTypedArray> CreateFast(Isolate* isolate,
Handle<JSTypedArray> exemplar,
int argc, Handle<Object>* argv,
const char* method_name);
// ES7 section 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList )
static MaybeHandle<JSTypedArray> SpeciesCreate(Isolate* isolate,
Handle<JSTypedArray> exemplar,
......
......@@ -85,79 +85,5 @@ 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
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment