Skip to content

Refactor to support liquid-c VM compilation of variables#1294

Merged
dylanahsmith merged 4 commits into
masterfrom
changes-for-liquid-c-vm-variable
Sep 30, 2020
Merged

Refactor to support liquid-c VM compilation of variables#1294
dylanahsmith merged 4 commits into
masterfrom
changes-for-liquid-c-vm-variable

Conversation

@dylanahsmith
Copy link
Copy Markdown
Contributor

Problem

In liquid-c, I would like to stop maintaining full compatibility with Liquid::BlockBody#nodelist, but right now liquid-c is being tested against both the liquid unit and integration tests, both of which have some coupling to that nodelist. Specifically, for liquid-c compilation of variables into VM code (Shopify/liquid-c#59) I wanted to avoid creating Liquid::Variable objects from the VM code, where we currently have direct node class comparison in the liquid tests.

Also, as part of having a different internal representation of Liquid::Variable, I would also like to use garbage collectable symbols for filter names in liquid-c, which a liquid integration test prevents.

Solution

I moved the test for ParseTreeVisitor to the test/unit directory, since that interface is deeply coupled to the nodelist. I also looked through the unit tests to find any that seem useful in testing liquid-c and converted some of them to integration tests.

I changed SecurityTest#test_does_not_add_filters_to_symbol_table to run the garbage collector before asserting that no new symbols were added, to exclude symbols that can be garbage collected. However, that alone proved to be unreliable since MRI uses an imprecise GC to mark the C stack, which can cause deterministic failures for a given build of ruby, which I had actually debugged to confirm that this was the case. To make this reliable, I used a separate thread for the code that created the symbol, so the symbol VALUE would only be written on a separate stack that wouldn't be marked once the thread has finished.

I've also extracted some code from Liquid::BlockBody#render_node rescue code into a rescue_render_node method to re-use in liquid-c for simplicity and to reduce duplication, since it doesn't seem like it is on a hot code path.

Comment thread lib/liquid/block_body.rb

test = %( {{ "some_string" | a_bad_filter }} )
# MRI imprecisely marks objects found on the C stack, which can result
# in uninitialized memory being marked. This can even result in the test failing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That is weird. TIL!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MRI's solution to marking VALUE references in running C functions is to scan the stack/registers for things that look like VALUE pointers heuristically. Uninitialized memory sometimes looks like a VALUE.

The ParseTreeVisitor exposes the liquid internals that won't be
kept compatible with liquid-c, so move it out of the integration
tests directory so that we can easily ignore it when testing liquid-c
since I would like to continue supporting these tests in liquid-c
in the foreseeable future.
@dylanahsmith dylanahsmith force-pushed the changes-for-liquid-c-vm-variable branch from cddd8ea to 33760f0 Compare September 25, 2020 15:25

test = %( {{ "some_string" | a_bad_filter }} )
# MRI imprecisely marks objects found on the C stack, which can result
# in uninitialized memory being marked. This can even result in the test failing
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

MRI's solution to marking VALUE references in running C functions is to scan the stack/registers for things that look like VALUE pointers heuristically. Uninitialized memory sometimes looks like a VALUE.

@dylanahsmith dylanahsmith merged commit efef03d into master Sep 30, 2020
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