diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 198 |
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); } |