diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 459 |
1 files changed, 300 insertions, 159 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 99e76725d5..02f6c3bb2c 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -6,6 +6,7 @@ #include "src/ast/compile-time-value.h" #include "src/ast/scopes.h" +#include "src/builtins/builtins-constructor.h" #include "src/code-stubs.h" #include "src/compilation-info.h" #include "src/compiler.h" @@ -496,24 +497,24 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { constant_pool_entry_(0), has_constant_pool_entry_(false) {} - void AddFunctionDeclaration(FeedbackVectorSlot slot, FunctionLiteral* func) { + void AddFunctionDeclaration(Handle<String> name, FeedbackVectorSlot slot, + FunctionLiteral* func) { DCHECK(!slot.IsInvalid()); - declarations_.push_back(std::make_pair(slot, func)); + declarations_.push_back(Declaration(name, slot, func)); } - void AddUndefinedDeclaration(FeedbackVectorSlot slot) { + void AddUndefinedDeclaration(Handle<String> name, FeedbackVectorSlot slot) { DCHECK(!slot.IsInvalid()); - declarations_.push_back(std::make_pair(slot, nullptr)); + declarations_.push_back(Declaration(name, slot, nullptr)); } - Handle<FixedArray> AllocateDeclarationPairs(CompilationInfo* info) { + Handle<FixedArray> AllocateDeclarations(CompilationInfo* info) { DCHECK(has_constant_pool_entry_); int array_index = 0; - Handle<FixedArray> pairs = info->isolate()->factory()->NewFixedArray( - static_cast<int>(declarations_.size() * 2), TENURED); - for (std::pair<FeedbackVectorSlot, FunctionLiteral*> declaration : - declarations_) { - FunctionLiteral* func = declaration.second; + Handle<FixedArray> data = info->isolate()->factory()->NewFixedArray( + static_cast<int>(declarations_.size() * 3), TENURED); + for (const Declaration& declaration : declarations_) { + FunctionLiteral* func = declaration.func; Handle<Object> initial_value; if (func == nullptr) { initial_value = info->isolate()->factory()->undefined_value(); @@ -526,10 +527,11 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { // will set stack overflow. if (initial_value.is_null()) return Handle<FixedArray>(); - pairs->set(array_index++, Smi::FromInt(declaration.first.ToInt())); - pairs->set(array_index++, *initial_value); + data->set(array_index++, *declaration.name); + data->set(array_index++, Smi::FromInt(declaration.slot.ToInt())); + data->set(array_index++, *initial_value); } - return pairs; + return data; } size_t constant_pool_entry() { @@ -547,7 +549,17 @@ class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject { bool empty() { return declarations_.empty(); } private: - ZoneVector<std::pair<FeedbackVectorSlot, FunctionLiteral*>> declarations_; + struct Declaration { + Declaration() : slot(FeedbackVectorSlot::Invalid()), func(nullptr) {} + Declaration(Handle<String> name, FeedbackVectorSlot slot, + FunctionLiteral* func) + : name(name), slot(slot), func(func) {} + + Handle<String> name; + FeedbackVectorSlot slot; + FunctionLiteral* func; + }; + ZoneVector<Declaration> declarations_; size_t constant_pool_entry_; bool has_constant_pool_entry_; }; @@ -565,6 +577,8 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) global_declarations_(0, info->zone()), function_literals_(0, info->zone()), native_function_literals_(0, info->zone()), + object_literals_(0, info->zone()), + array_literals_(0, info->zone()), execution_control_(nullptr), execution_context_(nullptr), execution_result_(nullptr), @@ -572,24 +586,23 @@ BytecodeGenerator::BytecodeGenerator(CompilationInfo* info) generator_state_(), loop_depth_(0), home_object_symbol_(info->isolate()->factory()->home_object_symbol()), - empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()) { - AstValueFactory* ast_value_factory = info->parse_info()->ast_value_factory(); - const AstRawString* prototype_string = ast_value_factory->prototype_string(); - ast_value_factory->Internalize(info->isolate()); - prototype_string_ = prototype_string->string(); -} + iterator_symbol_(info->isolate()->factory()->iterator_symbol()), + prototype_string_(info->isolate()->factory()->prototype_string()), + empty_fixed_array_(info->isolate()->factory()->empty_fixed_array()), + undefined_string_( + info->isolate()->ast_string_constants()->undefined_string()) {} Handle<BytecodeArray> BytecodeGenerator::FinalizeBytecode(Isolate* isolate) { - AllocateDeferredConstants(); + AllocateDeferredConstants(isolate); if (HasStackOverflow()) return Handle<BytecodeArray>(); return builder()->ToBytecodeArray(isolate); } -void BytecodeGenerator::AllocateDeferredConstants() { +void BytecodeGenerator::AllocateDeferredConstants(Isolate* isolate) { // Build global declaration pair arrays. for (GlobalDeclarationsBuilder* globals_builder : global_declarations_) { Handle<FixedArray> declarations = - globals_builder->AllocateDeclarationPairs(info()); + globals_builder->AllocateDeclarations(info()); if (declarations.is_null()) return SetStackOverflow(); builder()->InsertConstantPoolEntryAt(globals_builder->constant_pool_entry(), declarations); @@ -614,6 +627,27 @@ void BytecodeGenerator::AllocateDeferredConstants() { if (shared_info.is_null()) return SetStackOverflow(); builder()->InsertConstantPoolEntryAt(literal.second, shared_info); } + + // 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) { + // If constant properties is an empty fixed array, we've already added it + // to the constant pool when visiting the object literal. + Handle<FixedArray> constant_properties = + object_literal->GetOrBuildConstantProperties(isolate); + + builder()->InsertConstantPoolEntryAt(literal.second, constant_properties); + } + } + + // Build array literal constant elements + for (std::pair<ArrayLiteral*, size_t> literal : array_literals_) { + ArrayLiteral* array_literal = literal.first; + Handle<ConstantElementsPair> constant_elements = + array_literal->GetOrBuildConstantElements(isolate); + builder()->InsertConstantPoolEntryAt(literal.second, constant_elements); + } } void BytecodeGenerator::GenerateBytecode(uintptr_t stack_limit) { @@ -711,22 +745,25 @@ void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, LoopBuilder* loop_builder) { // Recall that stmt->yield_count() is always zero inside ordinary // (i.e. non-generator) functions. + if (stmt->yield_count() == 0) { + loop_builder->LoopHeader(); + } else { + // Collect all labels for generator resume points within the loop (if any) + // so that they can be bound to the loop header below. Also create fresh + // labels for these resume points, to be used inside the loop. + ZoneVector<BytecodeLabel> resume_points_in_loop(zone()); + size_t first_yield = stmt->first_yield_id(); + DCHECK_LE(first_yield + stmt->yield_count(), + generator_resume_points_.size()); + for (size_t id = first_yield; id < first_yield + stmt->yield_count(); + id++) { + auto& label = generator_resume_points_[id]; + resume_points_in_loop.push_back(label); + generator_resume_points_[id] = BytecodeLabel(); + } + + loop_builder->LoopHeader(&resume_points_in_loop); - // Collect all labels for generator resume points within the loop (if any) so - // that they can be bound to the loop header below. Also create fresh labels - // for these resume points, to be used inside the loop. - ZoneVector<BytecodeLabel> resume_points_in_loop(zone()); - size_t first_yield = stmt->first_yield_id(); - DCHECK_LE(first_yield + stmt->yield_count(), generator_resume_points_.size()); - for (size_t id = first_yield; id < first_yield + stmt->yield_count(); id++) { - auto& label = generator_resume_points_[id]; - resume_points_in_loop.push_back(label); - generator_resume_points_[id] = BytecodeLabel(); - } - - loop_builder->LoopHeader(&resume_points_in_loop); - - if (stmt->yield_count() > 0) { // If we are not resuming, fall through to loop body. // If we are resuming, perform state dispatch. BytecodeLabel not_resuming; @@ -751,10 +788,13 @@ void BytecodeGenerator::VisitGeneratorPrologue() { ->LoadAccumulatorWithRegister(generator_object) .JumpIfUndefined(®ular_call); - // This is a resume call. Restore registers and perform state dispatch. - // (The current context has already been restored by the trampoline.) + // This is a resume call. Restore the current context and the registers, then + // perform state dispatch. + Register dummy = register_allocator()->NewRegister(); builder() - ->ResumeGenerator(generator_object) + ->CallRuntime(Runtime::kInlineGeneratorGetContext, generator_object) + .PushContext(dummy) + .ResumeGenerator(generator_object) .StoreAccumulatorInRegister(generator_state_); BuildIndexedJump(generator_state_, 0, generator_resume_points_.size(), generator_resume_points_); @@ -795,7 +835,7 @@ void BytecodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) { case VariableLocation::UNALLOCATED: { DCHECK(!variable->binding_needs_init()); FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); - globals_builder()->AddUndefinedDeclaration(slot); + globals_builder()->AddUndefinedDeclaration(variable->name(), slot); break; } case VariableLocation::LOCAL: @@ -849,7 +889,8 @@ void BytecodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) { switch (variable->location()) { case VariableLocation::UNALLOCATED: { FeedbackVectorSlot slot = decl->proxy()->VariableFeedbackSlot(); - globals_builder()->AddFunctionDeclaration(slot, decl->fun()); + globals_builder()->AddFunctionDeclaration(variable->name(), slot, + decl->fun()); break; } case VariableLocation::PARAMETER: @@ -1300,7 +1341,7 @@ void BytecodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { // If requested, clear message object as we enter the catch block. if (stmt->clear_pending_message()) { - builder()->CallRuntime(Runtime::kInterpreterClearPendingMessage); + builder()->LoadTheHole().SetPendingMessage(); } // Load the catch context into the accumulator. @@ -1359,16 +1400,15 @@ void BytecodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { Register message = context; // Reuse register. // Clear message object as we enter the finally block. - builder() - ->CallRuntime(Runtime::kInterpreterClearPendingMessage) - .StoreAccumulatorInRegister(message); + builder()->LoadTheHole().SetPendingMessage().StoreAccumulatorInRegister( + message); // Evaluate the finally-block. Visit(stmt->finally_block()); try_control_builder.EndFinally(); // Pending message object is restored on exit. - builder()->CallRuntime(Runtime::kInterpreterSetPendingMessage, message); + builder()->LoadAccumulatorWithRegister(message).SetPendingMessage(); // Dynamic dispatch after the finally-block. commands.ApplyDeferredCommands(); @@ -1383,25 +1423,39 @@ void BytecodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { uint8_t flags = CreateClosureFlags::Encode(expr->pretenure(), scope()->is_function_scope()); size_t entry = builder()->AllocateConstantPoolEntry(); - builder()->CreateClosure(entry, flags); + int slot_index = feedback_index(expr->LiteralFeedbackSlot()); + builder()->CreateClosure(entry, slot_index, flags); function_literals_.push_back(std::make_pair(expr, entry)); } void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { - VisitClassLiteralForRuntimeDefinition(expr); + Register constructor = VisitForRegisterValue(expr->constructor()); + { + RegisterAllocationScope register_scope(this); + RegisterList args = register_allocator()->NewRegisterList(4); + VisitForAccumulatorValueOrTheHole(expr->extends()); + builder() + ->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 prototype = register_allocator()->NewRegister(); + builder()->StoreAccumulatorInRegister(prototype); - // Load the "prototype" from the constructor. - RegisterList args = register_allocator()->NewRegisterList(2); - Register literal = args[0]; - Register prototype = args[1]; - FeedbackVectorSlot slot = expr->PrototypeSlot(); - builder() - ->StoreAccumulatorInRegister(literal) - .LoadNamedProperty(literal, prototype_string(), feedback_index(slot)) - .StoreAccumulatorInRegister(prototype); + if (FunctionLiteral::NeedsHomeObject(expr->constructor())) { + // Prototype is already in the accumulator. + builder()->StoreNamedProperty(constructor, home_object_symbol(), + feedback_index(expr->HomeObjectSlot()), + language_mode()); + } - VisitClassLiteralProperties(expr, literal, prototype); - builder()->CallRuntime(Runtime::kToFastProperties, literal); + VisitClassLiteralProperties(expr, constructor, prototype); + BuildClassLiteralNameProperty(expr, constructor); + builder()->CallRuntime(Runtime::kToFastProperties, constructor); // Assign to class variable. if (expr->class_variable_proxy() != nullptr) { VariableProxy* proxy = expr->class_variable_proxy(); @@ -1413,28 +1467,12 @@ void BytecodeGenerator::VisitClassLiteral(ClassLiteral* expr) { } } -void BytecodeGenerator::VisitClassLiteralForRuntimeDefinition( - ClassLiteral* expr) { - RegisterAllocationScope register_scope(this); - RegisterList args = register_allocator()->NewRegisterList(4); - VisitForAccumulatorValueOrTheHole(expr->extends()); - builder()->StoreAccumulatorInRegister(args[0]); - VisitForRegisterValue(expr->constructor(), args[1]); - builder() - ->LoadLiteral(Smi::FromInt(expr->start_position())) - .StoreAccumulatorInRegister(args[2]) - .LoadLiteral(Smi::FromInt(expr->end_position())) - .StoreAccumulatorInRegister(args[3]) - .CallRuntime(Runtime::kDefineClass, args); -} - void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, - Register literal, + Register constructor, Register prototype) { RegisterAllocationScope register_scope(this); - RegisterList args = register_allocator()->NewRegisterList(5); - Register receiver = args[0], key = args[1], value = args[2], attr = args[3], - set_function_name = args[4]; + 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(); @@ -1444,14 +1482,18 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, ClassLiteral::Property* property = expr->properties()->at(i); // Set-up receiver. - Register new_receiver = property->is_static() ? literal : prototype; + Register new_receiver = property->is_static() ? constructor : prototype; if (new_receiver != old_receiver) { builder()->MoveRegister(new_receiver, receiver); old_receiver = new_receiver; } - VisitForAccumulatorValue(property->key()); - builder()->ConvertAccumulatorToName(key); + if (property->key()->IsStringLiteral()) { + VisitForRegisterValue(property->key(), key); + } else { + VisitForAccumulatorValue(property->key()); + builder()->ConvertAccumulatorToName(key); + } if (property->is_static() && property->is_computed_name()) { // The static prototype property is read only. We handle the non computed @@ -1479,20 +1521,26 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, switch (property->kind()) { case ClassLiteral::Property::METHOD: { + DataPropertyInLiteralFlags flags = DataPropertyInLiteralFlag::kDontEnum; + if (property->NeedsSetFunctionName()) { + flags |= DataPropertyInLiteralFlag::kSetFunctionName; + } + + FeedbackVectorSlot slot = property->GetStoreDataPropertySlot(); + DCHECK(!slot.IsInvalid()); + builder() - ->LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName())) - .StoreAccumulatorInRegister(set_function_name) - .CallRuntime(Runtime::kDefineDataPropertyInLiteral, args); + ->LoadAccumulatorWithRegister(value) + .StoreDataPropertyInLiteral(receiver, key, flags, + feedback_index(slot)); break; } case ClassLiteral::Property::GETTER: { - builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, - args.Truncate(4)); + builder()->CallRuntime(Runtime::kDefineGetterPropertyUnchecked, args); break; } case ClassLiteral::Property::SETTER: { - builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, - args.Truncate(4)); + builder()->CallRuntime(Runtime::kDefineSetterPropertyUnchecked, args); break; } case ClassLiteral::Property::FIELD: { @@ -1503,10 +1551,23 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, } } +void BytecodeGenerator::BuildClassLiteralNameProperty(ClassLiteral* expr, + Register literal) { + if (!expr->has_name_static_property() && + !expr->constructor()->raw_name()->IsEmpty()) { + 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()->AllocateConstantPoolEntry(); - builder()->CreateClosure(entry, NOT_TENURED); + int slot_index = feedback_index(expr->LiteralFeedbackSlot()); + builder()->CreateClosure(entry, slot_index, NOT_TENURED); native_function_literals_.push_back(std::make_pair(expr, entry)); } @@ -1567,19 +1628,24 @@ void BytecodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { } void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { - // Copy the literal boilerplate. + // Deep-copy the literal boilerplate. uint8_t flags = CreateObjectLiteralFlags::Encode( - FastCloneShallowObjectStub::IsSupported(expr), - FastCloneShallowObjectStub::PropertiesCount(expr->properties_count()), + expr->IsFastCloningSupported(), + ConstructorBuiltinsAssembler::FastCloneShallowObjectPropertiesCount( + expr->properties_count()), expr->ComputeFlags()); + + Register literal = register_allocator()->NewRegister(); + size_t entry; // If constant properties is an empty fixed array, use our cached // empty_fixed_array to ensure it's only added to the constant pool once. - Handle<FixedArray> constant_properties = expr->properties_count() == 0 - ? empty_fixed_array() - : expr->constant_properties(); - Register literal = register_allocator()->NewRegister(); - builder()->CreateObjectLiteral(constant_properties, expr->literal_index(), - flags, literal); + if (expr->properties_count() == 0) { + entry = builder()->GetConstantPoolEntry(empty_fixed_array()); + } else { + entry = builder()->AllocateConstantPoolEntry(); + object_literals_.push_back(std::make_pair(expr, entry)); + } + builder()->CreateObjectLiteral(entry, expr->literal_index(), flags, literal); // Store computed values into the literal. int property_index = 0; @@ -1592,6 +1658,7 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 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::MATERIALIZED_LITERAL: @@ -1700,18 +1767,26 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { case ObjectLiteral::Property::CONSTANT: case ObjectLiteral::Property::COMPUTED: case ObjectLiteral::Property::MATERIALIZED_LITERAL: { - RegisterList args = register_allocator()->NewRegisterList(5); - builder()->MoveRegister(literal, args[0]); + Register key = register_allocator()->NewRegister(); VisitForAccumulatorValue(property->key()); - builder()->ConvertAccumulatorToName(args[1]); - VisitForRegisterValue(property->value(), args[2]); - VisitSetHomeObject(args[2], literal, property); + builder()->ConvertAccumulatorToName(key); + + Register value = VisitForRegisterValue(property->value()); + VisitSetHomeObject(value, literal, property); + + DataPropertyInLiteralFlags data_property_flags = + DataPropertyInLiteralFlag::kNoFlags; + if (property->NeedsSetFunctionName()) { + data_property_flags |= DataPropertyInLiteralFlag::kSetFunctionName; + } + + FeedbackVectorSlot slot = property->GetStoreDataPropertySlot(); + DCHECK(!slot.IsInvalid()); + builder() - ->LoadLiteral(Smi::FromInt(NONE)) - .StoreAccumulatorInRegister(args[3]) - .LoadLiteral(Smi::FromInt(property->NeedsSetFunctionName())) - .StoreAccumulatorInRegister(args[4]); - builder()->CallRuntime(Runtime::kDefineDataPropertyInLiteral, args); + ->LoadAccumulatorWithRegister(value) + .StoreDataPropertyInLiteral(literal, key, data_property_flags, + feedback_index(slot)); break; } case ObjectLiteral::Property::GETTER: @@ -1732,6 +1807,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { builder()->CallRuntime(function_id, args); break; } + case ObjectLiteral::Property::SPREAD: { + RegisterList args = register_allocator()->NewRegisterList(2); + builder()->MoveRegister(literal, args[0]); + VisitForRegisterValue(property->value(), args[1]); + builder()->CallRuntime(Runtime::kCopyDataProperties, args); + break; + } case ObjectLiteral::Property::PROTOTYPE: UNREACHABLE(); // Handled specially above. break; @@ -1743,14 +1825,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { void BytecodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { // Deep-copy the literal boilerplate. - int runtime_flags = expr->ComputeFlags(); - bool use_fast_shallow_clone = - (runtime_flags & ArrayLiteral::kShallowElements) != 0 && - expr->values()->length() <= JSArray::kInitialMaxFastElementArray; - uint8_t flags = - CreateArrayLiteralFlags::Encode(use_fast_shallow_clone, runtime_flags); - builder()->CreateArrayLiteral(expr->constant_elements(), - expr->literal_index(), flags); + uint8_t flags = CreateArrayLiteralFlags::Encode( + expr->IsFastCloningSupported(), expr->ComputeFlags()); + + size_t entry = builder()->AllocateConstantPoolEntry(); + builder()->CreateArrayLiteral(entry, expr->literal_index(), flags); + array_literals_.push_back(std::make_pair(expr, entry)); + Register index, literal; // Evaluate all the non-constant subexpressions and store them into the @@ -1820,7 +1901,15 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, break; } case VariableLocation::UNALLOCATED: { - builder()->LoadGlobal(feedback_index(slot), typeof_mode); + // The global identifier "undefined" is immutable. Everything + // else could be reassigned. For performance, we do a pointer comparison + // rather than checking if the raw_name is really "undefined". + if (variable->raw_name() == undefined_string()) { + builder()->LoadUndefined(); + } else { + builder()->LoadGlobal(variable->name(), feedback_index(slot), + typeof_mode); + } break; } case VariableLocation::CONTEXT: { @@ -1920,25 +2009,19 @@ void BytecodeGenerator::BuildThrowIfHole(Handle<String> name) { builder()->Bind(&no_reference_error); } -void BytecodeGenerator::BuildThrowIfNotHole(Handle<String> name) { - // TODO(interpreter): Can the parser reduce the number of checks - // performed? Or should there be a ThrowIfNotHole bytecode. - BytecodeLabel no_reference_error, reference_error; - builder() - ->JumpIfNotHole(&reference_error) - .Jump(&no_reference_error) - .Bind(&reference_error); - BuildThrowReferenceError(name); - builder()->Bind(&no_reference_error); -} - void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op) { if (variable->is_this() && variable->mode() == CONST && op == Token::INIT) { // Perform an initialization check for 'this'. 'this' variable is the // only variable able to trigger bind operations outside the TDZ // via 'super' calls. - BuildThrowIfNotHole(variable->name()); + BytecodeLabel no_reference_error, reference_error; + builder() + ->JumpIfNotHole(&reference_error) + .Jump(&no_reference_error) + .Bind(&reference_error) + .CallRuntime(Runtime::kThrowSuperAlreadyCalledError) + .Bind(&no_reference_error); } else { // Perform an initialization check for let/const declared variables. // E.g. let x = (x = 20); is not allowed. @@ -2477,29 +2560,44 @@ void BytecodeGenerator::VisitCallSuper(Call* expr) { SuperCallReference* super = expr->expression()->AsSuperCallReference(); // Prepare the constructor to the super call. - Register this_function = VisitForRegisterValue(super->this_function_var()); - builder()->CallRuntime(Runtime::kInlineGetSuperConstructor, this_function); - - Register constructor = this_function; // Re-use dead this_function register. - builder()->StoreAccumulatorInRegister(constructor); - - RegisterList args = register_allocator()->NewGrowableRegisterList(); - VisitArguments(expr->arguments(), &args); - - // The new target is loaded into the accumulator from the - // {new.target} variable. - VisitForAccumulatorValue(super->new_target_var()); + VisitForAccumulatorValue(super->this_function_var()); + Register constructor = register_allocator()->NewRegister(); + builder()->GetSuperConstructor(constructor); + + ZoneList<Expression*>* args = expr->arguments(); + + // When a super call contains a spread, a CallSuper AST node is only created + // if there is exactly one spread, and it is the last argument. + if (!args->is_empty() && args->last()->IsSpread()) { + RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); + Register constructor_arg = + register_allocator()->GrowRegisterList(&args_regs); + builder()->MoveRegister(constructor, constructor_arg); + // Reserve argument reg for new.target in correct place for runtime call. + // TODO(petermarshall): Remove this when changing bytecode to use the new + // stub. + Register new_target = register_allocator()->GrowRegisterList(&args_regs); + VisitArguments(args, &args_regs); + VisitForRegisterValue(super->new_target_var(), new_target); + builder()->NewWithSpread(args_regs); + } else { + RegisterList args_regs = register_allocator()->NewGrowableRegisterList(); + VisitArguments(args, &args_regs); + // The new target is loaded into the accumulator from the + // {new.target} variable. + VisitForAccumulatorValue(super->new_target_var()); - // Call construct. - builder()->SetExpressionPosition(expr); - // TODO(turbofan): For now we do gather feedback on super constructor - // calls, utilizing the existing machinery to inline the actual call - // target and the JSCreate for the implicit receiver allocation. This - // is not an ideal solution for super constructor calls, but it gets - // the job done for now. In the long run we might want to revisit this - // and come up with a better way. - int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); - builder()->New(constructor, args, feedback_slot_index); + // Call construct. + builder()->SetExpressionPosition(expr); + // TODO(turbofan): For now we do gather feedback on super constructor + // calls, utilizing the existing machinery to inline the actual call + // target and the JSCreate for the implicit receiver allocation. This + // is not an ideal solution for super constructor calls, but it gets + // the job done for now. In the long run we might want to revisit this + // and come up with a better way. + int const feedback_slot_index = feedback_index(expr->CallFeedbackICSlot()); + builder()->New(constructor, args_regs, feedback_slot_index); + } } void BytecodeGenerator::VisitCallNew(CallNew* expr) { @@ -2800,15 +2898,43 @@ void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { Register lhs = VisitForRegisterValue(expr->left()); VisitForAccumulatorValue(expr->right()); FeedbackVectorSlot slot = expr->BinaryOperationFeedbackSlot(); + builder()->SetExpressionPosition(expr); builder()->BinaryOperation(expr->op(), lhs, feedback_index(slot)); } -void BytecodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); } +void BytecodeGenerator::VisitSpread(Spread* expr) { Visit(expr->expression()); } void BytecodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) { UNREACHABLE(); } +void BytecodeGenerator::VisitGetIterator(GetIterator* expr) { + FeedbackVectorSlot load_slot = expr->IteratorPropertyFeedbackSlot(); + FeedbackVectorSlot call_slot = expr->IteratorCallFeedbackSlot(); + + RegisterList args = register_allocator()->NewRegisterList(1); + Register method = register_allocator()->NewRegister(); + Register obj = args[0]; + + VisitForAccumulatorValue(expr->iterable()); + + // Let method be GetMethod(obj, @@iterator). + builder() + ->StoreAccumulatorInRegister(obj) + .LoadNamedProperty(obj, iterator_symbol(), feedback_index(load_slot)) + .StoreAccumulatorInRegister(method); + + // Let iterator be Call(method, obj). + builder()->Call(method, args, feedback_index(call_slot), + Call::NAMED_PROPERTY_CALL); + + // If Type(iterator) is not Object, throw a TypeError exception. + BytecodeLabel no_type_error; + builder()->JumpIfJSReceiver(&no_type_error); + builder()->CallRuntime(Runtime::kThrowSymbolIteratorInvalid); + builder()->Bind(&no_type_error); +} + void BytecodeGenerator::VisitThisFunction(ThisFunction* expr) { builder()->LoadAccumulatorWithRegister(Register::function_closure()); } @@ -2930,12 +3056,27 @@ void BytecodeGenerator::BuildNewLocalActivationContext() { .StoreAccumulatorInRegister(args[2]) .CallRuntime(Runtime::kPushModuleContext, args); } else { + DCHECK(scope->is_function_scope() || scope->is_eval_scope()); int slot_count = scope->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; - if (slot_count <= FastNewFunctionContextStub::kMaximumSlots) { - builder()->CreateFunctionContext(slot_count); + if (slot_count <= + ConstructorBuiltinsAssembler::MaximumFunctionContextSlots()) { + switch (scope->scope_type()) { + case EVAL_SCOPE: + builder()->CreateEvalContext(slot_count); + break; + case FUNCTION_SCOPE: + builder()->CreateFunctionContext(slot_count); + break; + default: + UNREACHABLE(); + } } else { - builder()->CallRuntime(Runtime::kNewFunctionContext, - Register::function_closure()); + RegisterList args = register_allocator()->NewRegisterList(2); + builder() + ->MoveRegister(Register::function_closure(), args[0]) + .LoadLiteral(Smi::FromInt(scope->scope_type())) + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kNewFunctionContext, args); } } } |