mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									1e215a66d2
								
							
						
					
					
						commit
						6f29716f9f
					
				
				
				Notes:
				
					git
				
				2020-12-24 14:29:13 +09:00 
				
			
			
			
		
		
					 6 changed files with 73 additions and 15 deletions
				
			
		| 
						 | 
					@ -125,6 +125,7 @@ The directive can specify special treatment for values assigned to constants:
 | 
				
			||||||
* +none+: (default)
 | 
					* +none+: (default)
 | 
				
			||||||
* +literal+: literals are implicitly frozen, others must be Ractor-shareable
 | 
					* +literal+: literals are implicitly frozen, others must be Ractor-shareable
 | 
				
			||||||
* +experimental_everything+: all made shareable
 | 
					* +experimental_everything+: all made shareable
 | 
				
			||||||
 | 
					* +experimental_copy+: copy deeply and make it shareable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
==== Mode +none+ (default)
 | 
					==== Mode +none+ (default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -168,22 +169,46 @@ The method Module#const_set is not affected.
 | 
				
			||||||
In this mode, all values assigned to constants are made shareable.
 | 
					In this mode, all values assigned to constants are made shareable.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # shareable_constant_value: experimental_everything
 | 
					  # shareable_constant_value: experimental_everything
 | 
				
			||||||
  FOO = Set.new[1, 2, {foo: []}] # => ok, since this is
 | 
					  FOO = Set[1, 2, {foo: []}]
 | 
				
			||||||
      # same as `Set.new[1, 2, {foo: [].freeze}.freeze].freeze`
 | 
					  # same as FOO = Ractor.make_sharable(...)
 | 
				
			||||||
 | 
					  # OR same as `FOO = Set[1, 2, {foo: [].freeze}.freeze].freeze`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  var = [{foo: []}]
 | 
					  var = [{foo: []}]
 | 
				
			||||||
  var.frozen? # => false (assignment was made to local variable)
 | 
					  var.frozen? # => false (assignment was made to local variable)
 | 
				
			||||||
  X = var # => calls `Ractor.make_shareable(var)`
 | 
					  X = var # => calls `Ractor.make_shareable(var)`
 | 
				
			||||||
  var.frozen? # => true
 | 
					  var.frozen? # => true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This mode is "experimental", because it might be too error prone,
 | 
					This mode is "experimental", because it might be error prone, for 
 | 
				
			||||||
for example by deep-freezing the constants of an external resource
 | 
					example by deep-freezing the constants of an external resource which 
 | 
				
			||||||
which could cause errors:
 | 
					could cause errors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # shareable_constant_value: experimental_everything
 | 
					  # shareable_constant_value: experimental_everything
 | 
				
			||||||
  FOO = SomeGem::Something::FOO
 | 
					  FOO = SomeGem::Something::FOO
 | 
				
			||||||
  # => deep freezes the gem's constant!
 | 
					  # => 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.
 | 
					The method Module#const_set is not affected.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
==== Scope
 | 
					==== Scope
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,4 +61,7 @@ rb_ractor_shareable_p(VALUE obj)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VALUE rb_ractor_make_shareable(VALUE obj);
 | 
				
			||||||
 | 
					VALUE rb_ractor_make_shareable_copy(VALUE obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* RUBY_RACTOR_H */
 | 
					#endif /* RUBY_RACTOR_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										25
									
								
								parse.y
									
										
									
									
									
								
							
							
						
						
									
										25
									
								
								parse.y
									
										
									
									
									
								
							| 
						 | 
					@ -58,6 +58,7 @@ struct lex_context;
 | 
				
			||||||
enum shareability {
 | 
					enum shareability {
 | 
				
			||||||
    shareable_none,
 | 
					    shareable_none,
 | 
				
			||||||
    shareable_literal,
 | 
					    shareable_literal,
 | 
				
			||||||
 | 
					    shareable_copy,
 | 
				
			||||||
    shareable_everything,
 | 
					    shareable_everything,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8053,6 +8054,10 @@ parser_set_shareable_constant_value(struct parser_params *p, const char *name, c
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
      case 'e': case 'E':
 | 
					      case 'e': case 'E':
 | 
				
			||||||
 | 
						if (STRCASECMP(val, "experimental_copy") == 0) {
 | 
				
			||||||
 | 
						    p->ctxt.shareable_constant_value = shareable_copy;
 | 
				
			||||||
 | 
						    return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (STRCASECMP(val, "experimental_everything") == 0) {
 | 
						if (STRCASECMP(val, "experimental_everything") == 0) {
 | 
				
			||||||
	    p->ctxt.shareable_constant_value = shareable_everything;
 | 
						    p->ctxt.shareable_constant_value = shareable_everything;
 | 
				
			||||||
	    return;
 | 
						    return;
 | 
				
			||||||
| 
						 | 
					@ -11048,11 +11053,18 @@ const_decl_path(struct parser_params *p, NODE **dest)
 | 
				
			||||||
extern VALUE rb_mRubyVMFrozenCore;
 | 
					extern VALUE rb_mRubyVMFrozenCore;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static NODE *
 | 
					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);
 | 
					    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 *
 | 
					static NODE *
 | 
				
			||||||
| 
						 | 
					@ -11089,8 +11101,6 @@ shareable_literal_value(NODE *node)
 | 
				
			||||||
#define SHAREABLE_BARE_EXPRESSION 1
 | 
					#define SHAREABLE_BARE_EXPRESSION 1
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VALUE rb_ractor_make_shareable(VALUE obj);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static NODE *
 | 
					static NODE *
 | 
				
			||||||
shareable_literal_constant(struct parser_params *p, enum shareability shareable,
 | 
					shareable_literal_constant(struct parser_params *p, enum shareability shareable,
 | 
				
			||||||
			   NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
 | 
								   NODE **dest, NODE *value, const YYLTYPE *loc, size_t level)
 | 
				
			||||||
| 
						 | 
					@ -11207,7 +11217,7 @@ shareable_literal_constant(struct parser_params *p, enum shareability shareable,
 | 
				
			||||||
    if (NIL_P(lit)) {
 | 
					    if (NIL_P(lit)) {
 | 
				
			||||||
	// if shareable_literal, all elements should have been ensured
 | 
						// if shareable_literal, all elements should have been ensured
 | 
				
			||||||
	// as shareable
 | 
						// as shareable
 | 
				
			||||||
	value = make_shareable_node(p, value, loc);
 | 
						value = make_shareable_node(p, value, false, loc);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
	nd_set_type(value, NODE_LIT);
 | 
						nd_set_type(value, NODE_LIT);
 | 
				
			||||||
| 
						 | 
					@ -11235,11 +11245,12 @@ shareable_constant_value(struct parser_params *p, enum shareability shareable,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      case shareable_copy:
 | 
				
			||||||
      case shareable_everything:
 | 
					      case shareable_everything:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
	    NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
 | 
						    NODE *lit = shareable_literal_constant(p, shareable, &lhs, value, loc, 0);
 | 
				
			||||||
	    if (lit) return lit;
 | 
						    if (lit) return lit;
 | 
				
			||||||
	    return make_shareable_node(p, value, loc);
 | 
						    return make_shareable_node(p, value, shareable == shareable_copy, loc);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	break;
 | 
						break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -184,6 +184,8 @@ bool rb_ractor_main_p_(void);
 | 
				
			||||||
void rb_ractor_finish_marking(void);
 | 
					void rb_ractor_finish_marking(void);
 | 
				
			||||||
void rb_ractor_atfork(rb_vm_t *vm, rb_thread_t *th);
 | 
					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
 | 
					RUBY_SYMBOL_EXPORT_BEGIN
 | 
				
			||||||
bool rb_ractor_shareable_p_continue(VALUE obj);
 | 
					bool rb_ractor_shareable_p_continue(VALUE obj);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1205,6 +1205,7 @@ x = __ENCODING__
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def test_shareable_constant_value_simple
 | 
					  def test_shareable_constant_value_simple
 | 
				
			||||||
 | 
					    obj = [['unsharable_value']]
 | 
				
			||||||
    a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
 | 
					    a, b, c = eval_separately("#{<<~"begin;"}\n#{<<~'end;'}")
 | 
				
			||||||
    begin;
 | 
					    begin;
 | 
				
			||||||
      # shareable_constant_value: experimental_everything
 | 
					      # shareable_constant_value: experimental_everything
 | 
				
			||||||
| 
						 | 
					@ -1222,6 +1223,18 @@ x = __ENCODING__
 | 
				
			||||||
    assert_ractor_shareable(c)
 | 
					    assert_ractor_shareable(c)
 | 
				
			||||||
    assert_equal([1], a[0])
 | 
					    assert_equal([1], a[0])
 | 
				
			||||||
    assert_ractor_shareable(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
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def test_shareable_constant_value_nested
 | 
					  def test_shareable_constant_value_nested
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								vm.c
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								vm.c
									
										
									
									
									
								
							| 
						 | 
					@ -994,9 +994,6 @@ collect_outer_variable_names(ID id, VALUE val, void *ptr)
 | 
				
			||||||
    return ID_TABLE_CONTINUE;
 | 
					    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 *
 | 
					static const rb_env_t *
 | 
				
			||||||
env_copy(const VALUE *src_ep, VALUE read_only_variables)
 | 
					env_copy(const VALUE *src_ep, VALUE read_only_variables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -3181,6 +3178,12 @@ m_core_make_shareable(VALUE recv, VALUE obj)
 | 
				
			||||||
    return rb_ractor_make_shareable(obj);
 | 
					    return rb_ractor_make_shareable(obj);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VALUE
 | 
				
			||||||
 | 
					m_core_make_shareable_copy(VALUE recv, VALUE obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    return rb_ractor_make_shareable_copy(obj);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static VALUE
 | 
					static VALUE
 | 
				
			||||||
m_core_ensure_shareable(VALUE recv, VALUE obj, VALUE name)
 | 
					m_core_ensure_shareable(VALUE recv, VALUE obj, VALUE name)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -3352,6 +3355,7 @@ Init_VM(void)
 | 
				
			||||||
    rb_define_method_id(klass, idProc, f_proc, 0);
 | 
					    rb_define_method_id(klass, idProc, f_proc, 0);
 | 
				
			||||||
    rb_define_method_id(klass, idLambda, f_lambda, 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", 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_define_method(klass, "ensure_shareable", m_core_ensure_shareable, 2);
 | 
				
			||||||
    rb_obj_freeze(fcore);
 | 
					    rb_obj_freeze(fcore);
 | 
				
			||||||
    RBASIC_CLEAR_CLASS(klass);
 | 
					    RBASIC_CLEAR_CLASS(klass);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue