Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strict parse Liquid::Variable.new objects to a Liquid::C::Expression #111

Merged
merged 3 commits into from
Oct 30, 2020

Conversation

dylanahsmith
Copy link
Contributor

@dylanahsmith dylanahsmith commented Oct 29, 2020

This solves the problem that #96 intended to solve in a simpler way, so that PR can be focused on introducing support for compiling tags to VM code. Instead, this PR compiles the variable expression and filtering into a Liquid::C::Expression object that is stored in the Liquid::Variable object's @name instance variable, which will be evaluated on render.

Benchmark

The liquid benchmark only uses the assign tag {% assign article = pages.frontpage %} and doesn't use the echo tag, so the benchmark is mostly for unaffected code. However, I wrote a micro-benchmark that shows the performance improvement

# frozen_string_literal: true

require 'bundler/setup'
require 'benchmark/ips'
require 'liquid/c'

PARSE_CONTEXT = Liquid::ParseContext.new
CONTEXT = Liquid::Context.new('x' => 1, 'y' => 2)

def parse
  Liquid::Variable.new("x | plus: y", PARSE_CONTEXT)
end

Benchmark.ips do |x|
  x.report("parse") { parse }
  variable = parse
  x.report("render") { variable.render(CONTEXT) }
  x.report("parse & render") { parse.render(CONTEXT) }
end

result on master

               parse     88.381k (± 3.2%) i/s -    445.068k in   5.041305s
              render    510.144k (± 2.3%) i/s -      2.577M in   5.053979s
      parse & render     67.412k (± 4.0%) i/s -    342.414k in   5.088448s

result on this branch

               parse    631.565k (± 3.0%) i/s -      3.160M in   5.009016s
              render    961.840k (± 4.0%) i/s -      4.858M in   5.060674s
      parse & render    355.364k (± 3.3%) i/s -      1.790M in   5.041629s

.parse_context = parse_context,
};
try_variable_strict_parse((VALUE)&parse_args);
RB_GC_GUARD(markup);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why this is needed. How is markup at risk of being GC'd?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't needed before try_variable_strict_parse is called, so the markup local variable could get re-used by the compiler and remove the reference to the object from the C stack. If the only reference to the markup object were passed into this method, then in theory, it seems like the GC could end up cleanup the string before we are done using it.

It probably isn't needed in practice, but it makes the code more obviously correct.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for clarifying!

Copy link
Contributor

@macournoyer macournoyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤯

Just unsure about that push_nil at the end.


if (p.cur.type == TOKEN_EOS)
if (p.cur.type == TOKEN_EOS) {
vm_assembler_add_push_nil(code);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand why you need to push nil here? Is it to make an empty variable leave something on the stack? Since expressions must always return a value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we need something left on the stack since it will be followed by a pop to get the return value

@dylanahsmith dylanahsmith merged commit ea85e64 into master Oct 30, 2020
@dylanahsmith dylanahsmith deleted the c-compile-var-object branch October 30, 2020 13:10
dylanahsmith added a commit that referenced this pull request Jan 7, 2021
Strict parse Liquid::Variable.new objects to a Liquid::C::Expression

(cherry picked from commit ea85e64)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants