From 5ae32b5bc0e07e5b1a4a440bd10345990c0879f4 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Mon, 30 Nov 2020 11:40:59 -0500 Subject: [PATCH 1/4] Implement serialize --- ext/liquid_c/block.c | 11 +++++++++++ ext/liquid_c/document_body.c | 28 ++++++++++++++++++++++++++++ ext/liquid_c/document_body.h | 9 +++++++++ lib/liquid/c.rb | 12 ++++++++++++ 4 files changed, 60 insertions(+) diff --git a/ext/liquid_c/block.c b/ext/liquid_c/block.c index 9ce95888..5eab0835 100644 --- a/ext/liquid_c/block.c +++ b/ext/liquid_c/block.c @@ -515,6 +515,16 @@ static VALUE block_body_disassemble(VALUE self) document_body_get_constants_ptr(entry), (const VALUE *)body->tags.data); } +static VALUE block_body_dump(VALUE self) +{ + block_body_t *body; + BlockBody_Get_Struct(self, body); + ensure_body_compiled(body); + + return document_body_dump(body->as.compiled.document_body_entry.body, + (uint32_t)body->as.compiled.document_body_entry.buffer_offset); +} + static VALUE block_body_add_evaluate_expression(VALUE self, VALUE expression) { @@ -604,6 +614,7 @@ void liquid_define_block_body() rb_define_method(cLiquidCBlockBody, "blank?", block_body_blank_p, 0); rb_define_method(cLiquidCBlockBody, "nodelist", block_body_nodelist, 0); rb_define_method(cLiquidCBlockBody, "disassemble", block_body_disassemble, 0); + rb_define_method(cLiquidCBlockBody, "dump", block_body_dump, 0); rb_define_method(cLiquidCBlockBody, "add_evaluate_expression", block_body_add_evaluate_expression, 1); rb_define_method(cLiquidCBlockBody, "add_find_variable", block_body_add_find_variable, 1); diff --git a/ext/liquid_c/document_body.c b/ext/liquid_c/document_body.c index 922920bc..05cd52b4 100644 --- a/ext/liquid_c/document_body.c +++ b/ext/liquid_c/document_body.c @@ -132,6 +132,34 @@ void document_body_write_block_body(VALUE self, bool blank, uint32_t render_scor } } + +VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_index) +{ + assert(BUILTIN_TYPE(body->constants) == T_ARRAY); + + uint32_t buffer_len = (uint32_t)c_buffer_size(&body->buffer); + + VALUE constants = rb_marshal_dump(body->constants, Qnil); + uint32_t constants_len = (uint32_t)RSTRING_LEN(constants); + + VALUE str = rb_str_buf_new(sizeof(document_body_header_t) + buffer_len + constants_len); + + document_body_header_t header = { + .entrypoint_block_index = entrypoint_block_index, + .buffer_offset = sizeof(document_body_header_t), + .buffer_len = buffer_len, + .constants_offset = sizeof(document_body_header_t) + buffer_len, + .constants_len = constants_len + }; + + rb_str_cat(str, (const char *)&header, sizeof(document_body_header_t)); + rb_str_cat(str, (const char *)body->buffer.data, buffer_len); + rb_str_append(str, constants); + + return str; +} + + void liquid_define_document_body() { cLiquidCDocumentBody = rb_define_class_under(mLiquidC, "DocumentBody", rb_cObject); diff --git a/ext/liquid_c/document_body.h b/ext/liquid_c/document_body.h index c4923cc2..f4470a84 100644 --- a/ext/liquid_c/document_body.h +++ b/ext/liquid_c/document_body.h @@ -26,6 +26,14 @@ typedef struct document_body { c_buffer_t buffer; } document_body_t; +typedef struct document_body_header { + uint32_t entrypoint_block_index; + uint32_t buffer_offset; + uint32_t buffer_len; + uint32_t constants_offset; + uint32_t constants_len; +} document_body_header_t; + typedef struct document_body_entry { document_body_t *body; size_t buffer_offset; @@ -34,6 +42,7 @@ typedef struct document_body_entry { void liquid_define_document_body(); VALUE document_body_new_instance(); void document_body_write_block_body(VALUE self, bool blank, uint32_t render_score, vm_assembler_t *code, document_body_entry_t *entry); +VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_index); static inline void document_body_entry_mark(document_body_entry_t *entry) { diff --git a/lib/liquid/c.rb b/lib/liquid/c.rb index d315612e..0f670732 100644 --- a/lib/liquid/c.rb +++ b/lib/liquid/c.rb @@ -109,6 +109,18 @@ def parse(tokenizer, parse_context) end end +Liquid::Template.class_eval do + def dump + @root.dump + end +end + +Liquid::Document.class_eval do + def dump + @body.dump + end +end + Liquid::Variable.class_eval do class << self # @api private From fc973fec3383be3ffaca3dd3980f2ffaa8456bd4 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 8 Jan 2021 10:45:16 -0500 Subject: [PATCH 2/4] Refactor entrypoint_block_index to entrypoint_block_offset --- ext/liquid_c/document_body.c | 4 ++-- ext/liquid_c/document_body.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/liquid_c/document_body.c b/ext/liquid_c/document_body.c index 05cd52b4..27ec8987 100644 --- a/ext/liquid_c/document_body.c +++ b/ext/liquid_c/document_body.c @@ -133,7 +133,7 @@ void document_body_write_block_body(VALUE self, bool blank, uint32_t render_scor } -VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_index) +VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_offset) { assert(BUILTIN_TYPE(body->constants) == T_ARRAY); @@ -145,7 +145,7 @@ VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_index) VALUE str = rb_str_buf_new(sizeof(document_body_header_t) + buffer_len + constants_len); document_body_header_t header = { - .entrypoint_block_index = entrypoint_block_index, + .entrypoint_block_offset = entrypoint_block_offset, .buffer_offset = sizeof(document_body_header_t), .buffer_len = buffer_len, .constants_offset = sizeof(document_body_header_t) + buffer_len, diff --git a/ext/liquid_c/document_body.h b/ext/liquid_c/document_body.h index f4470a84..8ad8aa5a 100644 --- a/ext/liquid_c/document_body.h +++ b/ext/liquid_c/document_body.h @@ -27,7 +27,7 @@ typedef struct document_body { } document_body_t; typedef struct document_body_header { - uint32_t entrypoint_block_index; + uint32_t entrypoint_block_offset; uint32_t buffer_offset; uint32_t buffer_len; uint32_t constants_offset; @@ -42,7 +42,7 @@ typedef struct document_body_entry { void liquid_define_document_body(); VALUE document_body_new_instance(); void document_body_write_block_body(VALUE self, bool blank, uint32_t render_score, vm_assembler_t *code, document_body_entry_t *entry); -VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_index); +VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_offset); static inline void document_body_entry_mark(document_body_entry_t *entry) { From 75f1c8f31ff492d9172499955f605202aec194b8 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 8 Jan 2021 10:58:38 -0500 Subject: [PATCH 3/4] Implement version in document_body_header_t --- ext/liquid_c/document_body.c | 1 + ext/liquid_c/document_body.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/ext/liquid_c/document_body.c b/ext/liquid_c/document_body.c index 27ec8987..74648160 100644 --- a/ext/liquid_c/document_body.c +++ b/ext/liquid_c/document_body.c @@ -145,6 +145,7 @@ VALUE document_body_dump(document_body_t *body, uint32_t entrypoint_block_offset VALUE str = rb_str_buf_new(sizeof(document_body_header_t) + buffer_len + constants_len); document_body_header_t header = { + .version = DOCUMENT_BODY_CURRENT_VERSION, .entrypoint_block_offset = entrypoint_block_offset, .buffer_offset = sizeof(document_body_header_t), .buffer_len = buffer_len, diff --git a/ext/liquid_c/document_body.h b/ext/liquid_c/document_body.h index 8ad8aa5a..7dcf43ed 100644 --- a/ext/liquid_c/document_body.h +++ b/ext/liquid_c/document_body.h @@ -26,7 +26,12 @@ typedef struct document_body { c_buffer_t buffer; } document_body_t; +/* Bump this version every time a backwards incompatible change has been made in the serialization headers. + */ +#define DOCUMENT_BODY_CURRENT_VERSION 0 + typedef struct document_body_header { + uint32_t version; uint32_t entrypoint_block_offset; uint32_t buffer_offset; uint32_t buffer_len; From f26621c4efd20b06aa559f1c85e3b2e9bca52228 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Fri, 8 Jan 2021 11:01:38 -0500 Subject: [PATCH 4/4] Check for little endian in extconf.rb --- ext/liquid_c/extconf.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/liquid_c/extconf.rb b/ext/liquid_c/extconf.rb index 6d823c9b..b860a7bc 100644 --- a/ext/liquid_c/extconf.rb +++ b/ext/liquid_c/extconf.rb @@ -1,5 +1,11 @@ # frozen_string_literal: true require 'mkmf' + +# if system endianness == network endianness (big endian) +if [1].pack('I') == [1].pack('N') + raise 'System incompatible with liquid-c, only little endian systems supported' +end + $CFLAGS << ' -std=c11 -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers' append_cflags('-fvisibility=hidden') # In Ruby 2.6 and earlier, the Ruby headers did not have struct timespec defined