diff options
author | Takashi Kokubun <takashikkbn@gmail.com> | 2023-03-11 13:32:58 -0800 |
---|---|---|
committer | Takashi Kokubun <takashikkbn@gmail.com> | 2023-03-11 14:19:46 -0800 |
commit | 0c0c88d383a09fef18d8cf8a1457d1649a2cbd46 (patch) | |
tree | 4c625c35cb6835b7c3e55de39d5087e393fd4cda | |
parent | 3a02c7818cb6cbcc70957dfc449ebf32f9dd9e0b (diff) |
Support multiple attributes with Primitive.attr!
-rw-r--r-- | compile.c | 51 | ||||
-rw-r--r-- | rjit_c.rb | 2 | ||||
-rw-r--r-- | tool/mk_builtin_loader.rb | 19 | ||||
-rw-r--r-- | vm_core.h | 13 | ||||
-rw-r--r-- | vm_insnhelper.c | 2 | ||||
-rw-r--r-- | yjit.c | 8 |
6 files changed, 67 insertions, 28 deletions
@@ -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 }, 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 @@ -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)); @@ -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 ); } |