Move shareable_constant_value logic from parse.y to compile.c

This commit is contained in:
yui-knk 2024-04-03 19:28:55 +09:00 коммит произвёл Yuichiro Kaneko
Родитель 4ef99905a6
Коммит 6056773105
7 изменённых файлов: 414 добавлений и 359 удалений

Просмотреть файл

@ -3534,6 +3534,7 @@ compile.$(OBJEXT): {$(VPATH)}prism/prism.h
compile.$(OBJEXT): {$(VPATH)}prism/version.h
compile.$(OBJEXT): {$(VPATH)}prism_compile.c
compile.$(OBJEXT): {$(VPATH)}prism_compile.h
compile.$(OBJEXT): {$(VPATH)}ractor.h
compile.$(OBJEXT): {$(VPATH)}re.h
compile.$(OBJEXT): {$(VPATH)}regex.h
compile.$(OBJEXT): {$(VPATH)}ruby_assert.h

373
compile.c
Просмотреть файл

@ -36,6 +36,7 @@
#include "internal/thread.h"
#include "internal/variable.h"
#include "iseq.h"
#include "ruby/ractor.h"
#include "ruby/re.h"
#include "ruby/util.h"
#include "vm_core.h"
@ -9375,6 +9376,8 @@ compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
return COMPILE_OK;
}
static int compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value);
static int
compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
@ -9418,7 +9421,7 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
/* cref [obj] */
if (!popped) ADD_INSN(ret, node, pop); /* cref */
if (lassign) ADD_LABEL(ret, lassign);
CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
/* cref value */
if (popped)
ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
@ -9432,7 +9435,7 @@ compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
ADD_INSN(ret, node, pop); /* [value] */
}
else {
CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", RNODE_OP_CDECL(node)->nd_value));
CHECK(compile_shareable_constant_value(iseq, ret, RNODE_OP_CDECL(node)->shareability, RNODE_OP_CDECL(node)->nd_head, RNODE_OP_CDECL(node)->nd_value));
/* cref obj value */
ADD_CALL(ret, node, RNODE_OP_CDECL(node)->nd_aid, INT2FIX(1));
/* cref value */
@ -9948,6 +9951,368 @@ compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node
return COMPILE_OK;
}
static int
compile_make_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, LINK_ANCHOR *sub, const NODE *value, bool copy)
{
ADD_INSN1(ret, value, putobject, rb_mRubyVMFrozenCore);
ADD_SEQ(ret, sub);
if (copy) {
/*
* NEW_CALL(fcore, rb_intern("make_shareable_copy"),
* NEW_LIST(value, loc), loc);
*/
ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable_copy"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
}
else {
/*
* NEW_CALL(fcore, rb_intern("make_shareable"),
* NEW_LIST(value, loc), loc);
*/
ADD_SEND_WITH_FLAG(ret, value, rb_intern("make_shareable"), INT2FIX(1), INT2FIX(VM_CALL_ARGS_SIMPLE));
}
return COMPILE_OK;
}
static VALUE
node_const_decl_val(const NODE *node)
{
VALUE path;
switch (nd_type(node)) {
case NODE_CDECL:
if (RNODE_CDECL(node)->nd_vid) {
path = rb_id2str(RNODE_CDECL(node)->nd_vid);
goto end;
}
else {
node = RNODE_CDECL(node)->nd_else;
}
break;
case NODE_COLON2:
break;
case NODE_COLON3:
// ::Const
path = rb_str_new_cstr("::");
rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
goto end;
default:
rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
UNREACHABLE_RETURN(0);
}
path = rb_ary_new();
if (node) {
for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
}
if (node && nd_type_p(node, NODE_CONST)) {
// Const::Name
rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
}
else if (node && nd_type_p(node, NODE_COLON3)) {
// ::Const::Name
rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
rb_ary_push(path, rb_str_new(0, 0));
}
else {
// expression::Name
rb_ary_push(path, rb_str_new_cstr("..."));
}
path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
}
end:
path = rb_fstring(path);
return path;
}
static VALUE
const_decl_path(NODE *dest)
{
VALUE path = Qnil;
if (!nd_type_p(dest, NODE_CALL)) {
path = node_const_decl_val(dest);
}
return path;
}
static int
compile_ensure_shareable_node(rb_iseq_t *iseq, LINK_ANCHOR *ret, NODE *dest, const NODE *value)
{
/*
*. RubyVM::FrozenCore.ensure_shareable(value, const_decl_path(dest))
*/
VALUE path = const_decl_path(dest);
ADD_INSN1(ret, value, putobject, rb_mRubyVMFrozenCore);
CHECK(COMPILE(ret, "compile_ensure_shareable_node", value));
ADD_INSN1(ret, value, putobject, path);
RB_OBJ_WRITTEN(iseq, Qundef, path);
ADD_SEND_WITH_FLAG(ret, value, rb_intern("ensure_shareable"), INT2FIX(2), INT2FIX(VM_CALL_ARGS_SIMPLE));
return COMPILE_OK;
}
#ifndef SHAREABLE_BARE_EXPRESSION
#define SHAREABLE_BARE_EXPRESSION 1
#endif
static int
compile_shareable_literal_constant(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, NODE *dest, const NODE *node, size_t level, VALUE *value_p, int *shareable_literal_p)
{
# define compile_shareable_literal_constant_next(node, anchor, value_p, shareable_literal_p) \
compile_shareable_literal_constant(iseq, anchor, shareable, dest, node, level+1, value_p, shareable_literal_p)
VALUE lit = Qnil;
DECL_ANCHOR(anchor);
enum node_type type = nd_type(node);
switch (type) {
case NODE_TRUE:
*value_p = Qtrue;
goto compile;
case NODE_FALSE:
*value_p = Qfalse;
goto compile;
case NODE_NIL:
*value_p = Qnil;
goto compile;
case NODE_LIT:
*value_p = RNODE_LIT(node)->nd_lit;
goto compile;
case NODE_SYM:
*value_p = rb_node_sym_string_val(node);
goto compile;
case NODE_REGX:
*value_p = rb_node_regx_string_val(node);
goto compile;
case NODE_LINE:
*value_p = rb_node_line_lineno_val(node);
goto compile;
case NODE_INTEGER:
*value_p = rb_node_integer_literal_val(node);
goto compile;
case NODE_FLOAT:
*value_p = rb_node_float_literal_val(node);
goto compile;
case NODE_RATIONAL:
*value_p = rb_node_rational_literal_val(node);
goto compile;
case NODE_IMAGINARY:
*value_p = rb_node_imaginary_literal_val(node);
goto compile;
case NODE_ENCODING:
*value_p = rb_node_encoding_val(node);
compile:
CHECK(COMPILE(ret, "shareable_literal_constant", node));
*shareable_literal_p = 1;
return COMPILE_OK;
case NODE_DSTR:
CHECK(COMPILE(ret, "shareable_literal_constant", node));
if (shareable == rb_parser_shareable_literal) {
/*
* NEW_CALL(node, idUMinus, 0, loc);
*
* -"#{var}"
*/
ADD_SEND_WITH_FLAG(ret, node, idUMinus, INT2FIX(0), INT2FIX(VM_CALL_ARGS_SIMPLE));
}
*value_p = Qundef;
*shareable_literal_p = 1;
return COMPILE_OK;
case NODE_STR:{
VALUE lit = rb_fstring(rb_node_str_string_val(node));
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
*value_p = lit;
*shareable_literal_p = 1;
return COMPILE_OK;
}
case NODE_FILE:{
VALUE lit = rb_fstring(rb_node_file_path_val(node));
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
*value_p = lit;
*shareable_literal_p = 1;
return COMPILE_OK;
}
case NODE_ZLIST:{
VALUE lit = rb_ary_new();
OBJ_FREEZE_RAW(lit);
ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
*value_p = lit;
*shareable_literal_p = 1;
return COMPILE_OK;
}
case NODE_LIST:{
INIT_ANCHOR(anchor);
lit = rb_ary_new();
for (NODE *n = (NODE *)node; n; n = RNODE_LIST(n)->nd_next) {
VALUE val;
int shareable_literal_p2;
NODE *elt = RNODE_LIST(n)->nd_head;
if (elt) {
CHECK(compile_shareable_literal_constant_next(elt, anchor, &val, &shareable_literal_p2));
if (shareable_literal_p2) {
/* noop */
}
else if (RTEST(lit)) {
rb_ary_clear(lit);
lit = Qfalse;
}
}
if (RTEST(lit)) {
if (!UNDEF_P(val)) {
rb_ary_push(lit, val);
}
else {
rb_ary_clear(lit);
lit = Qnil; /* make shareable at runtime */
}
}
}
break;
}
case NODE_HASH:{
if (!RNODE_HASH(node)->nd_brace) {
*value_p = Qundef;
*shareable_literal_p = 0;
return COMPILE_OK;
}
INIT_ANCHOR(anchor);
lit = rb_hash_new();
for (NODE *n = RNODE_HASH(node)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
VALUE key_val;
VALUE value_val;
int shareable_literal_p2;
NODE *key = RNODE_LIST(n)->nd_head;
NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
if (key) {
CHECK(compile_shareable_literal_constant_next(key, anchor, &key_val, &shareable_literal_p2));
if (shareable_literal_p2) {
/* noop */
}
else if (RTEST(lit)) {
rb_hash_clear(lit);
lit = Qfalse;
}
}
if (val) {
CHECK(compile_shareable_literal_constant_next(val, anchor, &value_val, &shareable_literal_p2));
if (shareable_literal_p2) {
/* noop */
}
else if (RTEST(lit)) {
rb_hash_clear(lit);
lit = Qfalse;
}
}
if (RTEST(lit)) {
if (!UNDEF_P(key_val) && !UNDEF_P(value_val)) {
rb_hash_aset(lit, key_val, value_val);
}
else {
rb_hash_clear(lit);
lit = Qnil; /* make shareable at runtime */
}
}
}
break;
}
default:
if (shareable == rb_parser_shareable_literal &&
(SHAREABLE_BARE_EXPRESSION || level > 0)) {
CHECK(compile_ensure_shareable_node(iseq, ret, dest, node));
*value_p = Qundef;
*shareable_literal_p = 1;
return COMPILE_OK;
}
CHECK(COMPILE(ret, "shareable_literal_constant", node));
*value_p = Qundef;
*shareable_literal_p = 0;
return COMPILE_OK;
}
/* Array or Hash */
if (!lit) {
if (nd_type(node) == NODE_LIST) {
ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
}
else if (nd_type(node) == NODE_HASH) {
int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
ADD_INSN1(anchor, node, newhash, INT2FIX(len));
}
*value_p = Qundef;
*shareable_literal_p = 0;
ADD_SEQ(ret, anchor);
return COMPILE_OK;
}
if (NIL_P(lit)) {
// if shareable_literal, all elements should have been ensured
// as shareable
if (nd_type(node) == NODE_LIST) {
ADD_INSN1(anchor, node, newarray, INT2FIX(RNODE_LIST(node)->as.nd_alen));
}
else if (nd_type(node) == NODE_HASH) {
int len = (int)RNODE_LIST(RNODE_HASH(node)->nd_head)->as.nd_alen;
ADD_INSN1(anchor, node, newhash, INT2FIX(len));
}
CHECK(compile_make_shareable_node(iseq, ret, anchor, node, false));
*value_p = Qundef;
*shareable_literal_p = 1;
}
else {
VALUE val = rb_ractor_make_shareable(lit);
ADD_INSN1(ret, node, putobject, val);
RB_OBJ_WRITTEN(iseq, Qundef, val);
*value_p = val;
*shareable_literal_p = 1;
}
return COMPILE_OK;
}
static int
compile_shareable_constant_value(rb_iseq_t *iseq, LINK_ANCHOR *ret, enum rb_parser_shareability shareable, const NODE *lhs, const NODE *value)
{
int literal_p = 0;
VALUE val;
DECL_ANCHOR(anchor);
INIT_ANCHOR(anchor);
switch (shareable) {
case rb_parser_shareable_none:
CHECK(COMPILE(ret, "compile_shareable_constant_value", value));
return COMPILE_OK;
case rb_parser_shareable_literal:
CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
ADD_SEQ(ret, anchor);
return COMPILE_OK;
case rb_parser_shareable_copy:
case rb_parser_shareable_everything:
CHECK(compile_shareable_literal_constant(iseq, anchor, shareable, (NODE *)lhs, value, 0, &val, &literal_p));
if (!literal_p) {
CHECK(compile_make_shareable_node(iseq, ret, anchor, value, shareable == rb_parser_shareable_copy));
}
else {
ADD_SEQ(ret, anchor);
}
return COMPILE_OK;
}
}
static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
/**
compile each node
@ -10130,7 +10495,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
case NODE_CDECL:{
if (RNODE_CDECL(node)->nd_vid) {
CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
if (!popped) {
ADD_INSN(ret, node, dup);
@ -10142,7 +10507,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const no
}
else {
compile_cpath(ret, iseq, RNODE_CDECL(node)->nd_else);
CHECK(COMPILE(ret, "lvalue", RNODE_CDECL(node)->nd_value));
CHECK(compile_shareable_constant_value(iseq, ret, RNODE_CDECL(node)->shareability, node, RNODE_CDECL(node)->nd_value));
ADD_INSN(ret, node, swap);
if (!popped) {

Просмотреть файл

@ -28,7 +28,6 @@ VALUE rb_node_dregx_string_val(const NODE *);
VALUE rb_node_line_lineno_val(const NODE *);
VALUE rb_node_file_path_val(const NODE *);
VALUE rb_node_encoding_val(const NODE *);
VALUE rb_node_const_decl_val(const NODE *node);
VALUE rb_node_integer_literal_val(const NODE *);
VALUE rb_node_float_literal_val(const NODE *);

Просмотреть файл

@ -60,6 +60,22 @@
field_flag; /* should be optimized away */ \
reset, field_flag = 0)
#define A_SHAREABILITY(shareability) \
switch (shareability) { \
case rb_parser_shareable_none: \
rb_str_cat_cstr(buf, "none"); \
break; \
case rb_parser_shareable_literal: \
rb_str_cat_cstr(buf, "literal"); \
break; \
case rb_parser_shareable_copy: \
rb_str_cat_cstr(buf, "experimental_copy"); \
break; \
case rb_parser_shareable_everything: \
rb_str_cat_cstr(buf, "experimental_everything"); \
break; \
}
#define SIMPLE_FIELD1(name, ann) SIMPLE_FIELD(FIELD_NAME_LEN(name, ann), FIELD_NAME_DESC(name, ann))
#define F_CUSTOM1(name, ann) SIMPLE_FIELD1(#name, ann)
#define F_ID(name, type, ann) SIMPLE_FIELD1(#name, ann) A_ID(type(node)->name)
@ -68,6 +84,7 @@
#define F_LIT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LIT(type(node)->name)
#define F_VALUE(name, val, ann) SIMPLE_FIELD1(#name, ann) A_LIT(val)
#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
#define F_SHAREABILITY(name, type, ann) SIMPLE_FIELD1(#name, ann) A_SHAREABILITY(type(node)->name)
#define F_NODE(name, type, ann) \
COMPOUND_FIELD1(#name, ann) {dump_node(buf, indent, comment, RNODE(type(node)->name));}
@ -463,6 +480,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
F_MSG(nd_vid, "constant", "0 (see extension field)");
F_NODE(nd_else, RNODE_CDECL, "extension");
}
F_SHAREABILITY(shareability, RNODE_CDECL, "shareability");
LAST_NODE;
F_NODE(nd_value, RNODE_CDECL, "rvalue");
return;
@ -513,6 +531,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("example: A::B ||= 1");
F_NODE(nd_head, RNODE_OP_CDECL, "constant");
F_ID(nd_aid, RNODE_OP_CDECL, "operator");
F_SHAREABILITY(shareability, RNODE_OP_CDECL, "shareability");
LAST_NODE;
F_NODE(nd_value, RNODE_OP_CDECL, "rvalue");
return;

319
parse.y
Просмотреть файл

@ -302,13 +302,6 @@ VALUE rb_ripper_none;
#include "ripper_init.h"
#endif
enum shareability {
shareable_none,
shareable_literal,
shareable_copy,
shareable_everything,
};
enum rescue_context {
before_rescue,
after_rescue,
@ -322,7 +315,7 @@ struct lex_context {
unsigned int in_argdef: 1;
unsigned int in_def: 1;
unsigned int in_class: 1;
BITFIELD(enum shareability, shareable_constant_value, 2);
BITFIELD(enum rb_parser_shareability, shareable_constant_value, 2);
BITFIELD(enum rescue_context, in_rescue, 2);
};
@ -1095,13 +1088,13 @@ static rb_node_lasgn_t *rb_node_lasgn_new(struct parser_params *p, ID nd_vid, NO
static rb_node_dasgn_t *rb_node_dasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
static rb_node_gasgn_t *rb_node_gasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
static rb_node_iasgn_t *rb_node_iasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
static rb_node_cdecl_t *rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, const YYLTYPE *loc);
static rb_node_cdecl_t *rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, enum rb_parser_shareability shareability, const YYLTYPE *loc);
static rb_node_cvasgn_t *rb_node_cvasgn_new(struct parser_params *p, ID nd_vid, NODE *nd_value, const YYLTYPE *loc);
static rb_node_op_asgn1_t *rb_node_op_asgn1_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *index, NODE *rvalue, const YYLTYPE *loc);
static rb_node_op_asgn2_t *rb_node_op_asgn2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, ID nd_vid, ID nd_mid, bool nd_aid, const YYLTYPE *loc);
static rb_node_op_asgn_or_t *rb_node_op_asgn_or_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
static rb_node_op_asgn_and_t *rb_node_op_asgn_and_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, const YYLTYPE *loc);
static rb_node_op_cdecl_t *rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, const YYLTYPE *loc);
static rb_node_op_cdecl_t *rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, enum rb_parser_shareability shareability, const YYLTYPE *loc);
static rb_node_call_t *rb_node_call_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
static rb_node_opcall_t *rb_node_opcall_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
static rb_node_fcall_t *rb_node_fcall_new(struct parser_params *p, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
@ -1125,7 +1118,6 @@ static rb_node_nth_ref_t *rb_node_nth_ref_new(struct parser_params *p, long nd_n
static rb_node_back_ref_t *rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc);
static rb_node_match2_t *rb_node_match2_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
static rb_node_match3_t *rb_node_match3_new(struct parser_params *p, NODE *nd_recv, NODE *nd_value, const YYLTYPE *loc);
static rb_node_lit_t *rb_node_lit_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc);
static rb_node_integer_t * rb_node_integer_new(struct parser_params *p, char* val, int base, const YYLTYPE *loc);
static rb_node_float_t * rb_node_float_new(struct parser_params *p, char* val, const YYLTYPE *loc);
static rb_node_rational_t * rb_node_rational_new(struct parser_params *p, char* val, int base, int seen_point, const YYLTYPE *loc);
@ -1204,13 +1196,13 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_DASGN(v,val,loc) (NODE *)rb_node_dasgn_new(p,v,val,loc)
#define NEW_GASGN(v,val,loc) (NODE *)rb_node_gasgn_new(p,v,val,loc)
#define NEW_IASGN(v,val,loc) (NODE *)rb_node_iasgn_new(p,v,val,loc)
#define NEW_CDECL(v,val,path,loc) (NODE *)rb_node_cdecl_new(p,v,val,path,loc)
#define NEW_CDECL(v,val,path,share,loc) (NODE *)rb_node_cdecl_new(p,v,val,path,share,loc)
#define NEW_CVASGN(v,val,loc) (NODE *)rb_node_cvasgn_new(p,v,val,loc)
#define NEW_OP_ASGN1(r,id,idx,rval,loc) (NODE *)rb_node_op_asgn1_new(p,r,id,idx,rval,loc)
#define NEW_OP_ASGN2(r,t,i,o,val,loc) (NODE *)rb_node_op_asgn2_new(p,r,val,i,o,t,loc)
#define NEW_OP_ASGN_OR(i,val,loc) (NODE *)rb_node_op_asgn_or_new(p,i,val,loc)
#define NEW_OP_ASGN_AND(i,val,loc) (NODE *)rb_node_op_asgn_and_new(p,i,val,loc)
#define NEW_OP_CDECL(v,op,val,loc) (NODE *)rb_node_op_cdecl_new(p,v,val,op,loc)
#define NEW_OP_CDECL(v,op,val,share,loc) (NODE *)rb_node_op_cdecl_new(p,v,val,op,share,loc)
#define NEW_CALL(r,m,a,loc) (NODE *)rb_node_call_new(p,r,m,a,loc)
#define NEW_OPCALL(r,m,a,loc) (NODE *)rb_node_opcall_new(p,r,m,a,loc)
#define NEW_FCALL(m,a,loc) rb_node_fcall_new(p,m,a,loc)
@ -1234,7 +1226,6 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_BACK_REF(n,loc) (NODE *)rb_node_back_ref_new(p,n,loc)
#define NEW_MATCH2(n1,n2,loc) (NODE *)rb_node_match2_new(p,n1,n2,loc)
#define NEW_MATCH3(r,n2,loc) (NODE *)rb_node_match3_new(p,r,n2,loc)
#define NEW_LIT(l,loc) (NODE *)rb_node_lit_new(p,l,loc)
#define NEW_INTEGER(val, base,loc) (NODE *)rb_node_integer_new(p,val,base,loc)
#define NEW_FLOAT(val,loc) (NODE *)rb_node_float_new(p,val,loc)
#define NEW_RATIONAL(val,base,seen_point,loc) (NODE *)rb_node_rational_new(p,val,base,seen_point,loc)
@ -9751,23 +9742,23 @@ parser_set_shareable_constant_value(struct parser_params *p, const char *name, c
switch (*val) {
case 'n': case 'N':
if (STRCASECMP(val, "none") == 0) {
p->ctxt.shareable_constant_value = shareable_none;
p->ctxt.shareable_constant_value = rb_parser_shareable_none;
return;
}
break;
case 'l': case 'L':
if (STRCASECMP(val, "literal") == 0) {
p->ctxt.shareable_constant_value = shareable_literal;
p->ctxt.shareable_constant_value = rb_parser_shareable_literal;
return;
}
break;
case 'e': case 'E':
if (STRCASECMP(val, "experimental_copy") == 0) {
p->ctxt.shareable_constant_value = shareable_copy;
p->ctxt.shareable_constant_value = rb_parser_shareable_copy;
return;
}
if (STRCASECMP(val, "experimental_everything") == 0) {
p->ctxt.shareable_constant_value = shareable_everything;
p->ctxt.shareable_constant_value = rb_parser_shareable_everything;
return;
}
break;
@ -12233,15 +12224,6 @@ rb_node_back_ref_new(struct parser_params *p, long nd_nth, const YYLTYPE *loc)
return n;
}
static rb_node_lit_t *
rb_node_lit_new(struct parser_params *p, VALUE nd_lit, const YYLTYPE *loc)
{
rb_node_lit_t *n = NODE_NEWNODE(NODE_LIT, rb_node_lit_t, loc);
n->nd_lit = nd_lit;
return n;
}
static rb_node_integer_t *
rb_node_integer_new(struct parser_params *p, char* val, int base, const YYLTYPE *loc)
{
@ -12652,23 +12634,25 @@ rb_node_encoding_new(struct parser_params *p, const YYLTYPE *loc)
}
static rb_node_cdecl_t *
rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, const YYLTYPE *loc)
rb_node_cdecl_new(struct parser_params *p, ID nd_vid, NODE *nd_value, NODE *nd_else, enum rb_parser_shareability shareability, const YYLTYPE *loc)
{
rb_node_cdecl_t *n = NODE_NEWNODE(NODE_CDECL, rb_node_cdecl_t, loc);
n->nd_vid = nd_vid;
n->nd_value = nd_value;
n->nd_else = nd_else;
n->shareability = shareability;
return n;
}
static rb_node_op_cdecl_t *
rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, const YYLTYPE *loc)
rb_node_op_cdecl_new(struct parser_params *p, NODE *nd_head, NODE *nd_value, ID nd_aid, enum rb_parser_shareability shareability, const YYLTYPE *loc)
{
rb_node_op_cdecl_t *n = NODE_NEWNODE(NODE_OP_CDECL, rb_node_op_cdecl_t, loc);
n->nd_head = nd_head;
n->nd_value = nd_value;
n->nd_aid = nd_aid;
n->shareability = shareability;
return n;
}
@ -13772,7 +13756,7 @@ assignable(struct parser_params *p, ID id, NODE *val, const YYLTYPE *loc)
case NODE_LASGN: return NEW_LASGN(id, val, loc);
case NODE_GASGN: return NEW_GASGN(id, val, loc);
case NODE_IASGN: return NEW_IASGN(id, val, loc);
case NODE_CDECL: return NEW_CDECL(id, val, 0, loc);
case NODE_CDECL: return NEW_CDECL(id, val, 0, p->ctxt.shareable_constant_value, loc);
case NODE_CVASGN: return NEW_CVASGN(id, val, loc);
}
/* TODO: FIXME */
@ -14043,256 +14027,8 @@ mark_lvar_used(struct parser_params *p, NODE *rhs)
}
}
static NODE *
const_decl_path(struct parser_params *p, NODE *dest)
{
NODE *n = dest;
if (!nd_type_p(dest, NODE_CALL)) {
const YYLTYPE *loc = &dest->nd_loc;
VALUE path = rb_node_const_decl_val(dest);
n = NEW_LIT(path, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(n)->nd_lit);
}
return n;
}
static NODE *
make_shareable_node(struct parser_params *p, NODE *value, bool copy, const YYLTYPE *loc)
{
NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, 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 *
ensure_shareable_node(struct parser_params *p, NODE *dest, NODE *value, const YYLTYPE *loc)
{
NODE *fcore = NEW_LIT(rb_mRubyVMFrozenCore, loc);
NODE *args = NEW_LIST(value, loc);
args = list_append(p, args, const_decl_path(p, dest));
return NEW_CALL(fcore, rb_intern("ensure_shareable"), args, loc);
}
static int is_static_content(NODE *node);
static VALUE
shareable_literal_value(struct parser_params *p, NODE *node)
{
if (!node) return Qnil;
enum node_type type = nd_type(node);
switch (type) {
case NODE_TRUE:
return Qtrue;
case NODE_FALSE:
return Qfalse;
case NODE_NIL:
return Qnil;
case NODE_SYM:
return rb_node_sym_string_val(node);
case NODE_LINE:
return rb_node_line_lineno_val(node);
case NODE_INTEGER:
return rb_node_integer_literal_val(node);
case NODE_FLOAT:
return rb_node_float_literal_val(node);
case NODE_RATIONAL:
return rb_node_rational_literal_val(node);
case NODE_IMAGINARY:
return rb_node_imaginary_literal_val(node);
case NODE_ENCODING:
return rb_node_encoding_val(node);
case NODE_REGX:
return rb_node_regx_string_val(node);
case NODE_LIT:
return RNODE_LIT(node)->nd_lit;
default:
return Qundef;
}
}
#ifndef SHAREABLE_BARE_EXPRESSION
#define SHAREABLE_BARE_EXPRESSION 1
#endif
static NODE *
shareable_literal_constant(struct parser_params *p, enum shareability shareable,
NODE *dest, NODE *value, const YYLTYPE *loc, size_t level)
{
# define shareable_literal_constant_next(n) \
shareable_literal_constant(p, shareable, dest, (n), &(n)->nd_loc, level+1)
VALUE lit = Qnil;
if (!value) return 0;
enum node_type type = nd_type(value);
switch (type) {
case NODE_TRUE:
case NODE_FALSE:
case NODE_NIL:
case NODE_LIT:
case NODE_SYM:
case NODE_REGX:
case NODE_LINE:
case NODE_INTEGER:
case NODE_FLOAT:
case NODE_RATIONAL:
case NODE_IMAGINARY:
case NODE_ENCODING:
return value;
case NODE_DSTR:
if (shareable == shareable_literal) {
value = NEW_CALL(value, idUMinus, 0, loc);
}
return value;
case NODE_STR:
lit = rb_str_to_interned_str(rb_node_str_string_val(value));
value = NEW_LIT(lit, loc);
RB_OBJ_WRITE(p->ast, &RNODE_LIT(value)->nd_lit, lit);
return value;
case NODE_FILE:
lit = rb_str_to_interned_str(rb_node_file_path_val(value));
value = NEW_LIT(lit, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(value)->nd_lit);
return value;
case NODE_ZLIST:
lit = rb_ary_new();
OBJ_FREEZE_RAW(lit);
NODE *n = NEW_LIT(lit, loc);
RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(n)->nd_lit);
return n;
case NODE_LIST:
lit = rb_ary_new();
for (NODE *n = value; n; n = RNODE_LIST(n)->nd_next) {
NODE *elt = RNODE_LIST(n)->nd_head;
if (elt) {
elt = shareable_literal_constant_next(elt);
if (elt) {
RNODE_LIST(n)->nd_head = elt;
}
else if (RTEST(lit)) {
rb_ary_clear(lit);
lit = Qfalse;
}
}
if (RTEST(lit)) {
VALUE e = shareable_literal_value(p, elt);
if (!UNDEF_P(e)) {
rb_ary_push(lit, e);
}
else {
rb_ary_clear(lit);
lit = Qnil; /* make shareable at runtime */
}
}
}
break;
case NODE_HASH:
if (!RNODE_HASH(value)->nd_brace) return 0;
lit = rb_hash_new();
for (NODE *n = RNODE_HASH(value)->nd_head; n; n = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_next) {
NODE *key = RNODE_LIST(n)->nd_head;
NODE *val = RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head;
if (key) {
key = shareable_literal_constant_next(key);
if (key) {
RNODE_LIST(n)->nd_head = key;
}
else if (RTEST(lit)) {
rb_hash_clear(lit);
lit = Qfalse;
}
}
if (val) {
val = shareable_literal_constant_next(val);
if (val) {
RNODE_LIST(RNODE_LIST(n)->nd_next)->nd_head = val;
}
else if (RTEST(lit)) {
rb_hash_clear(lit);
lit = Qfalse;
}
}
if (RTEST(lit)) {
VALUE k = shareable_literal_value(p, key);
VALUE v = shareable_literal_value(p, val);
if (!UNDEF_P(k) && !UNDEF_P(v)) {
rb_hash_aset(lit, k, v);
}
else {
rb_hash_clear(lit);
lit = Qnil; /* make shareable at runtime */
}
}
}
break;
default:
if (shareable == shareable_literal &&
(SHAREABLE_BARE_EXPRESSION || level > 0)) {
return ensure_shareable_node(p, dest, value, loc);
}
return 0;
}
/* Array or Hash */
if (!lit) return 0;
if (NIL_P(lit)) {
// if shareable_literal, all elements should have been ensured
// as shareable
value = make_shareable_node(p, value, false, loc);
}
else {
value = NEW_LIT(rb_ractor_make_shareable(lit), loc);
RB_OBJ_WRITTEN(p->ast, Qnil, RNODE_LIT(value)->nd_lit);
}
return value;
# undef shareable_literal_constant_next
}
static NODE *
shareable_constant_value(struct parser_params *p, enum shareability shareable,
NODE *lhs, NODE *value, const YYLTYPE *loc)
{
if (!value) return 0;
switch (shareable) {
case shareable_none:
return value;
case shareable_literal:
{
NODE *lit = shareable_literal_constant(p, shareable, lhs, value, loc, 0);
if (lit) return lit;
return value;
}
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, shareable == shareable_copy, loc);
}
break;
default:
UNREACHABLE_RETURN(0);
}
}
static NODE *
node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ctxt, const YYLTYPE *loc)
{
@ -14300,9 +14036,6 @@ node_assign(struct parser_params *p, NODE *lhs, NODE *rhs, struct lex_context ct
switch (nd_type(lhs)) {
case NODE_CDECL:
rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
/* fallthru */
case NODE_GASGN:
case NODE_IASGN:
case NODE_LASGN:
@ -15281,28 +15014,12 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c
if (lhs) {
ID vid = get_nd_vid(p, lhs);
YYLTYPE lhs_loc = lhs->nd_loc;
int shareable = ctxt.shareable_constant_value;
if (shareable) {
switch (nd_type(lhs)) {
case NODE_CDECL:
case NODE_COLON2:
case NODE_COLON3:
break;
default:
shareable = 0;
break;
}
}
if (op == tOROP) {
rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
set_nd_value(p, lhs, rhs);
nd_set_loc(lhs, loc);
asgn = NEW_OP_ASGN_OR(gettable(p, vid, &lhs_loc), lhs, loc);
}
else if (op == tANDOP) {
if (shareable) {
rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
}
set_nd_value(p, lhs, rhs);
nd_set_loc(lhs, loc);
asgn = NEW_OP_ASGN_AND(gettable(p, vid, &lhs_loc), lhs, loc);
@ -15310,9 +15027,6 @@ new_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct lex_c
else {
asgn = lhs;
rhs = NEW_CALL(gettable(p, vid, &lhs_loc), op, NEW_LIST(rhs, &rhs->nd_loc), loc);
if (shareable) {
rhs = shareable_constant_value(p, shareable, lhs, rhs, &rhs->nd_loc);
}
set_nd_value(p, asgn, rhs);
nd_set_loc(asgn, loc);
}
@ -15353,8 +15067,7 @@ new_const_op_assign(struct parser_params *p, NODE *lhs, ID op, NODE *rhs, struct
NODE *asgn;
if (lhs) {
rhs = shareable_constant_value(p, ctxt.shareable_constant_value, lhs, rhs, loc);
asgn = NEW_OP_CDECL(lhs, op, rhs, loc);
asgn = NEW_OP_CDECL(lhs, op, rhs, ctxt.shareable_constant_value, loc);
}
else {
asgn = NEW_ERROR(loc);
@ -15369,7 +15082,7 @@ const_decl(struct parser_params *p, NODE *path, const YYLTYPE *loc)
if (p->ctxt.in_def) {
yyerror1(loc, "dynamic constant assignment");
}
return NEW_CDECL(0, 0, (path), loc);
return NEW_CDECL(0, 0, (path), p->ctxt.shareable_constant_value, loc);
}
#ifdef RIPPER
static VALUE

Просмотреть файл

@ -994,54 +994,3 @@ rb_node_encoding_val(const NODE *node)
{
return rb_enc_from_encoding(RNODE_ENCODING(node)->enc);
}
VALUE
rb_node_const_decl_val(const NODE *node)
{
VALUE path;
switch (nd_type(node)) {
case NODE_CDECL:
if (RNODE_CDECL(node)->nd_vid) {
path = rb_id2str(RNODE_CDECL(node)->nd_vid);
goto end;
}
else {
node = RNODE_CDECL(node)->nd_else;
}
break;
case NODE_COLON2:
break;
case NODE_COLON3:
// ::Const
path = rb_str_new_cstr("::");
rb_str_append(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
goto end;
default:
rb_bug("unexpected node: %s", ruby_node_name(nd_type(node)));
UNREACHABLE_RETURN(0);
}
path = rb_ary_new();
if (node) {
for (; node && nd_type_p(node, NODE_COLON2); node = RNODE_COLON2(node)->nd_head) {
rb_ary_push(path, rb_id2str(RNODE_COLON2(node)->nd_mid));
}
if (node && nd_type_p(node, NODE_CONST)) {
// Const::Name
rb_ary_push(path, rb_id2str(RNODE_CONST(node)->nd_vid));
}
else if (node && nd_type_p(node, NODE_COLON3)) {
// ::Const::Name
rb_ary_push(path, rb_id2str(RNODE_COLON3(node)->nd_mid));
rb_ary_push(path, rb_str_new(0, 0));
}
else {
// expression::Name
rb_ary_push(path, rb_str_new_cstr("..."));
}
path = rb_ary_join(rb_ary_reverse(path), rb_str_new_cstr("::"));
}
end:
path = rb_fstring(path);
return path;
}

Просмотреть файл

@ -66,6 +66,13 @@ typedef struct rb_parser_string {
char *ptr;
} rb_parser_string_t;
enum rb_parser_shareability {
rb_parser_shareable_none,
rb_parser_shareable_literal,
rb_parser_shareable_copy,
rb_parser_shareable_everything,
};
/*
* AST Node
*/
@ -444,6 +451,7 @@ typedef struct RNode_CDECL {
ID nd_vid;
struct RNode *nd_value;
struct RNode *nd_else;
enum rb_parser_shareability shareability;
} rb_node_cdecl_t;
typedef struct RNode_CVASGN {
@ -492,6 +500,7 @@ typedef struct RNode_OP_CDECL {
struct RNode *nd_head;
struct RNode *nd_value;
ID nd_aid;
enum rb_parser_shareability shareability;
} rb_node_op_cdecl_t;
typedef struct RNode_CALL {