Skip to content

Commit

Permalink
Split Prism::Loader#load_node in one lambda per node type
Browse files Browse the repository at this point in the history
* Otherwise load_node is too big to compile and is forced to run in interpreter:
  oracle/truffleruby#3293 (comment)
* For the benchmark at oracle/truffleruby#3293 (comment)
  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
  • Loading branch information
eregon committed Oct 26, 2023
1 parent d088c0c commit a592ec3
Showing 1 changed file with 62 additions and 25 deletions.
87 changes: 62 additions & 25 deletions templates/lib/prism/serialize.rb.erb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ module Prism
@constant_pool = nil

@source = source
define_load_node_lambdas unless RUBY_ENGINE == 'ruby'
end

def load_encoding
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit a592ec3

Please sign in to comment.