ruby-changes:39578
From: ko1 <ko1@a...>
Date: Sat, 22 Aug 2015 05:48:14 +0900 (JST)
Subject: [ruby-changes:39578] ko1:r51659 (trunk): * vm_opts.h, iseq.c, iseq.h: add compile option to force frozen
ko1 2015-08-22 05:47:53 +0900 (Sat, 22 Aug 2015) New Revision: 51659 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=51659 Log: * vm_opts.h, iseq.c, iseq.h: add compile option to force frozen string literals. [Feature #11473] This addition is not specification change, but to try frozen string literal world discussed on [Feature #11473]. You can try frozen string literal world using this magical line: RubyVM::InstructionSequence.compile_option = {frozen_string_literal: true} Note that this is a global compilation option, so that you need to compile another script like that: p 'foo'.frozen? #=> false RubyVM::InstructionSequence.compile_option = {frozen_string_literal: true} p 'foo'.frozen? #=> false, because this line is already compiled. p eval("'foo'.frozen?") #=> true Details: * String literals are deduped by rb_fstring(). * Dynamic string literals ("...#{xyz}...") is now only frozen, not deduped. Maybe you have other ideas. Now, please do not use this option on your productions :) Of course, current specification can be changed. * compile.c: ditto. * test/ruby/test_iseq.rb: add a test. Modified files: trunk/ChangeLog trunk/compile.c trunk/iseq.c trunk/iseq.h trunk/test/ruby/test_iseq.rb trunk/vm_opts.h Index: ChangeLog =================================================================== --- ChangeLog (revision 51658) +++ ChangeLog (revision 51659) @@ -1,3 +1,38 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Aug 22 05:31:37 2015 Koichi Sasada <ko1@a...> + + * vm_opts.h, iseq.c, iseq.h: add compile option to force frozen + string literals. + [Feature #11473] + + This addition is not specification change, but to try frozen + string literal world discussed on [Feature #11473]. + + You can try frozen string literal world using this magical line: + + RubyVM::InstructionSequence.compile_option = + {frozen_string_literal: true} + + Note that this is a global compilation option, so that you need to + compile another script like that: + + p 'foo'.frozen? #=> false + RubyVM::InstructionSequence.compile_option = + {frozen_string_literal: true} + p 'foo'.frozen? #=> false, because this line is already compiled. + p eval("'foo'.frozen?") #=> true + + Details: + * String literals are deduped by rb_fstring(). + * Dynamic string literals ("...#{xyz}...") is now only frozen, + not deduped. Maybe you have other ideas. + + Now, please do not use this option on your productions :) + Of course, current specification can be changed. + + * compile.c: ditto. + + * test/ruby/test_iseq.rb: add a test. + Sat Aug 22 02:53:12 2015 Aaron Patterson <tenderlove@r...> * ext/psych/*: update to Psych 2.0.14 Index: iseq.c =================================================================== --- iseq.c (revision 51658) +++ iseq.c (revision 51659) @@ -338,7 +338,9 @@ static rb_compile_option_t COMPILE_OPTIO https://github.com/ruby/ruby/blob/trunk/iseq.c#L338 OPT_INSTRUCTIONS_UNIFICATION, /* int instructions_unification; */ OPT_STACK_CACHING, /* int stack_caching; */ OPT_TRACE_INSTRUCTION, /* int trace_instruction */ + OPT_FROZEN_STRING_LITERAL }; + static const rb_compile_option_t COMPILE_OPTION_FALSE = {0}; static void @@ -375,6 +377,7 @@ make_compile_option(rb_compile_option_t https://github.com/ruby/ruby/blob/trunk/iseq.c#L377 SET_COMPILE_OPTION(option, opt, instructions_unification); SET_COMPILE_OPTION(option, opt, stack_caching); SET_COMPILE_OPTION(option, opt, trace_instruction); + SET_COMPILE_OPTION(option, opt, frozen_string_literal); SET_COMPILE_OPTION_NUM(option, opt, debug_level); #undef SET_COMPILE_OPTION #undef SET_COMPILE_OPTION_NUM Index: iseq.h =================================================================== --- iseq.h (revision 51658) +++ iseq.h (revision 51659) @@ -61,6 +61,7 @@ struct rb_compile_option_struct { https://github.com/ruby/ruby/blob/trunk/iseq.h#L61 int instructions_unification; int stack_caching; int trace_instruction; + int frozen_string_literal; int debug_level; }; Index: compile.c =================================================================== --- compile.c (revision 51658) +++ compile.c (revision 51659) @@ -5002,10 +5002,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L5002 break; } case NODE_STR:{ - node->nd_lit = rb_fstring(node->nd_lit); debugp_param("nd_lit", node->nd_lit); if (!poped) { - ADD_INSN1(ret, line, putstring, node->nd_lit); + node->nd_lit = rb_fstring(node->nd_lit); + if (iseq->compile_data->option->frozen_string_literal) { + ADD_INSN1(ret, line, putobject, node->nd_lit); /* already frozen */ + } + else { + ADD_INSN1(ret, line, putstring, node->nd_lit); + } } break; } @@ -5015,6 +5020,11 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ https://github.com/ruby/ruby/blob/trunk/compile.c#L5020 if (poped) { ADD_INSN(ret, line, pop); } + else { + if (iseq->compile_data->option->frozen_string_literal) { + ADD_SEND (ret, line, idFreeze, INT2FIX(0)); + } + } break; } case NODE_XSTR:{ Index: vm_opts.h =================================================================== --- vm_opts.h (revision 51658) +++ vm_opts.h (revision 51659) @@ -23,7 +23,7 @@ https://github.com/ruby/ruby/blob/trunk/vm_opts.h#L23 #define OPT_PEEPHOLE_OPTIMIZATION 1 #define OPT_SPECIALISED_INSTRUCTION 1 #define OPT_INLINE_CONST_CACHE 1 - +#define OPT_FROZEN_STRING_LITERAL 0 /* Build Options. * You can't change these options at runtime. Index: test/ruby/test_iseq.rb =================================================================== --- test/ruby/test_iseq.rb (revision 51658) +++ test/ruby/test_iseq.rb (revision 51659) @@ -141,4 +141,17 @@ class TestISeq < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_iseq.rb#L141 assert_raise(TypeError, bug11159) {ISeq.compile(:foo)} assert_raise(TypeError, bug11159) {ISeq.compile(1)} end + + def test_frozen_string_literal_compile_option + $f = 'f' + line = __LINE__ + 2 + code = <<-'EOS' + ['foo', 'foo', "#{$f}foo"] + EOS + s1, s2, s3 = RubyVM::InstructionSequence.compile(code, __FILE__, __FILE__, line, {frozen_string_literal: true}).eval + assert(s1.frozen?) + assert(s2.frozen?) + assert(s3.frozen?) + assert(s1.object_id == s2.object_id) + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/