Revert "Reland "[runtime] Slightly optimize creation of class literals.""

This reverts commit 22932d6b43.

Reason for revert: TSAN https://build.chromium.org/p/client.v8/builders/V8%20Linux64%20TSAN/builds/18232

Original change's description:
> Reland "[runtime] Slightly optimize creation of class literals."
> 
> Bug: v8:5799
> Change-Id: I782ec131c7194aef20942a19750168a974913c3f
> Reviewed-on: https://chromium-review.googlesource.com/757337
> Commit-Queue: Igor Sheludko <ishell@chromium.org>
> Reviewed-by: Toon Verwaest <verwaest@chromium.org>
> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49291}

TBR=ulan@chromium.org,rmcilroy@chromium.org,jarin@chromium.org,ishell@chromium.org,verwaest@chromium.org

Change-Id: I0742d25b0e2364efc696d19492ba20614a3821fa
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:5799
Reviewed-on: https://chromium-review.googlesource.com/763458
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49303}
This commit is contained in:
Jakob Gruber 2017-11-10 16:00:13 +00:00 committed by Commit Bot
parent a3a67fe7a4
commit e4b394a1f4
24 changed files with 469 additions and 1429 deletions

View File

@ -1799,7 +1799,6 @@ v8_source_set("v8_base") {
"src/objects/js-array.h",
"src/objects/js-regexp-inl.h",
"src/objects/js-regexp.h",
"src/objects/literal-objects-inl.h",
"src/objects/literal-objects.cc",
"src/objects/literal-objects.h",
"src/objects/map-inl.h",

View File

@ -828,17 +828,6 @@ bool Literal::IsPropertyName() const {
return !string_->AsArrayIndex(&index);
}
bool Literal::AsArrayIndex(uint32_t* index) const {
if (type() == kString) {
return string_->AsArrayIndex(index);
} else {
DCHECK_EQ(kSmi, type());
DCHECK_LE(0, smi_);
*index = smi_;
return true;
}
}
bool Literal::ToUint32(uint32_t* value) const {
switch (type()) {
case kSmi:

View File

@ -1006,10 +1006,6 @@ class Literal final : public Expression {
// Returns true if literal represents a property name (i.e. cannot be parsed
// as array indices).
bool IsPropertyName() const;
// Returns true if literal represents an array index.
bool AsArrayIndex(uint32_t* index) const;
const AstRawString* AsRawPropertyName() {
DCHECK(IsPropertyName());
return string_;

View File

@ -191,7 +191,6 @@ enum class ObjectType {
#undef ENUM_STRUCT_ELEMENT
class AccessCheckNeeded;
class ClassBoilerplate;
class CompilationCacheTable;
class Constructor;
class Filler;

View File

@ -3115,7 +3115,6 @@ Handle<Map> Factory::CreateClassFunctionMap(Handle<JSFunction> empty_function) {
Handle<Map> map = NewMap(JS_FUNCTION_TYPE, JSFunction::kSizeWithPrototype);
map->set_has_prototype_slot(true);
map->set_is_constructor(true);
map->set_is_prototype_map(true);
map->set_is_callable();
Map::SetPrototype(map, empty_function);
@ -3124,8 +3123,8 @@ Handle<Map> Factory::CreateClassFunctionMap(Handle<JSFunction> empty_function) {
//
Map::EnsureDescriptorSlack(map, 2);
PropertyAttributes ro_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
PropertyAttributes rw_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
PropertyAttributes roc_attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
@ -3139,7 +3138,7 @@ Handle<Map> Factory::CreateClassFunctionMap(Handle<JSFunction> empty_function) {
{
// Add prototype accessor.
Descriptor d = Descriptor::AccessorConstant(
prototype_string(), function_prototype_accessor(), ro_attribs);
prototype_string(), function_prototype_accessor(), rw_attribs);
map->AppendDescriptor(&d);
}
return map;

View File

@ -283,7 +283,6 @@ using v8::MemoryPressureLevel;
V(CatchContextMap) \
V(CellMap) \
V(CodeMap) \
V(DescriptorArrayMap) \
V(EmptyByteArray) \
V(EmptyDescriptorArray) \
V(EmptyFixedArray) \

View File

@ -18,7 +18,6 @@
#include "src/interpreter/control-flow-builders.h"
#include "src/objects-inl.h"
#include "src/objects/debug-objects.h"
#include "src/objects/literal-objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/token.h"
@ -812,7 +811,7 @@ class BytecodeGenerator::FeedbackSlotCache : public ZoneObject {
BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
: zone_(info->zone()),
builder_(new (zone()) BytecodeArrayBuilder(
info->isolate(), zone(), info->num_parameters_including_this(),
info->isolate(), info->zone(), info->num_parameters_including_this(),
info->scope()->num_stack_slots(), info->feedback_vector_spec(),
info->SourcePositionRecordingMode())),
info_(info),
@ -827,7 +826,6 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info)
native_function_literals_(0, zone()),
object_literals_(0, zone()),
array_literals_(0, zone()),
class_literals_(0, zone()),
template_objects_(0, zone()),
execution_control_(nullptr),
execution_context_(nullptr),
@ -922,14 +920,6 @@ void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate,
builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
}
// Build class literal boilerplates.
for (std::pair<ClassLiteral*, size_t> literal : class_literals_) {
ClassLiteral* class_literal = literal.first;
Handle<ClassBoilerplate> class_boilerplate =
ClassBoilerplate::BuildClassBoilerplate(isolate, class_literal);
builder()->SetDeferredConstantPoolEntry(literal.second, class_boilerplate);
}
// Build template literals.
for (std::pair<GetTemplateObject*, size_t> literal : template_objects_) {
GetTemplateObject* get_template_object = literal.first;
@ -1773,74 +1763,35 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
}
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
size_t class_boilerplate_entry =
builder()->AllocateDeferredConstantPoolEntry();
class_literals_.push_back(std::make_pair(expr, class_boilerplate_entry));
VisitDeclarations(expr->scope()->declarations());
Register constructor = VisitForRegisterValue(expr->constructor());
{
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewGrowableRegisterList();
Register class_boilerplate = register_allocator()->GrowRegisterList(&args);
Register class_constructor = register_allocator()->GrowRegisterList(&args);
Register super_class = register_allocator()->GrowRegisterList(&args);
DCHECK_EQ(ClassBoilerplate::kFirstDynamicArgumentIndex,
args.register_count());
RegisterList args = register_allocator()->NewRegisterList(4);
VisitForAccumulatorValueOrTheHole(expr->extends());
builder()->StoreAccumulatorInRegister(super_class);
VisitFunctionLiteral(expr->constructor());
builder()
->StoreAccumulatorInRegister(class_constructor)
.LoadConstantPoolEntry(class_boilerplate_entry)
.StoreAccumulatorInRegister(class_boilerplate);
// Create computed names and method values nodes to store into the literal.
for (int i = 0; i < expr->properties()->length(); i++) {
ClassLiteral::Property* property = expr->properties()->at(i);
if (property->is_computed_name()) {
Register key = register_allocator()->GrowRegisterList(&args);
BuildLoadPropertyKey(property, key);
if (property->is_static()) {
// The static prototype property is read only. We handle the non
// computed property name case in the parser. Since this is the only
// case where we need to check for an own read only property we
// special case this so we do not need to do this for every property.
BytecodeLabel done;
builder()
->LoadLiteral(ast_string_constants()->prototype_string())
.CompareOperation(Token::Value::EQ_STRICT, key)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
.CallRuntime(Runtime::kThrowStaticPrototypeError)
.Bind(&done);
}
if (property->kind() == ClassLiteral::Property::FIELD) {
// Initialize field's name variable with the computed name.
DCHECK_NOT_NULL(property->computed_name_var());
builder()->LoadAccumulatorWithRegister(key);
BuildVariableAssignment(property->computed_name_var(), Token::INIT,
HoleCheckMode::kElided);
}
}
if (property->kind() == ClassLiteral::Property::FIELD) {
// We don't compute field's value here, but instead do it in the
// initializer function.
continue;
}
Register value = register_allocator()->GrowRegisterList(&args);
VisitForRegisterValue(property->value(), value);
}
builder()->CallRuntime(Runtime::kDefineClass, args);
->StoreAccumulatorInRegister(args[0])
.MoveRegister(constructor, args[1])
.LoadLiteral(Smi::FromInt(expr->start_position()))
.StoreAccumulatorInRegister(args[2])
.LoadLiteral(Smi::FromInt(expr->end_position()))
.StoreAccumulatorInRegister(args[3])
.CallRuntime(Runtime::kDefineClass, args);
}
Register class_constructor = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(class_constructor);
Register prototype = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(prototype);
if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
// Prototype is already in the accumulator.
FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
builder()->StoreHomeObjectProperty(constructor, feedback_index(slot),
language_mode());
}
VisitClassLiteralProperties(expr, constructor, prototype);
BuildClassLiteralNameProperty(expr, constructor);
// TODO(gsathya): Run this after initializing class static fields.
builder()->CallRuntime(Runtime::kToFastProperties, constructor);
// Assign to class variable.
if (expr->class_variable() != nullptr) {
DCHECK(expr->class_variable()->IsStackLocal() ||
@ -1859,6 +1810,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
builder()->LoadAccumulatorWithRegister(initializer);
BuildVariableAssignment(expr->instance_fields_initializer_var(),
Token::INIT, HoleCheckMode::kElided);
builder()->LoadAccumulatorWithRegister(constructor);
}
if (expr->static_fields_initializer() != nullptr) {
@ -1869,17 +1821,17 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
if (FunctionLiteral::NeedsHomeObject(expr->static_fields_initializer())) {
FeedbackSlot slot = feedback_spec()->AddStoreICSlot(language_mode());
builder()
->LoadAccumulatorWithRegister(class_constructor)
->LoadAccumulatorWithRegister(constructor)
.StoreHomeObjectProperty(initializer, feedback_index(slot),
language_mode());
}
builder()
->MoveRegister(class_constructor, args[0])
->MoveRegister(constructor, args[0])
.CallProperty(initializer, args,
feedback_index(feedback_spec()->AddCallICSlot()));
feedback_index(feedback_spec()->AddCallICSlot()))
.LoadAccumulatorWithRegister(constructor);
}
builder()->LoadAccumulatorWithRegister(class_constructor);
}
void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
@ -1894,6 +1846,95 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) {
}
}
void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr,
Register constructor,
Register prototype) {
RegisterAllocationScope register_scope(this);
RegisterList args = register_allocator()->NewRegisterList(4);
Register receiver = args[0], key = args[1], value = args[2], attr = args[3];
bool attr_assigned = false;
Register old_receiver = Register::invalid_value();
// Create nodes to store method values into the literal.
for (int i = 0; i < expr->properties()->length(); i++) {
ClassLiteral::Property* property = expr->properties()->at(i);
// Set-up receiver.
Register new_receiver = property->is_static() ? constructor : prototype;
if (new_receiver != old_receiver) {
builder()->MoveRegister(new_receiver, receiver);
old_receiver = new_receiver;
}
BuildLoadPropertyKey(property, key);
if (property->is_computed_name()) {
if (property->is_static()) {
// The static prototype property is read only. We handle the non
// computed property name case in the parser. Since this is the only
// case where we need to check for an own read only property we special
// case this so we do not need to do this for every property.
BytecodeLabel done;
builder()
->LoadLiteral(ast_string_constants()->prototype_string())
.CompareOperation(Token::Value::EQ_STRICT, key)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done)
.CallRuntime(Runtime::kThrowStaticPrototypeError)
.Bind(&done);
}
if (property->kind() == ClassLiteral::Property::FIELD) {
DCHECK_NOT_NULL(property->computed_name_var());
builder()->LoadAccumulatorWithRegister(key);
BuildVariableAssignment(property->computed_name_var(), Token::INIT,
HoleCheckMode::kElided);
// We don't define the field here, but instead do it in the
// initializer function.
continue;
}
}
VisitForRegisterValue(property->value(), value);
VisitSetHomeObject(value, receiver, property);
if (!attr_assigned) {
builder()
->LoadLiteral(Smi::FromInt(DONT_ENUM))
.StoreAccumulatorInRegister(attr);
attr_assigned = true;
}
switch (property->kind()) {
case ClassLiteral::Property::METHOD: {
DataPropertyInLiteralFlags flags = DataPropertyInLiteralFlag::kDontEnum;
if (property->NeedsSetFunctionName()) {
flags |= DataPropertyInLiteralFlag::kSetFunctionName;
}
FeedbackSlot slot =
feedback_spec()->AddStoreDataPropertyInLiteralICSlot();
builder()
->LoadAccumulatorWithRegister(value)
.StoreDataPropertyInLiteral(receiver, key, flags,
feedback_index(slot));
break;
}
case ClassLiteral::Property::GETTER: {
builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, args);
break;
}
case ClassLiteral::Property::SETTER: {
builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, args);
break;
}
case ClassLiteral::Property::FIELD: {
UNREACHABLE();
break;
}
}
}
}
void BytecodeGenerator::VisitInitializeClassFieldsStatement(
InitializeClassFieldsStatement* expr) {
RegisterList args = register_allocator()->NewRegisterList(3);
@ -1934,6 +1975,18 @@ void BytecodeGenerator::BuildInstanceFieldInitialization(
feedback_index(feedback_spec()->AddCallICSlot()));
}
void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr,
Register literal) {
if (!expr->has_name_static_property() &&
expr->constructor()->has_shared_name()) {
Runtime::FunctionId runtime_id =
expr->has_static_computed_names()
? Runtime::kInstallClassNameAccessorWithCheck
: Runtime::kInstallClassNameAccessor;
builder()->CallRuntime(runtime_id, literal);
}
}
void BytecodeGenerator::VisitNativeFunctionLiteral(
NativeFunctionLiteral* expr) {
size_t entry = builder()->AllocateDeferredConstantPoolEntry();

View File

@ -153,6 +153,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call);
void VisitClassLiteralProperties(ClassLiteral* expr, Register constructor,
Register prototype);
void BuildClassLiteralNameProperty(ClassLiteral* expr, Register constructor);
void BuildClassLiteral(ClassLiteral* expr);
void VisitNewTargetVariable(Variable* variable);
void VisitThisFunctionVariable(Variable* variable);
@ -305,7 +308,6 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
native_function_literals_;
ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
ControlScope* execution_control_;

View File

@ -152,8 +152,6 @@ bool HeapObject::IsJSGeneratorObject() const {
bool HeapObject::IsBoilerplateDescription() const { return IsFixedArray(); }
bool HeapObject::IsClassBoilerplate() const { return IsFixedArray(); }
bool HeapObject::IsExternal() const {
return map()->FindRootMap() == GetHeap()->external_map();
}

View File

@ -1145,9 +1145,6 @@ void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
os << "<no-shared-name>";
}
os << "\n - kind = " << kind();
if (needs_home_object()) {
os << "\n - needs_home_object";
}
os << "\n - function_map_index = " << function_map_index();
os << "\n - formal_parameter_count = " << internal_formal_parameter_count();
os << "\n - expected_nof_properties = " << expected_nof_properties();

View File

@ -15619,7 +15619,6 @@ template <typename Derived, typename Shape>
void Dictionary<Derived, Shape>::Print() {
OFStream os(stdout);
Print(os);
os << std::endl;
}
#endif
@ -17408,23 +17407,6 @@ Handle<Derived> Dictionary<Derived, Shape>::AtPut(Handle<Derived> dictionary,
return dictionary;
}
template <typename Derived, typename Shape>
Handle<Derived>
BaseNameDictionary<Derived, Shape>::AddNoUpdateNextEnumerationIndex(
Handle<Derived> dictionary, Key key, Handle<Object> value,
PropertyDetails details, int* entry_out) {
// Insert element at empty or deleted entry
return Dictionary<Derived, Shape>::Add(dictionary, key, value, details,
entry_out);
}
// GCC workaround: Explicitly instantiate template method for NameDictionary
// to avoid "undefined reference" issues during linking.
template Handle<NameDictionary>
BaseNameDictionary<NameDictionary, NameDictionaryShape>::
AddNoUpdateNextEnumerationIndex(Handle<NameDictionary>, Handle<Name>,
Handle<Object>, PropertyDetails, int*);
template <typename Derived, typename Shape>
Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
Handle<Derived> dictionary, Key key, Handle<Object> value,
@ -17436,7 +17418,7 @@ Handle<Derived> BaseNameDictionary<Derived, Shape>::Add(
int index = dictionary->NextEnumerationIndex();
details = details.set_index(index);
dictionary->SetNextEnumerationIndex(index + 1);
return AddNoUpdateNextEnumerationIndex(dictionary, key, value, details,
return Dictionary<Derived, Shape>::Add(dictionary, key, value, details,
entry_out);
}

View File

@ -977,7 +977,6 @@ template <class C> inline bool Is(Object* obj);
V(Callable) \
V(CallHandlerInfo) \
V(Cell) \
V(ClassBoilerplate) \
V(Code) \
V(CodeDataContainer) \
V(CompilationCacheTable) \

View File

@ -172,10 +172,6 @@ class BaseNameDictionary : public Dictionary<Derived, Shape> {
// Ensure enough space for n additional elements.
static Handle<Derived> EnsureCapacity(Handle<Derived> dictionary, int n);
MUST_USE_RESULT static Handle<Derived> AddNoUpdateNextEnumerationIndex(
Handle<Derived> dictionary, Key key, Handle<Object> value,
PropertyDetails details, int* entry_out = nullptr);
MUST_USE_RESULT static Handle<Derived> Add(Handle<Derived> dictionary,
Key key, Handle<Object> value,
PropertyDetails details,

View File

@ -1,51 +0,0 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_LITERAL_OBJECTS_INL_H_
#define V8_LITERAL_OBJECTS_INL_H_
#include "src/objects-inl.h"
#include "src/objects/literal-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
CAST_ACCESSOR(ClassBoilerplate)
BIT_FIELD_ACCESSORS(ClassBoilerplate, flags, install_class_name_accessor,
ClassBoilerplate::Flags::InstallClassNameAccessorBit)
BIT_FIELD_ACCESSORS(ClassBoilerplate, flags, arguments_count,
ClassBoilerplate::Flags::ArgumentsCountBits)
SMI_ACCESSORS(ClassBoilerplate, flags,
FixedArray::OffsetOfElementAt(kFlagsIndex));
ACCESSORS(ClassBoilerplate, static_properties_template, Object,
FixedArray::OffsetOfElementAt(kClassPropertiesTemplateIndex));
ACCESSORS(ClassBoilerplate, static_elements_template, Object,
FixedArray::OffsetOfElementAt(kClassElementsTemplateIndex));
ACCESSORS(ClassBoilerplate, static_computed_properties, FixedArray,
FixedArray::OffsetOfElementAt(kClassComputedPropertiesIndex));
ACCESSORS(ClassBoilerplate, instance_properties_template, Object,
FixedArray::OffsetOfElementAt(kPrototypePropertiesTemplateIndex));
ACCESSORS(ClassBoilerplate, instance_elements_template, Object,
FixedArray::OffsetOfElementAt(kPrototypeElementsTemplateIndex));
ACCESSORS(ClassBoilerplate, instance_computed_properties, FixedArray,
FixedArray::OffsetOfElementAt(kPrototypeComputedPropertiesIndex));
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_LITERAL_OBJECTS_INL_H_

View File

@ -4,12 +4,9 @@
#include "src/objects/literal-objects.h"
#include "src/accessors.h"
#include "src/ast/ast.h"
#include "src/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/objects/literal-objects-inl.h"
namespace v8 {
namespace internal {
@ -54,536 +51,5 @@ bool BoilerplateDescription::has_number_of_properties() const {
return length() % 2 != 0;
}
namespace {
inline int EncodeComputedEntry(ClassBoilerplate::ValueKind value_kind,
unsigned key_index) {
typedef ClassBoilerplate::ComputedEntryFlags Flags;
int flags = Flags::ValueKindBits::encode(value_kind) |
Flags::KeyIndexBits::encode(key_index);
return flags;
}
void AddToDescriptorArrayTemplate(
Isolate* isolate, Handle<DescriptorArray> descriptor_array_template,
Handle<Name> name, ClassBoilerplate::ValueKind value_kind,
Handle<Object> value) {
int entry = descriptor_array_template->Search(
*name, descriptor_array_template->number_of_descriptors());
// TODO(ishell): deduplicate properties at AST level, this will allow us to
// avoid creation of closures that will be overwritten anyway.
if (entry == DescriptorArray::kNotFound) {
// Entry not found, add new one.
Descriptor d;
if (value_kind == ClassBoilerplate::kData) {
d = Descriptor::DataConstant(name, value, DONT_ENUM);
} else {
DCHECK(value_kind == ClassBoilerplate::kGetter ||
value_kind == ClassBoilerplate::kSetter);
Handle<AccessorPair> pair = isolate->factory()->NewAccessorPair();
pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
: ACCESSOR_SETTER,
*value);
d = Descriptor::AccessorConstant(name, pair, DONT_ENUM);
}
descriptor_array_template->Append(&d);
} else {
// Entry found, update it.
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);
Object* raw_accessor = descriptor_array_template->GetValue(entry);
AccessorPair* pair;
if (raw_accessor->IsAccessorPair()) {
pair = AccessorPair::cast(raw_accessor);
} else {
Handle<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;
}
pair->set(value_kind == ClassBoilerplate::kGetter ? ACCESSOR_GETTER
: ACCESSOR_SETTER,
*value);
}
}
}
Handle<NameDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
Handle<NameDictionary> dictionary, Handle<Name> name, Handle<Object> value,
PropertyDetails details, int* entry_out = nullptr) {
return NameDictionary::AddNoUpdateNextEnumerationIndex(
dictionary, name, value, details, entry_out);
}
Handle<NumberDictionary> DictionaryAddNoUpdateNextEnumerationIndex(
Handle<NumberDictionary> dictionary, uint32_t element, Handle<Object> value,
PropertyDetails details, int* entry_out = nullptr) {
// NumberDictionary does not maintain the enumeration order, so it's
// a normal Add().
return NumberDictionary::Add(dictionary, element, value, details, entry_out);
}
void DictionaryUpdateMaxNumberKey(Handle<NameDictionary> dictionary,
Handle<Name> name) {
// No-op for name dictionaries.
}
void DictionaryUpdateMaxNumberKey(Handle<NumberDictionary> dictionary,
uint32_t element) {
dictionary->UpdateMaxNumberKey(element, Handle<JSObject>());
dictionary->set_requires_slow_elements();
}
constexpr int ComputeEnumerationIndex(int value_index) {
// We "shift" value indices to ensure that the enumeration index for the value
// will not overlap with minimum properties set for both class and prototype
// objects.
return value_index + Max(ClassBoilerplate::kMinimumClassPropertiesCount,
ClassBoilerplate::kMinimumPrototypePropertiesCount);
}
inline int GetExistingValueIndex(Object* value) {
return value->IsSmi() ? Smi::ToInt(value) : -1;
}
template <typename Dictionary, typename Key>
void AddToDictionaryTemplate(Isolate* isolate, Handle<Dictionary> dictionary,
Key key, int key_index,
ClassBoilerplate::ValueKind value_kind,
Object* value) {
int entry = dictionary->FindEntry(isolate, key);
if (entry == kNotFound) {
// Entry not found, add new one.
const bool is_elements_dictionary =
std::is_same<Dictionary, NumberDictionary>::value;
STATIC_ASSERT(is_elements_dictionary !=
(std::is_same<Dictionary, NameDictionary>::value));
int enum_order =
is_elements_dictionary ? 0 : ComputeEnumerationIndex(key_index);
Handle<Object> value_handle;
PropertyDetails details(
value_kind != ClassBoilerplate::kData ? kAccessor : kData, DONT_ENUM,
PropertyCellType::kNoCell, enum_order);
if (value_kind == ClassBoilerplate::kData) {
value_handle = handle(value, isolate);
} else {
AccessorComponent component = value_kind == ClassBoilerplate::kGetter
? ACCESSOR_GETTER
: ACCESSOR_SETTER;
Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
pair->set(component, value);
value_handle = pair;
}
// Add value to the dictionary without updating next enumeration index.
Handle<Dictionary> dict = DictionaryAddNoUpdateNextEnumerationIndex(
dictionary, key, value_handle, details, &entry);
// It is crucial to avoid dictionary reallocations because it may remove
// potential gaps in enumeration indices values that are necessary for
// inserting computed properties into right places in the enumeration order.
CHECK_EQ(*dict, *dictionary);
DictionaryUpdateMaxNumberKey(dictionary, key);
} else {
// Entry found, update it.
int enum_order = dictionary->DetailsAt(entry).dictionary_index();
Object* existing_value = dictionary->ValueAt(entry);
if (value_kind == ClassBoilerplate::kData) {
// Computed value is a normal method.
if (existing_value->IsAccessorPair()) {
AccessorPair* current_pair = AccessorPair::cast(existing_value);
int existing_getter_index =
GetExistingValueIndex(current_pair->getter());
int existing_setter_index =
GetExistingValueIndex(current_pair->setter());
if (existing_getter_index < key_index &&
existing_setter_index < key_index) {
// Both getter and setter were defined before the computed method,
// so overwrite both.
PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
enum_order);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, value);
} else {
if (existing_getter_index < key_index) {
DCHECK_LT(existing_setter_index, key_index);
// Getter was defined before the computed method and then it was
// overwritten by the current computed method which in turn was
// later overwritten by the setter method. So we clear the getter.
current_pair->set_getter(*isolate->factory()->null_value());
} else if (existing_setter_index < key_index) {
DCHECK_LT(existing_getter_index, key_index);
// Setter was defined before the computed method and then it was
// overwritten by the current computed method which in turn was
// later overwritten by the getter method. So we clear the setter.
current_pair->set_setter(*isolate->factory()->null_value());
}
}
} else {
// Overwrite existing value if it was defined before the computed one.
int existing_value_index = Smi::ToInt(existing_value);
if (existing_value_index < key_index) {
PropertyDetails details(kData, DONT_ENUM, PropertyCellType::kNoCell,
enum_order);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, value);
}
}
} else {
AccessorComponent component = value_kind == ClassBoilerplate::kGetter
? ACCESSOR_GETTER
: ACCESSOR_SETTER;
if (existing_value->IsAccessorPair()) {
AccessorPair* current_pair = AccessorPair::cast(existing_value);
int existing_component_index =
GetExistingValueIndex(current_pair->get(component));
if (existing_component_index < key_index) {
current_pair->set(component, value);
}
} else {
Handle<AccessorPair> pair(isolate->factory()->NewAccessorPair());
pair->set(component, value);
PropertyDetails details(kAccessor, DONT_ENUM,
PropertyCellType::kNoCell);
dictionary->DetailsAtPut(entry, details);
dictionary->ValueAtPut(entry, *pair);
}
}
}
}
} // namespace
// Helper class that eases building of a properties, elements and computed
// properties templates.
class ObjectDescriptor {
public:
void IncComputedCount() { ++computed_count_; }
void IncPropertiesCount() { ++property_count_; }
void IncElementsCount() { ++element_count_; }
bool has_computed_properties() const { return computed_count_ != 0; }
Handle<Object> properties_template() const {
return has_computed_properties()
? Handle<Object>::cast(properties_dictionary_template_)
: Handle<Object>::cast(descriptor_array_template_);
}
Handle<NumberDictionary> elements_template() const {
return elements_dictionary_template_;
}
Handle<FixedArray> computed_properties() const {
return computed_properties_;
}
void CreateTemplates(Isolate* isolate, int slack) {
Factory* factory = isolate->factory();
descriptor_array_template_ = factory->empty_descriptor_array();
properties_dictionary_template_ = factory->empty_property_dictionary();
if (property_count_ || has_computed_properties() || slack) {
if (has_computed_properties()) {
properties_dictionary_template_ = NameDictionary::New(
isolate, property_count_ + computed_count_ + slack);
} else {
descriptor_array_template_ =
DescriptorArray::Allocate(isolate, 0, property_count_ + slack);
// TODO(ishell): remove this code once we use |descriptor_array_map|
// for all descriptor arrays.
descriptor_array_template_->set_map_no_write_barrier(
*factory->descriptor_array_map());
}
}
elements_dictionary_template_ =
element_count_ || computed_count_
? NumberDictionary::New(isolate, element_count_ + computed_count_)
: factory->empty_slow_element_dictionary();
computed_properties_ =
computed_count_
? factory->NewFixedArray(computed_count_ *
ClassBoilerplate::kFullComputedEntrySize)
: factory->empty_fixed_array();
temp_handle_ = handle(Smi::kZero, isolate);
}
void AddConstant(Handle<Name> name, Handle<Object> value,
PropertyAttributes attribs) {
bool is_accessor = value->IsAccessorInfo();
DCHECK(!value->IsAccessorPair());
if (has_computed_properties()) {
PropertyKind kind = is_accessor ? i::kAccessor : i::kData;
PropertyDetails details(kind, attribs, PropertyCellType::kNoCell,
next_enumeration_index_++);
properties_dictionary_template_ =
DictionaryAddNoUpdateNextEnumerationIndex(
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(Isolate* isolate, Handle<Name> name,
ClassBoilerplate::ValueKind value_kind,
int value_index) {
Smi* value = Smi::FromInt(value_index);
if (has_computed_properties()) {
UpdateNextEnumerationIndex(value_index);
AddToDictionaryTemplate(isolate, properties_dictionary_template_, name,
value_index, value_kind, value);
} else {
*temp_handle_.location() = value;
AddToDescriptorArrayTemplate(isolate, descriptor_array_template_, name,
value_kind, temp_handle_);
}
}
void AddIndexedProperty(Isolate* isolate, uint32_t element,
ClassBoilerplate::ValueKind value_kind,
int value_index) {
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 next_index = ComputeEnumerationIndex(value_index);
DCHECK_LT(next_enumeration_index_, next_index);
next_enumeration_index_ = next_index;
}
void Finalize(Isolate* isolate) {
if (has_computed_properties()) {
properties_dictionary_template_->SetNextEnumerationIndex(
next_enumeration_index_);
isolate->heap()->RightTrimFixedArray(
*computed_properties_,
computed_properties_->length() - current_computed_index_);
} else {
DCHECK(descriptor_array_template_->IsSortedNoDuplicates());
}
}
private:
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<NameDictionary> properties_dictionary_template_;
Handle<NumberDictionary> elements_dictionary_template_;
Handle<FixedArray> computed_properties_;
// This temporary handle is used for storing to descriptor array.
Handle<Object> temp_handle_;
};
void ClassBoilerplate::AddToPropertiesTemplate(
Isolate* isolate, Handle<NameDictionary> dictionary, Handle<Name> name,
int key_index, ClassBoilerplate::ValueKind value_kind, Object* value) {
AddToDictionaryTemplate(isolate, dictionary, name, key_index, value_kind,
value);
}
void ClassBoilerplate::AddToElementsTemplate(
Isolate* isolate, Handle<NumberDictionary> dictionary, uint32_t key,
int key_index, ClassBoilerplate::ValueKind value_kind, Object* value) {
AddToDictionaryTemplate(isolate, dictionary, key, key_index, value_kind,
value);
}
Handle<ClassBoilerplate> ClassBoilerplate::BuildClassBoilerplate(
Isolate* isolate, ClassLiteral* expr) {
Factory* factory = isolate->factory();
ObjectDescriptor static_desc;
ObjectDescriptor instance_desc;
for (int i = 0; i < expr->properties()->length(); i++) {
ClassLiteral::Property* property = expr->properties()->at(i);
ObjectDescriptor& desc =
property->is_static() ? static_desc : instance_desc;
if (property->is_computed_name()) {
desc.IncComputedCount();
} else {
if (property->key()->AsLiteral()->IsPropertyName()) {
desc.IncPropertiesCount();
} else {
desc.IncElementsCount();
}
}
}
//
// Initialize class object template.
//
static_desc.CreateTemplates(isolate, kMinimumClassPropertiesCount);
Handle<DescriptorArray> class_function_descriptors(
isolate->native_context()->class_function_map()->instance_descriptors(),
isolate);
STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0);
{
// Add length_accessor.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(factory->length_string(),
factory->function_length_accessor(), attribs);
}
{
// Add prototype_accessor.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
static_desc.AddConstant(factory->prototype_string(),
factory->function_prototype_accessor(), attribs);
}
if (FunctionLiteral::NeedsHomeObject(expr->constructor())) {
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
Handle<Object> value(
Smi::FromInt(ClassBoilerplate::kPrototypeArgumentIndex), isolate);
static_desc.AddConstant(factory->home_object_symbol(), value, attribs);
}
{
Handle<Smi> start_position(Smi::FromInt(expr->start_position()), isolate);
Handle<Smi> end_position(Smi::FromInt(expr->end_position()), isolate);
Handle<Tuple2> class_positions =
factory->NewTuple2(start_position, end_position, NOT_TENURED);
static_desc.AddConstant(factory->class_positions_symbol(), class_positions,
DONT_ENUM);
}
//
// Initialize prototype object template.
//
instance_desc.CreateTemplates(isolate, kMinimumPrototypePropertiesCount);
{
Handle<Object> value(
Smi::FromInt(ClassBoilerplate::kConstructorArgumentIndex), isolate);
instance_desc.AddConstant(factory->constructor_string(), value, DONT_ENUM);
}
//
// Fill in class boilerplate.
//
int dynamic_argument_index = ClassBoilerplate::kFirstDynamicArgumentIndex;
for (int i = 0; i < expr->properties()->length(); i++) {
ClassLiteral::Property* property = expr->properties()->at(i);
ClassBoilerplate::ValueKind value_kind;
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:
if (property->is_computed_name()) {
++dynamic_argument_index;
}
continue;
}
ObjectDescriptor& desc =
property->is_static() ? static_desc : instance_desc;
if (property->is_computed_name()) {
int computed_name_index = dynamic_argument_index;
dynamic_argument_index += 2; // Computed name and value indices.
desc.AddComputed(value_kind, computed_name_index);
continue;
}
int value_index = 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(name->IsInternalizedString());
desc.AddNamedProperty(isolate, name, value_kind, value_index);
}
}
// Add name accessor to the class object if necessary.
bool install_class_name_accessor = false;
if (!expr->has_name_static_property() &&
expr->constructor()->has_shared_name()) {
if (static_desc.has_computed_properties()) {
// Install class name accessor if necessary during class literal
// instantiation.
install_class_name_accessor = true;
} else {
// Set class name accessor if the "name" method was not added yet.
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
static_desc.AddConstant(factory->name_string(),
factory->function_name_accessor(), attribs);
}
}
static_desc.Finalize(isolate);
instance_desc.Finalize(isolate);
Handle<ClassBoilerplate> class_boilerplate =
Handle<ClassBoilerplate>::cast(factory->NewFixedArray(kBoileplateLength));
class_boilerplate->set_flags(0);
class_boilerplate->set_install_class_name_accessor(
install_class_name_accessor);
class_boilerplate->set_arguments_count(dynamic_argument_index);
class_boilerplate->set_static_properties_template(
*static_desc.properties_template());
class_boilerplate->set_static_elements_template(
*static_desc.elements_template());
class_boilerplate->set_static_computed_properties(
*static_desc.computed_properties());
class_boilerplate->set_instance_properties_template(
*instance_desc.properties_template());
class_boilerplate->set_instance_elements_template(
*instance_desc.elements_template());
class_boilerplate->set_instance_computed_properties(
*instance_desc.computed_properties());
return class_boilerplate;
}
} // namespace internal
} // namespace v8

View File

@ -13,8 +13,6 @@
namespace v8 {
namespace internal {
class ClassLiteral;
// BoilerplateDescription is a list of properties consisting of name value
// pairs. In addition to the properties, it provides the projected number
// of properties in the backing store. This number includes properties with
@ -58,79 +56,6 @@ class ConstantElementsPair : public Tuple2 {
DISALLOW_IMPLICIT_CONSTRUCTORS(ConstantElementsPair);
};
class ClassBoilerplate : public FixedArray {
public:
enum ValueKind { kData, kGetter, kSetter };
struct Flags {
#define FLAGS_BIT_FIELDS(V, _) \
V(InstallClassNameAccessorBit, bool, 1, _) \
V(ArgumentsCountBits, int, 30, _)
DEFINE_BIT_FIELDS(FLAGS_BIT_FIELDS)
#undef FLAGS_BIT_FIELDS
};
struct ComputedEntryFlags {
#define COMPUTED_ENTRY_BIT_FIELDS(V, _) \
V(ValueKindBits, ValueKind, 2, _) \
V(KeyIndexBits, unsigned, 29, _)
DEFINE_BIT_FIELDS(COMPUTED_ENTRY_BIT_FIELDS)
#undef COMPUTED_ENTRY_BIT_FIELDS
};
enum DefineClassArgumentsIndices {
kConstructorArgumentIndex = 1,
kPrototypeArgumentIndex = 2,
// The index of a first dynamic argument passed to Runtime::kDefineClass
// function. The dynamic arguments are consist of method closures and
// computed property names.
kFirstDynamicArgumentIndex = 3,
};
static const int kMinimumClassPropertiesCount = 6;
static const int kMinimumPrototypePropertiesCount = 1;
DECL_CAST(ClassBoilerplate)
DECL_BOOLEAN_ACCESSORS(install_class_name_accessor)
DECL_INT_ACCESSORS(arguments_count)
DECL_ACCESSORS(static_properties_template, Object)
DECL_ACCESSORS(static_elements_template, Object)
DECL_ACCESSORS(static_computed_properties, FixedArray)
DECL_ACCESSORS(instance_properties_template, Object)
DECL_ACCESSORS(instance_elements_template, Object)
DECL_ACCESSORS(instance_computed_properties, FixedArray)
static void AddToPropertiesTemplate(Isolate* isolate,
Handle<NameDictionary> dictionary,
Handle<Name> name, int key_index,
ValueKind value_kind, Object* value);
static void AddToElementsTemplate(Isolate* isolate,
Handle<NumberDictionary> dictionary,
uint32_t key, int key_index,
ValueKind value_kind, Object* value);
static Handle<ClassBoilerplate> BuildClassBoilerplate(Isolate* isolate,
ClassLiteral* expr);
enum {
kFlagsIndex,
kClassPropertiesTemplateIndex,
kClassElementsTemplateIndex,
kClassComputedPropertiesIndex,
kPrototypePropertiesTemplateIndex,
kPrototypeElementsTemplateIndex,
kPrototypeComputedPropertiesIndex,
kBoileplateLength // last element
};
static const int kFullComputedEntrySize = 2;
private:
DECL_INT_ACCESSORS(flags)
};
} // namespace internal
} // namespace v8

View File

@ -496,18 +496,16 @@ class SharedFunctionInfo : public HeapObject {
DEFINE_BIT_FIELDS(DEBUGGER_HINTS_BIT_FIELDS)
#undef DEBUGGER_HINTS_BIT_FIELDS
// Indicates that this function uses a super property (or an eval that may
// use a super property).
// This is needed to set up the [[HomeObject]] on the function instance.
inline bool needs_home_object() const;
private:
// [raw_name]: Function name string or kNoSharedNameSentinel.
DECL_ACCESSORS(raw_name, Object)
inline void set_kind(FunctionKind kind);
inline void set_needs_home_object(bool value);
// Indicates that this function uses a super property (or an eval that may
// use a super property).
// This is needed to set up the [[HomeObject]] on the function instance.
DECL_BOOLEAN_ACCESSORS(needs_home_object)
friend class Factory;
friend class V8HeapExplorer;

View File

@ -13,7 +13,6 @@
#include "src/elements.h"
#include "src/isolate-inl.h"
#include "src/messages.h"
#include "src/objects/literal-objects-inl.h"
#include "src/runtime/runtime.h"
namespace v8 {
@ -105,450 +104,10 @@ RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
return isolate->heap()->home_object_symbol();
}
namespace {
template <typename Dictionary>
Handle<Name> KeyToName(Isolate* isolate, Handle<Object> key);
template <>
Handle<Name> KeyToName<NameDictionary>(Isolate* isolate, Handle<Object> key) {
DCHECK(key->IsName());
return Handle<Name>::cast(key);
}
template <>
Handle<Name> KeyToName<NumberDictionary>(Isolate* isolate, Handle<Object> key) {
DCHECK(key->IsSmi());
return isolate->factory()->NumberToString(key);
}
// Gets |index|'th argument which may be a class constructor object, a class
// prototype object or a class method. In the latter case the following
// post-processing may be required:
// 1) set [[HomeObject]] slot to given |home_object| value if the method's
// shared function info indicates that the method requires that;
// 2) set method's name to a concatenation of |name_prefix| and |key| if the
// method's shared function info indicates that method does not have a
// shared name.
template <typename Dictionary>
MaybeHandle<Object> GetMethodAndSetHomeObjectAndName(
Isolate* isolate, Arguments& args, Smi* index, Handle<JSObject> home_object,
Handle<String> name_prefix, Handle<Object> key) {
int int_index = Smi::ToInt(index);
// Class constructor and prototype values do not require post processing.
if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
return args.at<Object>(int_index);
}
Handle<JSFunction> method = args.at<JSFunction>(int_index);
if (method->shared()->needs_home_object()) {
const int kHomeObjectPropertyIndex = 2;
CHECK_EQ(
method->map()->instance_descriptors()->GetKey(kHomeObjectPropertyIndex),
isolate->heap()->home_object_symbol());
FieldIndex field_index =
FieldIndex::ForDescriptor(method->map(), kHomeObjectPropertyIndex);
method->RawFastPropertyAtPut(field_index, *home_object);
}
if (!method->shared()->has_shared_name()) {
// TODO(ishell): method does not have a shared name at this point only if
// the key is a computed property name. However, the bytecode generator
// explicitly generates ToName bytecodes to ensure that the computed
// property name is properly converted to Name. So, we can actually be smart
// here and avoid converting Smi keys back to Name.
Handle<Name> name = KeyToName<Dictionary>(isolate, key);
if (!JSFunction::SetName(method, name, name_prefix)) {
return MaybeHandle<Object>();
}
}
return method;
}
// Gets |index|'th argument which may be a class constructor object, a class
// prototype object or a class method. In the latter case the following
// post-processing may be required:
// 1) set [[HomeObject]] slot to given |home_object| value if the method's
// shared function info indicates that the method requires that;
// This is a simplified version of GetMethodWithSharedNameAndSetHomeObject()
// function above that is used when it's guaranteed that the method has
// shared name.
Object* GetMethodWithSharedNameAndSetHomeObject(Isolate* isolate,
Arguments& args, Object* index,
Object* home_object) {
DisallowHeapAllocation no_gc;
int int_index = Smi::ToInt(index);
// Class constructor and prototype values do not require post processing.
if (int_index < ClassBoilerplate::kFirstDynamicArgumentIndex) {
return args[int_index];
}
Handle<JSFunction> method = args.at<JSFunction>(int_index);
if (method->shared()->needs_home_object()) {
const int kHomeObjectPropertyIndex = 2;
CHECK_EQ(
method->map()->instance_descriptors()->GetKey(kHomeObjectPropertyIndex),
isolate->heap()->home_object_symbol());
FieldIndex field_index =
FieldIndex::ForDescriptor(method->map(), kHomeObjectPropertyIndex);
method->RawFastPropertyAtPut(field_index, home_object);
}
DCHECK(method->shared()->has_shared_name());
return *method;
}
template <typename Dictionary>
Handle<Dictionary> ShallowCopyDictionaryTemplate(
Isolate* isolate, Handle<Dictionary> dictionary_template) {
Handle<Map> dictionary_map(dictionary_template->map(), isolate);
Handle<Dictionary> dictionary =
Handle<Dictionary>::cast(isolate->factory()->CopyFixedArrayWithMap(
dictionary_template, dictionary_map));
// Clone all AccessorPairs in the dictionary.
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object* value = dictionary->ValueAt(i);
if (value->IsAccessorPair()) {
Handle<AccessorPair> pair(AccessorPair::cast(value), isolate);
pair = AccessorPair::Copy(pair);
dictionary->ValueAtPut(i, *pair);
}
}
return dictionary;
}
template <typename Dictionary>
bool SubstituteValues(Isolate* isolate, Handle<Dictionary> dictionary,
Handle<JSObject> receiver, Arguments& args,
bool* install_name_accessor = nullptr) {
Handle<Name> name_string = isolate->factory()->name_string();
// Replace all indices with proper methods.
int capacity = dictionary->Capacity();
for (int i = 0; i < capacity; i++) {
Object* maybe_key = dictionary->KeyAt(i);
if (!Dictionary::IsKey(isolate, maybe_key)) continue;
if (install_name_accessor && *install_name_accessor &&
(maybe_key == *name_string)) {
*install_name_accessor = false;
}
Handle<Object> key(maybe_key, isolate);
Handle<Object> value(dictionary->ValueAt(i), isolate);
if (value->IsAccessorPair()) {
Handle<AccessorPair> pair = Handle<AccessorPair>::cast(value);
Object* tmp = pair->getter();
if (tmp->IsSmi()) {
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetHomeObjectAndName<Dictionary>(
isolate, args, Smi::cast(tmp), receiver,
isolate->factory()->get_string(), key),
false);
pair->set_getter(*result);
}
tmp = pair->setter();
if (tmp->IsSmi()) {
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetHomeObjectAndName<Dictionary>(
isolate, args, Smi::cast(tmp), receiver,
isolate->factory()->set_string(), key),
false);
pair->set_setter(*result);
}
} else if (value->IsSmi()) {
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION_VALUE(
isolate, result,
GetMethodAndSetHomeObjectAndName<Dictionary>(
isolate, args, Smi::cast(*value), receiver,
isolate->factory()->empty_string(), key),
false);
dictionary->ValueAtPut(i, *result);
}
}
return true;
}
bool AddDescriptorsByTemplate(
Isolate* isolate, Handle<Map> map,
Handle<DescriptorArray> descriptors_template,
Handle<NumberDictionary> elements_dictionary_template,
Handle<JSObject> receiver, Arguments& args) {
int nof_descriptors = descriptors_template->number_of_descriptors();
Handle<DescriptorArray> descriptors =
DescriptorArray::Allocate(isolate, nof_descriptors, 0);
Handle<NumberDictionary> elements_dictionary =
*elements_dictionary_template ==
isolate->heap()->empty_slow_element_dictionary()
? elements_dictionary_template
: ShallowCopyDictionaryTemplate(isolate,
elements_dictionary_template);
// Read values from |descriptors_template| and store possibly post-processed
// values into "instantiated" |descriptors| array.
for (int i = 0; i < nof_descriptors; i++) {
Object* value = descriptors_template->GetValue(i);
if (value->IsAccessorPair()) {
Handle<AccessorPair> pair =
AccessorPair::Copy(handle(AccessorPair::cast(value), isolate));
value = *pair;
}
DisallowHeapAllocation no_gc;
Name* name = descriptors_template->GetKey(i);
DCHECK(name->IsUniqueName());
PropertyDetails details = descriptors_template->GetDetails(i);
if (details.location() == kDescriptor) {
if (details.kind() == kData) {
if (value->IsSmi()) {
value = GetMethodWithSharedNameAndSetHomeObject(isolate, args, value,
*receiver);
}
} else {
DCHECK_EQ(kAccessor, details.kind());
if (value->IsAccessorPair()) {
AccessorPair* pair = AccessorPair::cast(value);
Object* tmp = pair->getter();
if (tmp->IsSmi()) {
pair->set_getter(GetMethodWithSharedNameAndSetHomeObject(
isolate, args, tmp, *receiver));
}
tmp = pair->setter();
if (tmp->IsSmi()) {
pair->set_setter(GetMethodWithSharedNameAndSetHomeObject(
isolate, args, tmp, *receiver));
}
}
}
} else {
DCHECK_EQ(kField, details.location());
DCHECK(!details.representation().IsDouble());
}
descriptors->Set(i, name, value, details);
}
map->InitializeDescriptors(*descriptors,
LayoutDescriptor::FastPointerLayout());
// Commit the changes.
receiver->set_map(*map);
if (elements_dictionary->NumberOfElements() > 0) {
if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
receiver, args)) {
return false;
}
receiver->map()->set_elements_kind(DICTIONARY_ELEMENTS);
receiver->set_elements(*elements_dictionary);
}
return true;
}
bool AddDescriptorsByTemplate(
Isolate* isolate, Handle<Map> map,
Handle<NameDictionary> properties_dictionary_template,
Handle<NumberDictionary> elements_dictionary_template,
Handle<FixedArray> computed_properties, Handle<JSObject> receiver,
bool install_name_accessor, Arguments& args) {
int computed_properties_length = computed_properties->length();
// Shallow-copy properties template.
Handle<NameDictionary> properties_dictionary =
ShallowCopyDictionaryTemplate(isolate, properties_dictionary_template);
Handle<NumberDictionary> elements_dictionary =
ShallowCopyDictionaryTemplate(isolate, elements_dictionary_template);
typedef ClassBoilerplate::ValueKind ValueKind;
typedef ClassBoilerplate::ComputedEntryFlags ComputedEntryFlags;
// Merge computed properties with properties and elements dictionary
// templates.
int i = 0;
while (i < computed_properties_length) {
int flags = Smi::ToInt(computed_properties->get(i++));
ValueKind value_kind = ComputedEntryFlags::ValueKindBits::decode(flags);
int key_index = ComputedEntryFlags::KeyIndexBits::decode(flags);
Object* value = Smi::FromInt(key_index + 1); // Value follows name.
Handle<Object> key = args.at<Object>(key_index);
DCHECK(key->IsName());
uint32_t element;
Handle<Name> name = Handle<Name>::cast(key);
if (name->AsArrayIndex(&element)) {
ClassBoilerplate::AddToElementsTemplate(
isolate, elements_dictionary, element, key_index, value_kind, value);
} else {
name = isolate->factory()->InternalizeName(name);
ClassBoilerplate::AddToPropertiesTemplate(
isolate, properties_dictionary, name, key_index, value_kind, value);
}
}
// Replace all indices with proper methods.
if (!SubstituteValues<NameDictionary>(isolate, properties_dictionary,
receiver, args,
&install_name_accessor)) {
return false;
}
if (install_name_accessor) {
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
PropertyDetails details(kAccessor, attribs, PropertyCellType::kNoCell);
Handle<NameDictionary> dict = NameDictionary::Add(
properties_dictionary, isolate->factory()->name_string(),
isolate->factory()->function_name_accessor(), details);
CHECK_EQ(*dict, *properties_dictionary);
}
// Commit the changes.
receiver->set_map(*map);
receiver->set_raw_properties_or_hash(*properties_dictionary);
if (elements_dictionary->NumberOfElements() > 0) {
if (!SubstituteValues<NumberDictionary>(isolate, elements_dictionary,
receiver, args)) {
return false;
}
receiver->map()->set_elements_kind(DICTIONARY_ELEMENTS);
receiver->set_elements(*elements_dictionary);
}
return true;
}
Handle<JSObject> CreateClassPrototype(Isolate* isolate,
Handle<Object> prototype_parent,
Handle<JSFunction> constructor) {
Factory* factory = isolate->factory();
// Reserve in-object space for "constructor" property.
const int kInobjectFields = 0; // 1;
Handle<Map> map = factory->NewMap(
JS_OBJECT_TYPE, JSObject::kHeaderSize + kInobjectFields * kPointerSize);
map->set_is_prototype_map(true);
map->SetInObjectProperties(kInobjectFields);
Map::SetPrototype(map, prototype_parent);
map->SetConstructor(*constructor);
Map::SetShouldBeFastPrototypeMap(map, true, isolate);
Handle<JSObject> prototype = factory->NewJSObjectFromMap(map);
constructor->set_prototype_or_initial_map(*prototype);
return prototype;
}
bool InitClassPrototype(Isolate* isolate,
Handle<ClassBoilerplate> class_boilerplate,
Handle<JSObject> prototype,
Handle<JSFunction> constructor, Arguments& args) {
Handle<Map> map(prototype->map(), isolate);
Handle<FixedArray> computed_properties(
class_boilerplate->instance_computed_properties(), isolate);
Handle<NumberDictionary> elements_dictionary_template(
NumberDictionary::cast(class_boilerplate->instance_elements_template()),
isolate);
Handle<Object> properties_template(
class_boilerplate->instance_properties_template(), isolate);
if (properties_template->IsDictionary()) {
Handle<NameDictionary> properties_dictionary_template =
Handle<NameDictionary>::cast(properties_template);
map->set_dictionary_map(true);
map->set_migration_target(false);
map->set_may_have_interesting_symbols(true);
// map->set_construction_counter(Map::kNoSlackTracking);
prototype->set_raw_properties_or_hash(
*isolate->factory()->empty_property_dictionary());
// We care about name property only for class constructor.
const bool install_name_accessor = false;
return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, prototype,
install_name_accessor, args);
} else {
Handle<DescriptorArray> descriptors_template =
Handle<DescriptorArray>::cast(properties_template);
// The size of the prototype object is known at this point.
// So we can create it now and then add the rest instance methods to the
// map.
return AddDescriptorsByTemplate(isolate, map, descriptors_template,
elements_dictionary_template, prototype,
args);
}
}
bool InitClassConstructor(Isolate* isolate,
Handle<ClassBoilerplate> class_boilerplate,
Handle<Object> constructor_parent,
Handle<JSFunction> constructor, Arguments& args) {
Handle<Map> map(constructor->map(), isolate);
map = Map::CopyDropDescriptors(map);
DCHECK(map->is_prototype_map());
Map::SetShouldBeFastPrototypeMap(map, true, isolate);
if (!constructor_parent.is_null()) {
// Set map's prototype without triggering JSObject::OptimizeAsPrototype()
// for parent class.
// map->set_prototype(*constructor_parent);
Map::SetPrototype(map, constructor_parent);
}
Handle<NumberDictionary> elements_dictionary_template(
NumberDictionary::cast(class_boilerplate->static_elements_template()),
isolate);
Handle<FixedArray> computed_properties(
class_boilerplate->static_computed_properties(), isolate);
Handle<Object> properties_template(
class_boilerplate->static_properties_template(), isolate);
if (properties_template->IsDictionary()) {
Handle<NameDictionary> properties_dictionary_template =
Handle<NameDictionary>::cast(properties_template);
map->set_dictionary_map(true);
map->InitializeDescriptors(isolate->heap()->empty_descriptor_array(),
LayoutDescriptor::FastPointerLayout());
map->set_migration_target(false);
map->set_may_have_interesting_symbols(true);
map->set_construction_counter(Map::kNoSlackTracking);
bool install_name_accessor =
class_boilerplate->install_class_name_accessor() != 0;
return AddDescriptorsByTemplate(
isolate, map, properties_dictionary_template,
elements_dictionary_template, computed_properties, constructor,
install_name_accessor, args);
} else {
Handle<DescriptorArray> descriptors_template =
Handle<DescriptorArray>::cast(properties_template);
return AddDescriptorsByTemplate(isolate, map, descriptors_template,
elements_dictionary_template, constructor,
args);
}
}
MaybeHandle<Object> DefineClass(Isolate* isolate,
Handle<ClassBoilerplate> class_boilerplate,
Handle<Object> super_class,
Handle<JSFunction> constructor,
Arguments& args) {
static MaybeHandle<Object> DefineClass(Isolate* isolate,
Handle<Object> super_class,
Handle<JSFunction> constructor,
int start_position, int end_position) {
Handle<Object> prototype_parent;
Handle<Object> constructor_parent;
@ -573,10 +132,7 @@ MaybeHandle<Object> DefineClass(Isolate* isolate,
prototype_parent),
Object);
}
// Create new handle to avoid |constructor_parent| corruption because of
// |super_class| handle value overwriting via storing to
// args[ClassBoilerplate::kPrototypeArgumentIndex] below.
constructor_parent = handle(*super_class, isolate);
constructor_parent = super_class;
} else {
THROW_NEW_ERROR(isolate,
NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
@ -585,34 +141,97 @@ MaybeHandle<Object> DefineClass(Isolate* isolate,
}
}
Handle<JSObject> prototype =
CreateClassPrototype(isolate, prototype_parent, constructor);
DCHECK_EQ(*constructor, args[ClassBoilerplate::kConstructorArgumentIndex]);
args[ClassBoilerplate::kPrototypeArgumentIndex] = *prototype;
Handle<Map> map =
isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
map->set_is_prototype_map(true);
Map::SetPrototype(map, prototype_parent);
map->SetConstructor(*constructor);
Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
if (!InitClassConstructor(isolate, class_boilerplate, constructor_parent,
constructor, args) ||
!InitClassPrototype(isolate, class_boilerplate, prototype, constructor,
args)) {
DCHECK(isolate->has_pending_exception());
return MaybeHandle<Object>();
JSFunction::SetPrototype(constructor, prototype);
PropertyAttributes attribs =
static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
RETURN_ON_EXCEPTION(isolate,
JSObject::SetOwnPropertyIgnoreAttributes(
constructor, isolate->factory()->prototype_string(),
prototype, attribs),
Object);
if (!constructor_parent.is_null()) {
MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
false, kThrowOnError));
}
return constructor;
JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
constructor, DONT_ENUM);
// Install private properties that are used to construct the FunctionToString.
{
Handle<Smi> start(Smi::FromInt(start_position), isolate);
Handle<Smi> end(Smi::FromInt(end_position), isolate);
Handle<Tuple2> class_positions =
isolate->factory()->NewTuple2(start, end, NOT_TENURED);
RETURN_ON_EXCEPTION(
isolate,
Object::SetProperty(constructor,
isolate->factory()->class_positions_symbol(),
class_positions, LanguageMode::kStrict),
Object);
}
// Caller already has access to constructor, so return the prototype.
return prototype;
}
} // namespace
RUNTIME_FUNCTION(Runtime_DefineClass) {
HandleScope scope(isolate);
DCHECK_LE(ClassBoilerplate::kFirstDynamicArgumentIndex, args.length());
CONVERT_ARG_HANDLE_CHECKED(ClassBoilerplate, class_boilerplate, 0);
DCHECK_EQ(4, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 0);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 2);
DCHECK_EQ(class_boilerplate->arguments_count(), args.length());
CONVERT_SMI_ARG_CHECKED(start_position, 2);
CONVERT_SMI_ARG_CHECKED(end_position, 3);
RETURN_RESULT_OR_FAILURE(
isolate,
DefineClass(isolate, class_boilerplate, super_class, constructor, args));
isolate, DefineClass(isolate, super_class, constructor, start_position,
end_position));
}
namespace {
void InstallClassNameAccessor(Isolate* isolate, Handle<JSObject> object) {
Handle<String> name = isolate->factory()->name_string();
PropertyAttributes attrs =
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
// Cannot fail since this should only be called when creating an object
// literal.
CHECK(!JSObject::SetAccessor(
object, name, isolate->factory()->function_name_accessor(), attrs)
.is_null());
}
} // anonymous namespace
RUNTIME_FUNCTION(Runtime_InstallClassNameAccessor) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
InstallClassNameAccessor(isolate, object);
return *object;
}
RUNTIME_FUNCTION(Runtime_InstallClassNameAccessorWithCheck) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
// If a property named "name" is already defined, exit.
Handle<Name> key = isolate->factory()->name_string();
if (JSObject::HasRealNamedProperty(object, key).FromMaybe(false)) {
return *object;
}
// Define the "name" accessor.
InstallClassNameAccessor(isolate, object);
return *object;
}
namespace {

View File

@ -80,21 +80,23 @@ namespace internal {
F(BigIntToNumber, 1, 1) \
F(BigIntUnaryOp, 2, 1)
#define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowUnsupportedSuperError, 0, 1) \
F(ThrowConstructorNonCallableError, 1, 1) \
F(ThrowStaticPrototypeError, 0, 1) \
F(ThrowSuperAlreadyCalledError, 0, 1) \
F(ThrowSuperNotCalled, 0, 1) \
F(ThrowNotSuperConstructor, 2, 1) \
F(HomeObjectSymbol, 0, 1) \
F(DefineClass, -1 /* >= 3 */, 1) \
F(LoadFromSuper, 3, 1) \
F(LoadKeyedFromSuper, 3, 1) \
F(StoreToSuper_Strict, 4, 1) \
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \
#define FOR_EACH_INTRINSIC_CLASSES(F) \
F(ThrowUnsupportedSuperError, 0, 1) \
F(ThrowConstructorNonCallableError, 1, 1) \
F(ThrowStaticPrototypeError, 0, 1) \
F(ThrowSuperAlreadyCalledError, 0, 1) \
F(ThrowSuperNotCalled, 0, 1) \
F(ThrowNotSuperConstructor, 2, 1) \
F(HomeObjectSymbol, 0, 1) \
F(DefineClass, 4, 1) \
F(InstallClassNameAccessor, 1, 1) \
F(InstallClassNameAccessorWithCheck, 1, 1) \
F(LoadFromSuper, 3, 1) \
F(LoadKeyedFromSuper, 3, 1) \
F(StoreToSuper_Strict, 4, 1) \
F(StoreToSuper_Sloppy, 4, 1) \
F(StoreKeyedToSuper_Strict, 4, 1) \
F(StoreKeyedToSuper_Sloppy, 4, 1) \
F(GetSuperConstructor, 1, 1)
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \

View File

@ -1174,7 +1174,6 @@
'objects/js-regexp.h',
'objects/js-regexp-inl.h',
'objects/literal-objects.cc',
'objects/literal-objects-inl.h',
'objects/literal-objects.h',
'objects/map-inl.h',
'objects/map.h',

View File

@ -12,28 +12,40 @@ snippet: "
speak() { console.log(this.name + ' is speaking.'); }
}
"
frame size: 6
frame size: 8
parameter count: 1
bytecode array length: 31
bytecode array length: 67
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CreateClosure), U8(2), U8(1), U8(2),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(34),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(4),
B(Wide), B(LdaSmi), I16(148),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(5),
B(CreateClosure), U8(2), U8(1), U8(2),
B(Star), R(6),
B(LdaSmi), I8(2),
B(Star), R(7),
B(Ldar), R(6),
B(StaDataPropertyInLiteral), R(3), R(5), U8(1), U8(2),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
B(LdaUndefined),
/* 149 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["speak"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
@ -46,28 +58,40 @@ snippet: "
speak() { console.log(this.name + ' is speaking.'); }
}
"
frame size: 6
frame size: 8
parameter count: 1
bytecode array length: 31
bytecode array length: 67
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CreateClosure), U8(2), U8(1), U8(2),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(34),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(4),
B(Wide), B(LdaSmi), I16(148),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(LdaConstant), U8(1),
B(Star), R(5),
B(CreateClosure), U8(2), U8(1), U8(2),
B(Star), R(6),
B(LdaSmi), I8(2),
B(Star), R(7),
B(Ldar), R(6),
B(StaDataPropertyInLiteral), R(3), R(5), U8(1), U8(2),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
B(LdaUndefined),
/* 149 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["speak"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
@ -82,9 +106,9 @@ snippet: "
static [n1]() { return n1; }
}
"
frame size: 10
frame size: 9
parameter count: 1
bytecode array length: 68
bytecode array length: 106
bytecodes: [
B(CreateFunctionContext), U8(2),
B(PushContext), R(2),
@ -93,25 +117,36 @@ bytecodes: [
/* 43 E> */ B(StaCurrentContextSlot), U8(4),
/* 57 S> */ B(LdaConstant), U8(1),
/* 57 E> */ B(StaCurrentContextSlot), U8(5),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(3), U8(0), U8(2),
B(Star), R(4),
B(LdaConstant), U8(2),
B(CreateClosure), U8(2), U8(0), U8(2),
B(Star), R(3),
B(LdaTheHole),
B(Star), R(4),
B(LdaSmi), I8(62),
B(Star), R(6),
B(Wide), B(LdaSmi), I16(128),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(LdaImmutableCurrentContextSlot), U8(4),
/* 75 E> */ B(ToName), R(6),
B(CreateClosure), U8(4), U8(1), U8(2),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(7),
B(LdaSmi), I8(2),
B(Star), R(8),
B(Ldar), R(7),
B(StaDataPropertyInLiteral), R(4), R(6), U8(3), U8(2),
B(LdaImmutableCurrentContextSlot), U8(5),
/* 106 E> */ B(ToName), R(8),
B(LdaConstant), U8(5),
B(TestEqualStrictNoFeedback), R(8),
/* 106 E> */ B(ToName), R(6),
B(LdaConstant), U8(4),
B(TestEqualStrictNoFeedback), R(6),
B(Mov), R(3), R(5),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), R(0), U8(0),
B(CreateClosure), U8(6), U8(2), U8(2),
B(Star), R(9),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(7),
B(CreateClosure), U8(5), U8(4), U8(2),
B(StaDataPropertyInLiteral), R(5), R(6), U8(3), U8(5),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessorWithCheck), R(3), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
B(Star), R(0),
B(Star), R(1),
B(LdaUndefined),
@ -120,7 +155,6 @@ bytecodes: [
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["a"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["b"],
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["prototype"],
@ -135,29 +169,34 @@ snippet: "
class C { constructor() { count++; }}
return new C();
"
frame size: 6
frame size: 8
parameter count: 1
bytecode array length: 36
bytecode array length: 55
bytecodes: [
B(CreateFunctionContext), U8(1),
B(PushContext), R(2),
/* 30 E> */ B(StackCheck),
/* 46 S> */ B(LdaZero),
/* 46 E> */ B(StaCurrentContextSlot), U8(4),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(4),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(LdaTheHole),
B(Star), R(4),
B(LdaSmi), I8(49),
B(Star), R(6),
B(LdaSmi), I8(86),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
B(Star), R(0),
B(Star), R(1),
/* 94 S> */ B(Construct), R(1), R(0), U8(0), U8(1),
/* 102 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [
@ -168,37 +207,52 @@ snippet: "
(class {})
class E { static name () {}}
"
frame size: 6
frame size: 8
parameter count: 1
bytecode array length: 49
bytecode array length: 92
bytecodes: [
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
/* 34 S> */ B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(3),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(3), U8(1), U8(2),
B(Star), R(3),
B(LdaSmi), I8(35),
B(Star), R(5),
B(LdaSmi), I8(43),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(CreateClosure), U8(1), U8(1), U8(2),
B(Star), R(2),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(45),
B(Star), R(5),
B(LdaSmi), I8(73),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(LdaConstant), U8(2),
B(Star), R(2),
B(CreateClosure), U8(4), U8(2), U8(2),
B(Star), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(4),
B(CreateClosure), U8(3), U8(2), U8(2),
B(Star), R(6),
B(LdaSmi), I8(2),
B(Star), R(7),
B(Ldar), R(6),
B(StaDataPropertyInLiteral), R(4), R(5), U8(1), U8(3),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
B(LdaUndefined),
/* 74 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["name"],
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [

View File

@ -505,9 +505,9 @@ handlers: [
snippet: "
export default (class {});
"
frame size: 6
frame size: 8
parameter count: 2
bytecode array length: 121
bytecode array length: 140
bytecodes: [
B(Ldar), R(1),
B(JumpIfUndefined), U8(18),
@ -548,13 +548,19 @@ bytecodes: [
/* 26 S> */ B(Return),
B(Ldar), R(3),
B(StaCurrentContextSlot), U8(5),
B(LdaTheHole),
B(Star), R(5),
B(CreateClosure), U8(5), U8(0), U8(0),
B(Star), R(4),
B(LdaConstant), U8(4),
B(CreateClosure), U8(4), U8(0), U8(0),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(3),
B(LdaTheHole),
B(Star), R(4),
B(LdaSmi), I8(16),
B(Star), R(6),
B(LdaSmi), I8(24),
B(Star), R(7),
B(Mov), R(3), R(5),
B(CallRuntime), U16(Runtime::kDefineClass), R(4), U8(4),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(3), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(3), U8(1),
B(StaModuleVariable), I8(1), U8(0),
B(LdaCurrentContextSlot), U8(5),
/* 26 S> */ B(Return),
@ -564,7 +570,6 @@ constant pool: [
FIXED_ARRAY_TYPE,
Smi [10],
Smi [7],
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
]
handlers: [

View File

@ -10,21 +10,27 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(...[1, 2, 3]);
"
frame size: 5
frame size: 7
parameter count: 1
bytecode array length: 38
bytecode array length: 57
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(3),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(34),
B(Star), R(5),
B(LdaSmi), I8(88),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
/* 89 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(3),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(1), R(3), U8(1), U8(2),
@ -32,7 +38,6 @@ bytecodes: [
/* 110 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
TUPLE2_TYPE,
]
@ -44,23 +49,29 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(0, ...[1, 2, 3]);
"
frame size: 5
frame size: 7
parameter count: 1
bytecode array length: 41
bytecode array length: 60
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(3),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(34),
B(Star), R(5),
B(LdaSmi), I8(88),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
/* 89 S> */ B(LdaZero),
B(Star), R(3),
B(CreateArrayLiteral), U8(2), U8(1), U8(37),
B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(4),
B(Ldar), R(1),
/* 89 E> */ B(ConstructWithSpread), R(1), R(3), U8(2), U8(2),
@ -68,7 +79,6 @@ bytecodes: [
/* 113 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
TUPLE2_TYPE,
]
@ -80,27 +90,33 @@ snippet: "
class A { constructor(...args) { this.args = args; } }
new A(0, ...[1, 2, 3], 4);
"
frame size: 6
frame size: 7
parameter count: 1
bytecode array length: 62
bytecode array length: 81
bytecodes: [
/* 30 E> */ B(StackCheck),
B(LdaTheHole),
B(Star), R(4),
B(CreateClosure), U8(1), U8(0), U8(2),
B(Star), R(3),
B(LdaConstant), U8(0),
B(CreateClosure), U8(0), U8(0), U8(2),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kDefineClass), R(2), U8(3),
B(LdaTheHole),
B(Star), R(3),
B(LdaSmi), I8(34),
B(Star), R(5),
B(LdaSmi), I8(88),
B(Star), R(6),
B(Mov), R(2), R(4),
B(CallRuntime), U16(Runtime::kDefineClass), R(3), U8(4),
B(Star), R(3),
B(CallRuntime), U16(Runtime::kInstallClassNameAccessor), R(2), U8(1),
B(CallRuntime), U16(Runtime::kToFastProperties), R(2), U8(1),
B(Star), R(0),
B(Star), R(1),
/* 89 S> */ B(CreateArrayLiteral), U8(2), U8(1), U8(37),
/* 89 S> */ B(CreateArrayLiteral), U8(1), U8(1), U8(37),
B(Star), R(3),
B(CreateArrayLiteral), U8(3), U8(2), U8(37),
B(CreateArrayLiteral), U8(2), U8(2), U8(37),
B(Star), R(4),
B(CallJSRuntime), U8(%spread_iterable), R(4), U8(1),
B(Star), R(4),
B(CreateArrayLiteral), U8(4), U8(3), U8(37),
B(CreateArrayLiteral), U8(3), U8(3), U8(37),
B(Star), R(5),
B(CallJSRuntime), U8(%spread_arguments), R(3), U8(3),
B(Star), R(3),
@ -110,7 +126,6 @@ bytecodes: [
/* 116 S> */ B(Return),
]
constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
TUPLE2_TYPE,
TUPLE2_TYPE,

View File

@ -199,58 +199,58 @@ KNOWN_MAPS = {
0x02cf1: (171, "BlockContextMap"),
0x02d41: (171, "CatchContextMap"),
0x02d91: (171, "WithContextMap"),
0x02de1: (171, "DescriptorArrayMap"),
0x02e31: (148, "FixedDoubleArrayMap"),
0x02e81: (134, "MutableHeapNumberMap"),
0x02ed1: (172, "OrderedHashTableMap"),
0x02f21: (172, "NameDictionaryMap"),
0x02f71: (172, "GlobalDictionaryMap"),
0x02fc1: (172, "NumberDictionaryMap"),
0x03011: (171, "SloppyArgumentsElementsMap"),
0x03061: (180, "SmallOrderedHashMapMap"),
0x030b1: (181, "SmallOrderedHashSetMap"),
0x03101: (189, "JSMessageObjectMap"),
0x03151: (137, "BytecodeArrayMap"),
0x031a1: (171, "ModuleInfoMap"),
0x031f1: (177, "NoClosuresCellMap"),
0x03241: (177, "OneClosureCellMap"),
0x03291: (177, "ManyClosuresCellMap"),
0x032e1: (175, "PropertyArrayMap"),
0x03331: (130, "BigIntMap"),
0x03381: (64, "StringMap"),
0x033d1: (73, "ConsOneByteStringMap"),
0x03421: (65, "ConsStringMap"),
0x03471: (77, "ThinOneByteStringMap"),
0x034c1: (69, "ThinStringMap"),
0x03511: (67, "SlicedStringMap"),
0x03561: (75, "SlicedOneByteStringMap"),
0x035b1: (66, "ExternalStringMap"),
0x03601: (82, "ExternalStringWithOneByteDataMap"),
0x03651: (74, "ExternalOneByteStringMap"),
0x036a1: (98, "ShortExternalStringMap"),
0x036f1: (114, "ShortExternalStringWithOneByteDataMap"),
0x03741: (0, "InternalizedStringMap"),
0x03791: (2, "ExternalInternalizedStringMap"),
0x037e1: (18, "ExternalInternalizedStringWithOneByteDataMap"),
0x03831: (10, "ExternalOneByteInternalizedStringMap"),
0x03881: (34, "ShortExternalInternalizedStringMap"),
0x038d1: (50, "ShortExternalInternalizedStringWithOneByteDataMap"),
0x03921: (42, "ShortExternalOneByteInternalizedStringMap"),
0x03971: (106, "ShortExternalOneByteStringMap"),
0x039c1: (140, "FixedUint8ArrayMap"),
0x03a11: (139, "FixedInt8ArrayMap"),
0x03a61: (142, "FixedUint16ArrayMap"),
0x03ab1: (141, "FixedInt16ArrayMap"),
0x03b01: (144, "FixedUint32ArrayMap"),
0x03b51: (143, "FixedInt32ArrayMap"),
0x03ba1: (145, "FixedFloat32ArrayMap"),
0x03bf1: (146, "FixedFloat64ArrayMap"),
0x03c41: (147, "FixedUint8ClampedArrayMap"),
0x03c91: (158, "ScriptMap"),
0x03ce1: (182, "CodeDataContainerMap"),
0x03d31: (173, "FeedbackVectorMap"),
0x03d81: (171, "DebugEvaluateContextMap"),
0x03dd1: (171, "ScriptContextTableMap"),
0x02de1: (148, "FixedDoubleArrayMap"),
0x02e31: (134, "MutableHeapNumberMap"),
0x02e81: (172, "OrderedHashTableMap"),
0x02ed1: (172, "NameDictionaryMap"),
0x02f21: (172, "GlobalDictionaryMap"),
0x02f71: (172, "NumberDictionaryMap"),
0x02fc1: (171, "SloppyArgumentsElementsMap"),
0x03011: (180, "SmallOrderedHashMapMap"),
0x03061: (181, "SmallOrderedHashSetMap"),
0x030b1: (189, "JSMessageObjectMap"),
0x03101: (137, "BytecodeArrayMap"),
0x03151: (171, "ModuleInfoMap"),
0x031a1: (177, "NoClosuresCellMap"),
0x031f1: (177, "OneClosureCellMap"),
0x03241: (177, "ManyClosuresCellMap"),
0x03291: (175, "PropertyArrayMap"),
0x032e1: (130, "BigIntMap"),
0x03331: (64, "StringMap"),
0x03381: (73, "ConsOneByteStringMap"),
0x033d1: (65, "ConsStringMap"),
0x03421: (77, "ThinOneByteStringMap"),
0x03471: (69, "ThinStringMap"),
0x034c1: (67, "SlicedStringMap"),
0x03511: (75, "SlicedOneByteStringMap"),
0x03561: (66, "ExternalStringMap"),
0x035b1: (82, "ExternalStringWithOneByteDataMap"),
0x03601: (74, "ExternalOneByteStringMap"),
0x03651: (98, "ShortExternalStringMap"),
0x036a1: (114, "ShortExternalStringWithOneByteDataMap"),
0x036f1: (0, "InternalizedStringMap"),
0x03741: (2, "ExternalInternalizedStringMap"),
0x03791: (18, "ExternalInternalizedStringWithOneByteDataMap"),
0x037e1: (10, "ExternalOneByteInternalizedStringMap"),
0x03831: (34, "ShortExternalInternalizedStringMap"),
0x03881: (50, "ShortExternalInternalizedStringWithOneByteDataMap"),
0x038d1: (42, "ShortExternalOneByteInternalizedStringMap"),
0x03921: (106, "ShortExternalOneByteStringMap"),
0x03971: (140, "FixedUint8ArrayMap"),
0x039c1: (139, "FixedInt8ArrayMap"),
0x03a11: (142, "FixedUint16ArrayMap"),
0x03a61: (141, "FixedInt16ArrayMap"),
0x03ab1: (144, "FixedUint32ArrayMap"),
0x03b01: (143, "FixedInt32ArrayMap"),
0x03b51: (145, "FixedFloat32ArrayMap"),
0x03ba1: (146, "FixedFloat64ArrayMap"),
0x03bf1: (147, "FixedUint8ClampedArrayMap"),
0x03c41: (158, "ScriptMap"),
0x03c91: (182, "CodeDataContainerMap"),
0x03ce1: (173, "FeedbackVectorMap"),
0x03d31: (171, "DebugEvaluateContextMap"),
0x03d81: (171, "ScriptContextTableMap"),
0x03dd1: (171, "DescriptorArrayMap"),
0x03e21: (192, "ExternalMap"),
0x03e71: (106, "NativeSourceStringMap"),
0x03ec1: (165, "Tuple2Map"),