mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 03:32:45 +00:00 
			
		
		
		
	LibIDL+LibWeb: Resolve distinguishing argument index at build time
Aside from the obvious performance benefits, this will allow us to properly handle dictionary types. (whose dictionary-ness is only known at build-time) Much of the rest of the overload resolution algorithm steps can (and should) be evaluated at build-time as well, but this is a good first step.
This commit is contained in:
		
							parent
							
								
									048e179572
								
							
						
					
					
						commit
						f837f02eea
					
				
					 4 changed files with 44 additions and 43 deletions
				
			
		|  | @ -1925,7 +1925,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@@overload_suffi | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // https://webidl.spec.whatwg.org/#compute-the-effective-overload-set
 | // https://webidl.spec.whatwg.org/#compute-the-effective-overload-set
 | ||||||
| static EffectiveOverloadSet compute_the_effective_overload_set(auto const& overload_set) | static Vector<EffectiveOverloadSet::Item> compute_the_effective_overload_set(auto const& overload_set) | ||||||
| { | { | ||||||
|     // 1. Let S be an ordered set.
 |     // 1. Let S be an ordered set.
 | ||||||
|     Vector<EffectiveOverloadSet::Item> overloads; |     Vector<EffectiveOverloadSet::Item> overloads; | ||||||
|  | @ -2048,7 +2048,7 @@ static EffectiveOverloadSet compute_the_effective_overload_set(auto const& overl | ||||||
|         overload_id++; |         overload_id++; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return EffectiveOverloadSet { move(overloads) }; |     return overloads; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static DeprecatedString generate_constructor_for_idl_type(Type const& type) | static DeprecatedString generate_constructor_for_idl_type(Type const& type) | ||||||
|  | @ -2090,6 +2090,30 @@ static DeprecatedString generate_constructor_for_idl_type(Type const& type) | ||||||
|     VERIFY_NOT_REACHED(); |     VERIFY_NOT_REACHED(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index
 | ||||||
|  | static size_t resolve_distinguishing_argument_index(Vector<EffectiveOverloadSet::Item> const& items, size_t argument_count) | ||||||
|  | { | ||||||
|  |     for (auto argument_index = 0u; argument_index < argument_count; ++argument_index) { | ||||||
|  |         bool found_indistinguishable = false; | ||||||
|  | 
 | ||||||
|  |         for (auto first_item_index = 0u; first_item_index < items.size(); ++first_item_index) { | ||||||
|  |             for (auto second_item_index = first_item_index + 1; second_item_index < items.size(); ++second_item_index) { | ||||||
|  |                 if (!items[first_item_index].types[argument_index]->is_distinguishable_from(items[second_item_index].types[argument_index])) { | ||||||
|  |                     found_indistinguishable = true; | ||||||
|  |                     break; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             if (found_indistinguishable) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (!found_indistinguishable) | ||||||
|  |             return argument_index; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     VERIFY_NOT_REACHED(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, DeprecatedString const& class_name) | static void generate_overload_arbiter(SourceGenerator& generator, auto const& overload_set, DeprecatedString const& class_name) | ||||||
| { | { | ||||||
|     auto function_generator = generator.fork(); |     auto function_generator = generator.fork(); | ||||||
|  | @ -2102,8 +2126,7 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@) | ||||||
|     Optional<IDL::EffectiveOverloadSet> effective_overload_set; |     Optional<IDL::EffectiveOverloadSet> effective_overload_set; | ||||||
| )~~~"); | )~~~"); | ||||||
| 
 | 
 | ||||||
|     auto all_possible_effective_overloads = compute_the_effective_overload_set(overload_set); |     auto overloads_set = compute_the_effective_overload_set(overload_set); | ||||||
|     auto overloads_set = all_possible_effective_overloads.items(); |  | ||||||
|     auto maximum_argument_count = 0u; |     auto maximum_argument_count = 0u; | ||||||
|     for (auto const& overload : overloads_set) |     for (auto const& overload : overloads_set) | ||||||
|         maximum_argument_count = max(maximum_argument_count, overload.types.size()); |         maximum_argument_count = max(maximum_argument_count, overload.types.size()); | ||||||
|  | @ -2115,29 +2138,28 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@) | ||||||
|     // Namely, since that discards any overloads that don't have the exact number of arguments that were given,
 |     // Namely, since that discards any overloads that don't have the exact number of arguments that were given,
 | ||||||
|     // we simply only provide the overloads that do have that number of arguments.
 |     // we simply only provide the overloads that do have that number of arguments.
 | ||||||
|     for (auto argument_count = 0u; argument_count <= maximum_argument_count; ++argument_count) { |     for (auto argument_count = 0u; argument_count <= maximum_argument_count; ++argument_count) { | ||||||
|         // FIXME: Calculate the distinguishing argument index now instead of at runtime.
 |         Vector<EffectiveOverloadSet::Item> effective_overload_set; | ||||||
| 
 |  | ||||||
|         auto effective_overload_count = 0; |  | ||||||
|         for (auto const& overload : overloads_set) { |         for (auto const& overload : overloads_set) { | ||||||
|             if (overload.types.size() == argument_count) |             if (overload.types.size() == argument_count) | ||||||
|                 effective_overload_count++; |                 effective_overload_set.append(overload); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (effective_overload_count == 0) |         if (effective_overload_set.size() == 0) | ||||||
|             continue; |             continue; | ||||||
| 
 | 
 | ||||||
|  |         auto distinguishing_argument_index = 0u; | ||||||
|  |         if (effective_overload_set.size() > 1) | ||||||
|  |             distinguishing_argument_index = resolve_distinguishing_argument_index(effective_overload_set, argument_count); | ||||||
|  | 
 | ||||||
|         function_generator.set("current_argument_count", DeprecatedString::number(argument_count)); |         function_generator.set("current_argument_count", DeprecatedString::number(argument_count)); | ||||||
|         function_generator.set("overload_count", DeprecatedString::number(effective_overload_count)); |         function_generator.set("overload_count", DeprecatedString::number(effective_overload_set.size())); | ||||||
|         function_generator.appendln(R"~~~( |         function_generator.appendln(R"~~~( | ||||||
|     case @current_argument_count@: { |     case @current_argument_count@: { | ||||||
|         Vector<IDL::EffectiveOverloadSet::Item> overloads; |         Vector<IDL::EffectiveOverloadSet::Item> overloads; | ||||||
|         overloads.ensure_capacity(@overload_count@); |         overloads.ensure_capacity(@overload_count@); | ||||||
| )~~~"); | )~~~"); | ||||||
| 
 | 
 | ||||||
|         for (auto& overload : overloads_set) { |         for (auto& overload : effective_overload_set) { | ||||||
|             if (overload.types.size() != argument_count) |  | ||||||
|                 continue; |  | ||||||
| 
 |  | ||||||
|             StringBuilder types_builder; |             StringBuilder types_builder; | ||||||
|             types_builder.append("Vector<NonnullRefPtr<IDL::Type const>> { "sv); |             types_builder.append("Vector<NonnullRefPtr<IDL::Type const>> { "sv); | ||||||
|             StringBuilder optionality_builder; |             StringBuilder optionality_builder; | ||||||
|  | @ -2175,8 +2197,9 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@function.name:snakecase@) | ||||||
|             function_generator.appendln("        overloads.empend(@overload.callable_id@, @overload.types@, @overload.optionality_values@);"); |             function_generator.appendln("        overloads.empend(@overload.callable_id@, @overload.types@, @overload.optionality_values@);"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         function_generator.set("overload_set.distinguishing_argument_index", DeprecatedString::number(distinguishing_argument_index)); | ||||||
|         function_generator.append(R"~~~( |         function_generator.append(R"~~~( | ||||||
|         effective_overload_set.emplace(move(overloads)); |         effective_overload_set.emplace(move(overloads), @overload_set.distinguishing_argument_index@); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| )~~~"); | )~~~"); | ||||||
|  |  | ||||||
|  | @ -293,30 +293,6 @@ bool Type::is_json(Interface const& interface) const | ||||||
|     return false; |     return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // https://webidl.spec.whatwg.org/#dfn-distinguishing-argument-index
 |  | ||||||
| int EffectiveOverloadSet::distinguishing_argument_index() |  | ||||||
| { |  | ||||||
|     for (auto argument_index = 0u; argument_index < m_argument_count; ++argument_index) { |  | ||||||
|         bool found_indistinguishable = false; |  | ||||||
| 
 |  | ||||||
|         for (auto first_item_index = 0u; first_item_index < m_items.size(); ++first_item_index) { |  | ||||||
|             for (auto second_item_index = first_item_index + 1; second_item_index < m_items.size(); ++second_item_index) { |  | ||||||
|                 if (!m_items[first_item_index].types[argument_index]->is_distinguishable_from(m_items[second_item_index].types[argument_index])) { |  | ||||||
|                     found_indistinguishable = true; |  | ||||||
|                     break; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             if (found_indistinguishable) |  | ||||||
|                 break; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!found_indistinguishable) |  | ||||||
|             return argument_index; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     VERIFY_NOT_REACHED(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void EffectiveOverloadSet::remove_all_other_entries() | void EffectiveOverloadSet::remove_all_other_entries() | ||||||
| { | { | ||||||
|     Vector<Item> new_items; |     Vector<Item> new_items; | ||||||
|  |  | ||||||
|  | @ -415,9 +415,9 @@ public: | ||||||
|         Vector<Optionality> optionality_values; |         Vector<Optionality> optionality_values; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     EffectiveOverloadSet(Vector<Item> items) |     EffectiveOverloadSet(Vector<Item> items, size_t distinguishing_argument_index) | ||||||
|         : m_items(move(items)) |         : m_items(move(items)) | ||||||
|         , m_argument_count(m_items.is_empty() ? 0 : m_items.first().types.size()) |         , m_distinguishing_argument_index(distinguishing_argument_index) | ||||||
|     { |     { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -433,7 +433,7 @@ public: | ||||||
|     bool is_empty() const { return m_items.is_empty(); } |     bool is_empty() const { return m_items.is_empty(); } | ||||||
|     size_t size() const { return m_items.size(); } |     size_t size() const { return m_items.size(); } | ||||||
| 
 | 
 | ||||||
|     int distinguishing_argument_index(); |     size_t distinguishing_argument_index() const { return m_distinguishing_argument_index; } | ||||||
| 
 | 
 | ||||||
|     template<typename Matches> |     template<typename Matches> | ||||||
|     bool has_overload_with_matching_argument_at_index(size_t index, Matches matches) |     bool has_overload_with_matching_argument_at_index(size_t index, Matches matches) | ||||||
|  | @ -454,7 +454,7 @@ public: | ||||||
| private: | private: | ||||||
|     // FIXME: This should be an "ordered set".
 |     // FIXME: This should be an "ordered set".
 | ||||||
|     Vector<Item> m_items; |     Vector<Item> m_items; | ||||||
|     size_t m_argument_count; |     size_t m_distinguishing_argument_index { 0 }; | ||||||
| 
 | 
 | ||||||
|     Optional<size_t> m_last_matching_item_index; |     Optional<size_t> m_last_matching_item_index; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -56,6 +56,8 @@ static bool has_overload_with_argument_type_or_subtype_matching(IDL::EffectiveOv | ||||||
| // https://webidl.spec.whatwg.org/#es-overloads
 | // https://webidl.spec.whatwg.org/#es-overloads
 | ||||||
| JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads) | JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::EffectiveOverloadSet& overloads) | ||||||
| { | { | ||||||
|  |     // FIXME: The vast majority of this algorithm can be (and must be, in order to resolve the dictionary
 | ||||||
|  |     //  related FIXMEs below) evaluated at code-generation time.
 | ||||||
|     // 1. Let maxarg be the length of the longest type list of the entries in S.
 |     // 1. Let maxarg be the length of the longest type list of the entries in S.
 | ||||||
|     // 2. Let n be the size of args.
 |     // 2. Let n be the size of args.
 | ||||||
|     // 3. Initialize argcount to be min(maxarg, n).
 |     // 3. Initialize argcount to be min(maxarg, n).
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Idan Horowitz
						Idan Horowitz