summaryrefslogtreecommitdiff
path: root/deps/v8/src/interpreter/bytecode-generator.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r--deps/v8/src/interpreter/bytecode-generator.cc198
1 files changed, 149 insertions, 49 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc
index 79792a3d56..11a19443e1 100644
--- a/deps/v8/src/interpreter/bytecode-generator.cc
+++ b/deps/v8/src/interpreter/bytecode-generator.cc
@@ -4,7 +4,7 @@
#include "src/interpreter/bytecode-generator.h"
-#include "src/api.h"
+#include "src/api-inl.h"
#include "src/ast/ast-source-ranges.h"
#include "src/ast/scopes.h"
#include "src/builtins/builtins-constructor.h"
@@ -1815,6 +1815,14 @@ void BytecodeGenerator::AddToEagerLiteralsIfEager(FunctionLiteral* literal) {
}
}
+bool BytecodeGenerator::ShouldOptimizeAsOneShot() const {
+ if (!FLAG_enable_one_shot_optimization) return false;
+
+ if (loop_depth_ > 0) return false;
+
+ return info()->literal()->is_top_level() || info()->literal()->is_iife();
+}
+
void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr) {
size_t class_boilerplate_entry =
builder()->AllocateDeferredConstantPoolEntry();
@@ -2097,6 +2105,27 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
expr->flags());
}
+void BytecodeGenerator::BuildCreateObjectLiteral(Register literal,
+ uint8_t flags, size_t entry) {
+ if (ShouldOptimizeAsOneShot()) {
+ RegisterList args = register_allocator()->NewRegisterList(2);
+ builder()
+ ->LoadConstantPoolEntry(entry)
+ .StoreAccumulatorInRegister(args[0])
+ .LoadLiteral(Smi::FromInt(flags))
+ .StoreAccumulatorInRegister(args[1])
+ .CallRuntime(Runtime::kCreateObjectLiteralWithoutAllocationSite, args)
+ .StoreAccumulatorInRegister(literal);
+
+ } else {
+ // TODO(cbruni): Directly generate runtime call for literals we cannot
+ // optimize once the CreateShallowObjectLiteral stub is in sync with the TF
+ // optimizations.
+ int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
+ builder()->CreateObjectLiteral(entry, literal_index, flags, literal);
+ }
+}
+
void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
expr->InitDepthAndFlags();
@@ -2108,42 +2137,63 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
return;
}
- int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
// Deep-copy the literal boilerplate.
uint8_t flags = CreateObjectLiteralFlags::Encode(
expr->ComputeFlags(), expr->IsFastCloningSupported());
Register literal = register_allocator()->NewRegister();
- 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) {
- entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
+
+ // Create literal object.
+ int property_index = 0;
+ bool clone_object_spread =
+ expr->properties()->first()->kind() == ObjectLiteral::Property::SPREAD;
+ if (clone_object_spread) {
+ // Avoid the slow path for spreads in the following common cases:
+ // 1) `let obj = { ...source }`
+ // 2) `let obj = { ...source, override: 1 }`
+ // 3) `let obj = { ...source, ...overrides }`
+ RegisterAllocationScope register_scope(this);
+ Expression* property = expr->properties()->first()->value();
+ Register from_value = VisitForRegisterValue(property);
+
+ BytecodeLabels clone_object(zone());
+ builder()->JumpIfUndefined(clone_object.New());
+ builder()->JumpIfNull(clone_object.New());
+ builder()->ToObject(from_value);
+
+ clone_object.Bind(builder());
+ int clone_index = feedback_index(feedback_spec()->AddCloneObjectSlot());
+ builder()->CloneObject(from_value, flags, clone_index);
+ builder()->StoreAccumulatorInRegister(literal);
+ property_index++;
} else {
- entry = builder()->AllocateDeferredConstantPoolEntry();
- object_literals_.push_back(std::make_pair(expr, entry));
+ 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) {
+ entry = builder()->EmptyObjectBoilerplateDescriptionConstantPoolEntry();
+ } else {
+ entry = builder()->AllocateDeferredConstantPoolEntry();
+ object_literals_.push_back(std::make_pair(expr, entry));
+ }
+ BuildCreateObjectLiteral(literal, flags, entry);
}
- // TODO(cbruni): Directly generate runtime call for literals we cannot
- // optimize once the CreateShallowObjectLiteral stub is in sync with the TF
- // optimizations.
- builder()->CreateObjectLiteral(entry, literal_index, flags, literal);
// Store computed values into the literal.
- int property_index = 0;
AccessorTable accessor_table(zone());
for (; property_index < expr->properties()->length(); property_index++) {
ObjectLiteral::Property* property = expr->properties()->at(property_index);
if (property->is_computed_name()) break;
- if (property->IsCompileTimeValue()) continue;
+ if (!clone_object_spread && property->IsCompileTimeValue()) continue;
RegisterAllocationScope inner_register_scope(this);
Literal* key = property->key()->AsLiteral();
switch (property->kind()) {
case ObjectLiteral::Property::SPREAD:
- case ObjectLiteral::Property::CONSTANT:
UNREACHABLE();
+ case ObjectLiteral::Property::CONSTANT:
case ObjectLiteral::Property::MATERIALIZED_LITERAL:
- DCHECK(!property->value()->IsCompileTimeValue());
+ DCHECK(clone_object_spread || !property->value()->IsCompileTimeValue());
V8_FALLTHROUGH;
case ObjectLiteral::Property::COMPUTED: {
// It is safe to use [[Put]] here because the boilerplate already
@@ -2382,22 +2432,41 @@ void BytecodeGenerator::BuildArrayLiteralElementsInsertion(
void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
expr->InitDepthAndFlags();
+ uint8_t flags = CreateArrayLiteralFlags::Encode(
+ expr->IsFastCloningSupported(), expr->ComputeFlags());
- // Deep-copy the literal boilerplate.
- int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
- if (expr->is_empty()) {
+ bool is_empty = expr->is_empty();
+ bool optimize_as_one_shot = ShouldOptimizeAsOneShot();
+ size_t entry;
+ if (is_empty && optimize_as_one_shot) {
+ entry = builder()->EmptyArrayBoilerplateDescriptionConstantPoolEntry();
+ } else if (!is_empty) {
+ entry = builder()->AllocateDeferredConstantPoolEntry();
+ array_literals_.push_back(std::make_pair(expr, entry));
+ }
+
+ if (optimize_as_one_shot) {
+ // Create array literal without any allocation sites
+ RegisterAllocationScope register_scope(this);
+ RegisterList args = register_allocator()->NewRegisterList(2);
+ builder()
+ ->LoadConstantPoolEntry(entry)
+ .StoreAccumulatorInRegister(args[0])
+ .LoadLiteral(Smi::FromInt(flags))
+ .StoreAccumulatorInRegister(args[1])
+ .CallRuntime(Runtime::kCreateArrayLiteralWithoutAllocationSite, args);
+ } else if (is_empty) {
// Empty array literal fast-path.
+ int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
DCHECK(expr->IsFastCloningSupported());
builder()->CreateEmptyArrayLiteral(literal_index);
return;
+ } else {
+ // Deep-copy the literal boilerplate
+ int literal_index = feedback_index(feedback_spec()->AddLiteralSlot());
+ builder()->CreateArrayLiteral(entry, literal_index, flags);
}
- uint8_t flags = CreateArrayLiteralFlags::Encode(
- expr->IsFastCloningSupported(), expr->ComputeFlags());
- size_t entry = builder()->AllocateDeferredConstantPoolEntry();
- builder()->CreateArrayLiteral(entry, literal_index, flags);
- array_literals_.push_back(std::make_pair(expr, entry));
-
Register literal = register_allocator()->NewRegister();
builder()->StoreAccumulatorInRegister(literal);
// Insert all elements except the constant ones, since they are already there.
@@ -2751,6 +2820,54 @@ void BytecodeGenerator::BuildVariableAssignment(
}
}
+void BytecodeGenerator::BuildLoadNamedProperty(Property* property,
+ Register object,
+ const AstRawString* name) {
+ if (ShouldOptimizeAsOneShot()) {
+ RegisterList args = register_allocator()->NewRegisterList(2);
+ size_t name_index = builder()->GetConstantPoolEntry(name);
+ builder()
+ ->MoveRegister(object, args[0])
+ .LoadConstantPoolEntry(name_index)
+ .StoreAccumulatorInRegister(args[1])
+ .CallRuntime(Runtime::kInlineGetProperty, args);
+ } else {
+ FeedbackSlot slot = GetCachedLoadICSlot(property->obj(), name);
+ builder()->LoadNamedProperty(object, name, feedback_index(slot));
+ }
+}
+
+void BytecodeGenerator::BuildStoreNamedProperty(Property* property,
+ Register object,
+ const AstRawString* name) {
+ Register value;
+ if (!execution_result()->IsEffect()) {
+ value = register_allocator()->NewRegister();
+ builder()->StoreAccumulatorInRegister(value);
+ }
+
+ if (ShouldOptimizeAsOneShot()) {
+ RegisterList args = register_allocator()->NewRegisterList(4);
+ size_t name_index = builder()->GetConstantPoolEntry(name);
+ builder()
+ ->MoveRegister(object, args[0])
+ .StoreAccumulatorInRegister(args[2])
+ .LoadConstantPoolEntry(name_index)
+ .StoreAccumulatorInRegister(args[1])
+ .LoadLiteral(Smi::FromEnum(language_mode()))
+ .StoreAccumulatorInRegister(args[3])
+ .CallRuntime(Runtime::kSetProperty, args);
+ } else {
+ FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name);
+ builder()->StoreNamedProperty(object, name, feedback_index(slot),
+ language_mode());
+ }
+
+ if (!execution_result()->IsEffect()) {
+ builder()->LoadAccumulatorWithRegister(value);
+ }
+}
+
void BytecodeGenerator::VisitAssignment(Assignment* expr) {
DCHECK(expr->target()->IsValidReferenceExpression() ||
(expr->op() == Token::INIT && expr->target()->IsVariableProxy() &&
@@ -2812,8 +2929,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
case NAMED_PROPERTY: {
- FeedbackSlot slot = GetCachedLoadICSlot(property->obj(), name);
- builder()->LoadNamedProperty(object, name, feedback_index(slot));
+ BuildLoadNamedProperty(property, object, name);
break;
}
case KEYED_PROPERTY: {
@@ -2863,17 +2979,7 @@ void BytecodeGenerator::VisitAssignment(Assignment* expr) {
break;
}
case NAMED_PROPERTY: {
- FeedbackSlot slot = GetCachedStoreICSlot(property->obj(), name);
- Register value;
- if (!execution_result()->IsEffect()) {
- value = register_allocator()->NewRegister();
- builder()->StoreAccumulatorInRegister(value);
- }
- builder()->StoreNamedProperty(object, name, feedback_index(slot),
- language_mode());
- if (!execution_result()->IsEffect()) {
- builder()->LoadAccumulatorWithRegister(value);
- }
+ BuildStoreNamedProperty(property, object, name);
break;
}
case KEYED_PROPERTY: {
@@ -3339,11 +3445,9 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) {
UNREACHABLE();
case NAMED_PROPERTY: {
builder()->SetExpressionPosition(property);
- builder()->LoadNamedProperty(
- obj, property->key()->AsLiteral()->AsRawPropertyName(),
- feedback_index(GetCachedLoadICSlot(
- property->obj(),
- property->key()->AsLiteral()->AsRawPropertyName())));
+ const AstRawString* name =
+ property->key()->AsLiteral()->AsRawPropertyName();
+ BuildLoadNamedProperty(property, obj, name);
break;
}
case KEYED_PROPERTY: {
@@ -4726,11 +4830,7 @@ void BytecodeGenerator::VisitArgumentsObject(Variable* variable) {
// Allocate and initialize a new arguments object and assign to the
// {arguments} variable.
- CreateArgumentsType type =
- is_strict(language_mode()) || !info()->has_simple_parameters()
- ? CreateArgumentsType::kUnmappedArguments
- : CreateArgumentsType::kMappedArguments;
- builder()->CreateArguments(type);
+ builder()->CreateArguments(closure_scope()->GetArgumentsType());
BuildVariableAssignment(variable, Token::ASSIGN, HoleCheckMode::kElided);
}