Commit 65ffd616 authored by jameslahm's avatar jameslahm Committed by V8 LUCI CQ

[interpreter] create array literal boilerplates for spread calls

when BuildCreateArrayLiteral

In spread calls, create array literal boilerplates for
BuildCreateArrayLiteral rather than emit array literals
without any boilerplates

Bug: v8:11582
Change-Id: Ia0538bd043eab040c3059440e982c7f0037d1a3f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3507126Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79447}
parent 09090299
......@@ -373,7 +373,14 @@ void ObjectLiteral::CalculateEmitStore(Zone* zone) {
}
}
void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) {
int ObjectLiteralBoilerplateBuilder::ComputeFlags(bool disable_mementos) const {
int flags = LiteralBoilerplateBuilder::ComputeFlags(disable_mementos);
if (fast_elements()) flags |= ObjectLiteral::kFastElements;
if (has_null_prototype()) flags |= ObjectLiteral::kHasNullPrototype;
return flags;
}
void ObjectLiteralBoilerplateBuilder::InitFlagsForPendingNullPrototype(int i) {
// We still check for __proto__:null after computed property names.
for (; i < properties()->length(); i++) {
if (properties()->at(i)->IsNullPrototype()) {
......@@ -383,12 +390,19 @@ void ObjectLiteral::InitFlagsForPendingNullPrototype(int i) {
}
}
int ObjectLiteral::InitDepthAndFlags() {
if (is_initialized()) return depth();
int ObjectLiteralBoilerplateBuilder::EncodeLiteralType() {
int flags = AggregateLiteral::kNoFlags;
if (fast_elements()) flags |= ObjectLiteral::kFastElements;
if (has_null_prototype()) flags |= ObjectLiteral::kHasNullPrototype;
return flags;
}
void ObjectLiteralBoilerplateBuilder::InitDepthAndFlags() {
if (is_initialized()) return;
bool is_simple = true;
bool has_seen_prototype = false;
bool needs_initial_allocation_site = false;
int depth_acc = 1;
DepthKind depth_acc = kShallow;
uint32_t nof_properties = 0;
uint32_t elements = 0;
uint32_t max_element_index = 0;
......@@ -416,8 +430,8 @@ int ObjectLiteral::InitDepthAndFlags() {
MaterializedLiteral* literal = property->value()->AsMaterializedLiteral();
if (literal != nullptr) {
int subliteral_depth = literal->InitDepthAndFlags() + 1;
if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
LiteralBoilerplateBuilder::InitDepthAndFlags(literal);
depth_acc = kNotShallow;
needs_initial_allocation_site |= literal->NeedsInitialAllocationSite();
}
......@@ -448,11 +462,11 @@ int ObjectLiteral::InitDepthAndFlags() {
set_has_elements(elements > 0);
set_fast_elements((max_element_index <= 32) ||
((2 * elements) >= max_element_index));
return depth_acc;
}
template <typename IsolateT>
void ObjectLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
void ObjectLiteralBoilerplateBuilder::BuildBoilerplateDescription(
IsolateT* isolate) {
if (!boilerplate_description_.is_null()) return;
int index_keys = 0;
......@@ -487,7 +501,7 @@ void ObjectLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
MaterializedLiteral* m_literal = property->value()->AsMaterializedLiteral();
if (m_literal != nullptr) {
m_literal->BuildConstants(isolate);
BuildConstants(isolate, m_literal);
}
// Add CONSTANT and COMPUTED properties to boilerplate. Use the
......@@ -509,12 +523,14 @@ void ObjectLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
boilerplate_description_ = boilerplate_description;
}
template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void ObjectLiteral::
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void ObjectLiteralBoilerplateBuilder::
BuildBoilerplateDescription(Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void ObjectLiteral::
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void ObjectLiteralBoilerplateBuilder::
BuildBoilerplateDescription(LocalIsolate* isolate);
bool ObjectLiteral::IsFastCloningSupported() const {
bool ObjectLiteralBoilerplateBuilder::IsFastCloningSupported() const {
// The CreateShallowObjectLiteratal builtin doesn't copy elements, and object
// literals don't support copy-on-write (COW) elements for now.
// TODO(mvstanton): make object literals support COW elements.
......@@ -523,25 +539,53 @@ bool ObjectLiteral::IsFastCloningSupported() const {
ConstructorBuiltins::kMaximumClonedShallowObjectProperties;
}
int ArrayLiteral::InitDepthAndFlags() {
if (is_initialized()) return depth();
// static
template <typename IsolateT>
Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
Expression* expression, IsolateT* isolate) {
if (expression->IsLiteral()) {
return expression->AsLiteral()->BuildValue(isolate);
}
if (expression->IsCompileTimeValue()) {
if (expression->IsObjectLiteral()) {
ObjectLiteral* object_literal = expression->AsObjectLiteral();
DCHECK(object_literal->builder()->is_simple());
return object_literal->builder()->boilerplate_description();
} else {
DCHECK(expression->IsArrayLiteral());
ArrayLiteral* array_literal = expression->AsArrayLiteral();
DCHECK(array_literal->builder()->is_simple());
return array_literal->builder()->boilerplate_description();
}
}
return isolate->factory()->uninitialized_value();
}
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
Expression* expression, Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Object> LiteralBoilerplateBuilder::GetBoilerplateValue(
Expression* expression, LocalIsolate* isolate);
void ArrayLiteralBoilerplateBuilder::InitDepthAndFlags() {
if (is_initialized()) return;
int constants_length =
first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
first_spread_index_ >= 0 ? first_spread_index_ : values_->length();
// Fill in the literals.
bool is_simple = first_spread_index_ < 0;
bool is_holey = false;
ElementsKind kind = FIRST_FAST_ELEMENTS_KIND;
int depth_acc = 1;
DepthKind depth_acc = kShallow;
int array_index = 0;
for (; array_index < constants_length; array_index++) {
Expression* element = values()->at(array_index);
Expression* element = values_->at(array_index);
MaterializedLiteral* materialized_literal =
element->AsMaterializedLiteral();
if (materialized_literal != nullptr) {
int subliteral_depth = materialized_literal->InitDepthAndFlags() + 1;
if (subliteral_depth > depth_acc) depth_acc = subliteral_depth;
LiteralBoilerplateBuilder::InitDepthAndFlags(materialized_literal);
depth_acc = kNotShallow;
}
if (!element->IsCompileTimeValue()) {
......@@ -600,15 +644,15 @@ int ArrayLiteral::InitDepthAndFlags() {
// Array literals always need an initial allocation site to properly track
// elements transitions.
set_needs_initial_allocation_site(true);
return depth_acc;
}
template <typename IsolateT>
void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
void ArrayLiteralBoilerplateBuilder::BuildBoilerplateDescription(
IsolateT* isolate) {
if (!boilerplate_description_.is_null()) return;
int constants_length =
first_spread_index_ >= 0 ? first_spread_index_ : values()->length();
first_spread_index_ >= 0 ? first_spread_index_ : values_->length();
ElementsKind kind = boilerplate_descriptor_kind();
bool use_doubles = IsDoubleElementsKind(kind);
......@@ -624,7 +668,7 @@ void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
// Fill in the literals.
int array_index = 0;
for (; array_index < constants_length; array_index++) {
Expression* element = values()->at(array_index);
Expression* element = values_->at(array_index);
DCHECK(!element->IsSpread());
if (use_doubles) {
Literal* literal = element->AsLiteral();
......@@ -644,7 +688,7 @@ void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
} else {
MaterializedLiteral* m_literal = element->AsMaterializedLiteral();
if (m_literal != nullptr) {
m_literal->BuildConstants(isolate);
BuildConstants(isolate, m_literal);
}
// New handle scope here, needs to be after BuildContants().
......@@ -663,11 +707,9 @@ void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
boilerplate_value = Smi::zero();
}
DCHECK_EQ(
boilerplate_descriptor_kind(),
GetMoreGeneralElementsKind(boilerplate_descriptor_kind(),
boilerplate_value.OptimalElementsKind(
GetPtrComprCageBase(*elements))));
DCHECK_EQ(kind, GetMoreGeneralElementsKind(
kind, boilerplate_value.OptimalElementsKind(
GetPtrComprCageBase(*elements))));
FixedArray::cast(*elements).set(array_index, boilerplate_value);
}
......@@ -675,7 +717,7 @@ void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
// Simple and shallow arrays can be lazily copied, we transform the
// elements array to a copy-on-write array.
if (is_simple() && depth() == 1 && array_index > 0 &&
if (is_simple() && depth() == kShallow && array_index > 0 &&
IsSmiOrObjectElementsKind(kind)) {
elements->set_map_safe_transition(
ReadOnlyRoots(isolate).fixed_cow_array_map());
......@@ -685,87 +727,68 @@ void ArrayLiteral::BuildBoilerplateDescription(IsolateT* isolate) {
isolate->factory()->NewArrayBoilerplateDescription(kind, elements);
}
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void ArrayLiteral::BuildBoilerplateDescription(Isolate*
isolate);
V8_BASE_EXPORT) void ArrayLiteralBoilerplateBuilder::
BuildBoilerplateDescription(Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void ArrayLiteral::BuildBoilerplateDescription(LocalIsolate*
isolate);
V8_BASE_EXPORT) void ArrayLiteralBoilerplateBuilder::
BuildBoilerplateDescription(LocalIsolate*
bool ArrayLiteral::IsFastCloningSupported() const {
return depth() <= 1 &&
values_.length() <=
isolate);
bool ArrayLiteralBoilerplateBuilder::IsFastCloningSupported() const {
return depth() <= kShallow &&
values_->length() <=
ConstructorBuiltins::kMaximumClonedShallowArrayElements;
}
bool MaterializedLiteral::IsSimple() const {
if (IsArrayLiteral()) return AsArrayLiteral()->is_simple();
if (IsObjectLiteral()) return AsObjectLiteral()->is_simple();
if (IsArrayLiteral()) return AsArrayLiteral()->builder()->is_simple();
if (IsObjectLiteral()) return AsObjectLiteral()->builder()->is_simple();
DCHECK(IsRegExpLiteral());
return false;
}
template <typename IsolateT>
Handle<Object> MaterializedLiteral::GetBoilerplateValue(Expression* expression,
IsolateT* isolate) {
if (expression->IsLiteral()) {
return expression->AsLiteral()->BuildValue(isolate);
// static
void LiteralBoilerplateBuilder::InitDepthAndFlags(MaterializedLiteral* expr) {
if (expr->IsArrayLiteral()) {
return expr->AsArrayLiteral()->builder()->InitDepthAndFlags();
}
if (expression->IsCompileTimeValue()) {
if (expression->IsObjectLiteral()) {
ObjectLiteral* object_literal = expression->AsObjectLiteral();
DCHECK(object_literal->is_simple());
return object_literal->boilerplate_description();
} else {
DCHECK(expression->IsArrayLiteral());
ArrayLiteral* array_literal = expression->AsArrayLiteral();
DCHECK(array_literal->is_simple());
return array_literal->boilerplate_description();
}
if (expr->IsObjectLiteral()) {
return expr->AsObjectLiteral()->builder()->InitDepthAndFlags();
}
return isolate->factory()->uninitialized_value();
DCHECK(expr->IsRegExpLiteral());
}
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Object> MaterializedLiteral::GetBoilerplateValue(
Expression* expression, Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
Handle<Object> MaterializedLiteral::GetBoilerplateValue(
Expression* expression, LocalIsolate* isolate);
int MaterializedLiteral::InitDepthAndFlags() {
if (IsArrayLiteral()) return AsArrayLiteral()->InitDepthAndFlags();
if (IsObjectLiteral()) return AsObjectLiteral()->InitDepthAndFlags();
DCHECK(IsRegExpLiteral());
return 1;
}
bool MaterializedLiteral::NeedsInitialAllocationSite(
bool MaterializedLiteral::NeedsInitialAllocationSite() {
) {
if (IsArrayLiteral()) {
return AsArrayLiteral()->needs_initial_allocation_site();
return AsArrayLiteral()->builder()->needs_initial_allocation_site();
}
if (IsObjectLiteral()) {
return AsObjectLiteral()->needs_initial_allocation_site();
return AsObjectLiteral()->builder()->needs_initial_allocation_site();
}
DCHECK(IsRegExpLiteral());
return false;
}
template <typename IsolateT>
void MaterializedLiteral::BuildConstants(IsolateT* isolate) {
if (IsArrayLiteral()) {
AsArrayLiteral()->BuildBoilerplateDescription(isolate);
void LiteralBoilerplateBuilder::BuildConstants(IsolateT* isolate,
MaterializedLiteral* expr) {
if (expr->IsArrayLiteral()) {
expr->AsArrayLiteral()->builder()->BuildBoilerplateDescription(isolate);
return;
}
if (IsObjectLiteral()) {
AsObjectLiteral()->BuildBoilerplateDescription(isolate);
if (expr->IsObjectLiteral()) {
expr->AsObjectLiteral()->builder()->BuildBoilerplateDescription(isolate);
return;
}
DCHECK(IsRegExpLiteral());
DCHECK(expr->IsRegExpLiteral());
}
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void MaterializedLiteral::BuildConstants(Isolate* isolate);
template EXPORT_TEMPLATE_DEFINE(
V8_BASE_EXPORT) void MaterializedLiteral::BuildConstants(LocalIsolate*
isolate);
template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void LiteralBoilerplateBuilder::
BuildConstants(Isolate* isolate, MaterializedLiteral* expr);
template EXPORT_TEMPLATE_DEFINE(V8_BASE_EXPORT) void LiteralBoilerplateBuilder::
BuildConstants(LocalIsolate* isolate, MaterializedLiteral* expr);
template <typename IsolateT>
Handle<TemplateObjectDescription> GetTemplateObject::GetOrBuildDescription(
......
......@@ -1049,26 +1049,13 @@ class MaterializedLiteral : public Expression {
protected:
MaterializedLiteral(int pos, NodeType type) : Expression(pos, type) {}
friend class CompileTimeValue;
friend class ArrayLiteral;
friend class ObjectLiteral;
// Populate the depth field and any flags the literal has, returns the depth.
int InitDepthAndFlags();
bool NeedsInitialAllocationSite();
// Populate the constant properties/elements fixed array.
template <typename IsolateT>
void BuildConstants(IsolateT* isolate);
friend class CompileTimeValue;
// If the expression is a literal, return the literal value;
// if the expression is a materialized literal and is_simple
// then return an Array or Object Boilerplate Description
// Otherwise, return undefined literal as the placeholder
// in the object literal boilerplate.
template <typename IsolateT>
Handle<Object> GetBoilerplateValue(Expression* expression, IsolateT* isolate);
friend class LiteralBoilerplateBuilder;
friend class ArrayLiteralBoilerplateBuilder;
friend class ObjectLiteralBoilerplateBuilder;
};
// Node for capturing a regexp literal.
......@@ -1091,8 +1078,7 @@ class RegExpLiteral final : public MaterializedLiteral {
const AstRawString* const pattern_;
};
// Base class for Array and Object literals, providing common code for handling
// nested subliterals.
// Base class for Array and Object literals
class AggregateLiteral : public MaterializedLiteral {
public:
enum Flags {
......@@ -1103,22 +1089,47 @@ class AggregateLiteral : public MaterializedLiteral {
kIsShallowAndDisableMementos = kIsShallow | kDisableMementos,
};
bool is_initialized() const { return 0 < depth_; }
int depth() const {
protected:
AggregateLiteral(int pos, NodeType type) : MaterializedLiteral(pos, type) {}
};
// Base class for build literal boilerplate, providing common code for handling
// nested subliterals.
class LiteralBoilerplateBuilder {
public:
enum DepthKind { kUninitialized, kShallow, kNotShallow };
static constexpr int kDepthKindBits = 2;
STATIC_ASSERT((1 << kDepthKindBits) > kNotShallow);
bool is_initialized() const {
return kUninitialized != DepthField::decode(bit_field_);
}
DepthKind depth() const {
DCHECK(is_initialized());
return depth_;
return DepthField::decode(bit_field_);
}
bool is_shallow() const { return depth() == 1; }
// If the expression is a literal, return the literal value;
// if the expression is a materialized literal and is_simple
// then return an Array or Object Boilerplate Description
// Otherwise, return undefined literal as the placeholder
// in the object literal boilerplate.
template <typename IsolateT>
static Handle<Object> GetBoilerplateValue(Expression* expression,
IsolateT* isolate);
bool is_shallow() const { return depth() == kShallow; }
bool needs_initial_allocation_site() const {
return NeedsInitialAllocationSiteField::decode(bit_field_);
}
int ComputeFlags(bool disable_mementos = false) const {
int flags = kNoFlags;
if (is_shallow()) flags |= kIsShallow;
if (disable_mementos) flags |= kDisableMementos;
if (needs_initial_allocation_site()) flags |= kNeedsInitialAllocationSite;
int flags = AggregateLiteral::kNoFlags;
if (is_shallow()) flags |= AggregateLiteral::kIsShallow;
if (disable_mementos) flags |= AggregateLiteral::kDisableMementos;
if (needs_initial_allocation_site())
flags |= AggregateLiteral::kNeedsInitialAllocationSite;
return flags;
}
......@@ -1131,19 +1142,22 @@ class AggregateLiteral : public MaterializedLiteral {
}
private:
int depth_ : 31;
using NeedsInitialAllocationSiteField =
MaterializedLiteral::NextBitField<bool, 1>;
// we actually only care three conditions for depth
// - depth == kUninitialized, DCHECK(!is_initialized())
// - depth == kShallow, which means depth = 1
// - depth == kNotShallow, which means depth > 1
using DepthField = base::BitField<DepthKind, 0, kDepthKindBits>;
using NeedsInitialAllocationSiteField = DepthField::Next<bool, 1>;
using IsSimpleField = NeedsInitialAllocationSiteField::Next<bool, 1>;
using BoilerplateDescriptorKindField =
IsSimpleField::Next<ElementsKind, kFastElementsKindBits>;
protected:
friend class AstNodeFactory;
friend Zone;
AggregateLiteral(int pos, NodeType type)
: MaterializedLiteral(pos, type), depth_(0) {
bit_field_ |=
uint32_t bit_field_;
LiteralBoilerplateBuilder() {
bit_field_ =
DepthField::encode(kUninitialized) |
NeedsInitialAllocationSiteField::encode(false) |
IsSimpleField::encode(false) |
BoilerplateDescriptorKindField::encode(FIRST_FAST_ELEMENTS_KIND);
......@@ -1158,15 +1172,22 @@ class AggregateLiteral : public MaterializedLiteral {
bit_field_ = BoilerplateDescriptorKindField::update(bit_field_, kind);
}
void set_depth(int depth) {
void set_depth(DepthKind depth) {
DCHECK(!is_initialized());
depth_ = depth;
bit_field_ = DepthField::update(bit_field_, depth);
}
void set_needs_initial_allocation_site(bool required) {
bit_field_ = NeedsInitialAllocationSiteField::update(bit_field_, required);
}
// Populate the depth field and any flags the literal builder has
static void InitDepthAndFlags(MaterializedLiteral* expr);
// Populate the constant properties/elements fixed array.
template <typename IsolateT>
void BuildConstants(IsolateT* isolate, MaterializedLiteral* expr);
template <class T, int size>
using NextBitField = BoilerplateDescriptorKindField::Next<T, size>;
};
......@@ -1230,18 +1251,30 @@ class ObjectLiteralProperty final : public LiteralProperty {
bool emit_store_;
};
// An object literal has a boilerplate object that is used
// for minimizing the work when constructing it at runtime.
class ObjectLiteral final : public AggregateLiteral {
// class for build object boilerplate
class ObjectLiteralBoilerplateBuilder final : public LiteralBoilerplateBuilder {
public:
using Property = ObjectLiteralProperty;
ObjectLiteralBoilerplateBuilder(ZoneList<Property*>* properties,
uint32_t boilerplate_properties,
bool has_rest_property)
: properties_(properties),
boilerplate_properties_(boilerplate_properties) {
bit_field_ |= HasElementsField::encode(false) |
HasRestPropertyField::encode(has_rest_property) |
FastElementsField::encode(false) |
HasNullPrototypeField::encode(false);
}
Handle<ObjectBoilerplateDescription> boilerplate_description() const {
DCHECK(!boilerplate_description_.is_null());
return boilerplate_description_;
}
// Determines whether the {CreateShallowArrayLiteral} builtin can be used.
bool IsFastCloningSupported() const;
int properties_count() const { return boilerplate_properties_; }
const ZonePtrList<Property>* properties() const { return &properties_; }
const ZonePtrList<Property>* properties() const { return properties_; }
bool has_elements() const { return HasElementsField::decode(bit_field_); }
bool has_rest_property() const {
return HasRestPropertyField::decode(bit_field_);
......@@ -1251,18 +1284,9 @@ class ObjectLiteral final : public AggregateLiteral {
return HasNullPrototypeField::decode(bit_field_);
}
bool is_empty() const {
DCHECK(is_initialized());
return !has_elements() && properties_count() == 0 &&
properties()->length() == 0;
}
bool IsEmptyObjectLiteral() const {
return is_empty() && !has_null_prototype();
}
// Populate the depth field and flags, returns the depth.
int InitDepthAndFlags();
// Populate the boilerplate description.
template <typename IsolateT>
void BuildBoilerplateDescription(IsolateT* isolate);
// Get the boilerplate description, populating it if necessary.
template <typename IsolateT>
......@@ -1271,37 +1295,53 @@ class ObjectLiteral final : public AggregateLiteral {
if (boilerplate_description_.is_null()) {
BuildBoilerplateDescription(isolate);
}
return boilerplate_description();
return boilerplate_description_;
}
// Populate the boilerplate description.
template <typename IsolateT>
void BuildBoilerplateDescription(IsolateT* isolate);
bool is_empty() const {
DCHECK(is_initialized());
return !has_elements() && properties_count() == 0 &&
properties()->length() == 0;
}
// Assemble bitfield of flags for the CreateObjectLiteral helper.
int ComputeFlags(bool disable_mementos = false) const;
// Mark all computed expressions that are bound to a key that
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code is emitted.
void CalculateEmitStore(Zone* zone);
bool IsEmptyObjectLiteral() const {
return is_empty() && !has_null_prototype();
}
// Determines whether the {CreateShallowObjectLiteratal} builtin can be used.
bool IsFastCloningSupported() const;
int EncodeLiteralType();
// Assemble bitfield of flags for the CreateObjectLiteral helper.
int ComputeFlags(bool disable_mementos = false) const {
int flags = AggregateLiteral::ComputeFlags(disable_mementos);
if (fast_elements()) flags |= kFastElements;
if (has_null_prototype()) flags |= kHasNullPrototype;
return flags;
}
// Populate the depth field and flags, returns the depth.
void InitDepthAndFlags();
int EncodeLiteralType() {
int flags = kNoFlags;
if (fast_elements()) flags |= kFastElements;
if (has_null_prototype()) flags |= kHasNullPrototype;
return flags;
private:
void InitFlagsForPendingNullPrototype(int i);
void set_has_elements(bool has_elements) {
bit_field_ = HasElementsField::update(bit_field_, has_elements);
}
void set_fast_elements(bool fast_elements) {
bit_field_ = FastElementsField::update(bit_field_, fast_elements);
}
void set_has_null_protoype(bool has_null_prototype) {
bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype);
}
ZoneList<Property*>* properties_;
uint32_t boilerplate_properties_;
Handle<ObjectBoilerplateDescription> boilerplate_description_;
Variable* home_object() const { return home_object_; }
using HasElementsField = LiteralBoilerplateBuilder::NextBitField<bool, 1>;
using HasRestPropertyField = HasElementsField::Next<bool, 1>;
using FastElementsField = HasRestPropertyField::Next<bool, 1>;
using HasNullPrototypeField = FastElementsField::Next<bool, 1>;
};
// An object literal has a boilerplate object that is used
// for minimizing the work when constructing it at runtime.
class ObjectLiteral final : public AggregateLiteral {
public:
using Property = ObjectLiteralProperty;
enum Flags {
kFastElements = 1 << 3,
......@@ -1311,6 +1351,19 @@ class ObjectLiteral final : public AggregateLiteral {
static_cast<int>(AggregateLiteral::kNeedsInitialAllocationSite) <
static_cast<int>(kFastElements));
// Mark all computed expressions that are bound to a key that
// is shadowed by a later occurrence of the same key. For the
// marked expressions, no store code is emitted.
void CalculateEmitStore(Zone* zone);
ZoneList<Property*>* properties() { return &properties_; }
const ObjectLiteralBoilerplateBuilder* builder() const { return &builder_; }
ObjectLiteralBoilerplateBuilder* builder() { return &builder_; }
Variable* home_object() const { return home_object_; }
private:
friend class AstNodeFactory;
friend Zone;
......@@ -1319,51 +1372,38 @@ class ObjectLiteral final : public AggregateLiteral {
uint32_t boilerplate_properties, int pos,
bool has_rest_property, Variable* home_object)
: AggregateLiteral(pos, kObjectLiteral),
boilerplate_properties_(boilerplate_properties),
properties_(properties.ToConstVector(), zone),
home_object_(home_object) {
bit_field_ |= HasElementsField::encode(false) |
HasRestPropertyField::encode(has_rest_property) |
FastElementsField::encode(false) |
HasNullPrototypeField::encode(false);
}
void InitFlagsForPendingNullPrototype(int i);
home_object_(home_object),
builder_(&properties_, boilerplate_properties, has_rest_property) {}
void set_has_elements(bool has_elements) {
bit_field_ = HasElementsField::update(bit_field_, has_elements);
}
void set_fast_elements(bool fast_elements) {
bit_field_ = FastElementsField::update(bit_field_, fast_elements);
}
void set_has_null_protoype(bool has_null_prototype) {
bit_field_ = HasNullPrototypeField::update(bit_field_, has_null_prototype);
}
uint32_t boilerplate_properties_;
Handle<ObjectBoilerplateDescription> boilerplate_description_;
ZoneList<Property*> properties_;
Variable* home_object_;
using HasElementsField = AggregateLiteral::NextBitField<bool, 1>;
using HasRestPropertyField = HasElementsField::Next<bool, 1>;
using FastElementsField = HasRestPropertyField::Next<bool, 1>;
using HasNullPrototypeField = FastElementsField::Next<bool, 1>;
ObjectLiteralBoilerplateBuilder builder_;
};
// An array literal has a literals object that is used
// for minimizing the work when constructing it at runtime.
class ArrayLiteral final : public AggregateLiteral {
// class for build boilerplate for array literal, including
// array_literal, spread call elements
class ArrayLiteralBoilerplateBuilder final : public LiteralBoilerplateBuilder {
public:
ArrayLiteralBoilerplateBuilder(const ZonePtrList<Expression>* values,
int first_spread_index)
: values_(values), first_spread_index_(first_spread_index) {}
Handle<ArrayBoilerplateDescription> boilerplate_description() const {
return boilerplate_description_;
}
const ZonePtrList<Expression>* values() const { return &values_; }
// Determines whether the {CreateShallowArrayLiteral} builtin can be used.
bool IsFastCloningSupported() const;
// Assemble bitfield of flags for the CreateArrayLiteral helper.
int ComputeFlags(bool disable_mementos = false) const {
return LiteralBoilerplateBuilder::ComputeFlags(disable_mementos);
}
int first_spread_index() const { return first_spread_index_; }
// Populate the depth field and flags, returns the depth.
int InitDepthAndFlags();
// Populate the depth field and flags
void InitDepthAndFlags();
// Get the boilerplate description, populating it if necessary.
template <typename IsolateT>
......@@ -1379,13 +1419,19 @@ class ArrayLiteral final : public AggregateLiteral {
template <typename IsolateT>
void BuildBoilerplateDescription(IsolateT* isolate);
// Determines whether the {CreateShallowArrayLiteral} builtin can be used.
bool IsFastCloningSupported() const;
const ZonePtrList<Expression>* values_;
int first_spread_index_;
Handle<ArrayBoilerplateDescription> boilerplate_description_;
};
// Assemble bitfield of flags for the CreateArrayLiteral helper.
int ComputeFlags(bool disable_mementos = false) const {
return AggregateLiteral::ComputeFlags(disable_mementos);
}
// An array literal has a literals object that is used
// for minimizing the work when constructing it at runtime.
class ArrayLiteral final : public AggregateLiteral {
public:
const ZonePtrList<Expression>* values() const { return &values_; }
const ArrayLiteralBoilerplateBuilder* builder() const { return &builder_; }
ArrayLiteralBoilerplateBuilder* builder() { return &builder_; }
private:
friend class AstNodeFactory;
......@@ -1394,12 +1440,11 @@ class ArrayLiteral final : public AggregateLiteral {
ArrayLiteral(Zone* zone, const ScopedPtrList<Expression>& values,
int first_spread_index, int pos)
: AggregateLiteral(pos, kArrayLiteral),
first_spread_index_(first_spread_index),
values_(values.ToConstVector(), zone) {}
values_(values.ToConstVector(), zone),
builder_(&values_, first_spread_index) {}
int first_spread_index_;
Handle<ArrayBoilerplateDescription> boilerplate_description_;
ZonePtrList<Expression> values_;
ArrayLiteralBoilerplateBuilder builder_;
};
enum class HoleCheckMode { kRequired, kElided };
......
......@@ -1312,13 +1312,14 @@ void BytecodeGenerator::AllocateDeferredConstants(IsolateT* isolate,
}
// Build object literal constant properties
for (std::pair<ObjectLiteral*, size_t> literal : object_literals_) {
ObjectLiteral* object_literal = literal.first;
if (object_literal->properties_count() > 0) {
for (std::pair<ObjectLiteralBoilerplateBuilder*, size_t> literal :
object_literals_) {
ObjectLiteralBoilerplateBuilder* object_literal_builder = literal.first;
if (object_literal_builder->properties_count() > 0) {
// If constant properties is an empty fixed array, we've already added it
// to the constant pool when visiting the object literal.
Handle<ObjectBoilerplateDescription> constant_properties =
object_literal->GetOrBuildBoilerplateDescription(isolate);
object_literal_builder->GetOrBuildBoilerplateDescription(isolate);
builder()->SetDeferredConstantPoolEntry(literal.second,
constant_properties);
......@@ -1326,10 +1327,11 @@ void BytecodeGenerator::AllocateDeferredConstants(IsolateT* isolate,
}
// Build array literal constant elements
for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) {
ArrayLiteral* array_literal = literal.first;
for (std::pair<ArrayLiteralBoilerplateBuilder*, size_t> literal :
array_literals_) {
ArrayLiteralBoilerplateBuilder* array_literal_builder = literal.first;
Handle<ArrayBoilerplateDescription> constant_elements =
array_literal->GetOrBuildBoilerplateDescription(isolate);
array_literal_builder->GetOrBuildBoilerplateDescription(isolate);
builder()->SetDeferredConstantPoolEntry(literal.second, constant_elements);
}
......@@ -3032,12 +3034,12 @@ void BytecodeGenerator::BuildCreateObjectLiteral(Register literal,
}
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->InitDepthAndFlags();
expr->builder()->InitDepthAndFlags();
// Fast path for the empty object literal which doesn't need an
// AllocationSite.
if (expr->IsEmptyObjectLiteral()) {
DCHECK(expr->IsFastCloningSupported());
if (expr->builder()->IsEmptyObjectLiteral()) {
DCHECK(expr->builder()->IsFastCloningSupported());
builder()->CreateEmptyObjectLiteral();
return;
}
......@@ -3052,7 +3054,8 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
// Deep-copy the literal boilerplate.
uint8_t flags = CreateObjectLiteralFlags::Encode(
expr->ComputeFlags(), expr->IsFastCloningSupported());
expr->builder()->ComputeFlags(),
expr->builder()->IsFastCloningSupported());
Register literal = register_allocator()->NewRegister();
......@@ -3076,11 +3079,11 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
size_t entry;
// If constant properties is an empty fixed array, use a cached empty fixed
// array to ensure it's only added to the constant pool once.
if (expr->properties_count() == 0) {
if (expr->builder()->properties_count() == 0) {
entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
} else {
entry = builder()->AllocateDeferredConstantPoolEntry();
object_literals_.push_back(std::make_pair(expr, entry));
object_literals_.push_back(std::make_pair(expr->builder(), entry));
}
BuildCreateObjectLiteral(literal, flags, entry);
}
......@@ -3373,7 +3376,7 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
->LoadNamedProperty(array, length, length_load_slot)
.StoreAccumulatorInRegister(index);
}
} else if (expr != nullptr) {
} else {
// There are some elements before the first (if any) spread, and we can
// use a boilerplate when creating the initial array from those elements.
......@@ -3381,29 +3384,54 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
// be created during finalization, and will contain all the constant
// elements before the first spread. This also handle the empty array case
// and one-shot optimization.
ArrayLiteralBoilerplateBuilder* array_literal_builder = nullptr;
if (expr != nullptr) {
array_literal_builder = expr->builder();
} else {
DCHECK(!elements->is_empty());
// get first_spread_index
int first_spread_index = -1;
for (auto iter = elements->begin(); iter != elements->end(); iter++) {
if ((*iter)->IsSpread()) {
first_spread_index = static_cast<int>(iter - elements->begin());
break;
}
}
array_literal_builder = zone()->New<ArrayLiteralBoilerplateBuilder>(
elements, first_spread_index);
array_literal_builder->InitDepthAndFlags();
}
DCHECK(array_literal_builder != nullptr);
uint8_t flags = CreateArrayLiteralFlags::Encode(
expr->IsFastCloningSupported(), expr->ComputeFlags());
array_literal_builder->IsFastCloningSupported(),
array_literal_builder->ComputeFlags());
if (is_empty) {
// Empty array literal fast-path.
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
DCHECK(expr->IsFastCloningSupported());
DCHECK(array_literal_builder->IsFastCloningSupported());
builder()->CreateEmptyArrayLiteral(literal_index);
} else {
// Create array literal from boilerplate.
size_t entry = builder()->AllocateDeferredConstantPoolEntry();
array_literals_.push_back(std::make_pair(expr, entry));
array_literals_.push_back(std::make_pair(array_literal_builder, entry));
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
builder()->CreateArrayLiteral(entry, literal_index, flags);
}
builder()->StoreAccumulatorInRegister(array);
ZonePtrList<Expression>::const_iterator first_spread_or_end =
array_literal_builder->first_spread_index() >= 0
? current + array_literal_builder->first_spread_index()
: end;
// Insert the missing non-constant elements, up until the first spread
// index, into the initial array (the remaining elements will be inserted
// below).
DCHECK_EQ(current, elements->begin());
ZonePtrList<Expression>::const_iterator first_spread_or_end =
expr->first_spread_index() >= 0 ? current + expr->first_spread_index()
: end;
int array_index = 0;
for (; current != first_spread_or_end; ++current, array_index++) {
Expression* subexpr = *current;
......@@ -3426,17 +3454,6 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
->LoadLiteral(Smi::FromInt(array_index))
.StoreAccumulatorInRegister(index);
}
} else {
// TODO(v8:11582): Support allocating boilerplates here.
// In other cases, we prepare an empty array to be filled in below.
DCHECK(!elements->is_empty());
int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
builder()
->CreateEmptyArrayLiteral(literal_index)
.StoreAccumulatorInRegister(array);
// Prepare the index for the first element.
builder()->LoadLiteral(Smi::FromInt(0)).StoreAccumulatorInRegister(index);
}
// Now build insertions for the remaining elements from current to end.
......@@ -3491,7 +3508,7 @@ void BytecodeGenerator::BuildCreateArrayLiteral(
}
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
expr->InitDepthAndFlags();
expr->builder()->InitDepthAndFlags();
BuildCreateArrayLiteral(expr->values(), expr);
}
......@@ -4314,7 +4331,7 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
// Store the assignment value in a register.
Register value;
RegisterList rest_runtime_callargs;
if (pattern->has_rest_property()) {
if (pattern->builder()->has_rest_property()) {
rest_runtime_callargs =
register_allocator()->NewRegisterList(pattern->properties()->length());
value = rest_runtime_callargs[0];
......@@ -4378,8 +4395,8 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
if (pattern_key->IsPropertyName()) {
value_name = pattern_key->AsLiteral()->AsRawPropertyName();
}
if (pattern->has_rest_property() || !value_name) {
if (pattern->has_rest_property()) {
if (pattern->builder()->has_rest_property() || !value_name) {
if (pattern->builder()->has_rest_property()) {
value_key = rest_runtime_callargs[i + 1];
} else {
value_key = register_allocator()->NewRegister();
......@@ -4396,9 +4413,9 @@ void BytecodeGenerator::BuildDestructuringObjectAssignment(
} else {
// We only need the key for non-computed properties when it is numeric
// or is being saved for the rest_runtime_callargs.
DCHECK(
pattern_key->IsNumberLiteral() ||
(pattern->has_rest_property() && pattern_key->IsPropertyName()));
DCHECK(pattern_key->IsNumberLiteral() ||
(pattern->builder()->has_rest_property() &&
pattern_key->IsPropertyName()));
VisitForRegisterValue(pattern_key, value_key);
}
}
......
......@@ -519,8 +519,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
native_function_literals_;
ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
ZoneVector<std::pair<ObjectLiteralBoilerplateBuilder*, size_t>>
object_literals_;
ZoneVector<std::pair<ArrayLiteralBoilerplateBuilder*, size_t>>
array_literals_;
ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
......
......@@ -65,43 +65,38 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 95
bytecode array length: 88
bytecodes: [
/* 34 S> */ B(LdaGlobal), U8(0), U8(0),
B(Star1),
/* 39 E> */ B(GetNamedProperty), R(1), U8(1), U8(2),
B(Star0),
B(CreateEmptyArrayLiteral), U8(4),
B(CreateArrayLiteral), U8(2), U8(4), U8(37),
B(Star3),
B(LdaZero),
B(Star2),
B(LdaZero),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(Ldar), R(2),
B(Inc), U8(7),
B(LdaSmi), I8(1),
B(Star2),
/* 49 S> */ B(CreateArrayLiteral), U8(2), U8(8), U8(37),
/* 49 S> */ B(CreateArrayLiteral), U8(3), U8(5), U8(37),
B(Star6),
/* 49 E> */ B(GetIterator), R(6), U8(9), U8(11),
/* 49 E> */ B(GetIterator), R(6), U8(6), U8(8),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star5),
B(GetNamedProperty), R(5), U8(3), U8(13),
B(GetNamedProperty), R(5), U8(4), U8(10),
B(Star4),
B(CallProperty0), R(4), R(5), U8(19),
B(Star6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(GetNamedProperty), R(6), U8(4), U8(21),
B(GetNamedProperty), R(6), U8(5), U8(21),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(6), U8(5), U8(15),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(GetNamedProperty), R(6), U8(6), U8(12),
B(StaInArrayLiteral), R(3), R(2), U8(17),
B(Ldar), R(2),
B(Inc), U8(7),
B(Inc), U8(16),
B(Star2),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(4),
B(StaInArrayLiteral), R(3), R(2), U8(5),
B(StaInArrayLiteral), R(3), R(2), U8(17),
B(Mov), R(3), R(2),
/* 39 E> */ B(CallJSRuntime), U8(%reflect_apply), R(0), U8(3),
B(LdaUndefined),
......@@ -111,6 +106,7 @@ constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["Math"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["max"],
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......
......@@ -90,7 +90,7 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 117
bytecode array length: 110
bytecodes: [
B(CreateBlockContext), U8(0),
B(PushContext), R(1),
......@@ -105,38 +105,33 @@ bytecodes: [
B(Star3),
B(PopContext), R(1),
B(Mov), R(4), R(0),
/* 89 S> */ B(CreateEmptyArrayLiteral), U8(0),
/* 89 S> */ B(CreateArrayLiteral), U8(3), U8(0), U8(37),
B(Star3),
B(LdaZero),
B(Star2),
B(LdaZero),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(Ldar), R(2),
B(Inc), U8(3),
B(LdaSmi), I8(1),
B(Star2),
/* 101 S> */ B(CreateArrayLiteral), U8(3), U8(4), U8(37),
/* 101 S> */ B(CreateArrayLiteral), U8(4), U8(1), U8(37),
B(Star6),
/* 101 E> */ B(GetIterator), R(6), U8(5), U8(7),
/* 101 E> */ B(GetIterator), R(6), U8(2), U8(4),
B(Mov), R(4), R(1),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star5),
B(GetNamedProperty), R(5), U8(4), U8(9),
B(GetNamedProperty), R(5), U8(5), U8(6),
B(Star4),
B(CallProperty0), R(4), R(5), U8(15),
B(Star6),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(6), U8(1),
B(GetNamedProperty), R(6), U8(5), U8(17),
B(GetNamedProperty), R(6), U8(6), U8(17),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(6), U8(6), U8(11),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(GetNamedProperty), R(6), U8(7), U8(8),
B(StaInArrayLiteral), R(3), R(2), U8(13),
B(Ldar), R(2),
B(Inc), U8(3),
B(Inc), U8(12),
B(Star2),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(4),
B(StaInArrayLiteral), R(3), R(2), U8(1),
B(StaInArrayLiteral), R(3), R(2), U8(13),
B(Mov), R(3), R(2),
/* 89 E> */ B(CallJSRuntime), U8(%reflect_construct), R(1), U8(2),
B(LdaUndefined),
......@@ -147,6 +142,7 @@ constant pool: [
FIXED_ARRAY_TYPE,
SHARED_FUNCTION_INFO_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......
......@@ -93,7 +93,7 @@ snippet: "
"
frame size: 11
parameter count: 1
bytecode array length: 111
bytecode array length: 103
bytecodes: [
/* 128 E> */ B(CreateRestParameter),
B(Star3),
......@@ -101,36 +101,31 @@ bytecodes: [
B(Mov), R(3), R(2),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(5),
B(CreateEmptyArrayLiteral), U8(0),
B(CreateArrayLiteral), U8(0), U8(0), U8(37),
B(Star7),
B(LdaZero),
B(Star6),
B(LdaSmi), I8(1),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(Ldar), R(6),
B(Inc), U8(3),
/* 152 S> */ B(Star6),
/* 152 E> */ B(GetIterator), R(3), U8(4), U8(6),
/* 152 E> */ B(GetIterator), R(3), U8(1), U8(3),
B(Mov), R(1), R(4),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowSymbolIteratorInvalid), R(0), U8(0),
B(Star9),
B(GetNamedProperty), R(9), U8(0), U8(8),
B(GetNamedProperty), R(9), U8(1), U8(5),
B(Star8),
B(CallProperty0), R(8), R(9), U8(14),
B(Star10),
B(JumpIfJSReceiver), U8(7),
B(CallRuntime), U16(Runtime::kThrowIteratorResultNotAnObject), R(10), U8(1),
B(GetNamedProperty), R(10), U8(1), U8(16),
B(GetNamedProperty), R(10), U8(2), U8(16),
B(JumpIfToBooleanTrue), U8(18),
B(GetNamedProperty), R(10), U8(2), U8(10),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(GetNamedProperty), R(10), U8(3), U8(7),
B(StaInArrayLiteral), R(7), R(6), U8(12),
B(Ldar), R(6),
B(Inc), U8(3),
B(Inc), U8(11),
B(Star6),
B(JumpLoop), U8(31), I8(0),
B(LdaSmi), I8(1),
B(StaInArrayLiteral), R(7), R(6), U8(1),
B(StaInArrayLiteral), R(7), R(6), U8(12),
B(ThrowIfNotSuperConstructor), R(5),
B(Mov), R(5), R(6),
B(Mov), R(0), R(8),
......@@ -144,6 +139,7 @@ bytecodes: [
/* 162 S> */ B(Return),
]
constant pool: [
ARRAY_BOILERPLATE_DESCRIPTION_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["next"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["done"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["value"],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment