From: Adam Strzelecki Date: 2008-06-12T00:43:10+09:00 Subject: [ruby-core:17220] VM::InstructionSequence to_a->load->to_a != to_a Hello, There's apparently a bug in VM::InstructionSequence.load code, coz code generated with to_a, loaded back and again to_a is not the same as one emitted just with to_a. Of course label names differ, but also local_size and args_size are different for blocks (instructions seems to be OK). After my initial enthusiasm, I realised that VM::InstructionSequence.load doesn't work as it should at all. Actually it is not possible to call any function/method with argument with current code. Here's sample test showing the differences: ----------------------------------------------------- #!/usr/bin/env ruby-1.9 require 'zlib' code = VM::InstructionSequence.compile_file 'test.rb' STDOUT.puts code.to_a.inspect.gsub(/, \[/, ",\n\t[") code = VM::InstructionSequence.load code.to_a STDERR.puts code.to_a.inspect.gsub(/, \[/, ",\n\t[") ----------------------------------------------------- I've compared STDOUT & STDERR using samples/test.rb & I got plenty of local_size differences like: - ["YARV", 1, 1, 1, {:arg_size=>1, :local_size=>2, :stack_max=>2}, "block in
", "test.rb", :block, + ["YARV", 1, 1, 1, {:arg_size=>1, :local_size=>1, :stack_max=>2}, "block in
", "test.rb", :block, It seems that iseq_build_from_ary @ compile.c is broken, I'm not sure about to_a. I've did some fixes (diff below): 1) Regardless of iseq->type it seems that local_size is always local_table_size + 1, also in original code opt (=1) is added twice to local_size (= local_table_size = opt + RARRAY_LEN(locals)) 2) It should be iseq->arg_opts = RARRAY_LEN(arg_opt_labels) With those fixes I've managed to limit the differences of to_a->load- >to_a != to_a, but still those are not the same. Also I've managed to call methods with args from restored with VM::InstructionSequence.load code, but it seems it does works weird (slow + hungs). Best regards, -- Adam Index: compile.c =================================================================== --- compile.c (revision 17097) +++ compile.c (working copy) @@ -4983,22 +4983,16 @@ VALUE exception, VALUE body) { int i; - int opt = 0; ID *tbl; struct st_table *labels_table = st_init_numtable(); DECL_ANCHOR(anchor); INIT_ANCHOR(anchor); - if (iseq->type == ISEQ_TYPE_METHOD || - iseq->type == ISEQ_TYPE_TOP || - iseq->type == ISEQ_TYPE_CLASS) { - opt = 1; - } - iseq->local_table_size = opt + RARRAY_LEN(locals); + iseq->local_table_size = RARRAY_LEN(locals); iseq->local_table = tbl = (ID *)ALLOC_N(ID *, iseq- >local_table_size); - iseq->local_size = opt + iseq->local_table_size; + iseq->local_size = 1 + iseq->local_table_size; for (i=0; iarg_post_len = FIX2INT(arg_post_len); iseq->arg_post_start = FIX2INT(arg_post_start); iseq->arg_block = FIX2INT(arg_block); - iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, RARRAY_LEN(arg_opt_labels)); + iseq->arg_opts = RARRAY_LEN(arg_opt_labels); + iseq->arg_opt_table = (VALUE *)ALLOC_N(VALUE, iseq->arg_opts); if (iseq->arg_block != -1) { iseq->arg_size = iseq->arg_block + 1; @@ -5037,7 +5032,7 @@ iseq->arg_size = iseq->arg_rest + 1; } else { - iseq->arg_size = iseq->argc + iseq->arg_opts; + iseq->arg_size = iseq->argc + (iseq->arg_opts ? iseq->arg_opts - 1 : 0); } for (i=0; i