summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2023-03-11 13:32:58 -0800
committerTakashi Kokubun <takashikkbn@gmail.com>2023-03-11 14:19:46 -0800
commit0c0c88d383a09fef18d8cf8a1457d1649a2cbd46 (patch)
tree4c625c35cb6835b7c3e55de39d5087e393fd4cda
parent3a02c7818cb6cbcc70957dfc449ebf32f9dd9e0b (diff)
Support multiple attributes with Primitive.attr!
-rw-r--r--compile.c51
-rw-r--r--rjit_c.rb2
-rw-r--r--tool/mk_builtin_loader.rb19
-rw-r--r--vm_core.h13
-rw-r--r--vm_insnhelper.c2
-rw-r--r--yjit.c8
6 files changed, 67 insertions, 28 deletions
diff --git a/compile.c b/compile.c
index 7a6f324601..76658fc153 100644
--- a/compile.c
+++ b/compile.c
@@ -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;
diff --git a/rjit_c.rb b/rjit_c.rb
index 7b69d043bd..3aeda8b3b4 100644
--- a/rjit_c.rb
+++ b/rjit_c.rb
@@ -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 },
diff --git a/tool/mk_builtin_loader.rb b/tool/mk_builtin_loader.rb
index dce76d1c5f..d6cd32e97c 100644
--- a/tool/mk_builtin_loader.rb
+++ b/tool/mk_builtin_loader.rb
@@ -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
diff --git a/vm_core.h b/vm_core.h
index 2bdd278b46..53019b08a3 100644
--- a/vm_core.h
+++ b/vm_core.h
@@ -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 */
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index ff91c3c362..b3e732d26a 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -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));
diff --git a/yjit.c b/yjit.c
index f5037e6217..50e5818c13 100644
--- a/yjit.c
+++ b/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
);
}