aboutsummaryrefslogtreecommitdiffstats
path: root/vm_callinfo.h
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2020-01-08 08:20:36 +0900
committerKoichi Sasada <ko1@atdot.net>2020-02-22 09:58:59 +0900
commitf2286925f08406bc857f7b03ad6779a5d61443ae (patch)
tree62d056c0a8c253f17fccd4a506ddb6cbf1f7bed5 /vm_callinfo.h
parenta1eb1fabef1bca0696449cd358d93f5a644d5914 (diff)
downloadruby-f2286925f08406bc857f7b03ad6779a5d61443ae.tar.gz
VALUE size packed callinfo (ci).
Now, rb_call_info contains how to call the method with tuple of (mid, orig_argc, flags, kwarg). Most of cases, kwarg == NULL and mid+argc+flags only requires 64bits. So this patch packed rb_call_info to VALUE (1 word) on such cases. If we can not represent it in VALUE, then use imemo_callinfo which contains conventional callinfo (rb_callinfo, renamed from rb_call_info). iseq->body->ci_kw_size is removed because all of callinfo is VALUE size (packed ci or a pointer to imemo_callinfo). To access ci information, we need to use these functions: vm_ci_mid(ci), _flag(ci), _argc(ci), _kwarg(ci). struct rb_call_info_kw_arg is renamed to rb_callinfo_kwarg. rb_funcallv_with_cc() and rb_method_basic_definition_p_with_cc() is temporary removed because cd->ci should be marked.
Diffstat (limited to 'vm_callinfo.h')
-rw-r--r--vm_callinfo.h206
1 files changed, 206 insertions, 0 deletions
diff --git a/vm_callinfo.h b/vm_callinfo.h
new file mode 100644
index 0000000000..33d4f614da
--- /dev/null
+++ b/vm_callinfo.h
@@ -0,0 +1,206 @@
+#include "debug_counter.h"
+
+enum vm_call_flag_bits {
+ VM_CALL_ARGS_SPLAT_bit, /* m(*args) */
+ VM_CALL_ARGS_BLOCKARG_bit, /* m(&block) */
+ VM_CALL_FCALL_bit, /* m(...) */
+ VM_CALL_VCALL_bit, /* m */
+ VM_CALL_ARGS_SIMPLE_bit, /* (ci->flag & (SPLAT|BLOCKARG)) && blockiseq == NULL && ci->kw_arg == NULL */
+ VM_CALL_BLOCKISEQ_bit, /* has blockiseq */
+ VM_CALL_KWARG_bit, /* has kwarg */
+ VM_CALL_KW_SPLAT_bit, /* m(**opts) */
+ VM_CALL_TAILCALL_bit, /* located at tail position */
+ VM_CALL_SUPER_bit, /* super */
+ VM_CALL_ZSUPER_bit, /* zsuper */
+ VM_CALL_OPT_SEND_bit, /* internal flag */
+ VM_CALL__END
+};
+
+#define VM_CALL_ARGS_SPLAT (0x01 << VM_CALL_ARGS_SPLAT_bit)
+#define VM_CALL_ARGS_BLOCKARG (0x01 << VM_CALL_ARGS_BLOCKARG_bit)
+#define VM_CALL_FCALL (0x01 << VM_CALL_FCALL_bit)
+#define VM_CALL_VCALL (0x01 << VM_CALL_VCALL_bit)
+#define VM_CALL_ARGS_SIMPLE (0x01 << VM_CALL_ARGS_SIMPLE_bit)
+#define VM_CALL_BLOCKISEQ (0x01 << VM_CALL_BLOCKISEQ_bit)
+#define VM_CALL_KWARG (0x01 << VM_CALL_KWARG_bit)
+#define VM_CALL_KW_SPLAT (0x01 << VM_CALL_KW_SPLAT_bit)
+#define VM_CALL_TAILCALL (0x01 << VM_CALL_TAILCALL_bit)
+#define VM_CALL_SUPER (0x01 << VM_CALL_SUPER_bit)
+#define VM_CALL_ZSUPER (0x01 << VM_CALL_ZSUPER_bit)
+#define VM_CALL_OPT_SEND (0x01 << VM_CALL_OPT_SEND_bit)
+
+struct rb_callinfo_kwarg {
+ int keyword_len;
+ VALUE keywords[1];
+};
+
+static inline size_t
+rb_callinfo_kwarg_bytes(int keyword_len)
+{
+ return rb_size_mul_add_or_raise(
+ keyword_len - 1,
+ sizeof(VALUE),
+ sizeof(struct rb_callinfo_kwarg),
+ rb_eRuntimeError);
+}
+
+// imemo_callinfo
+struct rb_callinfo {
+ VALUE flags;
+ const struct rb_callinfo_kwarg *kwarg;
+ VALUE mid;
+ VALUE flag;
+ VALUE argc;
+};
+
+#ifndef USE_EMBED_CI
+#define USE_EMBED_CI 1
+#endif
+
+#if SIZEOF_VALUE == 8
+#define CI_EMBED_TAG_bits 1
+#define CI_EMBED_ARGC_bits 15
+#define CI_EMBED_FLAG_bits 16
+#define CI_EMBED_ID_bits 32
+#elif SIZEOF_VALUE == 4
+#define CI_EMBED_TAG_bits 1
+#define CI_EMBED_ARGC_bits 4
+#define CI_EMBED_FLAG_bits 12
+#define CI_EMBED_ID_bits 15
+#endif
+
+#if (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits + CI_EMBED_ID_bits) != (SIZEOF_VALUE * 8)
+#error
+#endif
+
+#define CI_EMBED_FLAG 0x01
+#define CI_EMBED_ARGC_SHFT (CI_EMBED_TAG_bits)
+#define CI_EMBED_ARGC_MASK ((1UL<<CI_EMBED_ARGC_bits) - 1)
+#define CI_EMBED_FLAG_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits)
+#define CI_EMBED_FLAG_MASK ((1UL<<CI_EMBED_FLAG_bits) - 1)
+#define CI_EMBED_ID_SHFT (CI_EMBED_TAG_bits + CI_EMBED_ARGC_bits + CI_EMBED_FLAG_bits)
+#define CI_EMBED_ID_MASK ((1UL<<CI_EMBED_ID_bits) - 1)
+
+static inline int
+vm_ci_packed_p(const struct rb_callinfo *ci)
+{
+#if USE_EMBED_CI
+ if (LIKELY(((VALUE)ci) & 0x01)) {
+ return 1;
+ }
+ else {
+ VM_ASSERT(imemo_type_p((VALUE)ci, imemo_callinfo));
+ return 0;
+ }
+#else
+ return 0;
+#endif
+}
+
+static inline ID
+vm_ci_mid(const struct rb_callinfo *ci)
+{
+ if (vm_ci_packed_p(ci)) {
+ return (((VALUE)ci) >> CI_EMBED_ID_SHFT) & CI_EMBED_ID_MASK;
+ }
+ else {
+ return (ID)ci->mid;
+ }
+}
+
+static inline unsigned int
+vm_ci_flag(const struct rb_callinfo *ci)
+{
+ if (vm_ci_packed_p(ci)) {
+ return (unsigned int)((((VALUE)ci) >> CI_EMBED_FLAG_SHFT) & CI_EMBED_FLAG_MASK);
+ }
+ else {
+ return (unsigned int)ci->flag;
+ }
+}
+
+static inline unsigned int
+vm_ci_argc(const struct rb_callinfo *ci)
+{
+ if (vm_ci_packed_p(ci)) {
+ return (unsigned int)((((VALUE)ci) >> CI_EMBED_ARGC_SHFT) & CI_EMBED_ARGC_MASK);
+ }
+ else {
+ return (unsigned int)ci->argc;
+ }
+}
+
+static inline const struct rb_callinfo_kwarg *
+vm_ci_kwarg(const struct rb_callinfo *ci)
+{
+ if (vm_ci_packed_p(ci)) {
+ return NULL;
+ }
+ else {
+ return ci->kwarg;
+ }
+}
+
+#if 0 // for debug
+static inline void
+vm_ci_dump(const struct rb_callinfo *ci)
+{
+ if (vm_ci_packed_p(ci)) {
+ fprintf(stderr, "packed_ci ID:%s flag:%x argc:%u\n",
+ rb_id2name(vm_ci_mid(ci)), vm_ci_flag(ci), vm_ci_argc(ci));
+ }
+ else {
+ rp(ci);
+ }
+}
+#endif
+
+#define vm_ci_new(mid, flag, argc, kwarg) vm_ci_new_(mid, flag, argc, kwarg, __FILE__, __LINE__)
+#define vm_ci_new_runtime(mid, flag, argc, kwarg) vm_ci_new_runtime_(mid, flag, argc, kwarg, __FILE__, __LINE__)
+
+static inline const struct rb_callinfo *
+vm_ci_new_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
+{
+#if USE_EMBED_CI
+
+ if ((mid & ~CI_EMBED_ID_MASK) == 0 &&
+ (argc & ~CI_EMBED_ARGC_MASK) == 0 &&
+ kwarg == NULL) {
+ VALUE embed_ci =
+ 1L |
+ ((VALUE)argc << CI_EMBED_ARGC_SHFT) |
+ ((VALUE)flag << CI_EMBED_FLAG_SHFT) |
+ ((VALUE)mid << CI_EMBED_ID_SHFT);
+ RB_DEBUG_COUNTER_INC(ci_packed);
+ return (const struct rb_callinfo *)embed_ci;
+ }
+#endif
+ const bool debug = 0;
+ if (debug) fprintf(stderr, "%s:%d ", file, line);
+ const struct rb_callinfo *ci = (const struct rb_callinfo *)
+ rb_imemo_new(imemo_callinfo,
+ (VALUE)mid,
+ (VALUE)flag,
+ (VALUE)argc,
+ (VALUE)kwarg);
+ if (debug) rp(ci);
+ if (kwarg) {
+ RB_DEBUG_COUNTER_INC(ci_kw);
+ }
+ else {
+ RB_DEBUG_COUNTER_INC(ci_nokw);
+ }
+
+ VM_ASSERT(vm_ci_flag(ci) == flag);
+ VM_ASSERT(vm_ci_argc(ci) == argc);
+
+ return ci;
+}
+
+
+static inline const struct rb_callinfo *
+vm_ci_new_runtime_(ID mid, unsigned int flag, unsigned int argc, const struct rb_callinfo_kwarg *kwarg, const char *file, int line)
+{
+ RB_DEBUG_COUNTER_INC(ci_runtime);
+ return vm_ci_new_(mid, flag, argc, kwarg, file, line);
+}