diff options
-rw-r--r-- | yjit_codegen.c | 76 | ||||
-rw-r--r-- | yjit_core.c | 41 | ||||
-rw-r--r-- | yjit_core.h | 2 |
3 files changed, 118 insertions, 1 deletions
diff --git a/yjit_codegen.c b/yjit_codegen.c index 388c8b1e17..51f8f4ea54 100644 --- a/yjit_codegen.c +++ b/yjit_codegen.c @@ -119,6 +119,18 @@ jit_peek_at_self(jitstate_t *jit, ctx_t *ctx) return jit->ec->cfp->self; } +static VALUE +jit_peek_at_local(jitstate_t *jit, ctx_t *ctx, int n) +{ + RUBY_ASSERT(jit_at_current_insn(jit)); + + int32_t local_table_size = jit->iseq->body->local_table_size; + RUBY_ASSERT(n < (int)jit->iseq->body->local_table_size); + + const VALUE *ep = jit->ec->cfp->ep; + return ep[-VM_ENV_DATA_SIZE - local_table_size + n + 1]; +} + // When we know a VALUE to be static, this returns an appropriate val_type_t static val_type_t jit_type_of_value(VALUE val) @@ -232,11 +244,70 @@ _add_comment(codeblock_t* cb, const char* comment_str) #define ADD_COMMENT(cb, comment) _add_comment((cb), (comment)) yjit_comment_array_t yjit_code_comments; +// Verify the ctx's types and mappings against the compile-time stack, self, +// and locals. +static void +verify_ctx(jitstate_t *jit, ctx_t *ctx) +{ + // Only able to check types when at current insn + RUBY_ASSERT(jit_at_current_insn(jit)); + + VALUE self_val = jit_peek_at_self(jit, ctx); + if (type_diff(jit_type_of_value(self_val), ctx->self_type) == INT_MAX) { + rb_bug("verify_ctx: ctx type (%s) incompatible with actual value of self: %s", yjit_type_name(ctx->self_type), rb_obj_info(self_val)); + } + + for (int i = 0; i < ctx->stack_size && i < MAX_TEMP_TYPES; i++) { + temp_type_mapping_t learned = ctx_get_opnd_mapping(ctx, OPND_STACK(i)); + VALUE val = jit_peek_at_stack(jit, ctx, i); + val_type_t detected = jit_type_of_value(val); + + if (learned.mapping.kind == TEMP_SELF) { + if (self_val != val) { + rb_bug("verify_ctx: stack value was mapped to self, but values did not match\n" + " stack: %s\n" + " self: %s", + rb_obj_info(val), + rb_obj_info(self_val)); + } + } + + if (learned.mapping.kind == TEMP_LOCAL) { + int local_idx = learned.mapping.idx; + VALUE local_val = jit_peek_at_local(jit, ctx, local_idx); + if (local_val != val) { + rb_bug("verify_ctx: stack value was mapped to local, but values did not match\n" + " stack: %s\n" + " local %i: %s", + rb_obj_info(val), + local_idx, + rb_obj_info(local_val)); + } + } + + if (type_diff(detected, learned.type) == INT_MAX) { + rb_bug("verify_ctx: ctx type (%s) incompatible with actual value on stack: %s", yjit_type_name(learned.type), rb_obj_info(val)); + } + } + + int32_t local_table_size = jit->iseq->body->local_table_size; + for (int i = 0; i < local_table_size && i < MAX_TEMP_TYPES; i++) { + val_type_t learned = ctx->local_types[i]; + VALUE val = jit_peek_at_local(jit, ctx, i); + val_type_t detected = jit_type_of_value(val); + + if (type_diff(detected, learned) == INT_MAX) { + rb_bug("verify_ctx: ctx type (%s) incompatible with actual value of local: %s", yjit_type_name(learned), rb_obj_info(val)); + } + } +} + #else #define GEN_COUNTER_INC(cb, counter_name) ((void)0) #define COUNTED_EXIT(side_exit, counter_name) side_exit #define ADD_COMMENT(cb, comment) ((void)0) +#define verify_ctx(jit, ctx) ((void)0) #endif // if RUBY_DEBUG @@ -484,6 +555,11 @@ yjit_gen_block(block_t *block, rb_execution_context_t *ec) jit.pc = pc; jit.opcode = opcode; + // Verify our existing assumption (DEBUG) + if (jit_at_current_insn(&jit)) { + verify_ctx(&jit, ctx); + } + // Lookup the codegen function for this instruction codegen_fn gen_fn = gen_fns[opcode]; if (!gen_fn) { diff --git a/yjit_core.c b/yjit_core.c index 95bdcc1fa4..0d43129f01 100644 --- a/yjit_core.c +++ b/yjit_core.c @@ -33,6 +33,8 @@ ctx_stack_push_mapping(ctx_t* ctx, temp_type_mapping_t mapping) ctx->temp_types[ctx->stack_size] = mapping.type; RUBY_ASSERT(mapping.mapping.kind != TEMP_LOCAL || mapping.mapping.idx < MAX_LOCAL_TYPES); + RUBY_ASSERT(mapping.mapping.kind != TEMP_STACK || mapping.mapping.idx == 0); + RUBY_ASSERT(mapping.mapping.kind != TEMP_SELF || mapping.mapping.idx == 0); } ctx->stack_size += 1; @@ -155,7 +157,6 @@ ctx_get_opnd_type(const ctx_t* ctx, insn_opnd_t opnd) rb_bug("unreachable"); } -int type_diff(val_type_t src, val_type_t dst); #define UPGRADE_TYPE(dest, src) do { \ RUBY_ASSERT(type_diff((src), (dest)) != INT_MAX); \ (dest) = (src); \ @@ -283,6 +284,44 @@ void ctx_clear_local_types(ctx_t* ctx) memset(&ctx->local_types, 0, sizeof(ctx->local_types)); } +/* The name of a type, for debugging */ +const char * +yjit_type_name(val_type_t type) +{ + RUBY_ASSERT(!(type.is_imm && type.is_heap)); + + switch (type.type) { + case ETYPE_UNKNOWN: + if (type.is_imm) { + return "unknown immediate"; + } else if (type.is_heap) { + return "unknown heap"; + } else { + return "unknown"; + } + case ETYPE_NIL: + return "nil"; + case ETYPE_TRUE: + return "true"; + case ETYPE_FALSE: + return "false"; + case ETYPE_FIXNUM: + return "fixnum"; + case ETYPE_FLONUM: + return "flonum"; + case ETYPE_ARRAY: + return "array"; + case ETYPE_HASH: + return "hash"; + case ETYPE_SYMBOL: + return "symbol"; + case ETYPE_STRING: + return "string"; + } + + UNREACHABLE_RETURN(""); +} + /* Compute a difference between two value types Returns 0 if the two are the same diff --git a/yjit_core.h b/yjit_core.h index c4bbf05833..8530225cd5 100644 --- a/yjit_core.h +++ b/yjit_core.h @@ -270,6 +270,8 @@ void ctx_upgrade_opnd_type(ctx_t* ctx, insn_opnd_t opnd, val_type_t type); void ctx_set_local_type(ctx_t* ctx, size_t idx, val_type_t type); void ctx_clear_local_types(ctx_t* ctx); int ctx_diff(const ctx_t* src, const ctx_t* dst); +int type_diff(val_type_t src, val_type_t dst); +const char *yjit_type_name(val_type_t type); temp_type_mapping_t ctx_get_opnd_mapping(const ctx_t* ctx, insn_opnd_t opnd); void ctx_set_opnd_mapping(ctx_t* ctx, insn_opnd_t opnd, temp_type_mapping_t type_mapping); |