[前][次][番号順一覧][スレッド一覧]

ruby-changes:64541

From: Koichi <ko1@a...>
Date: Thu, 24 Dec 2020 14:29:07 +0900 (JST)
Subject: [ruby-changes:64541] 6f29716f9f (master): shareable_constant_value: experimental_copy

https://git.ruby-lang.org/ruby.git/commit/?id=6f29716f9f

From 6f29716f9ffb710af7f344839ec67ef2b8a48ab2 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Thu, 24 Dec 2020 10:59:27 +0900
Subject: shareable_constant_value: experimental_copy

"experimental_everything" makes the assigned value, it means
the assignment change the state of assigned value.
"experimental_copy" tries to make a deep copy and make copyied object
sharable.

diff --git a/doc/syntax/comments.rdoc b/doc/syntax/comments.rdoc
index 6ce8fa1..a808ca8 100644
--- a/doc/syntax/comments.rdoc
+++ b/doc/syntax/comments.rdoc
@@ -125,6 +125,7 @@ The directive can specify special treatment for values assigned to constants: https://github.com/ruby/ruby/blob/trunk/doc/syntax/comments.rdoc#L125
 * +none+: (default)
 * +literal+: literals are implicitly frozen, others must be Ractor-shareable
 * +experimental_everything+: all made shareable
+* +experimental_copy+: copy deeply and make it shareable
 
 ==== Mode +none+ (default)
 
@@ -168,22 +169,46 @@ The method Module#const_set is not affected. https://github.com/ruby/ruby/blob/trunk/doc/syntax/comments.rdoc#L169
 In this mode, all values assigned to constants are made shareable.
 
   # shareable_constant_value: experimental_everything
-  FOO = Set.new[1, 2, {foo: []}] # => ok, since this is
-      # same as `Set.new[1, 2, {foo: [].freeze}.freeze].freeze`
+  FOO = Set[1, 2, {foo: []}]
+  # same as FOO = Ractor.make_sharable(...)
+  # OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze`
 
   var = [{foo: []}]
   var.frozen? # => false (assignment was made to local variable)
   X = var # => calls `Ractor.make_shareable(var)`
   var.frozen? # => true
 
-This mode is "experimental", because it might be too error prone,
-for example by deep-freezing the constants of an external resource
-which could cause errors:
+This mode is "experimental", because it might be error prone, for 
+example by deep-freezing the constants of an external resource which 
+could cause errors:
 
   # shareable_constant_value: experimental_everything
   FOO = SomeGem::Something::FOO
   # => deep freezes the gem's constant!
 
+We will revisit to consider removing "experimental_" or removing this 
+mode by checking usages before Ruby 3.1.
+
+The method Module#const_set is not affected.
+
+==== Mode +experimental_copy+
+
+In this mode, all values assigned to constants are copyied deeply and
+made shareable. It is safer mode than +experimental_everything+.
+
+  # shareable_constant_value: experimental_everything
+  var = [{foo: []}]
+  var.frozen? # => false (assignment was made to local variable)
+  X = var # => calls `Ractor.make_shareable(var, copy: true)`
+  var.frozen? # => false
+  Ractor.shareable?(var) #=> false
+  Ractor.shareable?(X) #=> true
+  var.object_id == X.object_id #=> false
+
+This mode is "experimental", because it is not discussed enough.
+We will revisit to consider removing "experimental_" or removing this 
+mode by checking usages before Ruby 3.1.
+
 The method Module#const_set is not affected.
 
 ==== Scope
diff --git a/include/ruby/ractor.h b/include/ruby/ractor.h
index 327d4f4..239df9c 100644
--- a/include/ruby/ractor.h
+++ b/include/ruby/ractor.h
@@ -61,4 +61,7 @@ rb_ractor_shareable_p(VALUE obj) https://github.com/ruby/ruby/blob/trunk/include/ruby/ractor.h#L61
     }
 }
 
+VALUE rb_ractor_make_shareable(VALUE obj);
+VALUE rb_ractor_make_shareable_copy(VALUE obj);
+
 #endif /* RUBY_RACTOR_H */
diff --git a/parse.y b/parse.y
index 570a400..fa70b1b 100644
--- a/parse.y
+++ b/parse.y
@@ -58,6 +58,7 @@ struct lex_context; https://github.com/ruby/ruby/blob/trunk/parse.y#L58
 enum shareability {
     shareable_none,
     shareable_literal,
+    shareable_copy,
     shareable_everything,
 };
 
@@ -8053,6 +8054,10 @@ parser_set_shareable_constant_value(struct parser_params *p, const char *name, c https://github.com/ruby/ruby/blob/trunk/parse.y#L8054
 	}
 	break;
       case 'e': case 'E':
+	if (STRCASECMP(val, "experimental_copy") == 0) {
+	    p->ctxt.shareable_constant_value = shareable_copy;
+	    return;
+	}
 	if (STRCASECMP(val, "experimental_everything") == 0) {
 	    p->ctxt.shareable_constant_value = shareable_everything;
 	    return;
@@ -11048,11 +11053,18 @@ const_decl_path(struct parser_params *p, NODE **dest) https://github.com/ruby/ruby/blob/trunk/parse.y#L11053
 extern VALUE rb_mRubyVMFrozenCore;
 
 static NODE *
-make_shareable_node(struct parser_params *p, NODE *value, const YYLTYPE *loc)
+make_shareable_node(struct parser_params *p, NODE *value, bool copy, const YYLTYPE *loc)
 {
     NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
-    return NEW_CALL(fcore, rb_intern("make_shareable"),
-		    NEW_LIST(value, loc), loc);
+
+    if (copy) {
+        return NEW_CALL(fcore, rb_intern("make_shareable_copy"),
+                        NEW_LIST(value, loc), loc);
+    }
+    else {
+        return NEW_CALL(fcore, rb_intern("make_shareable"),
+                        NEW_LIST(value, loc), loc);
+    }
 }
 
 static NODE *
@@ -11089,8 +11101,6 @@ shareable_literal_value(NODE *node) https://github.com/ruby/ruby/blob/trunk/parse.y#L11101
 #define SHAREABLE_BARE_EXPRESSION 1
 #endif
 
-VALUE rb_ractor_make_shareable(VALUE obj);
-
 static NODE *
 shareable_literal_constant(struct parser_params *p, enum shareability shareable,
 			   NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
@@ -11207,7 +11217,7 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable, https://github.com/ruby/ruby/blob/trunk/parse.y#L11217
     if (NIL_P(lit)) {
 	// if shareable_literal, all elements should have been ensured
 	// as shareable
-	value = make_shareable_node(p, value, loc);
+	value = make_shareable_node(p, value, false, loc);
     }
     else {
 	nd_set_type(value, NODE_LIT);
@@ -11235,11 +11245,12 @@ shareable_constant_value(struct parser_params *p, enum shareability shareable, https://github.com/ruby/ruby/blob/trunk/parse.y#L11245
 	}
 	break;
 
+      case shareable_copy:
       case shareable_everything:
 	{
 	    NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
 	    if (lit) return lit;
-	    return make_shareable_node(p, value, loc);
+	    return make_shareable_node(p, value, shareable == shareable_copy, loc);
 	}
 	break;
 
diff --git a/ractor_core.h b/ractor_core.h
index 0aa66f6..2516277 100644
--- a/ractor_core.h
+++ b/ractor_core.h
@@ -184,6 +184,8 @@ bool rb_ractor_main_p_(void); https://github.com/ruby/ruby/blob/trunk/ractor_core.h#L184
 void rb_ractor_finish_marking(void);
 void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
 
+VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
+
 RUBY_SYMBOL_EXPORT_BEGIN
 bool rb_ractor_shareable_p_continue(VALUE obj);
 
diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb
index 2e3fbc9..5f638af 100644
--- a/test/ruby/test_parse.rb
+++ b/test/ruby/test_parse.rb
@@ -1205,6 +1205,7 @@ x = __ENCODING__ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_parse.rb#L1205
   end
 
   def test_shareable_constant_value_simple
+    obj = [['unsharable_value']]
     a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
     begin;
       # shareable_constant_value: experimental_everything
@@ -1222,6 +1223,18 @@ x = __ENCODING__ https://github.com/ruby/ruby/blob/trunk/test/ruby/test_parse.rb#L1223
     assert_ractor_shareable(c)
     assert_equal([1], a[0])
     assert_ractor_shareable(a[0])
+
+    a, obj = eval_separately(<<~'end;')
+      # shareable_constant_value: experimental_copy
+      obj = [["unshareable"]]
+      A = obj
+      [A, obj]
+    end;
+
+    assert_ractor_shareable(a)
+    assert_not_ractor_shareable(obj)
+    assert_equal obj, a
+    assert !obj.equal?(a)
   end
 
   def test_shareable_constant_value_nested
diff --git a/vm.c b/vm.c
index a30ba9c..696cffb 100644
--- a/vm.c
+++ b/vm.c
@@ -994,9 +994,6 @@ collect_outer_variable_names(ID id, VALUE val, void *ptr) https://github.com/ruby/ruby/blob/trunk/vm.c#L994
     return ID_TABLE_CONTINUE;
 }
 
-VALUE rb_ractor_make_shareable(VALUE obj);
-VALUE rb_ractor_ensure_shareable(VALUE obj, VALUE name);
-
 static const rb_env_t *
 env_copy(const VALUE *src_ep, VALUE read_only_variables)
 {
@@ -3182,6 +3179,12 @@ m_core_make_shareable(VALUE recv, VALUE obj) https://github.com/ruby/ruby/blob/trunk/vm.c#L3179
 }
 
 static VALUE
+m_core_make_shareable_copy(VALUE recv, VALUE obj)
+{
+    return rb_ractor_make_shareable_copy(obj);
+}
+
+static VALUE
 m_core_ensure_shareable(VALUE recv, VALUE obj, VALUE name)
 {
     return rb_ractor_ensure_shareable(obj, name);
@@ -3352,6 +3355,7 @@ Init_VM(void) https://github.com/ruby/ruby/blob/trunk/vm.c#L3355
     rb_define_method_id(klass, idProc, f_proc, 0);
     rb_define_method_id(klass, idLambda, f_lambda, 0);
     rb_define_method(klass, "make_shareable", m_core_make_shareable, 1);
+    rb_define_method(klass, "make_shareable_copy", m_core_make_shareable_copy, 1);
     rb_define_method(klass, "ensure_shareable", m_core_ensure_shareable, 2);
     rb_obj_freeze(fcore);
     RBASIC_CLEAR_CLASS(klass);
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]