diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 276 |
1 files changed, 156 insertions, 120 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 29065d6a55..92ae15127e 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -2042,7 +2042,71 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { VisitDeclarations(expr->scope()->declarations()); Register class_constructor = register_allocator()->NewRegister(); + // Create the class brand symbol and store it on the context during class + // evaluation. This will be stored in the instance later in the constructor. + // We do this early so that invalid access to private methods or accessors + // in computed property keys throw. + if (expr->scope()->brand() != nullptr) { + Register brand = register_allocator()->NewRegister(); + const AstRawString* class_name = + expr->scope()->class_variable() != nullptr + ? expr->scope()->class_variable()->raw_name() + : ast_string_constants()->empty_string(); + builder() + ->LoadLiteral(class_name) + .StoreAccumulatorInRegister(brand) + .CallRuntime(Runtime::kCreatePrivateNameSymbol, brand); + BuildVariableAssignment(expr->scope()->brand(), Token::INIT, + HoleCheckMode::kElided); + } + AccessorTable<ClassLiteral::Property> private_accessors(zone()); + for (int i = 0; i < expr->private_members()->length(); i++) { + ClassLiteral::Property* property = expr->private_members()->at(i); + DCHECK(property->is_private()); + switch (property->kind()) { + case ClassLiteral::Property::FIELD: { + // Initialize the private field variables early. + // Create the private name symbols for fields during class + // evaluation and store them on the context. These will be + // used as keys later during instance or static initialization. + RegisterAllocationScope private_name_register_scope(this); + Register private_name = register_allocator()->NewRegister(); + VisitForRegisterValue(property->key(), private_name); + builder() + ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) + .StoreAccumulatorInRegister(private_name) + .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name); + DCHECK_NOT_NULL(property->private_name_var()); + BuildVariableAssignment(property->private_name_var(), Token::INIT, + HoleCheckMode::kElided); + break; + } + case ClassLiteral::Property::METHOD: { + // We can initialize the private methods and accessors later so that the + // home objects can be assigned right after the creation of the + // closures, and those are guarded by the brand checks. + break; + } + // Collect private accessors into a table to merge the creation of + // those closures later. + case ClassLiteral::Property::GETTER: { + Literal* key = property->key()->AsLiteral(); + DCHECK_NULL(private_accessors.LookupOrInsert(key)->getter); + private_accessors.LookupOrInsert(key)->getter = property; + break; + } + case ClassLiteral::Property::SETTER: { + Literal* key = property->key()->AsLiteral(); + DCHECK_NULL(private_accessors.LookupOrInsert(key)->setter); + private_accessors.LookupOrInsert(key)->setter = property; + break; + } + default: + UNREACHABLE(); + } + } + { RegisterAllocationScope register_scope(this); RegisterList args = register_allocator()->NewGrowableRegisterList(); @@ -2065,8 +2129,8 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { .StoreAccumulatorInRegister(class_boilerplate); // Create computed names and method values nodes to store into the literal. - for (int i = 0; i < expr->properties()->length(); i++) { - ClassLiteral::Property* property = expr->properties()->at(i); + for (int i = 0; i < expr->public_members()->length(); i++) { + ClassLiteral::Property* property = expr->public_members()->at(i); if (property->is_computed_name()) { Register key = register_allocator()->GrowRegisterList(&args); @@ -2099,50 +2163,7 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { } } - if (property->is_private()) { - // Assign private class member's name variables. - switch (property->kind()) { - case ClassLiteral::Property::FIELD: { - // Create the private name symbols for fields during class - // evaluation and store them on the context. These will be - // used as keys later during instance or static initialization. - RegisterAllocationScope private_name_register_scope(this); - Register private_name = register_allocator()->NewRegister(); - VisitForRegisterValue(property->key(), private_name); - builder() - ->LoadLiteral(property->key()->AsLiteral()->AsRawPropertyName()) - .StoreAccumulatorInRegister(private_name) - .CallRuntime(Runtime::kCreatePrivateNameSymbol, private_name); - DCHECK_NOT_NULL(property->private_name_var()); - BuildVariableAssignment(property->private_name_var(), Token::INIT, - HoleCheckMode::kElided); - break; - } - case ClassLiteral::Property::METHOD: { - // Create the closures for private methods. - VisitForAccumulatorValue(property->value()); - BuildVariableAssignment(property->private_name_var(), Token::INIT, - HoleCheckMode::kElided); - break; - } - case ClassLiteral::Property::GETTER: { - Literal* key = property->key()->AsLiteral(); - DCHECK_NULL(private_accessors.LookupOrInsert(key)->getter); - private_accessors.LookupOrInsert(key)->getter = property; - break; - } - case ClassLiteral::Property::SETTER: { - Literal* key = property->key()->AsLiteral(); - DCHECK_NULL(private_accessors.LookupOrInsert(key)->setter); - private_accessors.LookupOrInsert(key)->setter = property; - break; - } - } - // The private fields are initialized in the initializer function and - // the private brand for the private methods are initialized in the - // constructor instead. - continue; - } + DCHECK(!property->is_private()); if (property->kind() == ClassLiteral::Property::FIELD) { // We don't compute field's value here, but instead do it in the @@ -2160,60 +2181,55 @@ void BytecodeGenerator::BuildClassLiteral(ClassLiteral* expr, Register name) { builder()->StoreAccumulatorInRegister(prototype); // Assign to class variable. - if (expr->class_variable() != nullptr) { - DCHECK(expr->class_variable()->IsStackLocal() || - expr->class_variable()->IsContextSlot()); + Variable* class_variable = expr->scope()->class_variable(); + if (class_variable != nullptr && class_variable->is_used()) { + DCHECK(class_variable->IsStackLocal() || class_variable->IsContextSlot()); builder()->LoadAccumulatorWithRegister(class_constructor); - BuildVariableAssignment(expr->class_variable(), Token::INIT, + BuildVariableAssignment(class_variable, Token::INIT, HoleCheckMode::kElided); } - // Create the class brand symbol and store it on the context - // during class evaluation. This will be stored in the - // receiver later in the constructor. - if (expr->scope()->brand() != nullptr) { - Register brand = register_allocator()->NewRegister(); - const AstRawString* class_name = - expr->class_variable() != nullptr - ? expr->class_variable()->raw_name() - : ast_string_constants()->empty_string(); - builder() - ->LoadLiteral(class_name) - .StoreAccumulatorInRegister(brand) - .CallRuntime(Runtime::kCreatePrivateNameSymbol, brand); - BuildVariableAssignment(expr->scope()->brand(), Token::INIT, - HoleCheckMode::kElided); - - // Store the home object for any private methods that need - // them. We do this here once the prototype and brand symbol has - // been created. Private accessors have their home object set later - // when they are defined. - for (int i = 0; i < expr->properties()->length(); i++) { + // Create the closures of private methods, and store the home object for + // any private methods that need them. + if (expr->has_private_methods()) { + for (int i = 0; i < expr->private_members()->length(); i++) { + ClassLiteral::Property* property = expr->private_members()->at(i); + if (property->kind() != ClassLiteral::Property::METHOD) { + continue; + } RegisterAllocationScope register_scope(this); - ClassLiteral::Property* property = expr->properties()->at(i); + VisitForAccumulatorValue(property->value()); + BuildVariableAssignment(property->private_name_var(), Token::INIT, + HoleCheckMode::kElided); + Register home_object = property->private_name_var()->is_static() + ? class_constructor + : prototype; if (property->NeedsHomeObjectOnClassPrototype()) { Register func = register_allocator()->NewRegister(); - BuildVariableLoad(property->private_name_var(), HoleCheckMode::kElided); builder()->StoreAccumulatorInRegister(func); - VisitSetHomeObject(func, prototype, property); + VisitSetHomeObject(func, home_object, property); } } + } - // Define accessors, using only a single call to the runtime for each pair - // of corresponding getters and setters. - for (auto accessors : private_accessors.ordered_accessors()) { - RegisterAllocationScope inner_register_scope(this); - RegisterList accessors_reg = register_allocator()->NewRegisterList(2); - ClassLiteral::Property* getter = accessors.second->getter; - ClassLiteral::Property* setter = accessors.second->setter; - VisitLiteralAccessor(prototype, getter, accessors_reg[0]); - VisitLiteralAccessor(prototype, setter, accessors_reg[1]); - builder()->CallRuntime(Runtime::kCreatePrivateAccessors, accessors_reg); - Variable* var = getter != nullptr ? getter->private_name_var() - : setter->private_name_var(); - DCHECK_NOT_NULL(var); - BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided); - } + // Define private accessors, using only a single call to the runtime for + // each pair of corresponding getters and setters, in the order the first + // component is declared. Store the home objects if necessary. + for (auto accessors : private_accessors.ordered_accessors()) { + RegisterAllocationScope inner_register_scope(this); + RegisterList accessors_reg = register_allocator()->NewRegisterList(2); + ClassLiteral::Property* getter = accessors.second->getter; + ClassLiteral::Property* setter = accessors.second->setter; + bool is_static = + getter != nullptr ? getter->is_static() : setter->is_static(); + Register home_object = is_static ? class_constructor : prototype; + VisitLiteralAccessor(home_object, getter, accessors_reg[0]); + VisitLiteralAccessor(home_object, setter, accessors_reg[1]); + builder()->CallRuntime(Runtime::kCreatePrivateAccessors, accessors_reg); + Variable* var = getter != nullptr ? getter->private_name_var() + : setter->private_name_var(); + DCHECK_NOT_NULL(var); + BuildVariableAssignment(var, Token::INIT, HoleCheckMode::kElided); } if (expr->instance_members_initializer_function() != nullptr) { @@ -3086,7 +3102,8 @@ void BytecodeGenerator::BuildAsyncReturn(int source_position) { .StoreAccumulatorInRegister(args[2]) // done .CallRuntime(Runtime::kInlineAsyncGeneratorResolve, args); } else { - DCHECK(IsAsyncFunction(info()->literal()->kind())); + DCHECK(IsAsyncFunction(info()->literal()->kind()) || + IsAsyncModule(info()->literal()->kind())); RegisterList args = register_allocator()->NewRegisterList(3); builder() ->MoveRegister(generator_object(), args[0]) // generator @@ -3921,7 +3938,8 @@ void BytecodeGenerator::BuildAssignment( Property* property = lhs_data.expr()->AsProperty(); Register object = VisitForRegisterValue(property->obj()); Register key = VisitForRegisterValue(property->key()); - BuildPrivateBrandCheck(property, object); + BuildPrivateBrandCheck(property, object, + MessageTemplate::kInvalidPrivateMemberWrite); BuildPrivateSetterAccess(object, key, value); if (!execution_result()->IsEffect()) { builder()->LoadAccumulatorWithRegister(value); @@ -4004,6 +4022,12 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) { // in the accumulator. When the generator is resumed, the sent value is loaded // in the accumulator. void BytecodeGenerator::BuildSuspendPoint(int position) { + // Because we eliminate jump targets in dead code, we also eliminate resumes + // when the suspend is not emitted because otherwise the below call to Bind + // would start a new basic block and the code would be considered alive. + if (builder()->RemainderOfBlockIsDead()) { + return; + } const int suspend_id = suspend_count_++; RegisterList registers = register_allocator()->AllLiveRegisters(); @@ -4454,12 +4478,14 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { case PRIVATE_GETTER_ONLY: case PRIVATE_GETTER_AND_SETTER: { Register key = VisitForRegisterValue(property->key()); - BuildPrivateBrandCheck(property, obj); + BuildPrivateBrandCheck(property, obj, + MessageTemplate::kInvalidPrivateMemberRead); BuildPrivateGetterAccess(obj, key); break; } case PRIVATE_METHOD: { - BuildPrivateBrandCheck(property, obj); + BuildPrivateBrandCheck(property, obj, + MessageTemplate::kInvalidPrivateMemberRead); // In the case of private methods, property->key() is the function to be // loaded (stored in a context slot), so load this directly. VisitForAccumulatorValue(property->key()); @@ -4499,15 +4525,29 @@ void BytecodeGenerator::BuildPrivateSetterAccess(Register object, } void BytecodeGenerator::BuildPrivateBrandCheck(Property* property, - Register object) { + Register object, + MessageTemplate tmpl) { Variable* private_name = property->key()->AsVariableProxy()->var(); - DCHECK(private_name->requires_brand_check()); + DCHECK(IsPrivateMethodOrAccessorVariableMode(private_name->mode())); ClassScope* scope = private_name->scope()->AsClassScope(); - Variable* brand = scope->brand(); - BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided); - builder()->SetExpressionPosition(property); - builder()->LoadKeyedProperty( - object, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); + if (private_name->is_static()) { + DCHECK_NOT_NULL(scope->class_variable()); + // For static private methods, the only valid receiver is the class. + // Load the class constructor. + BuildVariableLoadForAccumulatorValue(scope->class_variable(), + HoleCheckMode::kElided); + BytecodeLabel return_check; + builder()->CompareReference(object).JumpIfTrue( + ToBooleanMode::kAlreadyBoolean, &return_check); + BuildInvalidPropertyAccess(tmpl, property); + builder()->Bind(&return_check); + } else { + BuildVariableLoadForAccumulatorValue(scope->brand(), + HoleCheckMode::kElided); + builder()->SetExpressionPosition(property); + builder()->LoadKeyedProperty( + object, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); + } } void BytecodeGenerator::VisitPropertyLoadForRegister(Register obj, @@ -5113,7 +5153,8 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { case PRIVATE_GETTER_AND_SETTER: { object = VisitForRegisterValue(property->obj()); key = VisitForRegisterValue(property->key()); - BuildPrivateBrandCheck(property, object); + BuildPrivateBrandCheck(property, object, + MessageTemplate::kInvalidPrivateMemberRead); BuildPrivateGetterAccess(object, key); break; } @@ -5407,7 +5448,8 @@ void BytecodeGenerator::BuildGetIterator(IteratorType hint) { // If method is undefined, // Let syncMethod be GetMethod(obj, @@iterator) builder() - ->GetIterator(obj, feedback_index(feedback_spec()->AddLoadICSlot())) + ->LoadIteratorProperty(obj, + feedback_index(feedback_spec()->AddLoadICSlot())) .StoreAccumulatorInRegister(method); // Let syncIterator be Call(syncMethod, obj) @@ -5426,24 +5468,17 @@ void BytecodeGenerator::BuildGetIterator(IteratorType hint) { RegisterAllocationScope scope(this); Register obj = register_allocator()->NewRegister(); - Register method = register_allocator()->NewRegister(); - - // Let method be GetMethod(obj, @@iterator). - builder() - ->StoreAccumulatorInRegister(obj) - .GetIterator(obj, feedback_index(feedback_spec()->AddLoadICSlot())) - .StoreAccumulatorInRegister(method); + int load_feedback_index = + feedback_index(feedback_spec()->AddLoadICSlot()); + int call_feedback_index = + feedback_index(feedback_spec()->AddCallICSlot()); - // Let iterator be Call(method, obj). - builder()->CallProperty(method, RegisterList(obj), - feedback_index(feedback_spec()->AddCallICSlot())); + // Let method be GetMethod(obj, @@iterator) and + // iterator be Call(method, obj). If Type(iterator) is not Object, + // throw a SymbolIteratorInvalid exception. + builder()->StoreAccumulatorInRegister(obj).GetIterator( + obj, load_feedback_index, call_feedback_index); } - - // 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); } } @@ -6102,8 +6137,9 @@ void BytecodeGenerator::BuildGeneratorObjectVariableInitialization() { RegisterAllocationScope register_scope(this); RegisterList args = register_allocator()->NewRegisterList(2); Runtime::FunctionId function_id = - (IsAsyncFunction(info()->literal()->kind()) && - !IsAsyncGeneratorFunction(info()->literal()->kind())) + ((IsAsyncFunction(info()->literal()->kind()) && + !IsAsyncGeneratorFunction(info()->literal()->kind())) || + IsAsyncModule(info()->literal()->kind())) ? Runtime::kInlineAsyncFunctionEnter : Runtime::kInlineCreateJSGeneratorObject; builder() |