diff options
Diffstat (limited to 'deps/v8/src/interpreter/bytecode-generator.cc')
-rw-r--r-- | deps/v8/src/interpreter/bytecode-generator.cc | 169 |
1 files changed, 134 insertions, 35 deletions
diff --git a/deps/v8/src/interpreter/bytecode-generator.cc b/deps/v8/src/interpreter/bytecode-generator.cc index 706580ac14..d3b27b4375 100644 --- a/deps/v8/src/interpreter/bytecode-generator.cc +++ b/deps/v8/src/interpreter/bytecode-generator.cc @@ -915,6 +915,45 @@ class BytecodeGenerator::IteratorRecord final { Register next_; }; +namespace { + +// A map from property names to getter/setter pairs allocated in the zone that +// also provides a way of accessing the pairs in the order they were first +// added so that the generated bytecode is always the same. +class AccessorTable + : public base::TemplateHashMap<Literal, ObjectLiteral::Accessors, + bool (*)(void*, void*), + ZoneAllocationPolicy> { + public: + explicit AccessorTable(Zone* zone) + : base::TemplateHashMap<Literal, ObjectLiteral::Accessors, + bool (*)(void*, void*), ZoneAllocationPolicy>( + Literal::Match, ZoneAllocationPolicy(zone)), + zone_(zone) {} + + Iterator lookup(Literal* literal) { + Iterator it = find(literal, true, ZoneAllocationPolicy(zone_)); + if (it->second == nullptr) { + it->second = new (zone_) ObjectLiteral::Accessors(); + ordered_accessors_.push_back({literal, it->second}); + } + return it; + } + + const std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>>& + ordered_accessors() { + return ordered_accessors_; + } + + private: + std::vector<std::pair<Literal*, ObjectLiteral::Accessors*>> + ordered_accessors_; + + Zone* zone_; +}; + +} // namespace + #ifdef DEBUG static bool IsInEagerLiterals( @@ -1354,7 +1393,8 @@ void BytecodeGenerator::VisitModuleNamespaceImports() { RegisterAllocationScope register_scope(this); Register module_request = register_allocator()->NewRegister(); - ModuleDescriptor* descriptor = closure_scope()->AsModuleScope()->module(); + SourceTextModuleDescriptor* descriptor = + closure_scope()->AsModuleScope()->module(); for (auto entry : descriptor->namespace_imports()) { builder() ->LoadLiteral(Smi::FromInt(entry->module_request)) @@ -2201,6 +2241,19 @@ void BytecodeGenerator::VisitInitializeClassMembersStatement( } } +void BytecodeGenerator::BuildThrowPrivateMethodWriteError( + const AstRawString* name) { + RegisterAllocationScope register_scope(this); + RegisterList args = register_allocator()->NewRegisterList(2); + builder() + ->LoadLiteral(Smi::FromEnum(MessageTemplate::kInvalidPrivateMethodWrite)) + .StoreAccumulatorInRegister(args[0]) + .LoadLiteral(name) + .StoreAccumulatorInRegister(args[1]) + .CallRuntime(Runtime::kNewTypeError, args) + .Throw(); +} + void BytecodeGenerator::BuildPrivateBrandInitialization(Register receiver) { RegisterList brand_args = register_allocator()->NewRegisterList(2); Variable* brand = info()->scope()->outer_scope()->AsClassScope()->brand(); @@ -2366,13 +2419,6 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 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); @@ -2473,14 +2519,13 @@ void BytecodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { // Define accessors, using only a single call to the runtime for each pair of // corresponding getters and setters. - for (AccessorTable::Iterator it = accessor_table.begin(); - it != accessor_table.end(); ++it) { + for (auto accessors : accessor_table.ordered_accessors()) { RegisterAllocationScope inner_register_scope(this); RegisterList args = register_allocator()->NewRegisterList(5); builder()->MoveRegister(literal, args[0]); - VisitForRegisterValue(it->first, args[1]); - VisitObjectLiteralAccessor(literal, it->second->getter, args[2]); - VisitObjectLiteralAccessor(literal, it->second->setter, args[3]); + VisitForRegisterValue(accessors.first, args[1]); + VisitObjectLiteralAccessor(literal, accessors.second->getter, args[2]); + VisitObjectLiteralAccessor(literal, accessors.second->setter, args[3]); builder() ->LoadLiteral(Smi::FromInt(NONE)) .StoreAccumulatorInRegister(args[4]) @@ -3156,6 +3201,13 @@ BytecodeGenerator::AssignmentLhsData::NamedSuperProperty( } // static BytecodeGenerator::AssignmentLhsData +BytecodeGenerator::AssignmentLhsData::PrivateMethod(Register object, + const AstRawString* name) { + return AssignmentLhsData(PRIVATE_METHOD, nullptr, RegisterList(), object, + Register(), nullptr, name); +} +// static +BytecodeGenerator::AssignmentLhsData BytecodeGenerator::AssignmentLhsData::KeyedSuperProperty( RegisterList super_property_args) { return AssignmentLhsData(KEYED_SUPER_PROPERTY, nullptr, super_property_args, @@ -3185,6 +3237,13 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs( Register key = VisitForRegisterValue(property->key()); return AssignmentLhsData::KeyedProperty(object, key); } + case PRIVATE_METHOD: { + DCHECK(!property->IsSuperAccess()); + AccumulatorPreservingScope scope(this, accumulator_preserving_mode); + Register object = VisitForRegisterValue(property->obj()); + const AstRawString* name = property->key()->AsVariableProxy()->raw_name(); + return AssignmentLhsData::PrivateMethod(object, name); + } case NAMED_SUPER_PROPERTY: { AccumulatorPreservingScope scope(this, accumulator_preserving_mode); RegisterList super_property_args = @@ -3219,15 +3278,16 @@ BytecodeGenerator::AssignmentLhsData BytecodeGenerator::PrepareAssignmentLhs( // Build the iteration finalizer called in the finally block of an iteration // protocol execution. This closes the iterator if needed, and suppresses any -// exception it throws if necessary. +// exception it throws if necessary, including the exception when the return +// method is not callable. // // In pseudo-code, this builds: // // if (!done) { // let method = iterator.return // if (method !== null && method !== undefined) { -// if (typeof(method) !== "function") throw TypeError // try { +// if (typeof(method) !== "function") throw TypeError // let return_val = method.call(iterator) // if (!%IsObject(return_val)) throw TypeError // } catch (e) { @@ -3259,33 +3319,35 @@ void BytecodeGenerator::BuildFinalizeIteration( .JumpIfUndefined(iterator_is_done.New()) .JumpIfNull(iterator_is_done.New()); - // if (typeof(method) !== "function") throw TypeError - BytecodeLabel if_callable; - builder() - ->CompareTypeOf(TestTypeOfFlags::LiteralFlag::kFunction) - .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &if_callable); - { - // throw %NewTypeError(kReturnMethodNotCallable) - RegisterAllocationScope register_scope(this); - RegisterList new_type_error_args = register_allocator()->NewRegisterList(2); - builder() - ->LoadLiteral(Smi::FromEnum(MessageTemplate::kReturnMethodNotCallable)) - .StoreAccumulatorInRegister(new_type_error_args[0]) - .LoadLiteral(ast_string_constants()->empty_string()) - .StoreAccumulatorInRegister(new_type_error_args[1]) - .CallRuntime(Runtime::kNewTypeError, new_type_error_args) - .Throw(); - } - builder()->Bind(&if_callable); - { RegisterAllocationScope register_scope(this); BuildTryCatch( // try { + // if (typeof(method) !== "function") throw TypeError // let return_val = method.call(iterator) // if (!%IsObject(return_val)) throw TypeError // } [&]() { + BytecodeLabel if_callable; + builder() + ->CompareTypeOf(TestTypeOfFlags::LiteralFlag::kFunction) + .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &if_callable); + { + // throw %NewTypeError(kReturnMethodNotCallable) + RegisterAllocationScope register_scope(this); + RegisterList new_type_error_args = + register_allocator()->NewRegisterList(2); + builder() + ->LoadLiteral( + Smi::FromEnum(MessageTemplate::kReturnMethodNotCallable)) + .StoreAccumulatorInRegister(new_type_error_args[0]) + .LoadLiteral(ast_string_constants()->empty_string()) + .StoreAccumulatorInRegister(new_type_error_args[1]) + .CallRuntime(Runtime::kNewTypeError, new_type_error_args) + .Throw(); + } + builder()->Bind(&if_callable); + RegisterList args(iterator.object()); builder()->CallProperty( method, args, feedback_index(feedback_spec()->AddCallICSlot())); @@ -3736,6 +3798,10 @@ void BytecodeGenerator::BuildAssignment( lhs_data.super_property_args()); break; } + case PRIVATE_METHOD: { + BuildThrowPrivateMethodWriteError(lhs_data.name()); + break; + } } } @@ -3781,6 +3847,10 @@ void BytecodeGenerator::VisitCompoundAssignment(CompoundAssignment* expr) { lhs_data.super_property_args().Truncate(3)); break; } + case PRIVATE_METHOD: { + BuildThrowPrivateMethodWriteError(lhs_data.name()); + break; + } } BinaryOperation* binop = expr->AsCompoundAssignment()->binary_operation(); FeedbackSlot slot = feedback_spec()->AddBinaryOpICSlot(); @@ -4238,6 +4308,23 @@ void BytecodeGenerator::VisitPropertyLoad(Register obj, Property* property) { case KEYED_SUPER_PROPERTY: VisitKeyedSuperPropertyLoad(property, Register::invalid_value()); break; + case PRIVATE_METHOD: { + Variable* private_name = property->key()->AsVariableProxy()->var(); + + // Perform the brand check. + DCHECK(private_name->requires_brand_check()); + ClassScope* scope = private_name->scope()->AsClassScope(); + Variable* brand = scope->brand(); + BuildVariableLoadForAccumulatorValue(brand, HoleCheckMode::kElided); + builder()->SetExpressionPosition(property); + builder()->LoadKeyedProperty( + obj, feedback_index(feedback_spec()->AddKeyedLoadICSlot())); + + // 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()); + break; + } } } @@ -4342,7 +4429,8 @@ void BytecodeGenerator::VisitCall(Call* expr) { // the semantics of the underlying call type. switch (call_type) { case Call::NAMED_PROPERTY_CALL: - case Call::KEYED_PROPERTY_CALL: { + case Call::KEYED_PROPERTY_CALL: + case Call::PRIVATE_CALL: { Property* property = callee_expr->AsProperty(); VisitAndPushIntoRegisterList(property->obj(), &args); VisitPropertyLoadForRegister(args.last_register(), property, callee); @@ -4678,6 +4766,7 @@ void BytecodeGenerator::VisitDelete(UnaryOperation* unary) { // Delete of an object property is allowed both in sloppy // and strict modes. Property* property = expr->AsProperty(); + DCHECK(!property->IsPrivateReference()); Register object = VisitForRegisterValue(property->obj()); VisitForAccumulatorValue(property->key()); builder()->Delete(object, language_mode()); @@ -4785,6 +4874,11 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { builder()->CallRuntime(Runtime::kLoadKeyedFromSuper, load_super_args); break; } + case PRIVATE_METHOD: { + BuildThrowPrivateMethodWriteError( + property->key()->AsVariableProxy()->raw_name()); + break; + } } // Save result for postfix expressions. @@ -4851,6 +4945,11 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) { .CallRuntime(Runtime::kStoreKeyedToSuper, super_property_args); break; } + case PRIVATE_METHOD: { + BuildThrowPrivateMethodWriteError( + property->key()->AsVariableProxy()->raw_name()); + break; + } } // Restore old value for postfix expressions. |