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:
parent
a3a67fe7a4
commit
e4b394a1f4
1
BUILD.gn
1
BUILD.gn
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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_;
|
||||
|
@ -191,7 +191,6 @@ enum class ObjectType {
|
||||
#undef ENUM_STRUCT_ELEMENT
|
||||
|
||||
class AccessCheckNeeded;
|
||||
class ClassBoilerplate;
|
||||
class CompilationCacheTable;
|
||||
class Constructor;
|
||||
class Filler;
|
||||
|
@ -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;
|
||||
|
@ -283,7 +283,6 @@ using v8::MemoryPressureLevel;
|
||||
V(CatchContextMap) \
|
||||
V(CellMap) \
|
||||
V(CodeMap) \
|
||||
V(DescriptorArrayMap) \
|
||||
V(EmptyByteArray) \
|
||||
V(EmptyDescriptorArray) \
|
||||
V(EmptyFixedArray) \
|
||||
|
@ -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();
|
||||
|
@ -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_;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) \
|
||||
|
@ -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,
|
||||
|
@ -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_
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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) \
|
||||
|
@ -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',
|
||||
|
@ -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: [
|
||||
|
@ -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: [
|
||||
|
@ -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,
|
||||
|
@ -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"),
|
||||
|
Loading…
Reference in New Issue
Block a user