From d28a941f9cf5a6ed6a61693ae86234c6734f676d Mon Sep 17 00:00:00 2001 From: Michael Go Date: Tue, 1 Feb 2022 13:50:49 -0400 Subject: [PATCH] store constant index in instruction --- ext/liquid_c/block.c | 18 +++--- ext/liquid_c/expression.c | 12 +++- ext/liquid_c/variable.c | 12 +++- ext/liquid_c/vm.c | 76 +++++++++++++++++--------- ext/liquid_c/vm.h | 2 +- ext/liquid_c/vm_assembler.c | 103 ++++++++++++++++++++++++++++++----- ext/liquid_c/vm_assembler.h | 41 ++++++++++---- test/unit/block_test.rb | 20 +++---- test/unit/expression_test.rb | 8 +-- 9 files changed, 214 insertions(+), 78 deletions(-) diff --git a/ext/liquid_c/block.c b/ext/liquid_c/block.c index e15b81c7..5bd90070 100644 --- a/ext/liquid_c/block.c +++ b/ext/liquid_c/block.c @@ -365,7 +365,6 @@ static VALUE block_body_remove_blank_strings(VALUE self) rb_raise(rb_eRuntimeError, "remove_blank_strings only support being called on a blank block body"); } - VALUE *const_ptr = (VALUE *)body->as.intermediate.code->constants.data; uint8_t *ip = body->as.intermediate.code->instructions.data; while (*ip != OP_LEAVE) { @@ -380,7 +379,7 @@ static VALUE block_body_remove_blank_strings(VALUE self) body->as.intermediate.render_score--; } } - liquid_vm_next_instruction((const uint8_t **)&ip, (const VALUE **)&const_ptr); + liquid_vm_next_instruction((const uint8_t **)&ip); } return Qnil; @@ -410,7 +409,7 @@ static VALUE block_body_nodelist(VALUE self) VALUE nodelist = rb_ary_new_capa(body_header->render_score); - const VALUE *const_ptr = document_body_get_constants_ptr(entry); + const VALUE *constants = &entry->body->constants; const uint8_t *ip = block_body_instructions_ptr(body_header); while (true) { switch (*ip) { @@ -434,7 +433,9 @@ static VALUE block_body_nodelist(VALUE self) } case OP_WRITE_NODE: { - rb_ary_push(nodelist, const_ptr[0]); + uint16_t constant_index = (ip[1] << 8) | ip[2]; + VALUE node = RARRAY_AREF(*constants, constant_index); + rb_ary_push(nodelist, node); break; } @@ -442,7 +443,7 @@ static VALUE block_body_nodelist(VALUE self) rb_ary_push(nodelist, variable_placeholder); break; } - liquid_vm_next_instruction(&ip, &const_ptr); + liquid_vm_next_instruction(&ip); } loop_break: @@ -458,8 +459,11 @@ static VALUE block_body_disassemble(VALUE self) document_body_entry_t *entry = &body->as.compiled.document_body_entry; block_body_header_t *header = document_body_get_block_body_header_ptr(entry); const uint8_t *start_ip = block_body_instructions_ptr(header); - return vm_assembler_disassemble(start_ip, start_ip + header->instructions_bytes, - document_body_get_constants_ptr(entry)); + return vm_assembler_disassemble( + start_ip, + start_ip + header->instructions_bytes, + &entry->body->constants + ); } diff --git a/ext/liquid_c/expression.c b/ext/liquid_c/expression.c index aced239a..db7f99b7 100644 --- a/ext/liquid_c/expression.c +++ b/ext/liquid_c/expression.c @@ -94,8 +94,16 @@ static VALUE expression_disassemble(VALUE self) { expression_t *expression; Expression_Get_Struct(self, expression); - return vm_assembler_disassemble(expression->code.instructions.data, expression->code.instructions.data_end, - (const VALUE *)expression->code.constants.data); + + VALUE constants = rb_ary_new(); + uint32_t constants_len = (uint32_t)(c_buffer_size(&expression->code.constants) / sizeof(VALUE)); + rb_ary_cat(constants, (VALUE *)expression->code.constants.data, constants_len); + + return vm_assembler_disassemble( + expression->code.instructions.data, + expression->code.instructions.data_end, + &constants + ); } void liquid_define_expression(void) diff --git a/ext/liquid_c/variable.c b/ext/liquid_c/variable.c index 4e269176..dbd10630 100644 --- a/ext/liquid_c/variable.c +++ b/ext/liquid_c/variable.c @@ -96,8 +96,18 @@ static VALUE variable_strict_parse_rescue(VALUE uncast_args, VALUE exception) vm_assembler_t *code = parse_args->code; // undo partial strict parse + uint8_t *last_constants_data_end = (uint8_t *)code->constants.data + rescue_args->constants_size; + VALUE *const_ptr = (VALUE *)last_constants_data_end; + st_table *constants_table = code->constants_table; + + while((uint8_t *)const_ptr < code->constants.data_end) { + st_data_t key = (st_data_t)const_ptr[0]; + st_delete(constants_table, &key, 0); + const_ptr++; + } + code->instructions.data_end = code->instructions.data + rescue_args->instructions_size; - code->constants.data_end = code->constants.data + rescue_args->constants_size; + code->constants.data_end = last_constants_data_end; code->stack_size = rescue_args->stack_size; if (rb_obj_is_kind_of(exception, cLiquidSyntaxError) == Qfalse) diff --git a/ext/liquid_c/vm.c b/ext/liquid_c/vm.c index ed3c66df..744fdb85 100644 --- a/ext/liquid_c/vm.c +++ b/ext/liquid_c/vm.c @@ -231,20 +231,18 @@ static void hash_bulk_insert(long argc, const VALUE *argv, VALUE hash) static VALUE vm_render_until_error(VALUE uncast_args) { vm_render_until_error_args_t *args = (void *)uncast_args; - const VALUE *const_ptr = args->const_ptr; + const VALUE *constants = args->const_ptr; const uint8_t *ip = args->ip; vm_t *vm = args->vm; VALUE output = args->output; + uint16_t constant_index; + VALUE constant = Qnil; args->ip = NULL; // used by vm_render_rescue, NULL to indicate that it isn't in a rescue block while (true) { switch (*ip++) { case OP_LEAVE: return false; - - case OP_PUSH_CONST: - vm_stack_push(vm, *const_ptr++); - break; case OP_PUSH_NIL: vm_stack_push(vm, Qnil); break; @@ -268,8 +266,14 @@ static VALUE vm_render_until_error(VALUE uncast_args) break; } case OP_FIND_STATIC_VAR: - vm_stack_push(vm, *const_ptr++); - /* fallthrough */ + { + constant_index = (ip[0] << 8) | ip[1]; + constant = constants[constant_index]; + ip += 2; + VALUE value = context_find_variable(&vm->context, constant, Qtrue); + vm_stack_push(vm, value); + break; + } case OP_FIND_VAR: { VALUE key = vm_stack_pop(vm); @@ -279,11 +283,16 @@ static VALUE vm_render_until_error(VALUE uncast_args) } case OP_LOOKUP_CONST_KEY: case OP_LOOKUP_COMMAND: - vm_stack_push(vm, *const_ptr++); - /* fallthrough */ + { + constant_index = (ip[0] << 8) | ip[1]; + constant = constants[constant_index]; + ip += 2; + vm_stack_push(vm, constant); + } + /* fallthrough */ case OP_LOOKUP_KEY: { - bool is_command = ip[-1] == OP_LOOKUP_COMMAND; + bool is_command = ip[-3] == OP_LOOKUP_COMMAND; VALUE key = vm_stack_pop(vm); VALUE object = vm_stack_pop(vm); VALUE result = variable_lookup_key(vm->context.self, object, key, is_command); @@ -313,13 +322,20 @@ static VALUE vm_render_until_error(VALUE uncast_args) case OP_BUILTIN_FILTER: { VALUE filter_name; + uint8_t num_args; + if (ip[-1] == OP_FILTER) { - filter_name = *const_ptr++; + constant_index = (ip[0] << 8) | ip[1]; + constant = constants[constant_index]; + filter_name = RARRAY_AREF(constant, 0); + num_args = RARRAY_AREF(constant, 1); + ip += 2; } else { assert(ip[-1] == OP_BUILTIN_FILTER); filter_name = builtin_filters[*ip++].sym; + num_args = *ip++; // includes input argument } - uint8_t num_args = *ip++; // includes input argument + VALUE *args_ptr = vm_stack_pop_n_use_in_place(vm, num_args); VALUE result = vm_invoke_filter(vm, filter_name, num_args, args_ptr); vm_stack_push(vm, result); @@ -360,13 +376,29 @@ static VALUE vm_render_until_error(VALUE uncast_args) break; } + case OP_PUSH_CONST: + { + constant_index = (ip[0] << 8) | ip[1]; + constant = constants[constant_index]; + ip += 2; + vm_stack_push(vm, constant); + break; + } + case OP_WRITE_NODE: - rb_funcall(cLiquidBlockBody, id_render_node, 3, vm->context.self, output, (VALUE)*const_ptr++); + { + constant_index = (ip[0] << 8) | ip[1]; + constant = constants[constant_index]; + ip += 2; + rb_funcall(cLiquidBlockBody, id_render_node, 3, vm->context.self, output, constant); + if (RARRAY_LEN(vm->context.interrupts)) { return false; } + resource_limits_increment_write_score(vm->context.resource_limits, output); break; + } case OP_RENDER_VARIABLE_RESCUE: // Save state used by vm_render_rescue to rescue from a variable rendering exception args->node_line_number = ip; @@ -374,7 +406,6 @@ static VALUE vm_render_until_error(VALUE uncast_args) // following OP_POP_WRITE_VARIABLE to resume rendering from ip += 3; args->ip = ip; - args->const_ptr = const_ptr; break; case OP_POP_WRITE: { @@ -414,7 +445,7 @@ VALUE liquid_vm_evaluate(VALUE context, vm_assembler_t *code) return ret; } -void liquid_vm_next_instruction(const uint8_t **ip_ptr, const VALUE **const_ptr_ptr) +void liquid_vm_next_instruction(const uint8_t **ip_ptr) { const uint8_t *ip = *ip_ptr; @@ -436,26 +467,19 @@ void liquid_vm_next_instruction(const uint8_t **ip_ptr, const VALUE **const_ptr_ case OP_BUILTIN_FILTER: case OP_PUSH_INT16: - ip += 2; - break; - - case OP_WRITE_NODE: case OP_PUSH_CONST: + case OP_WRITE_NODE: case OP_FIND_STATIC_VAR: case OP_LOOKUP_CONST_KEY: case OP_LOOKUP_COMMAND: - (*const_ptr_ptr)++; + case OP_FILTER: + ip += 2; break; case OP_RENDER_VARIABLE_RESCUE: ip += 3; break; - case OP_FILTER: - ip++; - (*const_ptr_ptr)++; - break; - case OP_WRITE_RAW_W: case OP_JUMP_FWD_W: { @@ -514,7 +538,7 @@ static VALUE vm_render_rescue(VALUE uncast_args, VALUE exception) enum opcode last_op; do { last_op = *ip; - liquid_vm_next_instruction(&ip, &render_args->const_ptr); + liquid_vm_next_instruction(&ip); } while (last_op != OP_POP_WRITE); render_args->ip = ip; // remove temporary stack values from variable evaluation diff --git a/ext/liquid_c/vm.h b/ext/liquid_c/vm.h index 19bb024b..8319e009 100644 --- a/ext/liquid_c/vm.h +++ b/ext/liquid_c/vm.h @@ -15,7 +15,7 @@ typedef struct vm { void liquid_define_vm(void); vm_t *vm_from_context(VALUE context); void liquid_vm_render(block_body_header_t *block, const VALUE *const_ptr, VALUE context, VALUE output); -void liquid_vm_next_instruction(const uint8_t **ip_ptr, const size_t **const_ptr_ptr); +void liquid_vm_next_instruction(const uint8_t **ip_ptr); bool liquid_vm_filtering(VALUE context); VALUE liquid_vm_evaluate(VALUE context, vm_assembler_t *code); diff --git a/ext/liquid_c/vm_assembler.c b/ext/liquid_c/vm_assembler.c index 5bdf3dd7..12d66f1a 100644 --- a/ext/liquid_c/vm_assembler.c +++ b/ext/liquid_c/vm_assembler.c @@ -74,6 +74,7 @@ void vm_assembler_init(vm_assembler_t *code) { code->instructions = c_buffer_allocate(8); code->constants = c_buffer_allocate(8 * sizeof(VALUE)); + code->constants_table = st_init_numtable(); vm_assembler_common_init(code); } @@ -81,6 +82,7 @@ void vm_assembler_reset(vm_assembler_t *code) { c_buffer_reset(&code->instructions); c_buffer_reset(&code->constants); + st_clear(code->constants_table); vm_assembler_common_init(code); } @@ -88,6 +90,7 @@ void vm_assembler_free(vm_assembler_t *code) { c_buffer_free(&code->instructions); c_buffer_free(&code->constants); + st_free_table(code->constants_table); } void vm_assembler_gc_mark(vm_assembler_t *code) @@ -95,12 +98,20 @@ void vm_assembler_gc_mark(vm_assembler_t *code) c_buffer_rb_gc_mark(&code->constants); } -VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, const VALUE *const_ptr) +VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, const VALUE *constants) { const uint8_t *ip = start_ip; VALUE output = rb_str_buf_new(32); + VALUE constant = Qnil; + while (ip < end_ip) { rb_str_catf(output, "0x%04lx: ", ip - start_ip); + + if (vm_assembler_opcode_has_constant(*ip)) { + uint16_t constant_index = (ip[1] << 8) | ip[2]; + constant = RARRAY_AREF(*constants, constant_index); + } + switch (*ip) { case OP_LEAVE: rb_str_catf(output, "leave\n"); @@ -177,28 +188,32 @@ VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, c } case OP_WRITE_NODE: - rb_str_catf(output, "write_node(%+"PRIsVALUE")\n", const_ptr[0]); + rb_str_catf(output, "write_node(%+"PRIsVALUE")\n", constant); break; case OP_PUSH_CONST: - rb_str_catf(output, "push_const(%+"PRIsVALUE")\n", const_ptr[0]); + rb_str_catf(output, "push_const(%+"PRIsVALUE")\n", constant); break; case OP_FIND_STATIC_VAR: - rb_str_catf(output, "find_static_var(%+"PRIsVALUE")\n", const_ptr[0]); + rb_str_catf(output, "find_static_var(%+"PRIsVALUE")\n", constant); break; case OP_LOOKUP_CONST_KEY: - rb_str_catf(output, "lookup_const_key(%+"PRIsVALUE")\n", const_ptr[0]); + rb_str_catf(output, "lookup_const_key(%+"PRIsVALUE")\n", constant); break; case OP_LOOKUP_COMMAND: - rb_str_catf(output, "lookup_command(%+"PRIsVALUE")\n", const_ptr[0]); + rb_str_catf(output, "lookup_command(%+"PRIsVALUE")\n", constant); break; case OP_FILTER: - rb_str_catf(output, "filter(name: %+"PRIsVALUE", num_args: %u)\n", const_ptr[0], ip[1]); + { + VALUE filter_name = RARRAY_AREF(constant, 0); + uint8_t num_args = RARRAY_AREF(constant, 1); + rb_str_catf(output, "filter(name: %+"PRIsVALUE", num_args: %u)\n", filter_name, num_args); break; + } case OP_BUILTIN_FILTER: rb_str_catf(output, "builtin_filter(name: :%s, num_args: %u)\n", builtin_filters[ip[1]].name, ip[2]); @@ -208,16 +223,58 @@ VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, c rb_str_catf(output, "\n", ip[0]); break; } - liquid_vm_next_instruction(&ip, &const_ptr); + liquid_vm_next_instruction(&ip); } return output; } +struct merge_constants_table_func_args { + st_table *hash; + size_t increment_amount; +}; + +static int merge_constants_table(st_data_t key, st_data_t value, VALUE _arg) +{ + struct merge_constants_table_func_args *arg = (struct merge_constants_table_func_args *)_arg; + st_table *dest_hash = arg->hash; + uint16_t new_value = value + arg->increment_amount; + st_insert(dest_hash, key, new_value); + + return ST_CONTINUE; +} + +void update_instructions_constants_table_index_ref(c_buffer_t *instructions, size_t increment_amount, c_buffer_t *constants) +{ + uint8_t *ip = instructions->data; + + while (ip < instructions->data_end) { + if (vm_assembler_opcode_has_constant(*ip)) { + uint16_t constant_index = (ip[1] << 8) | ip[2]; + uint16_t new_constant_index = constant_index + increment_amount; + ip[1] = new_constant_index >> 8; + ip[2] = (uint8_t)new_constant_index; + } + + liquid_vm_next_instruction((const uint8_t **)&ip); + } +} + void vm_assembler_concat(vm_assembler_t *dest, vm_assembler_t *src) { - c_buffer_concat(&dest->instructions, &src->instructions); + size_t dest_element_count = c_buffer_size(&dest->constants) / sizeof(VALUE); + + // merge src constants table into dest constants table with new index + struct merge_constants_table_func_args arg; + arg.hash = dest->constants_table; + arg.increment_amount = dest_element_count; + st_foreach(src->constants_table, merge_constants_table, (VALUE)&arg); + + // merge constants array c_buffer_concat(&dest->constants, &src->constants); + update_instructions_constants_table_index_ref(&src->instructions, dest_element_count, &dest->constants); + c_buffer_concat(&dest->instructions, &src->instructions); + size_t max_src_stack_size = dest->stack_size + src->max_stack_size; if (max_src_stack_size > dest->max_stack_size) dest->max_stack_size = max_src_stack_size; @@ -250,8 +307,7 @@ void vm_assembler_add_write_raw(vm_assembler_t *code, const char *string, size_t void vm_assembler_add_write_node(vm_assembler_t *code, VALUE node) { - vm_assembler_write_opcode(code, OP_WRITE_NODE); - vm_assembler_write_ruby_constant(code, node); + vm_assembler_add_op_with_constant(code, node, OP_WRITE_NODE); } void vm_assembler_add_push_fixnum(vm_assembler_t *code, VALUE num) @@ -298,15 +354,17 @@ void vm_assembler_add_filter(vm_assembler_t *code, VALUE filter_name, size_t arg st_data_t builtin_index; bool is_builtin = st_lookup(builtin_filter_table, filter_name, &builtin_index); - uint8_t *instructions = c_buffer_extend_for_write(&code->instructions, is_builtin ? 3 : 2); if (is_builtin) { + uint8_t *instructions = c_buffer_extend_for_write(&code->instructions, 3); *instructions++ = OP_BUILTIN_FILTER; *instructions++ = builtin_index; + *instructions++ = arg_count + 1; // include input } else { - vm_assembler_write_ruby_constant(code, filter_name); - *instructions++ = OP_FILTER; + VALUE filter_args = rb_ary_new_capa(2); + rb_ary_push(filter_args, filter_name); + rb_ary_push(filter_args, arg_count + 1); + vm_assembler_add_op_with_constant(code, filter_args, OP_FILTER); } - *instructions++ = arg_count + 1; // include input } static void ensure_parsing(vm_assembler_t *code) @@ -344,6 +402,7 @@ void vm_assembler_add_evaluate_expression_from_ruby(vm_assembler_t *code, VALUE default: break; } + vm_assembler_add_push_const(code, expression); } @@ -407,6 +466,20 @@ void vm_assembler_add_filter_from_ruby(vm_assembler_t *code, VALUE filter_name, vm_assembler_add_filter(code, filter_name, arg_count); } +bool vm_assembler_opcode_has_constant(uint8_t ip) { + if ( + ip == OP_PUSH_CONST || + ip == OP_WRITE_NODE || + ip == OP_FIND_STATIC_VAR || + ip == OP_LOOKUP_CONST_KEY || + ip == OP_LOOKUP_COMMAND || + ip == OP_FILTER + ) { + return true; + } + return false; +} + void liquid_define_vm_assembler(void) { builtin_filter_table = st_init_numtable_with_size(ARRAY_LENGTH(builtin_filters)); diff --git a/ext/liquid_c/vm_assembler.h b/ext/liquid_c/vm_assembler.h index dbc6e786..638f7f8c 100644 --- a/ext/liquid_c/vm_assembler.h +++ b/ext/liquid_c/vm_assembler.h @@ -43,6 +43,7 @@ extern filter_desc_t builtin_filters[]; typedef struct vm_assembler { c_buffer_t instructions; c_buffer_t constants; + st_table *constants_table; size_t max_stack_size; size_t stack_size; size_t protected_stack_size; @@ -54,7 +55,7 @@ void vm_assembler_init(vm_assembler_t *code); void vm_assembler_reset(vm_assembler_t *code); void vm_assembler_free(vm_assembler_t *code); void vm_assembler_gc_mark(vm_assembler_t *code); -VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, const VALUE *const_ptr); +VALUE vm_assembler_disassemble(const uint8_t *start_ip, const uint8_t *end_ip, const VALUE *constants); void vm_assembler_concat(vm_assembler_t *dest, vm_assembler_t *src); void vm_assembler_require_stack_args(vm_assembler_t *code, unsigned int count); @@ -72,9 +73,11 @@ void vm_assembler_add_new_int_range_from_ruby(vm_assembler_t *code); void vm_assembler_add_hash_new_from_ruby(vm_assembler_t *code, VALUE hash_size_obj); void vm_assembler_add_filter_from_ruby(vm_assembler_t *code, VALUE filter_name, VALUE arg_count_obj); +bool vm_assembler_opcode_has_constant(uint8_t ip); + static inline size_t vm_assembler_alloc_memsize(const vm_assembler_t *code) { - return c_buffer_capacity(&code->instructions) + c_buffer_capacity(&code->constants); + return c_buffer_capacity(&code->instructions) + c_buffer_capacity(&code->constants) + sizeof(st_table); } static inline void vm_assembler_write_opcode(vm_assembler_t *code, enum opcode op) @@ -82,9 +85,19 @@ static inline void vm_assembler_write_opcode(vm_assembler_t *code, enum opcode o c_buffer_write_byte(&code->instructions, op); } -static inline void vm_assembler_write_ruby_constant(vm_assembler_t *code, VALUE constant) +static inline uint16_t vm_assembler_write_ruby_constant(vm_assembler_t *code, VALUE constant) { - c_buffer_write(&code->constants, &constant, sizeof(VALUE)); + st_table *constants_table = code->constants_table; + st_data_t index_value; + + if (st_lookup(constants_table, constant, &index_value)) { + return (uint16_t)index_value; + } else { + uint16_t index = c_buffer_size(&code->constants) / sizeof(VALUE); + st_insert(constants_table, constant, index); + c_buffer_write(&code->constants, &constant, sizeof(VALUE)); + return index; + } } static inline void vm_assembler_increment_stack_size(vm_assembler_t *code, size_t amount) @@ -100,6 +113,14 @@ static inline void vm_assembler_reserve_stack_size(vm_assembler_t *code, size_t code->stack_size -= amount; } +static inline void vm_assembler_add_op_with_constant(vm_assembler_t *code, VALUE constant, uint8_t opcode) +{ + uint16_t index = vm_assembler_write_ruby_constant(code, constant); + uint8_t *instructions = c_buffer_extend_for_write(&code->instructions, 3); + instructions[0] = opcode; + instructions[1] = index >> 8; + instructions[2] = (uint8_t)index; +} static inline void vm_assembler_add_leave(vm_assembler_t *code) { @@ -170,15 +191,13 @@ static inline void vm_assembler_add_push_int16(vm_assembler_t *code, int16_t val static inline void vm_assembler_add_push_const(vm_assembler_t *code, VALUE constant) { vm_assembler_increment_stack_size(code, 1); - vm_assembler_write_ruby_constant(code, constant); - vm_assembler_write_opcode(code, OP_PUSH_CONST); + vm_assembler_add_op_with_constant(code, constant, OP_PUSH_CONST); } static inline void vm_assembler_add_find_static_variable(vm_assembler_t *code, VALUE key) { vm_assembler_increment_stack_size(code, 1); - vm_assembler_write_ruby_constant(code, key); - vm_assembler_write_opcode(code, OP_FIND_STATIC_VAR); + vm_assembler_add_op_with_constant(code, key, OP_FIND_STATIC_VAR); } static inline void vm_assembler_add_find_variable(vm_assembler_t *code) @@ -190,8 +209,7 @@ static inline void vm_assembler_add_find_variable(vm_assembler_t *code) static inline void vm_assembler_add_lookup_const_key(vm_assembler_t *code, VALUE key) { vm_assembler_reserve_stack_size(code, 1); // push 1, pop 2, push 1 - vm_assembler_write_ruby_constant(code, key); - vm_assembler_write_opcode(code, OP_LOOKUP_CONST_KEY); + vm_assembler_add_op_with_constant(code, key, OP_LOOKUP_CONST_KEY); } static inline void vm_assembler_add_lookup_key(vm_assembler_t *code) @@ -203,8 +221,7 @@ static inline void vm_assembler_add_lookup_key(vm_assembler_t *code) static inline void vm_assembler_add_lookup_command(vm_assembler_t *code, VALUE command) { vm_assembler_reserve_stack_size(code, 1); // push 1, pop 2, push 1 - vm_assembler_write_ruby_constant(code, command); - vm_assembler_write_opcode(code, OP_LOOKUP_COMMAND); + vm_assembler_add_op_with_constant(code, command, OP_LOOKUP_COMMAND); } static inline void vm_assembler_add_new_int_range(vm_assembler_t *code) diff --git a/test/unit/block_test.rb b/test/unit/block_test.rb index a9eac23f..8f9c8ca4 100644 --- a/test/unit/block_test.rb +++ b/test/unit/block_test.rb @@ -78,14 +78,14 @@ def test_disassemble 0x0000: write_raw("raw") 0x0005: render_variable_rescue(line_number: 2) 0x0009: find_static_var("var") - 0x000a: push_const("none") - 0x000b: push_const("allow_false") - 0x000c: push_true - 0x000d: hash_new(1) - 0x000f: builtin_filter(name: :default, num_args: 3) - 0x0012: pop_write - 0x0013: write_node(#{increment_node.inspect}) - 0x0014: leave + 0x000c: push_const(\"none\") + 0x000f: push_const(\"allow_false\") + 0x0012: push_true + 0x0013: hash_new(1) + 0x0015: builtin_filter(name: :default, num_args: 3) + 0x0018: pop_write + 0x0019: write_node(#{increment_node.inspect}) + 0x001c: leave ASM end @@ -115,11 +115,11 @@ def read_template_file(template_path) def test_include_partial_with_syntax_error old_file_system = Liquid::Template.file_system begin - Liquid::Template.file_system = StubFileSystem.new({ + Liquid::Template.file_system = StubFileSystem.new( "invalid" => "{% foo %}", "valid" => '{% include "nested" %}', "nested" => "valid", - }) + ) template = Liquid::Template.parse("{% include 'invalid' %},{% include 'valid' %}") assert_equal("Liquid syntax error: Unknown tag 'foo',valid", template.render) diff --git a/test/unit/expression_test.rb b/test/unit/expression_test.rb index 81c7d4d7..08e1bae4 100644 --- a/test/unit/expression_test.rb +++ b/test/unit/expression_test.rb @@ -143,10 +143,10 @@ def test_disassemble expression = Liquid::C::Expression.strict_parse("foo.bar[123]") assert_equal(<<~ASM, expression.disassemble) 0x0000: find_static_var("foo") - 0x0001: lookup_const_key("bar") - 0x0002: push_int8(123) - 0x0004: lookup_key - 0x0005: leave + 0x0003: lookup_const_key("bar") + 0x0006: push_int8(123) + 0x0008: lookup_key + 0x0009: leave ASM end