From a592ec346a46b84dabbd0282bdbf91804d950910 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Thu, 12 Oct 2023 16:54:44 +0200 Subject: [PATCH] Split Prism::Loader#load_node in one lambda per node type * Otherwise load_node is too big to compile and is forced to run in interpreter: https://github.com/oracle/truffleruby/issues/3293#issuecomment-1759730996 * For the benchmark at https://github.com/oracle/truffleruby/issues/3293#issuecomment-1759790280 TruffleRuby Native 23.1.0: Before: 10.574041 After: 5.592436 JRuby 9.4.3.0: Before: 7.037780 After: 3.995317 JRuby 9.4.3.0 -Xcompile.invokedynamic=true: Before: 7.047832 After: 2.269294 --- templates/lib/prism/serialize.rb.erb | 87 ++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/templates/lib/prism/serialize.rb.erb b/templates/lib/prism/serialize.rb.erb index 2dda111d354..01588c6dae3 100644 --- a/templates/lib/prism/serialize.rb.erb +++ b/templates/lib/prism/serialize.rb.erb @@ -47,6 +47,7 @@ module Prism @constant_pool = nil @source = source + define_load_node_lambdas unless RUBY_ENGINE == 'ruby' end def load_encoding @@ -194,32 +195,68 @@ module Prism load_constant(index - 1) if index != 0 end - def load_node - type = io.getbyte - location = load_location + if RUBY_ENGINE == 'ruby' + def load_node + type = io.getbyte + location = load_location + + case type + <%- nodes.each_with_index do |node, index| -%> + when <%= index + 1 %> then + <%- if node.needs_serialized_length? -%> + load_serialized_length + <%- end -%> + <%= node.name %>.new(<%= (node.fields.map { |field| + case field + when Prism::NodeField then "load_node" + when Prism::OptionalNodeField then "load_optional_node" + when Prism::StringField then "load_string" + when Prism::NodeListField then "Array.new(load_varint) { load_node }" + when Prism::ConstantField then "load_required_constant" + when Prism::OptionalConstantField then "load_optional_constant" + when Prism::ConstantListField then "Array.new(load_varint) { load_required_constant }" + when Prism::LocationField then "load_location" + when Prism::OptionalLocationField then "load_optional_location" + when Prism::UInt32Field, Prism::FlagsField then "load_varint" + else raise + end + } + ["location"]).join(", ") -%>) + <%- end -%> + end + end + else + def load_node + type = io.getbyte + @load_node_lambdas[type].call + end - case type - <%- nodes.each_with_index do |node, index| -%> - when <%= index + 1 %> then - <%- if node.needs_serialized_length? -%> - load_serialized_length - <%- end -%> - <%= node.name %>.new(<%= (node.fields.map { |field| - case field - when Prism::NodeField then "load_node" - when Prism::OptionalNodeField then "load_optional_node" - when Prism::StringField then "load_string" - when Prism::NodeListField then "Array.new(load_varint) { load_node }" - when Prism::ConstantField then "load_required_constant" - when Prism::OptionalConstantField then "load_optional_constant" - when Prism::ConstantListField then "Array.new(load_varint) { load_required_constant }" - when Prism::LocationField then "load_location" - when Prism::OptionalLocationField then "load_optional_location" - when Prism::UInt32Field, Prism::FlagsField then "load_varint" - else raise - end - } + ["location"]).join(", ") -%>) - <%- end -%> + def define_load_node_lambdas + @load_node_lambdas = [ + nil, + <%- nodes.each do |node| -%> + -> { + location = load_location + <%- if node.needs_serialized_length? -%> + load_serialized_length + <%- end -%> + <%= node.name %>.new(<%= (node.fields.map { |field| + case field + when Prism::NodeField then "load_node" + when Prism::OptionalNodeField then "load_optional_node" + when Prism::StringField then "load_string" + when Prism::NodeListField then "Array.new(load_varint) { load_node }" + when Prism::ConstantField then "load_required_constant" + when Prism::OptionalConstantField then "load_optional_constant" + when Prism::ConstantListField then "Array.new(load_varint) { load_required_constant }" + when Prism::LocationField then "load_location" + when Prism::OptionalLocationField then "load_optional_location" + when Prism::UInt32Field, Prism::FlagsField then "load_varint" + else raise + end + } + ["location"]).join(", ") -%>) + }, + <%- end -%> + ] end end end