summaryrefslogtreecommitdiff
path: root/iseq.c
diff options
context:
space:
mode:
authormame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-08-23 08:32:30 +0000
committermame <mame@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2018-08-23 08:32:30 +0000
commitd574683c40d42c1ec834c99c2717cbd8de442353 (patch)
tree1fcdc749e929fe7d036d1dd6a8e969041e669792 /iseq.c
parentbf6e2eb7e7ca144dc8a71d87d36edb0d852519a2 (diff)
iseq.c: add a map from encoded insn to insn data
This enhances rb_vm_insn_addr2insn which retrieves a decoded insn number from encoded insn. The insn data table include not only decoded insn number, but also its len, trace and non-trace version of encoded insn. This table can be used to simplify trace instrumentation. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'iseq.c')
-rw-r--r--iseq.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/iseq.c b/iseq.c
index cbd216089e..424771c738 100644
--- a/iseq.c
+++ b/iseq.c
@@ -2862,6 +2862,58 @@ rb_iseq_defined_string(enum defined_type type)
return str;
}
+/* A map from encoded_insn to insn_data: decoded insn number, its len,
+ * non-trace version of encoded insn, and trace version. */
+
+static st_table *encoded_insn_data;
+typedef struct insn_data_struct {
+ int insn;
+ int insn_len;
+ void *notrace_encoded_insn;
+ void *trace_encoded_insn;
+} insn_data_t;
+static insn_data_t insn_data[VM_INSTRUCTION_SIZE/2];
+
+void
+rb_vm_encoded_insn_data_table_init(void)
+{
+#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
+ const void * const *table = rb_vm_get_insns_address_table();
+#define INSN_CODE(insn) ((VALUE)table[insn])
+#else
+#define INSN_CODE(insn) (insn)
+#endif
+ st_data_t insn;
+ encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
+
+ for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
+ st_data_t key1 = (st_data_t)INSN_CODE(insn);
+ st_data_t key2 = (st_data_t)INSN_CODE(insn + VM_INSTRUCTION_SIZE/2);
+
+ insn_data[insn].insn = insn;
+ insn_data[insn].insn_len = insn_len(insn);
+ insn_data[insn].notrace_encoded_insn = (void *) key1;
+ insn_data[insn].trace_encoded_insn = (void *) key2;
+
+ st_add_direct(encoded_insn_data, key1, (st_data_t)&insn_data[insn]);
+ st_add_direct(encoded_insn_data, key2, (st_data_t)&insn_data[insn]);
+ }
+}
+
+int
+rb_vm_insn_addr2insn(const void *addr)
+{
+ st_data_t key = (st_data_t)addr;
+ st_data_t val;
+
+ if (st_lookup(encoded_insn_data, key, &val)) {
+ insn_data_t *e = (insn_data_t *)val;
+ return (int)e->insn;
+ }
+
+ rb_bug("rb_vm_insn_addr2insn: invalid insn address: %p", addr);
+}
+
#define TRACE_INSN_P(insn) ((insn) >= VM_INSTRUCTION_SIZE/2)