summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-21 20:47:53 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-21 20:47:53 +0000
commit7cf523c7db67c22ffc09b38a9c5bea057f578db2 (patch)
tree93119a59a19abdd3a1d931fc27c5828b234418e8
parent42c3a67748da667cb87afd7928718c537cdd8201 (diff)
* 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. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51659 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog35
-rw-r--r--compile.c14
-rw-r--r--iseq.c3
-rw-r--r--iseq.h1
-rw-r--r--test/ruby/test_iseq.rb13
-rw-r--r--vm_opts.h2
6 files changed, 65 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index a18ae217f9..fd00ba1abc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+Sat Aug 22 05:31:37 2015 Koichi Sasada <ko1@atdot.net>
+
+ * 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@ruby-lang.org>
* ext/psych/*: update to Psych 2.0.14
diff --git a/compile.c b/compile.c
index 26ee3b24fa..07cd7a6100 100644
--- a/compile.c
+++ b/compile.c
@@ -5002,10 +5002,15 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped)
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_ANCHOR *ret, NODE * node, int poped)
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:{
diff --git a/iseq.c b/iseq.c
index 9b32c0a20d..fa89f512d8 100644
--- a/iseq.c
+++ b/iseq.c
@@ -338,7 +338,9 @@ static rb_compile_option_t COMPILE_OPTION_DEFAULT = {
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 *option, VALUE opt)
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
diff --git a/iseq.h b/iseq.h
index 315a73f3c7..f796905470 100644
--- a/iseq.h
+++ b/iseq.h
@@ -61,6 +61,7 @@ struct rb_compile_option_struct {
int instructions_unification;
int stack_caching;
int trace_instruction;
+ int frozen_string_literal;
int debug_level;
};
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 686646ddd8..3938fb3d48 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -141,4 +141,17 @@ class TestISeq < Test::Unit::TestCase
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
diff --git a/vm_opts.h b/vm_opts.h
index b67e2543e7..ad81208e80 100644
--- a/vm_opts.h
+++ b/vm_opts.h
@@ -23,7 +23,7 @@
#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.