#include "src/objects/literal-objects.h"
#include "src/ast/ast.h"
#include "src/base/logging.h"
#include "src/builtins/accessors.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/heap/factory.h"
#include "src/heap/local-factory-inl.h"
#include "src/objects/dictionary.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-regexp.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
#include "src/objects/struct-inl.h"
#include "src/sandbox/isolate.h"
namespace v8 {
namespace internal {
namespace {
constexpr int kDummyEnumerationIndex = 0;
inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
unsigned key_index) {
using Flags = ClassBoilerplate::ComputedEntryFlags;
int flags = Flags::ValueKindBits::encode(value_kind) |
Flags::KeyIndexBits::encode(key_index);
return flags;
}
void SetAccessorPlaceholderIndices(Tagged<AccessorPair> pair,
ClassBoilerplate::ValueKind value_kind,
Tagged<Smi> index) {
switch (value_kind) {
case ClassBoilerplate::kGetter:
pair->set_getter(index);
break;
case ClassBoilerplate::kSetter:
pair->set_setter(index);
break;
case ClassBoilerplate::kAutoAccessor:
pair->set_getter(index);
pair->set_setter(Smi::FromInt(Smi::ToInt(index) + 1));
break;
default:
UNREACHABLE();
}
}
void SetAccessorPlaceholderIndices(Tagged<AccessorPair> pair,
ClassBoilerplate::ValueKind value_kind,
Tagged<Smi> index, ReleaseStoreTag tag) {
switch (value_kind) {
case ClassBoilerplate::kGetter:
pair->set_getter(index, tag);
break;
case ClassBoilerplate::kSetter:
pair->set_setter(index, tag);
break;
case ClassBoilerplate::kAutoAccessor:
pair->set_getter(index, tag);
pair->set_setter(Smi::FromInt(Smi::ToInt(index) + 1), tag);
break;
default:
UNREACHABLE();
}
}
template <typename IsolateT>
void AddToDescriptorArrayTemplate(
IsolateT* isolate, DirectHandle<DescriptorArray> descriptor_array_template,
DirectHandle<Name> name, ClassBoilerplate::ValueKind value_kind,
DirectHandle<Object> value) {
InternalIndex entry = descriptor_array_template->Search(
*name, descriptor_array_template->number_of_descriptors());
if (entry.is_not_found()) {
Descriptor d;
if (value_kind == ClassBoilerplate::kData) {
d = Descriptor::DataConstant(name, value, DONT_ENUM);
} else {
DCHECK(value_kind == ClassBoilerplate::kGetter ||
value_kind == ClassBoilerplate::kSetter ||
value_kind == ClassBoilerplate::kAutoAccessor);
DirectHandle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
SetAccessorPlaceholderIndices(*pair, value_kind, Cast<Smi>(*value));
d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
}
descriptor_array_template->Append(&d);
} else {
int sorted_index = descriptor_array_template->GetDetails(entry).pointer();
if (value_kind == ClassBoilerplate::kData) {
Descriptor d = Descriptor::DataConstant(name, value, DONT_ENUM);
d.SetSortedKeyIndex(sorted_index);
descriptor_array_template->Set(entry, &d);
} else {
DCHECK(value_kind == ClassBoilerplate::kGetter ||
value_kind == ClassBoilerplate::kSetter ||
value_kind == ClassBoilerplate::kAutoAccessor);
Tagged<Object> raw_accessor =
descriptor_array_template->GetStrongValue(entry);
Tagged<AccessorPair> pair;
if (IsAccessorPair(raw_accessor)) {
pair = Cast<AccessorPair>(raw_accessor);
} else {
DirectHandle<AccessorPair> new_pair =
isolate->factory()->NewAccessorPair();
Descriptor d = Descriptor::AccessorConstant(name, new_pair, DONT_ENUM);
d.SetSortedKeyIndex(sorted_index);
descriptor_array_template->Set(entry, &d);
pair = *new_pair;
}
SetAccessorPlaceholderIndices(pair, value_kind, Cast<Smi>(*value),
kReleaseStore);
}
}
}
template <typename IsolateT>
Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
IsolateT* isolate, Handle<NameDictionary> dictionary,
DirectHandle<Name> name, DirectHandle<Object> value,
PropertyDetails details, InternalIndex* entry_out = nullptr) {
return NameDictionary::AddNoUpdateNextEnumerationIndex(
isolate, dictionary, name, value, details, entry_out);
}
template <typename IsolateT>
Handle<SwissNameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
IsolateT* isolate, Handle<SwissNameDictionary> dictionary,
DirectHandle<Name> name, DirectHandle<Object> value,
PropertyDetails details, InternalIndex* entry_out = nullptr) {
return SwissNameDictionary::Add(isolate, dictionary, name, value, details);
}
template <typename IsolateT>
DirectHandle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t element,
DirectHandle<Object> value, PropertyDetails details,
InternalIndex* entry_out = nullptr) {
return NumberDictionary::Add(isolate, dictionary, element, value, details,
entry_out);
}
template <template <typename> typename HandleType, typename Dictionary>
void DictionaryUpdateMaxNumberKey(HandleType<Dictionary> dictionary,
DirectHandle<Name> name)
requires(
std::is_convertible_v<HandleType<Dictionary>, DirectHandle<Dictionary>>)
{
static_assert((std::is_same_v<Dictionary, SwissNameDictionary> ||
std::is_same_v<Dictionary, NameDictionary>));
}
void DictionaryUpdateMaxNumberKey(DirectHandle<NumberDictionary> dictionary,
uint32_t element) {
dictionary->UpdateMaxNumberKey(element, DirectHandle<JSObject>());
dictionary->set_requires_slow_elements();
}
constexpr int ComputeEnumerationIndex(int value_index) {
return value_index +
std::max({ClassBoilerplate::kMinimumClassPropertiesCount,
ClassBoilerplate::kMinimumPrototypePropertiesCount});
}
constexpr int kAccessorNotDefined = -1;
inline int GetExistingValueIndex(Tagged<Object> value) {
return IsSmi(value) ? Smi::ToInt(value) : kAccessorNotDefined;
}
template <typename IsolateT, typename Dictionary, typename Key>
void AddToDictionaryTemplate(IsolateT* isolate, Handle<Dictionary> dictionary,
Key key, int key_index,
ClassBoilerplate::ValueKind value_kind,
Tagged<Smi> value) {
InternalIndex entry = dictionary->FindEntry(isolate, key);
const bool is_elements_dictionary =
std::is_same_v<Dictionary, NumberDictionary>;
static_assert(is_elements_dictionary !=
(std::is_same_v<Dictionary, NameDictionary> ||
std::is_same_v<Dictionary, SwissNameDictionary>));
if (entry.is_not_found()) {
int enum_order =
Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
? kDummyEnumerationIndex
: ComputeEnumerationIndex(key_index);
DirectHandle<Object> value_handle;
PropertyDetails details(
value_kind != ClassBoilerplate::kData ? PropertyKind::kAccessor
: PropertyKind::kData,
DONT_ENUM, PropertyDetails::kConstIfDictConstnessTracking, enum_order);
if (value_kind == ClassBoilerplate::kData) {
value_handle = direct_handle(value, isolate);
} else {
DCHECK(value_kind == ClassBoilerplate::kGetter ||
value_kind == ClassBoilerplate::kSetter ||
value_kind == ClassBoilerplate::kAutoAccessor);
DirectHandle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
SetAccessorPlaceholderIndices(*pair, value_kind, Cast<Smi>(value));
value_handle = pair;
}
DirectHandle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
isolate, dictionary, key, value_handle, details, &entry);
CHECK_EQ(*dict, *dictionary);
DictionaryUpdateMaxNumberKey(dictionary, key);
} else {
int enum_order_existing =
Dictionary::kIsOrderedDictionaryType
? kDummyEnumerationIndex
: dictionary->DetailsAt(entry).dictionary_index();
int enum_order_computed =
Dictionary::kIsOrderedDictionaryType || is_elements_dictionary
? kDummyEnumerationIndex
: ComputeEnumerationIndex(key_index);
Tagged<Object> existing_value = dictionary->ValueAt(entry);
if (value_kind == ClassBoilerplate::kData) {
if (IsAccessorPair(existing_value)) {
Tagged<AccessorPair> current_pair = Cast<AccessorPair>(existing_value);
int existing_getter_index =
GetExistingValueIndex(current_pair->getter());
int existing_setter_index =
GetExistingValueIndex(current_pair->setter());
static_assert(kAccessorNotDefined < 0);
DCHECK(existing_getter_index >= 0 || existing_setter_index >= 0);
if (existing_getter_index < key_index &&
existing_setter_index < key_index) {
PropertyDetails details(
PropertyKind::kData, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_existing);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, value);
} else if (existing_getter_index != kAccessorNotDefined &&
existing_getter_index < key_index) {
DCHECK_LT(key_index, existing_setter_index);
current_pair->set_getter(*isolate->factory()->null_value());
} else if (existing_setter_index != kAccessorNotDefined &&
existing_setter_index < key_index) {
DCHECK_LT(key_index, existing_getter_index);
current_pair->set_setter(*isolate->factory()->null_value());
} else {
DCHECK(key_index < existing_getter_index ||
existing_getter_index == kAccessorNotDefined);
DCHECK(key_index < existing_setter_index ||
existing_setter_index == kAccessorNotDefined);
DCHECK(existing_getter_index != kAccessorNotDefined ||
existing_setter_index != kAccessorNotDefined);
if (!is_elements_dictionary) {
PropertyDetails details = dictionary->DetailsAt(entry);
details = details.set_index(enum_order_computed);
dictionary->DetailsAtPut(entry, details);
}
}
} else {
DCHECK(value_kind == ClassBoilerplate::kData);
DCHECK_IMPLIES(!IsSmi(existing_value), IsAccessorInfo(existing_value));
DCHECK_IMPLIES(!IsSmi(existing_value),
Cast<AccessorInfo>(existing_value)->name() ==
*isolate->factory()->length_string() ||
Cast<AccessorInfo>(existing_value)->name() ==
*isolate->factory()->name_string());
if (!IsSmi(existing_value) || Smi::ToInt(existing_value) < key_index) {
PropertyDetails details(
PropertyKind::kData, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_existing);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, value);
} else {
if (!is_elements_dictionary) {
PropertyDetails details(
PropertyKind::kData, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_computed);
dictionary->DetailsAtPut(entry, details);
}
}
}
} else {
if (IsAccessorPair(existing_value)) {
Tagged<AccessorPair> current_pair = Cast<AccessorPair>(existing_value);
bool updated = false;
switch (value_kind) {
case ClassBoilerplate::kAutoAccessor: {
int existing_get_component_index =
GetExistingValueIndex(current_pair->get(ACCESSOR_GETTER));
int existing_set_component_index =
GetExistingValueIndex(current_pair->get(ACCESSOR_SETTER));
if (existing_get_component_index < key_index &&
existing_set_component_index < key_index) {
SetAccessorPlaceholderIndices(current_pair, value_kind, value,
kReleaseStore);
updated = true;
} else {
if (existing_get_component_index < key_index) {
SetAccessorPlaceholderIndices(current_pair,
ClassBoilerplate::kGetter, value,
kReleaseStore);
updated = true;
} else if (existing_set_component_index < key_index) {
SetAccessorPlaceholderIndices(
current_pair, ClassBoilerplate::kSetter,
Smi::FromInt(Smi::ToInt(value) + 1), kReleaseStore);
updated = true;
}
}
break;
}
case ClassBoilerplate::kGetter:
case ClassBoilerplate::kSetter: {
AccessorComponent component =
value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
: ACCESSOR_SETTER;
int existing_component_index =
GetExistingValueIndex(current_pair->get(component));
if (existing_component_index < key_index) {
SetAccessorPlaceholderIndices(current_pair, value_kind, value,
kReleaseStore);
updated = true;
}
break;
}
default:
UNREACHABLE();
}
if (!updated) {
if (!is_elements_dictionary) {
PropertyDetails details(
PropertyKind::kAccessor, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_computed);
dictionary->DetailsAtPut(entry, details);
}
}
} else {
DCHECK(!IsAccessorPair(existing_value));
DCHECK(value_kind != ClassBoilerplate::kData);
if (!IsSmi(existing_value) || Smi::ToInt(existing_value) < key_index) {
DirectHandle<AccessorPair> pair(
isolate->factory()->NewAccessorPair());
SetAccessorPlaceholderIndices(*pair, value_kind, value);
PropertyDetails details(
PropertyKind::kAccessor, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_existing);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, *pair);
} else {
if (!is_elements_dictionary) {
PropertyDetails details(
PropertyKind::kData, DONT_ENUM,
PropertyDetails::kConstIfDictConstnessTracking,
enum_order_computed);
dictionary->DetailsAtPut(entry, details);
}
}
}
}
}
}
}
template <typename IsolateT>
class ObjectDescriptor {
public:
void IncComputedCount() { ++computed_count_; }
void IncPropertiesCount() { ++property_count_; }
void IncElementsCount() { ++element_count_; }
explicit ObjectDescriptor(int property_slack)
: property_slack_(property_slack) {}
bool HasDictionaryProperties() const {
return computed_count_ > 0 ||
(property_count_ + property_slack_) > kMaxNumberOfDescriptors;
}
Handle<Object> properties_template() const {
return HasDictionaryProperties() ? properties_dictionary_template_
: Cast<Object>(descriptor_array_template_);
}
Handle<NumberDictionary> elements_template() const {
return elements_dictionary_template_;
}
Handle<FixedArray> computed_properties() const {
return computed_properties_;
}
void CreateTemplates(IsolateT* isolate) {
auto* factory = isolate->factory();
descriptor_array_template_ = factory->empty_descriptor_array();
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties_dictionary_template_ =
factory->empty_swiss_property_dictionary();
} else {
properties_dictionary_template_ = factory->empty_property_dictionary();
}
if (property_count_ || computed_count_ || property_slack_) {
if (HasDictionaryProperties()) {
int need_space_for =
property_count_ + computed_count_ + property_slack_;
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties_dictionary_template_ =
isolate->factory()->NewSwissNameDictionary(need_space_for,
AllocationType::kOld);
} else {
properties_dictionary_template_ = NameDictionary::New(
isolate, need_space_for, AllocationType::kOld);
}
} else {
descriptor_array_template_ = DescriptorArray::Allocate(
isolate, 0, property_count_ + property_slack_,
AllocationType::kOld);
}
}
elements_dictionary_template_ =
element_count_ || computed_count_
? NumberDictionary::New(isolate, element_count_ + computed_count_,
AllocationType::kOld)
: factory->empty_slow_element_dictionary();
computed_properties_ =
computed_count_
? factory->NewFixedArray(computed_count_, AllocationType::kOld)
: factory->empty_fixed_array();
temp_handle_ = handle(Smi::zero(), isolate);
}
void AddConstant(IsolateT* isolate, DirectHandle<Name> name,
DirectHandle<Object> value, PropertyAttributes attribs) {
bool is_accessor = IsAccessorInfo(*value);
DCHECK(!IsAccessorPair(*value));
if (HasDictionaryProperties()) {
PropertyKind kind =
is_accessor ? i::PropertyKind::kAccessor : i::PropertyKind::kData;
int enum_order = V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
? kDummyEnumerationIndex
: next_enumeration_index_++;
PropertyDetails details(kind, attribs, PropertyCellType::kNoCell,
enum_order);
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties_dictionary_template_ =
DictionaryAddNoUpdateNextEnumerationIndex(
isolate, properties_ordered_dictionary_template(), name, value,
details);
} else {
properties_dictionary_template_ =
DictionaryAddNoUpdateNextEnumerationIndex(
isolate, properties_dictionary_template(), name, value,
details);
}
} else {
Descriptor d = is_accessor
? Descriptor::AccessorConstant(name, value, attribs)
: Descriptor::DataConstant(name, value, attribs);
descriptor_array_template_->Append(&d);
}
}
void AddNamedProperty(IsolateT* isolate, Handle<Name> name,
ClassBoilerplate::ValueKind value_kind,
int value_index) {
Tagged<Smi> value = Smi::FromInt(value_index);
if (HasDictionaryProperties()) {
UpdateNextEnumerationIndex(value_index);
if (V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
AddToDictionaryTemplate(isolate,
properties_ordered_dictionary_template(), name,
value_index, value_kind, value);
} else {
AddToDictionaryTemplate(isolate, properties_dictionary_template(), name,
value_index, value_kind, value);
}
} else {
temp_handle_.PatchValue(value);
AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
value_kind, temp_handle_);
}
}
void AddIndexedProperty(IsolateT* isolate, uint32_t element,
ClassBoilerplate::ValueKind value_kind,
int value_index) {
Tagged<Smi> value = Smi::FromInt(value_index);
AddToDictionaryTemplate(isolate, elements_dictionary_template_, element,
value_index, value_kind, value);
}
void AddComputed(ClassBoilerplate::ValueKind value_kind, int key_index) {
int value_index = key_index + 1;
UpdateNextEnumerationIndex(value_index);
int flags = EncodeComputedEntry(value_kind, key_index);
computed_properties_->set(current_computed_index_++, Smi::FromInt(flags));
}
void UpdateNextEnumerationIndex(int value_index) {
int current_index = ComputeEnumerationIndex(value_index);
DCHECK_LE(next_enumeration_index_, current_index);
next_enumeration_index_ = current_index + 1;
}
void Finalize(IsolateT* isolate) {
if (HasDictionaryProperties()) {
DCHECK_EQ(current_computed_index_, computed_properties_->length());
if (!V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL) {
properties_dictionary_template()->set_next_enumeration_index(
next_enumeration_index_);
}
} else {
DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
}
}
private:
Handle<NameDictionary> properties_dictionary_template() const {
return Cast<NameDictionary>(properties_dictionary_template_);
}
Handle<SwissNameDictionary> properties_ordered_dictionary_template() const {
return Cast<SwissNameDictionary>(properties_dictionary_template_);
}
const int property_slack_;
int property_count_ = 0;
int next_enumeration_index_ = PropertyDetails::kInitialIndex;
int element_count_ = 0;
int computed_count_ = 0;
int current_computed_index_ = 0;
Handle<DescriptorArray> descriptor_array_template_;
Handle<HeapObject> properties_dictionary_template_;
Handle<NumberDictionary> elements_dictionary_template_;
Handle<FixedArray> computed_properties_;
Handle<Object> temp_handle_;
};
template <typename IsolateT, typename PropertyDict>
void ClassBoilerplate::AddToPropertiesTemplate(
IsolateT* isolate, Handle<PropertyDict> dictionary, Handle<Name> name,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value) {
AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
value);
}
template void ClassBoilerplate::AddToPropertiesTemplate(
Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
template void ClassBoilerplate::AddToPropertiesTemplate(
LocalIsolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
template void ClassBoilerplate::AddToPropertiesTemplate(
Isolate* isolate, Handle<SwissNameDictionary> dictionary, Handle<Name> name,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
template <typename IsolateT>
void ClassBoilerplate::AddToElementsTemplate(
IsolateT* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value) {
AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
value);
}
template void ClassBoilerplate::AddToElementsTemplate(
Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
template void ClassBoilerplate::AddToElementsTemplate(
LocalIsolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
int key_index, ClassBoilerplate::ValueKind value_kind, Tagged<Smi> value);
template <typename IsolateT>
Handle<ClassBoilerplate> ClassBoilerplate::New(IsolateT* isolate,
ClassLiteral* expr,
AllocationType allocation) {
typename IsolateT::HandleScopeType scope(isolate);
auto* factory = isolate->factory();
ObjectDescriptor<IsolateT> static_desc(kMinimumClassPropertiesCount);
ObjectDescriptor<IsolateT> instance_desc(kMinimumPrototypePropertiesCount);
for (int i = 0; i < expr->public_members()->length(); i++) {
ClassLiteral::Property* property = expr->public_members()->at(i);
ObjectDescriptor<IsolateT>& desc =
property->is_static() ? static_desc : instance_desc;
if (property->is_computed_name()) {
if (property->kind() != ClassLiteral::Property::FIELD) {
desc.IncComputedCount();
}
} else {
if (property->key()->AsLiteral()->IsPropertyName()) {
desc.IncPropertiesCount();
} else {
desc.IncElementsCount();
}
}
}
static_desc.CreateTemplates(isolate);
static_assert(JSFunction::kLengthDescriptorIndex == 0);
{
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(isolate, factory->length_string(),
factory->function_length_accessor(), attribs);
}
{
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(isolate, factory->name_string(),
factory->function_name_accessor(), attribs);
}
{
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
static_desc.AddConstant(isolate, factory->prototype_string(),
factory->function_prototype_accessor(), attribs);
}
{
DirectHandle<ClassPositions> class_positions = factory->NewClassPositions(
expr->start_position(), expr->end_position());
static_desc.AddConstant(isolate, factory->class_positions_symbol(),
class_positions, DONT_ENUM);
}
instance_desc.CreateTemplates(isolate);
{
DirectHandle<Object> value(
Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
instance_desc.AddConstant(isolate, factory->constructor_string(), value,
DONT_ENUM);
}
int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
for (int i = 0; i < expr->public_members()->length(); i++) {
ClassLiteral::Property* property = expr->public_members()->at(i);
ClassBoilerplate::ValueKind value_kind;
int value_index = dynamic_argument_index;
switch (property->kind()) {
case ClassLiteral::Property::METHOD:
value_kind = ClassBoilerplate::kData;
break;
case ClassLiteral::Property::GETTER:
value_kind = ClassBoilerplate::kGetter;
break;
case ClassLiteral::Property::SETTER:
value_kind = ClassBoilerplate::kSetter;
break;
case ClassLiteral::Property::FIELD:
DCHECK_IMPLIES(property->is_computed_name(), !property->is_private());
if (property->is_computed_name()) {
++dynamic_argument_index;
}
continue;
case ClassLiteral::Property::AUTO_ACCESSOR:
value_kind = ClassBoilerplate::kAutoAccessor;
++dynamic_argument_index;
}
ObjectDescriptor<IsolateT>& desc =
property->is_static() ? static_desc : instance_desc;
if (property->is_computed_name()) {
int computed_name_index = value_index;
dynamic_argument_index += 2;
desc.AddComputed(value_kind, computed_name_index);
continue;
}
dynamic_argument_index++;
Literal* key_literal = property->key()->AsLiteral();
uint32_t index;
if (key_literal->AsArrayIndex(&index)) {
desc.AddIndexedProperty(isolate, index, value_kind, value_index);
} else {
Handle<String> name = key_literal->AsRawPropertyName()->string();
DCHECK(IsInternalizedString(*name));
desc.AddNamedProperty(isolate, name, value_kind, value_index);
}
}
static_desc.Finalize(isolate);
instance_desc.Finalize(isolate);
auto result = Cast<ClassBoilerplate>(
factory->NewStruct(CLASS_BOILERPLATE_TYPE, allocation));
result->set_arguments_count(dynamic_argument_index);
result->set_static_properties_template(*static_desc.properties_template());
result->set_static_elements_template(*static_desc.elements_template());
result->set_static_computed_properties(*static_desc.computed_properties());
result->set_instance_properties_template(
*instance_desc.properties_template());
result->set_instance_elements_template(*instance_desc.elements_template());
result->set_instance_computed_properties(
*instance_desc.computed_properties());
return scope.CloseAndEscape(result);
}
template Handle<ClassBoilerplate> ClassBoilerplate::New(
Isolate* isolate, ClassLiteral* expr, AllocationType allocation);
template Handle<ClassBoilerplate> ClassBoilerplate::New(
LocalIsolate* isolate, ClassLiteral* expr, AllocationType allocation);
void ArrayBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
os << " " << ElementsKindToString(elements_kind()) << ", "
<< Brief(constant_elements());
}
void RegExpBoilerplateDescription::BriefPrintDetails(std::ostream& os) {
static_assert(JSRegExp::kDataOffset == JSObject::kHeaderSize);
static_assert(JSRegExp::kSourceOffset == JSRegExp::kDataOffset + kTaggedSize);
static_assert(JSRegExp::kFlagsOffset ==
JSRegExp::kSourceOffset + kTaggedSize);
static_assert(JSRegExp::kHeaderSize == JSRegExp::kFlagsOffset + kTaggedSize);
IsolateForSandbox isolate = GetCurrentIsolateForSandbox();
os << " " << Brief(data(isolate)) << ", " << Brief(source()) << ", "
<< flags();
}
}
}