Support multiple attributes with Primitive.attr!

This commit is contained in:
Takashi Kokubun 2023-03-11 13:32:58 -08:00
Родитель 3a02c7818c
Коммит 0c0c88d383
6 изменённых файлов: 67 добавлений и 28 удалений

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

@ -8214,6 +8214,47 @@ delegate_call_p(const rb_iseq_t *iseq, unsigned int argc, const LINK_ANCHOR *arg
}
}
// Compile Primitive.attr! :inline, ...
static int
compile_builtin_attr(rb_iseq_t *iseq, const NODE *node)
{
VALUE symbol;
VALUE string;
if (!node) goto no_arg;
while (node) {
if (!nd_type_p(node, NODE_LIST)) goto bad_arg;
const NODE *next = node->nd_next;
node = node->nd_head;
if (!node) goto no_arg;
if (!nd_type_p(node, NODE_LIT)) goto bad_arg;
symbol = node->nd_lit;
if (!SYMBOL_P(symbol)) goto non_symbol_arg;
string = rb_sym_to_s(symbol);
if (strcmp(RSTRING_PTR(string), "inline") == 0) {
ISEQ_BODY(iseq)->builtin_attrs |= BUILTIN_ATTR_INLINE;
}
else {
goto unknown_arg;
}
node = next;
}
return COMPILE_OK;
no_arg:
COMPILE_ERROR(ERROR_ARGS "attr!: no argument");
return COMPILE_NG;
non_symbol_arg:
COMPILE_ERROR(ERROR_ARGS "non symbol argument to attr!: %s", rb_builtin_class_name(symbol));
return COMPILE_NG;
unknown_arg:
COMPILE_ERROR(ERROR_ARGS "unknown argument to attr!: %s", RSTRING_PTR(string));
return COMPILE_NG;
bad_arg:
UNKNOWN_NODE("attr!", node, COMPILE_NG);
}
static int
compile_builtin_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, const NODE *line_node, int popped)
{
@ -8337,9 +8378,7 @@ compile_builtin_function_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NOD
return COMPILE_OK;
}
else if (strcmp("attr!", builtin_func) == 0) {
// There's only "inline" attribute for now
ISEQ_BODY(iseq)->builtin_inline_p = true;
return COMPILE_OK;
return compile_builtin_attr(iseq, args_node);
}
else if (strcmp("arg!", builtin_func) == 0) {
return compile_builtin_arg(iseq, ret, args_node, line_node, popped);
@ -12122,7 +12161,7 @@ ibf_dump_iseq_each(struct ibf_dump *dump, const rb_iseq_t *iseq)
ibf_dump_write_small_value(dump, body->ci_size);
ibf_dump_write_small_value(dump, body->stack_max);
ibf_dump_write_small_value(dump, body->catch_except_p);
ibf_dump_write_small_value(dump, body->builtin_inline_p);
ibf_dump_write_small_value(dump, body->builtin_attrs);
#undef IBF_BODY_OFFSET
@ -12235,7 +12274,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
const unsigned int ci_size = (unsigned int)ibf_load_small_value(load, &reading_pos);
const unsigned int stack_max = (unsigned int)ibf_load_small_value(load, &reading_pos);
const char catch_except_p = (char)ibf_load_small_value(load, &reading_pos);
const bool builtin_inline_p = (bool)ibf_load_small_value(load, &reading_pos);
const unsigned int builtin_attrs = (unsigned int)ibf_load_small_value(load, &reading_pos);
// setup fname and dummy frame
VALUE path = ibf_load_object(load, location_pathobj_index);
@ -12308,7 +12347,7 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
load_body->location.code_location.end_pos.lineno = location_code_location_end_pos_lineno;
load_body->location.code_location.end_pos.column = location_code_location_end_pos_column;
load_body->catch_except_p = catch_except_p;
load_body->builtin_inline_p = builtin_inline_p;
load_body->builtin_attrs = builtin_attrs;
load_body->ivc_size = ivc_size;
load_body->icvarc_size = icvarc_size;

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

@ -1256,7 +1256,7 @@ module RubyVM::RJIT # :nodoc: all
ci_size: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), ci_size)")],
stack_max: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), stack_max)")],
catch_except_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), catch_except_p)")],
builtin_inline_p: [self._Bool, Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_inline_p)")],
builtin_attrs: [CType::Immediate.parse("unsigned int"), Primitive.cexpr!("OFFSETOF((*((struct rb_iseq_constant_body *)NULL)), builtin_attrs)")],
mark_bits: [CType::Union.new(
"", Primitive.cexpr!("SIZEOF(((struct rb_iseq_constant_body *)NULL)->mark_bits)"),
list: CType::Pointer.new { self.iseq_bits_t },

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

@ -44,13 +44,17 @@ def inline_text argc, arg1
arg1.join("").rstrip
end
def inline_attr(argc, arg1)
raise "argc (#{argc}) of attr! should be 1" unless argc == 1
attr = symbol_literal(arg1)
unless BUILTIN_ATTRS.include?(attr)
raise "attr (#{attr}) was not in: #{BUILTIN_ATTRS.join(', ')}"
def inline_attrs(args)
raise "args was empty" if args.empty?
attrs = []
args.each do |arg|
attr = symbol_literal(arg)
unless BUILTIN_ATTRS.include?(attr)
raise "attr (#{attr}) was not in: #{BUILTIN_ATTRS.join(', ')}"
end
attrs << attr
end
attr
attrs
end
def make_cfunc_name inlines, name, lineno
@ -159,7 +163,8 @@ def collect_builtin base, tree, name, bs, inlines, locals = nil
if /(.+)[\!\?]\z/ =~ func_name
case $1
when 'attr'
text = inline_attr(argc, args.first)
# Compile-time validation only. compile.c will parse them.
inline_attrs(args)
break
when 'cstmt'
text = inline_text argc, args.first

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

@ -365,6 +365,12 @@ enum rb_iseq_type {
ISEQ_TYPE_PLAIN
};
// Attributes specified by Primitive.attr!
enum rb_builtin_attr {
// If true, this ISeq does not call methods.
BUILTIN_ATTR_INLINE = 0x01,
};
struct rb_iseq_constant_body {
enum rb_iseq_type type;
@ -484,12 +490,7 @@ struct rb_iseq_constant_body {
unsigned int stack_max; /* for stack overflow check */
bool catch_except_p; // If a frame of this ISeq may catch exception, set true.
// If true, this ISeq is leaf *and* backtraces are not used, for example,
// by rb_profile_frames. We verify only leafness on VM_CHECK_MODE though.
// Note that GC allocations might use backtraces due to
// ObjectSpace#trace_object_allocations.
// For more details, see: https://bugs.ruby-lang.org/issues/16956
bool builtin_inline_p;
unsigned int builtin_attrs; // Union of rb_builtin_attr
union {
iseq_bits_t * list; /* Find references for GC */

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

@ -6395,7 +6395,7 @@ lookup_builtin_invoker(int argc)
static inline VALUE
invoke_bf(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, const struct rb_builtin_function* bf, const VALUE *argv)
{
const bool canary_p = ISEQ_BODY(reg_cfp->iseq)->builtin_inline_p; // Verify an assumption of `Primitive.attr! 'inline'`
const bool canary_p = ISEQ_BODY(reg_cfp->iseq)->builtin_attrs & BUILTIN_ATTR_INLINE; // Verify an assumption of `Primitive.attr! :inline`
SETUP_CANARY(canary_p);
VALUE ret = (*lookup_builtin_invoker(bf->argc))(ec, reg_cfp->self, argv, (rb_insn_func_t)bf->func_ptr);
CHECK_CANARY(canary_p, BIN(invokebuiltin));

8
yjit.c
Просмотреть файл

@ -620,12 +620,6 @@ rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
return iseq->body->iseq_encoded;
}
bool
rb_get_iseq_body_builtin_inline_p(const rb_iseq_t *iseq)
{
return iseq->body->builtin_inline_p;
}
unsigned
rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
{
@ -741,7 +735,7 @@ rb_leaf_invokebuiltin_iseq_p(const rb_iseq_t *iseq)
return (iseq->body->iseq_size == (invokebuiltin_len + leave_len) &&
rb_vm_insn_addr2opcode((void *)iseq->body->iseq_encoded[0]) == BIN(opt_invokebuiltin_delegate_leave) &&
rb_vm_insn_addr2opcode((void *)iseq->body->iseq_encoded[invokebuiltin_len]) == BIN(leave) &&
iseq->body->builtin_inline_p
(iseq->body->builtin_attrs & BUILTIN_ATTR_INLINE) != 0
);
}