зеркало из https://github.com/github/ruby.git
Put YJIT into a single compilation unit
For upstreaming, we want functions we export either prefixed with "rb_" or made static. Historically we haven't been following this rule, so we were "leaking" a lot of symbols as `make leak-globals` would tell us. This change unifies everything YJIT into a single compilation unit, yjit.o, and makes everything unprefixed static to pass `make leak-globals`. This manual "unified build" setup is similar to that of vm.o. Having everything in one compilation unit allows static functions to be visible across YJIT files and removes the need for declarations in headers in some cases. Unnecessary declarations were removed. Other changes of note: - switched to MJIT_SYMBOL_EXPORT_BEGIN which indicates stuff as being off limits for native extensions - the first include of each YJIT file is change to be "internal.h" - undefined MAP_STACK before explicitly redefining it since it collide's with a definition in system headers. Consider renaming?
This commit is contained in:
Родитель
25eed28483
Коммит
f6da559d5b
1031
common.mk
1031
common.mk
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,7 +1,9 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
clang -std=gnu99 -Wall -Werror -Wshorten-64-to-32 yjit_asm.c yjit_asm_tests.c -o asm_test
|
||||
clang -std=gnu99 -Wall -Werror -Wno-error=unused-function -Wshorten-64-to-32 yjit_asm.c yjit_asm_tests.c -o asm_test
|
||||
|
||||
./asm_test
|
||||
|
||||
|
|
|
@ -4808,7 +4808,7 @@ vm_ic_update(const rb_iseq_t *iseq, IC ic, VALUE val, const VALUE *reg_ep)
|
|||
ruby_vm_const_missing_count = 0;
|
||||
RB_OBJ_WRITE(iseq, &ic->entry, ice);
|
||||
#ifndef MJIT_HEADER
|
||||
yjit_constant_ic_update(iseq, ic);
|
||||
rb_yjit_constant_ic_update(iseq, ic);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ update_global_event_hook(rb_event_flag_t vm_events)
|
|||
// Invalidate all code if listening for any TracePoint event.
|
||||
// Internal events fire inside C routines so don't need special handling.
|
||||
// Do this last so other ractors see updated vm events when they wake up.
|
||||
yjit_tracing_invalidate_all();
|
||||
rb_yjit_tracing_invalidate_all();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1220,7 +1220,7 @@ rb_tracepoint_enable_for_target(VALUE tpval, VALUE target, VALUE target_line)
|
|||
rb_raise(rb_eArgError, "can not enable any hooks");
|
||||
}
|
||||
|
||||
yjit_tracing_invalidate_all();
|
||||
rb_yjit_tracing_invalidate_all();
|
||||
|
||||
ruby_vm_event_local_num++;
|
||||
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
// YJIT combined compilation unit. This setup allows spreading functions
|
||||
// across different files without having to worry about putting things
|
||||
// in headers and prefixing function names.
|
||||
#include "internal.h"
|
||||
#include "vm_core.h"
|
||||
#include "vm_callinfo.h"
|
||||
#include "builtin.h"
|
||||
#include "insns.inc"
|
||||
#include "insns_info.inc"
|
||||
#include "vm_sync.h"
|
||||
#include "yjit.h"
|
||||
|
||||
#include "yjit_asm.c"
|
||||
|
||||
// Code block into which we write machine code
|
||||
static codeblock_t block;
|
||||
static codeblock_t *cb = NULL;
|
||||
|
||||
// Code block into which we write out-of-line machine code
|
||||
static codeblock_t outline_block;
|
||||
static codeblock_t *ocb = NULL;
|
||||
|
||||
#if YJIT_STATS
|
||||
// Comments for generated code
|
||||
struct yjit_comment {
|
||||
uint32_t offset;
|
||||
const char *comment;
|
||||
};
|
||||
|
||||
typedef rb_darray(struct yjit_comment) yjit_comment_array_t;
|
||||
static yjit_comment_array_t yjit_code_comments;
|
||||
|
||||
// Counters for generated code
|
||||
#define YJIT_DECLARE_COUNTERS(...) struct rb_yjit_runtime_counters { \
|
||||
int64_t __VA_ARGS__; \
|
||||
}; \
|
||||
static char yjit_counter_names[] = #__VA_ARGS__;
|
||||
|
||||
YJIT_DECLARE_COUNTERS(
|
||||
exec_instruction,
|
||||
|
||||
send_keywords,
|
||||
send_kw_splat,
|
||||
send_args_splat,
|
||||
send_block_arg,
|
||||
send_ivar_set_method,
|
||||
send_zsuper_method,
|
||||
send_undef_method,
|
||||
send_optimized_method,
|
||||
send_missing_method,
|
||||
send_bmethod,
|
||||
send_refined_method,
|
||||
send_cfunc_ruby_array_varg,
|
||||
send_cfunc_argc_mismatch,
|
||||
send_cfunc_toomany_args,
|
||||
send_cfunc_tracing,
|
||||
send_iseq_tailcall,
|
||||
send_iseq_arity_error,
|
||||
send_iseq_only_keywords,
|
||||
send_iseq_complex_callee,
|
||||
send_not_implemented_method,
|
||||
send_getter_arity,
|
||||
send_se_cf_overflow,
|
||||
send_se_protected_check_failed,
|
||||
|
||||
traced_cfunc_return,
|
||||
|
||||
invokesuper_me_changed,
|
||||
invokesuper_block,
|
||||
|
||||
leave_se_interrupt,
|
||||
leave_interp_return,
|
||||
leave_start_pc_non_zero,
|
||||
|
||||
getivar_se_self_not_heap,
|
||||
getivar_idx_out_of_range,
|
||||
|
||||
setivar_se_self_not_heap,
|
||||
setivar_idx_out_of_range,
|
||||
setivar_val_heapobject,
|
||||
setivar_name_not_mapped,
|
||||
setivar_not_object,
|
||||
setivar_frozen,
|
||||
|
||||
oaref_argc_not_one,
|
||||
oaref_arg_not_fixnum,
|
||||
|
||||
opt_getinlinecache_miss,
|
||||
|
||||
binding_allocations,
|
||||
binding_set,
|
||||
|
||||
vm_insns_count,
|
||||
compiled_iseq_count,
|
||||
compiled_block_count,
|
||||
|
||||
invalidation_count,
|
||||
invalidate_method_lookup,
|
||||
invalidate_bop_redefined,
|
||||
invalidate_ractor_spawn,
|
||||
invalidate_constant_state_bump,
|
||||
invalidate_constant_ic_fill,
|
||||
|
||||
constant_state_bumps,
|
||||
|
||||
expandarray_splat,
|
||||
expandarray_postarg,
|
||||
expandarray_not_array,
|
||||
expandarray_rhs_too_small,
|
||||
|
||||
gbpp_block_param_modified,
|
||||
gbpp_block_handler_not_iseq,
|
||||
|
||||
// Member with known name for iterating over counters
|
||||
last_member
|
||||
)
|
||||
|
||||
static struct rb_yjit_runtime_counters yjit_runtime_counters = { 0 };
|
||||
#undef YJIT_DECLARE_COUNTERS
|
||||
|
||||
#endif // YJIT_STATS
|
||||
|
||||
// The number of bytes counting from the beginning of the inline code block
|
||||
// that should not be changed. After patching for global invalidation, no one
|
||||
// should make changes to the invalidated code region anymore. This is used to
|
||||
// break out of invalidation race when there are multiple ractors.
|
||||
static uint32_t yjit_codepage_frozen_bytes = 0;
|
||||
|
||||
#include "yjit_utils.c"
|
||||
#include "yjit_core.c"
|
||||
#include "yjit_iface.c"
|
||||
#include "yjit_codegen.c"
|
8
yjit.h
8
yjit.h
|
@ -62,10 +62,10 @@ struct rb_yjit_options {
|
|||
bool test_backend;
|
||||
};
|
||||
|
||||
RUBY_SYMBOL_EXPORT_BEGIN
|
||||
MJIT_SYMBOL_EXPORT_BEGIN
|
||||
bool rb_yjit_enabled_p(void);
|
||||
unsigned rb_yjit_call_threshold(void);
|
||||
RUBY_SYMBOL_EXPORT_END
|
||||
MJIT_SYMBOL_EXPORT_END
|
||||
|
||||
void rb_yjit_invalidate_all_method_lookup_assumptions(void);
|
||||
void rb_yjit_method_lookup_change(VALUE klass, ID mid);
|
||||
|
@ -81,7 +81,7 @@ void rb_yjit_iseq_mark(const struct rb_iseq_constant_body *body);
|
|||
void rb_yjit_iseq_update_references(const struct rb_iseq_constant_body *body);
|
||||
void rb_yjit_iseq_free(const struct rb_iseq_constant_body *body);
|
||||
void rb_yjit_before_ractor_spawn(void);
|
||||
void yjit_constant_ic_update(const rb_iseq_t *iseq, IC ic);
|
||||
void yjit_tracing_invalidate_all(void);
|
||||
void rb_yjit_constant_ic_update(const rb_iseq_t *iseq, IC ic);
|
||||
void rb_yjit_tracing_invalidate_all(void);
|
||||
|
||||
#endif // #ifndef YJIT_H
|
||||
|
|
37
yjit_asm.c
37
yjit_asm.c
|
@ -1,6 +1,9 @@
|
|||
// For MAP_ANONYMOUS on GNU/Linux
|
||||
#define _GNU_SOURCE
|
||||
|
||||
// This file is a fragment of the yjit.o compilation unit. See yjit.c.
|
||||
//
|
||||
// Note that the definition for some of these functions don't specify
|
||||
// static inline, but their declaration in yjit_asm.h do. The resulting
|
||||
// linkage is the same as if they both specify. The relevant sections in
|
||||
// N1256 is 6.2.2p4, 6.2.2p5, and 6.7.4p5.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -97,7 +100,7 @@ x86opnd_t mem_opnd_sib(uint32_t num_bits, x86opnd_t base_reg, x86opnd_t index_re
|
|||
return opnd;
|
||||
}
|
||||
|
||||
x86opnd_t resize_opnd(x86opnd_t opnd, uint32_t num_bits)
|
||||
static x86opnd_t resize_opnd(x86opnd_t opnd, uint32_t num_bits)
|
||||
{
|
||||
assert (num_bits % 8 == 0);
|
||||
x86opnd_t sub = opnd;
|
||||
|
@ -220,10 +223,10 @@ uint8_t *alloc_exec_mem(uint32_t mem_size)
|
|||
}
|
||||
|
||||
// Head of the list of free code pages
|
||||
code_page_t *freelist = NULL;
|
||||
static code_page_t *freelist = NULL;
|
||||
|
||||
// Allocate a single code page from a pool of free pages
|
||||
code_page_t *alloc_code_page()
|
||||
code_page_t *alloc_code_page(void)
|
||||
{
|
||||
// If the free list is empty
|
||||
if (!freelist) {
|
||||
|
@ -443,7 +446,7 @@ void cb_link_labels(codeblock_t *cb)
|
|||
}
|
||||
|
||||
// Check if an operand needs a REX byte to be encoded
|
||||
bool rex_needed(x86opnd_t opnd)
|
||||
static bool rex_needed(x86opnd_t opnd)
|
||||
{
|
||||
if (opnd.type == OPND_NONE || opnd.type == OPND_IMM)
|
||||
{
|
||||
|
@ -467,7 +470,7 @@ bool rex_needed(x86opnd_t opnd)
|
|||
}
|
||||
|
||||
// Check if an SIB byte is needed to encode this operand
|
||||
bool sib_needed(x86opnd_t opnd)
|
||||
static bool sib_needed(x86opnd_t opnd)
|
||||
{
|
||||
if (opnd.type != OPND_MEM)
|
||||
return false;
|
||||
|
@ -480,7 +483,7 @@ bool sib_needed(x86opnd_t opnd)
|
|||
}
|
||||
|
||||
// Compute the size of the displacement field needed for a memory operand
|
||||
uint32_t disp_size(x86opnd_t opnd)
|
||||
static uint32_t disp_size(x86opnd_t opnd)
|
||||
{
|
||||
assert (opnd.type == OPND_MEM);
|
||||
|
||||
|
@ -546,7 +549,7 @@ static void cb_write_opcode(codeblock_t *cb, uint8_t opcode, x86opnd_t reg)
|
|||
}
|
||||
|
||||
// Encode an RM instruction
|
||||
void cb_write_rm(
|
||||
static void cb_write_rm(
|
||||
codeblock_t *cb,
|
||||
bool szPref,
|
||||
bool rexW,
|
||||
|
@ -707,7 +710,7 @@ void cb_write_rm(
|
|||
}
|
||||
|
||||
// Encode a mul-like single-operand RM instruction
|
||||
void write_rm_unary(
|
||||
static void write_rm_unary(
|
||||
codeblock_t *cb,
|
||||
const char *mnem,
|
||||
uint8_t opMemReg8,
|
||||
|
@ -736,7 +739,7 @@ void write_rm_unary(
|
|||
}
|
||||
|
||||
// Encode an add-like RM instruction with multiple possible encodings
|
||||
void cb_write_rm_multi(
|
||||
static void cb_write_rm_multi(
|
||||
codeblock_t *cb,
|
||||
const char *mnem,
|
||||
uint8_t opMemReg8,
|
||||
|
@ -835,7 +838,7 @@ void cb_write_rm_multi(
|
|||
}
|
||||
|
||||
// Encode a single-operand shift instruction
|
||||
void cb_write_shift(
|
||||
static void cb_write_shift(
|
||||
codeblock_t *cb,
|
||||
const char *mnem,
|
||||
uint8_t opMemOnePref,
|
||||
|
@ -886,7 +889,7 @@ void cb_write_shift(
|
|||
|
||||
// Encode a relative jump to a label (direct or conditional)
|
||||
// Note: this always encodes a 32-bit offset
|
||||
void cb_write_jcc(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op1, uint32_t label_idx)
|
||||
static void cb_write_jcc(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op1, uint32_t label_idx)
|
||||
{
|
||||
//cb.writeASM(mnem, label);
|
||||
|
||||
|
@ -903,7 +906,7 @@ void cb_write_jcc(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op1, u
|
|||
}
|
||||
|
||||
// Encode a relative jump to a pointer at a 32-bit offset (direct or conditional)
|
||||
void cb_write_jcc_ptr(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op1, uint8_t *dst_ptr)
|
||||
static void cb_write_jcc_ptr(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op1, uint8_t *dst_ptr)
|
||||
{
|
||||
//cb.writeASM(mnem, label);
|
||||
|
||||
|
@ -924,7 +927,7 @@ void cb_write_jcc_ptr(codeblock_t *cb, const char *mnem, uint8_t op0, uint8_t op
|
|||
}
|
||||
|
||||
// Encode a conditional move instruction
|
||||
void cb_write_cmov(codeblock_t *cb, const char *mnem, uint8_t opcode1, x86opnd_t dst, x86opnd_t src)
|
||||
static void cb_write_cmov(codeblock_t *cb, const char *mnem, uint8_t opcode1, x86opnd_t dst, x86opnd_t src)
|
||||
{
|
||||
//cb.writeASM(mnem, dst, src);
|
||||
|
||||
|
@ -977,7 +980,7 @@ void and(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1)
|
|||
}
|
||||
|
||||
// call - Call to a pointer with a 32-bit displacement offset
|
||||
void call_rel32(codeblock_t *cb, int32_t rel32)
|
||||
static void call_rel32(codeblock_t *cb, int32_t rel32)
|
||||
{
|
||||
//cb.writeASM("call", rel32);
|
||||
|
||||
|
|
296
yjit_asm.h
296
yjit_asm.h
|
@ -234,20 +234,20 @@ static const x86opnd_t R15B = { OPND_REG, 8, .as.reg = { REG_GP, 15 }};
|
|||
#define C_ARG_REGS ( (x86opnd_t[]){ RDI, RSI, RDX, RCX, R8, R9 } )
|
||||
|
||||
// Compute the number of bits needed to store a signed or unsigned value
|
||||
uint32_t sig_imm_size(int64_t imm);
|
||||
uint32_t unsig_imm_size(uint64_t imm);
|
||||
static inline uint32_t sig_imm_size(int64_t imm);
|
||||
static inline uint32_t unsig_imm_size(uint64_t imm);
|
||||
|
||||
// Memory operand with base register and displacement/offset
|
||||
x86opnd_t mem_opnd(uint32_t num_bits, x86opnd_t base_reg, int32_t disp);
|
||||
static inline x86opnd_t mem_opnd(uint32_t num_bits, x86opnd_t base_reg, int32_t disp);
|
||||
|
||||
// Scale-index-base memory operand
|
||||
x86opnd_t mem_opnd_sib(uint32_t num_bits, x86opnd_t base_reg, x86opnd_t index_reg, int32_t scale, int32_t disp);
|
||||
static inline x86opnd_t mem_opnd_sib(uint32_t num_bits, x86opnd_t base_reg, x86opnd_t index_reg, int32_t scale, int32_t disp);
|
||||
|
||||
// Immediate number operand
|
||||
x86opnd_t imm_opnd(int64_t val);
|
||||
static inline x86opnd_t imm_opnd(int64_t val);
|
||||
|
||||
// Constant pointer operand
|
||||
x86opnd_t const_ptr_opnd(const void *ptr);
|
||||
static inline x86opnd_t const_ptr_opnd(const void *ptr);
|
||||
|
||||
// Struct member operand
|
||||
#define member_opnd(base_reg, struct_type, member_name) mem_opnd( \
|
||||
|
@ -265,150 +265,150 @@ x86opnd_t const_ptr_opnd(const void *ptr);
|
|||
)
|
||||
|
||||
// Machine code allocation
|
||||
uint8_t *alloc_exec_mem(uint32_t mem_size);
|
||||
code_page_t *alloc_code_page(void);
|
||||
void free_code_page(code_page_t *code_page);
|
||||
static uint8_t *alloc_exec_mem(uint32_t mem_size);
|
||||
static code_page_t *alloc_code_page(void);
|
||||
static void free_code_page(code_page_t *code_page);
|
||||
|
||||
// Code block methods
|
||||
void cb_init(codeblock_t *cb, uint8_t *mem_block, uint32_t mem_size);
|
||||
void cb_align_pos(codeblock_t *cb, uint32_t multiple);
|
||||
void cb_set_pos(codeblock_t *cb, uint32_t pos);
|
||||
void cb_set_write_ptr(codeblock_t *cb, uint8_t *code_ptr);
|
||||
uint8_t *cb_get_ptr(codeblock_t *cb, uint32_t index);
|
||||
uint8_t *cb_get_write_ptr(codeblock_t *cb);
|
||||
void cb_write_byte(codeblock_t *cb, uint8_t byte);
|
||||
void cb_write_bytes(codeblock_t *cb, uint32_t num_bytes, ...);
|
||||
void cb_write_int(codeblock_t *cb, uint64_t val, uint32_t num_bits);
|
||||
uint32_t cb_new_label(codeblock_t *cb, const char *name);
|
||||
void cb_write_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void cb_label_ref(codeblock_t *cb, uint32_t label_idx);
|
||||
void cb_link_labels(codeblock_t *cb);
|
||||
|
||||
static inline void cb_init(codeblock_t *cb, uint8_t *mem_block, uint32_t mem_size);
|
||||
static inline void cb_align_pos(codeblock_t *cb, uint32_t multiple);
|
||||
static inline void cb_set_pos(codeblock_t *cb, uint32_t pos);
|
||||
static inline void cb_set_write_ptr(codeblock_t *cb, uint8_t *code_ptr);
|
||||
static inline uint8_t *cb_get_ptr(codeblock_t *cb, uint32_t index);
|
||||
static inline uint8_t *cb_get_write_ptr(codeblock_t *cb);
|
||||
static inline void cb_write_byte(codeblock_t *cb, uint8_t byte);
|
||||
static inline void cb_write_bytes(codeblock_t *cb, uint32_t num_bytes, ...);
|
||||
static inline void cb_write_int(codeblock_t *cb, uint64_t val, uint32_t num_bits);
|
||||
static inline uint32_t cb_new_label(codeblock_t *cb, const char *name);
|
||||
static inline void cb_write_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void cb_label_ref(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void cb_link_labels(codeblock_t *cb);
|
||||
|
||||
// Encode individual instructions into a code block
|
||||
void add(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void and(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void call_ptr(codeblock_t *cb, x86opnd_t scratch_reg, uint8_t *dst_ptr);
|
||||
void call_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void call(codeblock_t *cb, x86opnd_t opnd);
|
||||
void cmova(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovae(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovb(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovbe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovc(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmove(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovg(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovge(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovl(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovle(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovna(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnae(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnb(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnbe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnc(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovne(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovng(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnge(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnl(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnle(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovno(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnp(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovns(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovnz(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovo(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovp(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovpe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovpo(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovs(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmovz(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void cmp(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void cdq(codeblock_t *cb);
|
||||
void cqo(codeblock_t *cb);
|
||||
void int3(codeblock_t *cb);
|
||||
void ja_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jae_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jb_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jbe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jc_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void je_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jg_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jge_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jl_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jle_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jna_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnae_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnb_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnbe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnc_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jne_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jng_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnge_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnl_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnle_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jno_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jns_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jnz_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jo_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jpe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jpo_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void js_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jz_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void ja_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jae_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jb_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jbe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jc_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void je_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jg_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jge_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jl_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jle_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jna_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnae_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnb_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnbe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnc_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jne_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jng_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnge_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnl_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnle_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jno_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jns_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jnz_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jo_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jpe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jpo_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void js_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jz_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jmp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
void jmp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
void jmp_rm(codeblock_t *cb, x86opnd_t opnd);
|
||||
void jmp32(codeblock_t *cb, int32_t offset);
|
||||
void lea(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void mov(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void movsx(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
void neg(codeblock_t *cb, x86opnd_t opnd);
|
||||
void nop(codeblock_t *cb, uint32_t length);
|
||||
void not(codeblock_t *cb, x86opnd_t opnd);
|
||||
void or(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void pop(codeblock_t *cb, x86opnd_t reg);
|
||||
void popfq(codeblock_t *cb);
|
||||
void push(codeblock_t *cb, x86opnd_t opnd);
|
||||
void pushfq(codeblock_t *cb);
|
||||
void ret(codeblock_t *cb);
|
||||
void sal(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void sar(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void shl(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void shr(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void sub(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void test(codeblock_t *cb, x86opnd_t rm_opnd, x86opnd_t test_opnd);
|
||||
void ud2(codeblock_t *cb);
|
||||
void xchg(codeblock_t *cb, x86opnd_t rm_opnd, x86opnd_t r_opnd);
|
||||
void xor(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
void cb_write_lock_prefix(codeblock_t *cb);
|
||||
static inline void add(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void and(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void call_ptr(codeblock_t *cb, x86opnd_t scratch_reg, uint8_t *dst_ptr);
|
||||
static inline void call_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void call(codeblock_t *cb, x86opnd_t opnd);
|
||||
static inline void cmova(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovae(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovb(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovbe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovc(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmove(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovg(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovge(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovl(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovle(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovna(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnae(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnb(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnbe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnc(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovne(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovng(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnge(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnl(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnle(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovno(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnp(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovns(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovnz(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovo(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovp(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovpe(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovpo(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovs(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmovz(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void cmp(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void cdq(codeblock_t *cb);
|
||||
static inline void cqo(codeblock_t *cb);
|
||||
static inline void int3(codeblock_t *cb);
|
||||
static inline void ja_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jae_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jb_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jbe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jc_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void je_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jg_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jge_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jl_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jle_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jna_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnae_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnb_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnbe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnc_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jne_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jng_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnge_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnl_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnle_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jno_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jns_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jnz_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jo_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jpe_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jpo_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void js_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jz_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void ja_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jae_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jb_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jbe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jc_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void je_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jg_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jge_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jl_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jle_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jna_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnae_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnb_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnbe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnc_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jne_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jng_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnge_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnl_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnle_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jno_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jns_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jnz_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jo_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jpe_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jpo_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void js_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jz_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jmp_label(codeblock_t *cb, uint32_t label_idx);
|
||||
static inline void jmp_ptr(codeblock_t *cb, uint8_t *ptr);
|
||||
static inline void jmp_rm(codeblock_t *cb, x86opnd_t opnd);
|
||||
static inline void jmp32(codeblock_t *cb, int32_t offset);
|
||||
static inline void lea(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void mov(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void movsx(codeblock_t *cb, x86opnd_t dst, x86opnd_t src);
|
||||
static inline void neg(codeblock_t *cb, x86opnd_t opnd);
|
||||
static inline void nop(codeblock_t *cb, uint32_t length);
|
||||
static inline void not(codeblock_t *cb, x86opnd_t opnd);
|
||||
static inline void or(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void pop(codeblock_t *cb, x86opnd_t reg);
|
||||
static inline void popfq(codeblock_t *cb);
|
||||
static inline void push(codeblock_t *cb, x86opnd_t opnd);
|
||||
static inline void pushfq(codeblock_t *cb);
|
||||
static inline void ret(codeblock_t *cb);
|
||||
static inline void sal(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void sar(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void shl(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void shr(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void sub(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void test(codeblock_t *cb, x86opnd_t rm_opnd, x86opnd_t test_opnd);
|
||||
static inline void ud2(codeblock_t *cb);
|
||||
static inline void xchg(codeblock_t *cb, x86opnd_t rm_opnd, x86opnd_t r_opnd);
|
||||
static inline void xor(codeblock_t *cb, x86opnd_t opnd0, x86opnd_t opnd1);
|
||||
static inline void cb_write_lock_prefix(codeblock_t *cb);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// For MAP_ANONYMOUS on GNU/Linux
|
||||
#define _GNU_SOURCE 1
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "yjit_asm.h"
|
||||
|
||||
#include "yjit_asm.c"
|
||||
|
||||
// Print the bytes in a code block
|
||||
void print_bytes(codeblock_t* cb)
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
// This file is a fragment of the yjit.o compilation unit. See yjit.c.
|
||||
#include "internal.h"
|
||||
#include "insns.inc"
|
||||
#include "vm_core.h"
|
||||
#include "vm_sync.h"
|
||||
#include "vm_callinfo.h"
|
||||
#include "builtin.h"
|
||||
#include "gc.h"
|
||||
#include "internal/compile.h"
|
||||
#include "internal/class.h"
|
||||
|
@ -12,7 +8,6 @@
|
|||
#include "internal/string.h"
|
||||
#include "internal/variable.h"
|
||||
#include "internal/re.h"
|
||||
#include "insns_info.inc"
|
||||
#include "probes.h"
|
||||
#include "probes_helper.h"
|
||||
#include "yjit.h"
|
||||
|
@ -20,7 +15,6 @@
|
|||
#include "yjit_core.h"
|
||||
#include "yjit_codegen.h"
|
||||
#include "yjit_asm.h"
|
||||
#include "yjit_utils.h"
|
||||
|
||||
// Map from YARV opcodes to code generation functions
|
||||
static codegen_fn gen_fns[VM_INSTRUCTION_SIZE] = { NULL };
|
||||
|
@ -28,14 +22,6 @@ static codegen_fn gen_fns[VM_INSTRUCTION_SIZE] = { NULL };
|
|||
// Map from method entries to code generation functions
|
||||
static st_table *yjit_method_codegen_table = NULL;
|
||||
|
||||
// Code block into which we write machine code
|
||||
static codeblock_t block;
|
||||
codeblock_t *cb = NULL;
|
||||
|
||||
// Code block into which we write out-of-line machine code
|
||||
static codeblock_t outline_block;
|
||||
codeblock_t *ocb = NULL;
|
||||
|
||||
// Code for exiting back to the interpreter from the leave insn
|
||||
static void *leave_exit_code;
|
||||
|
||||
|
@ -52,12 +38,6 @@ typedef rb_darray(struct codepage_patch) patch_array_t;
|
|||
|
||||
static patch_array_t global_inval_patches = NULL;
|
||||
|
||||
// The number of bytes counting from the beginning of the inline code block
|
||||
// that should not be changed. After patching for global invalidation, no one
|
||||
// should make changes to the invalidated code region anymore. This is used to
|
||||
// break out of invalidation race when there are multiple ractors.
|
||||
uint32_t yjit_codepage_frozen_bytes = 0;
|
||||
|
||||
// Print the current source location for debugging purposes
|
||||
RBIMPL_ATTR_MAYBE_UNUSED()
|
||||
static void
|
||||
|
@ -240,7 +220,6 @@ _add_comment(codeblock_t *cb, const char *comment_str)
|
|||
|
||||
// Comments for generated machine code
|
||||
#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.
|
||||
|
@ -366,7 +345,7 @@ yjit_gen_exit(VALUE *exit_pc, ctx_t *ctx, codeblock_t *cb)
|
|||
#if YJIT_STATS
|
||||
if (rb_yjit_opts.gen_stats) {
|
||||
mov(cb, RDI, const_ptr_opnd(exit_pc));
|
||||
call_ptr(cb, RSI, (void *)&rb_yjit_count_side_exit_op);
|
||||
call_ptr(cb, RSI, (void *)&yjit_count_side_exit_op);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -519,7 +498,7 @@ gen_full_cfunc_return(void)
|
|||
Compile an interpreter entry block to be inserted into an iseq
|
||||
Returns `NULL` if compilation fails.
|
||||
*/
|
||||
uint8_t *
|
||||
static uint8_t *
|
||||
yjit_entry_prologue(codeblock_t *cb, const rb_iseq_t *iseq)
|
||||
{
|
||||
RUBY_ASSERT(cb != NULL);
|
||||
|
@ -605,7 +584,7 @@ jit_jump_to_next_insn(jitstate_t *jit, const ctx_t *current_context)
|
|||
}
|
||||
|
||||
// Compile a sequence of bytecode instructions for a given basic block version
|
||||
void
|
||||
static void
|
||||
yjit_gen_block(block_t *block, rb_execution_context_t *ec)
|
||||
{
|
||||
RUBY_ASSERT(cb != NULL);
|
||||
|
@ -1981,7 +1960,7 @@ gen_opt_gt(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
|
|||
|
||||
// Implements specialized equality for either two fixnum or two strings
|
||||
// Returns true if code was generated, otherwise false
|
||||
bool
|
||||
static bool
|
||||
gen_equality_specialized(jitstate_t *jit, ctx_t *ctx, uint8_t *side_exit)
|
||||
{
|
||||
VALUE comptime_a = jit_peek_at_stack(jit, ctx, 1);
|
||||
|
@ -2605,7 +2584,7 @@ gen_opt_case_dispatch(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
|
|||
return YJIT_KEEP_COMPILING; // continue with the next instruction
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
gen_branchif_branch(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t shape)
|
||||
{
|
||||
switch (shape) {
|
||||
|
@ -2661,7 +2640,7 @@ gen_branchif(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
|
|||
return YJIT_END_BLOCK;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
gen_branchunless_branch(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t shape)
|
||||
{
|
||||
switch (shape) {
|
||||
|
@ -2717,7 +2696,7 @@ gen_branchunless(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb)
|
|||
return YJIT_END_BLOCK;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
gen_branchnil_branch(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t shape)
|
||||
{
|
||||
switch (shape) {
|
||||
|
@ -4342,7 +4321,7 @@ static void invalidate_all_blocks_for_tracing(const rb_iseq_t *iseq);
|
|||
// In addition to patching, we prevent future entries into invalidated code by
|
||||
// removing all live blocks from their iseq.
|
||||
void
|
||||
yjit_tracing_invalidate_all(void)
|
||||
rb_yjit_tracing_invalidate_all(void)
|
||||
{
|
||||
if (!rb_yjit_enabled_p()) return;
|
||||
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
#ifndef YJIT_CODEGEN_H
|
||||
#define YJIT_CODEGEN_H 1
|
||||
|
||||
#include "stddef.h"
|
||||
#include "yjit_core.h"
|
||||
|
||||
// Code blocks we generate code into
|
||||
extern codeblock_t *cb;
|
||||
extern codeblock_t *ocb;
|
||||
extern uint32_t yjit_codepage_frozen_bytes;
|
||||
|
||||
typedef enum codegen_status {
|
||||
YJIT_END_BLOCK,
|
||||
YJIT_KEEP_COMPILING,
|
||||
|
@ -18,10 +10,10 @@ typedef enum codegen_status {
|
|||
// Code generation function signature
|
||||
typedef codegen_status_t (*codegen_fn)(jitstate_t *jit, ctx_t *ctx, codeblock_t *cb);
|
||||
|
||||
uint8_t *yjit_entry_prologue(codeblock_t *cb, const rb_iseq_t *iseq);
|
||||
static uint8_t *yjit_entry_prologue(codeblock_t *cb, const rb_iseq_t *iseq);
|
||||
|
||||
void yjit_gen_block(block_t *block, rb_execution_context_t *ec);
|
||||
static void yjit_gen_block(block_t *block, rb_execution_context_t *ec);
|
||||
|
||||
void yjit_init_codegen(void);
|
||||
static void yjit_init_codegen(void);
|
||||
|
||||
#endif // #ifndef YJIT_CODEGEN_H
|
||||
|
|
79
yjit_core.c
79
yjit_core.c
|
@ -1,11 +1,10 @@
|
|||
#include "ruby/ruby.h"
|
||||
// This file is a fragment of the yjit.o compilation unit. See yjit.c.
|
||||
#include "internal.h"
|
||||
#include "vm_sync.h"
|
||||
#include "builtin.h"
|
||||
|
||||
#include "yjit.h"
|
||||
#include "yjit_asm.h"
|
||||
#include "yjit_utils.h"
|
||||
#include "yjit_iface.h"
|
||||
#include "yjit_core.h"
|
||||
#include "yjit_codegen.h"
|
||||
|
@ -13,7 +12,7 @@
|
|||
/*
|
||||
Get an operand for the adjusted stack pointer address
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_sp_opnd(ctx_t *ctx, int32_t offset_bytes)
|
||||
{
|
||||
int32_t offset = (ctx->sp_offset * sizeof(VALUE)) + offset_bytes;
|
||||
|
@ -24,7 +23,7 @@ ctx_sp_opnd(ctx_t *ctx, int32_t offset_bytes)
|
|||
Push one new value on the temp stack with an explicit mapping
|
||||
Return a pointer to the new stack top
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_push_mapping(ctx_t *ctx, temp_type_mapping_t mapping)
|
||||
{
|
||||
// Keep track of the type and mapping of the value
|
||||
|
@ -50,7 +49,7 @@ ctx_stack_push_mapping(ctx_t *ctx, temp_type_mapping_t mapping)
|
|||
Push one new value on the temp stack
|
||||
Return a pointer to the new stack top
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_push(ctx_t *ctx, val_type_t type)
|
||||
{
|
||||
temp_type_mapping_t mapping = { MAP_STACK, type };
|
||||
|
@ -60,7 +59,7 @@ ctx_stack_push(ctx_t *ctx, val_type_t type)
|
|||
/*
|
||||
Push the self value on the stack
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_push_self(ctx_t *ctx)
|
||||
{
|
||||
temp_type_mapping_t mapping = { MAP_SELF, TYPE_UNKNOWN };
|
||||
|
@ -70,7 +69,7 @@ ctx_stack_push_self(ctx_t *ctx)
|
|||
/*
|
||||
Push a local variable on the stack
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_push_local(ctx_t *ctx, size_t local_idx)
|
||||
{
|
||||
if (local_idx >= MAX_LOCAL_TYPES) {
|
||||
|
@ -88,7 +87,7 @@ ctx_stack_push_local(ctx_t *ctx, size_t local_idx)
|
|||
Pop N values off the stack
|
||||
Return a pointer to the stack top before the pop operation
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_pop(ctx_t *ctx, size_t n)
|
||||
{
|
||||
RUBY_ASSERT(n <= ctx->stack_size);
|
||||
|
@ -116,7 +115,7 @@ ctx_stack_pop(ctx_t *ctx, size_t n)
|
|||
/**
|
||||
Get an operand pointing to a slot on the temp stack
|
||||
*/
|
||||
x86opnd_t
|
||||
static x86opnd_t
|
||||
ctx_stack_opnd(ctx_t *ctx, int32_t idx)
|
||||
{
|
||||
// SP points just above the topmost value
|
||||
|
@ -129,7 +128,7 @@ ctx_stack_opnd(ctx_t *ctx, int32_t idx)
|
|||
/**
|
||||
Get the type of an instruction operand
|
||||
*/
|
||||
val_type_t
|
||||
static val_type_t
|
||||
ctx_get_opnd_type(const ctx_t *ctx, insn_opnd_t opnd)
|
||||
{
|
||||
if (opnd.is_self)
|
||||
|
@ -159,6 +158,8 @@ ctx_get_opnd_type(const ctx_t *ctx, insn_opnd_t opnd)
|
|||
rb_bug("unreachable");
|
||||
}
|
||||
|
||||
static 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); \
|
||||
|
@ -171,7 +172,8 @@ This value must be compatible and at least as specific as the previously known t
|
|||
If this value originated from self, or an lvar, the learned type will be
|
||||
propagated back to its source.
|
||||
*/
|
||||
void ctx_upgrade_opnd_type(ctx_t *ctx, insn_opnd_t opnd, val_type_t type)
|
||||
static void
|
||||
ctx_upgrade_opnd_type(ctx_t *ctx, insn_opnd_t opnd, val_type_t type)
|
||||
{
|
||||
if (opnd.is_self) {
|
||||
UPGRADE_TYPE(ctx->self_type, type);
|
||||
|
@ -208,7 +210,7 @@ Get both the type and mapping (where the value originates) of an operand.
|
|||
This is can be used with ctx_stack_push_mapping or ctx_set_opnd_mapping to copy
|
||||
a stack value's type while maintaining the mapping.
|
||||
*/
|
||||
temp_type_mapping_t
|
||||
static temp_type_mapping_t
|
||||
ctx_get_opnd_mapping(const ctx_t *ctx, insn_opnd_t opnd)
|
||||
{
|
||||
temp_type_mapping_t type_mapping;
|
||||
|
@ -238,7 +240,7 @@ ctx_get_opnd_mapping(const ctx_t *ctx, insn_opnd_t opnd)
|
|||
/*
|
||||
Overwrite both the type and mapping of a stack operand.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ctx_set_opnd_mapping(ctx_t *ctx, insn_opnd_t opnd, temp_type_mapping_t type_mapping)
|
||||
{
|
||||
// self is always MAP_SELF
|
||||
|
@ -260,7 +262,8 @@ ctx_set_opnd_mapping(ctx_t *ctx, insn_opnd_t opnd, temp_type_mapping_t type_mapp
|
|||
/**
|
||||
Set the type of a local variable
|
||||
*/
|
||||
void ctx_set_local_type(ctx_t *ctx, size_t idx, val_type_t type)
|
||||
static void
|
||||
ctx_set_local_type(ctx_t *ctx, size_t idx, val_type_t type)
|
||||
{
|
||||
if (idx >= MAX_LOCAL_TYPES)
|
||||
return;
|
||||
|
@ -279,7 +282,8 @@ void ctx_set_local_type(ctx_t *ctx, size_t idx, val_type_t type)
|
|||
|
||||
// Erase local variable type information
|
||||
// eg: because of a call we can't track
|
||||
void ctx_clear_local_types(ctx_t *ctx)
|
||||
static void
|
||||
ctx_clear_local_types(ctx_t *ctx)
|
||||
{
|
||||
// When clearing local types we must detach any stack mappings to those
|
||||
// locals. Even if local values may have changed, stack values will not.
|
||||
|
@ -297,7 +301,7 @@ void ctx_clear_local_types(ctx_t *ctx)
|
|||
|
||||
|
||||
/* This returns an appropriate val_type_t based on a known value */
|
||||
val_type_t
|
||||
static val_type_t
|
||||
yjit_type_of_value(VALUE val)
|
||||
{
|
||||
if (SPECIAL_CONST_P(val)) {
|
||||
|
@ -340,7 +344,8 @@ yjit_type_of_value(VALUE val)
|
|||
}
|
||||
|
||||
/* The name of a type, for debugging */
|
||||
const char *
|
||||
RBIMPL_ATTR_MAYBE_UNUSED()
|
||||
static const char *
|
||||
yjit_type_name(val_type_t type)
|
||||
{
|
||||
RUBY_ASSERT(!(type.is_imm && type.is_heap));
|
||||
|
@ -385,7 +390,8 @@ Returns 0 if the two are the same
|
|||
Returns > 0 if different but compatible
|
||||
Returns INT_MAX if incompatible
|
||||
*/
|
||||
int type_diff(val_type_t src, val_type_t dst)
|
||||
static int
|
||||
type_diff(val_type_t src, val_type_t dst)
|
||||
{
|
||||
RUBY_ASSERT(!src.is_heap || !src.is_imm);
|
||||
RUBY_ASSERT(!dst.is_heap || !dst.is_imm);
|
||||
|
@ -420,7 +426,8 @@ Returns 0 if the two contexts are the same
|
|||
Returns > 0 if different but compatible
|
||||
Returns INT_MAX if incompatible
|
||||
*/
|
||||
int ctx_diff(const ctx_t *src, const ctx_t *dst)
|
||||
static int
|
||||
ctx_diff(const ctx_t *src, const ctx_t *dst)
|
||||
{
|
||||
// Can only lookup the first version in the chain
|
||||
if (dst->chain_depth != 0)
|
||||
|
@ -493,7 +500,7 @@ int ctx_diff(const ctx_t *src, const ctx_t *dst)
|
|||
}
|
||||
|
||||
// Get all blocks for a particular place in an iseq.
|
||||
rb_yjit_block_array_t
|
||||
static rb_yjit_block_array_t
|
||||
yjit_get_version_array(const rb_iseq_t *iseq, unsigned idx)
|
||||
{
|
||||
struct rb_iseq_constant_body *body = iseq->body;
|
||||
|
@ -594,7 +601,8 @@ make_branch_entry(block_t *block, const ctx_t *src_ctx, branchgen_fn gen_fn)
|
|||
}
|
||||
|
||||
// Retrieve a basic block version for an (iseq, idx) tuple
|
||||
block_t *find_block_version(blockid_t blockid, const ctx_t *ctx)
|
||||
static block_t *
|
||||
find_block_version(blockid_t blockid, const ctx_t *ctx)
|
||||
{
|
||||
rb_yjit_block_array_t versions = yjit_get_version_array(blockid.iseq, blockid.idx);
|
||||
|
||||
|
@ -629,7 +637,8 @@ block_t *find_block_version(blockid_t blockid, const ctx_t *ctx)
|
|||
|
||||
// Produce a generic context when the block version limit is hit for a blockid
|
||||
// Note that this will mutate the ctx argument
|
||||
void limit_block_versions(blockid_t blockid, ctx_t *ctx)
|
||||
static void
|
||||
limit_block_versions(blockid_t blockid, ctx_t *ctx)
|
||||
{
|
||||
// Guard chains implement limits separately, do nothing
|
||||
if (ctx->chain_depth > 0)
|
||||
|
@ -651,7 +660,8 @@ void limit_block_versions(blockid_t blockid, ctx_t *ctx)
|
|||
}
|
||||
|
||||
// Compile a new block version immediately
|
||||
block_t *gen_block_version(blockid_t blockid, const ctx_t *start_ctx, rb_execution_context_t *ec)
|
||||
static block_t *
|
||||
gen_block_version(blockid_t blockid, const ctx_t *start_ctx, rb_execution_context_t *ec)
|
||||
{
|
||||
// Allocate a new block version object
|
||||
block_t *block = calloc(1, sizeof(block_t));
|
||||
|
@ -717,7 +727,8 @@ block_t *gen_block_version(blockid_t blockid, const ctx_t *start_ctx, rb_executi
|
|||
}
|
||||
|
||||
// Generate a block version that is an entry point inserted into an iseq
|
||||
uint8_t *gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx, rb_execution_context_t *ec)
|
||||
static uint8_t *
|
||||
gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx, rb_execution_context_t *ec)
|
||||
{
|
||||
// If we aren't at PC 0, don't generate code
|
||||
// See yjit_pc_guard
|
||||
|
@ -842,7 +853,8 @@ branch_stub_hit(branch_t *branch, const uint32_t target_idx, rb_execution_contex
|
|||
}
|
||||
|
||||
// Get a version or stub corresponding to a branch target
|
||||
uint8_t *get_branch_target(
|
||||
static uint8_t *
|
||||
get_branch_target(
|
||||
blockid_t target,
|
||||
const ctx_t *ctx,
|
||||
branch_t *branch,
|
||||
|
@ -880,7 +892,8 @@ uint8_t *get_branch_target(
|
|||
return stub_addr;
|
||||
}
|
||||
|
||||
void gen_branch(
|
||||
static void
|
||||
gen_branch(
|
||||
jitstate_t *jit,
|
||||
const ctx_t *src_ctx,
|
||||
blockid_t target0,
|
||||
|
@ -908,7 +921,7 @@ void gen_branch(
|
|||
branch->end_pos = cb->write_pos;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
gen_jump_branch(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t shape)
|
||||
{
|
||||
switch (shape) {
|
||||
|
@ -925,7 +938,8 @@ gen_jump_branch(codeblock_t *cb, uint8_t *target0, uint8_t *target1, uint8_t sha
|
|||
}
|
||||
}
|
||||
|
||||
void gen_direct_jump(
|
||||
static void
|
||||
gen_direct_jump(
|
||||
jitstate_t *jit,
|
||||
const ctx_t *ctx,
|
||||
blockid_t target0
|
||||
|
@ -963,7 +977,8 @@ void gen_direct_jump(
|
|||
}
|
||||
|
||||
// Create a stub to force the code up to this point to be executed
|
||||
void defer_compilation(
|
||||
static void
|
||||
defer_compilation(
|
||||
jitstate_t *jit,
|
||||
ctx_t *cur_ctx
|
||||
)
|
||||
|
@ -997,7 +1012,7 @@ void defer_compilation(
|
|||
}
|
||||
|
||||
// Remove all references to a block then free it.
|
||||
void
|
||||
static void
|
||||
yjit_free_block(block_t *block)
|
||||
{
|
||||
yjit_unlink_method_lookup_dependency(block);
|
||||
|
@ -1064,7 +1079,7 @@ block_array_remove(rb_yjit_block_array_t block_array, block_t *block)
|
|||
}
|
||||
|
||||
// Invalidate one specific block version
|
||||
void
|
||||
static void
|
||||
invalidate_block_version(block_t *block)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
|
@ -1164,7 +1179,7 @@ invalidate_block_version(block_t *block)
|
|||
// fprintf(stderr, "invalidation done\n");
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
yjit_init_core(void)
|
||||
{
|
||||
// Nothing yet
|
||||
|
|
56
yjit_core.h
56
yjit_core.h
|
@ -97,7 +97,10 @@ typedef struct yjit_temp_mapping
|
|||
} temp_mapping_t;
|
||||
STATIC_ASSERT(temp_mapping_size, sizeof(temp_mapping_t) == 1);
|
||||
|
||||
// By default, temps are just temps on the stack
|
||||
// By default, temps are just temps on the stack.
|
||||
// Name conflict with an mmap flag. This is a struct instance,
|
||||
// so the compiler will check for wrong usage.
|
||||
#undef MAP_STACK
|
||||
#define MAP_STACK ( (temp_mapping_t) { 0 } )
|
||||
|
||||
// Temp value is actually self
|
||||
|
@ -300,55 +303,4 @@ typedef struct JITState
|
|||
|
||||
} jitstate_t;
|
||||
|
||||
// Context object methods
|
||||
x86opnd_t ctx_sp_opnd(ctx_t* ctx, int32_t offset_bytes);
|
||||
x86opnd_t ctx_stack_push_mapping(ctx_t* ctx, temp_type_mapping_t mapping);
|
||||
x86opnd_t ctx_stack_push(ctx_t* ctx, val_type_t type);
|
||||
x86opnd_t ctx_stack_push_self(ctx_t* ctx);
|
||||
x86opnd_t ctx_stack_push_local(ctx_t* ctx, size_t local_idx);
|
||||
x86opnd_t ctx_stack_pop(ctx_t* ctx, size_t n);
|
||||
x86opnd_t ctx_stack_opnd(ctx_t* ctx, int32_t idx);
|
||||
val_type_t ctx_get_opnd_type(const ctx_t* ctx, insn_opnd_t opnd);
|
||||
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);
|
||||
val_type_t yjit_type_of_value(VALUE val);
|
||||
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);
|
||||
|
||||
block_t* find_block_version(blockid_t blockid, const ctx_t* ctx);
|
||||
block_t* gen_block_version(blockid_t blockid, const ctx_t* ctx, rb_execution_context_t *ec);
|
||||
uint8_t* gen_entry_point(const rb_iseq_t *iseq, uint32_t insn_idx, rb_execution_context_t *ec);
|
||||
void yjit_free_block(block_t *block);
|
||||
rb_yjit_block_array_t yjit_get_version_array(const rb_iseq_t *iseq, unsigned idx);
|
||||
|
||||
void gen_branch(
|
||||
jitstate_t* jit,
|
||||
const ctx_t* src_ctx,
|
||||
blockid_t target0,
|
||||
const ctx_t* ctx0,
|
||||
blockid_t target1,
|
||||
const ctx_t* ctx1,
|
||||
branchgen_fn gen_fn
|
||||
);
|
||||
|
||||
void gen_direct_jump(
|
||||
jitstate_t* jit,
|
||||
const ctx_t* ctx,
|
||||
blockid_t target0
|
||||
);
|
||||
|
||||
void defer_compilation(
|
||||
jitstate_t* jit,
|
||||
ctx_t* cur_ctx
|
||||
);
|
||||
|
||||
void invalidate_block_version(block_t* block);
|
||||
|
||||
void yjit_init_core(void);
|
||||
|
||||
#endif // #ifndef YJIT_CORE_H
|
||||
|
|
43
yjit_iface.c
43
yjit_iface.c
|
@ -1,14 +1,12 @@
|
|||
#include "ruby/ruby.h"
|
||||
#include "vm_core.h"
|
||||
#include "insns.inc"
|
||||
// This file is a fragment of the yjit.o compilation unit. See yjit.c.
|
||||
#include "internal.h"
|
||||
#include "vm_sync.h"
|
||||
#include "vm_callinfo.h"
|
||||
#include "builtin.h"
|
||||
#include "gc.h"
|
||||
#include "iseq.h"
|
||||
#include "internal/compile.h"
|
||||
#include "internal/class.h"
|
||||
#include "insns_info.inc"
|
||||
#include "yjit.h"
|
||||
#include "yjit_iface.h"
|
||||
#include "yjit_codegen.h"
|
||||
|
@ -31,13 +29,8 @@ static VALUE cYjitCodeComment;
|
|||
#if YJIT_STATS
|
||||
extern const int rb_vm_max_insn_name_size;
|
||||
static int64_t exit_op_count[VM_INSTRUCTION_SIZE] = { 0 };
|
||||
struct rb_yjit_runtime_counters yjit_runtime_counters = { 0 };
|
||||
#endif
|
||||
|
||||
// Machine code blocks (executable memory)
|
||||
extern codeblock_t *cb;
|
||||
extern codeblock_t *ocb;
|
||||
|
||||
// Hash table of encoded instructions
|
||||
extern st_table *rb_encoded_insn_data;
|
||||
|
||||
|
@ -50,7 +43,7 @@ static const rb_data_type_t yjit_block_type = {
|
|||
};
|
||||
|
||||
// Get the PC for a given index in an iseq
|
||||
VALUE *
|
||||
static VALUE *
|
||||
yjit_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
|
||||
{
|
||||
RUBY_ASSERT(iseq != NULL);
|
||||
|
@ -61,7 +54,7 @@ yjit_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
|
|||
}
|
||||
|
||||
// For debugging. Print the disassembly of an iseq.
|
||||
void
|
||||
static void
|
||||
yjit_print_iseq(const rb_iseq_t *iseq)
|
||||
{
|
||||
char *ptr;
|
||||
|
@ -71,7 +64,7 @@ yjit_print_iseq(const rb_iseq_t *iseq)
|
|||
fprintf(stderr, "%.*s\n", (int)len, ptr);
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
yjit_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
|
||||
{
|
||||
const VALUE at_pc = *pc;
|
||||
|
@ -84,7 +77,7 @@ yjit_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
|
|||
}
|
||||
|
||||
// Verify that calling with cd on receiver goes to callee
|
||||
void
|
||||
static void
|
||||
check_cfunc_dispatch(VALUE receiver, struct rb_callinfo *ci, void *callee, rb_callable_method_entry_t *compile_time_cme)
|
||||
{
|
||||
if (METHOD_ENTRY_INVALIDATED(compile_time_cme)) {
|
||||
|
@ -114,7 +107,7 @@ struct yjit_root_struct {
|
|||
// Hash table of BOP blocks
|
||||
static st_table *blocks_assuming_bops;
|
||||
|
||||
bool
|
||||
static bool
|
||||
assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop)
|
||||
{
|
||||
if (BASIC_OP_UNREDEFINED_P(bop, redefined_flag)) {
|
||||
|
@ -205,7 +198,7 @@ add_lookup_dependency_i(st_data_t *key, st_data_t *value, st_data_t data, int ex
|
|||
// rb_yjit_cme_invalidate() invalidates the block.
|
||||
//
|
||||
// @raise NoMemoryError
|
||||
void
|
||||
static void
|
||||
assume_method_lookup_stable(VALUE receiver_klass, const rb_callable_method_entry_t *cme, block_t *block)
|
||||
{
|
||||
RUBY_ASSERT(cme_validity_dependency);
|
||||
|
@ -227,7 +220,7 @@ static st_table *blocks_assuming_single_ractor_mode;
|
|||
|
||||
// Can raise NoMemoryError.
|
||||
RBIMPL_ATTR_NODISCARD()
|
||||
bool
|
||||
static bool
|
||||
assume_single_ractor_mode(block_t *block) {
|
||||
if (rb_multi_ractor_p()) return false;
|
||||
|
||||
|
@ -239,8 +232,9 @@ static st_table *blocks_assuming_stable_global_constant_state;
|
|||
|
||||
// Assume that the global constant state has not changed since call to this function.
|
||||
// Can raise NoMemoryError.
|
||||
void
|
||||
assume_stable_global_constant_state(block_t *block) {
|
||||
static void
|
||||
assume_stable_global_constant_state(block_t *block)
|
||||
{
|
||||
st_insert(blocks_assuming_stable_global_constant_state, (st_data_t)block, 1);
|
||||
}
|
||||
|
||||
|
@ -382,7 +376,8 @@ rb_yjit_cme_invalidate(VALUE cme)
|
|||
void
|
||||
rb_yjit_invalidate_all_method_lookup_assumptions(void)
|
||||
{
|
||||
// TODO: implement
|
||||
// It looks like Module#using actually doesn't need to invalidate all the
|
||||
// method caches, so we do nothing here for now.
|
||||
}
|
||||
|
||||
// Remove a block from the method lookup dependency table
|
||||
|
@ -431,7 +426,7 @@ remove_cme_validity_dependency(block_t *block, const rb_callable_method_entry_t
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
yjit_unlink_method_lookup_dependency(block_t *block)
|
||||
{
|
||||
cme_dependency_t *cme_dep;
|
||||
|
@ -442,7 +437,7 @@ yjit_unlink_method_lookup_dependency(block_t *block)
|
|||
rb_darray_free(block->cme_dependencies);
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
yjit_block_assumptions_free(block_t *block)
|
||||
{
|
||||
st_data_t as_st_data = (st_data_t)block;
|
||||
|
@ -595,7 +590,7 @@ rb_yjit_constant_state_changed(void)
|
|||
// Invalidate the block for the matching opt_getinlinecache so it could regenerate code
|
||||
// using the new value in the constant cache.
|
||||
void
|
||||
yjit_constant_ic_update(const rb_iseq_t *iseq, IC ic)
|
||||
rb_yjit_constant_ic_update(const rb_iseq_t *iseq, IC ic)
|
||||
{
|
||||
// We can't generate code in these situations, so no need to invalidate.
|
||||
// See gen_opt_getinlinecache.
|
||||
|
@ -839,8 +834,8 @@ rb_yjit_collect_binding_set(void)
|
|||
yjit_runtime_counters.binding_set++;
|
||||
}
|
||||
|
||||
const VALUE *
|
||||
rb_yjit_count_side_exit_op(const VALUE *exit_pc)
|
||||
static const VALUE *
|
||||
yjit_count_side_exit_op(const VALUE *exit_pc)
|
||||
{
|
||||
int insn = rb_vm_insn_addr2opcode((const void *)*exit_pc);
|
||||
exit_op_count[insn]++;
|
||||
|
|
123
yjit_iface.h
123
yjit_iface.h
|
@ -16,128 +16,17 @@
|
|||
# define YJIT_DEFAULT_CALL_THRESHOLD 10
|
||||
#endif
|
||||
|
||||
#if YJIT_STATS
|
||||
struct yjit_comment {
|
||||
uint32_t offset;
|
||||
const char *comment;
|
||||
};
|
||||
|
||||
typedef rb_darray(struct yjit_comment) yjit_comment_array_t;
|
||||
|
||||
extern yjit_comment_array_t yjit_code_comments;
|
||||
#endif // if YJIT_STATS
|
||||
|
||||
|
||||
#if YJIT_STATS
|
||||
|
||||
#define YJIT_DECLARE_COUNTERS(...) struct rb_yjit_runtime_counters { \
|
||||
int64_t __VA_ARGS__; \
|
||||
}; \
|
||||
static char yjit_counter_names[] = #__VA_ARGS__;
|
||||
|
||||
YJIT_DECLARE_COUNTERS(
|
||||
exec_instruction,
|
||||
|
||||
send_keywords,
|
||||
send_kw_splat,
|
||||
send_args_splat,
|
||||
send_block_arg,
|
||||
send_ivar_set_method,
|
||||
send_zsuper_method,
|
||||
send_undef_method,
|
||||
send_optimized_method,
|
||||
send_missing_method,
|
||||
send_bmethod,
|
||||
send_refined_method,
|
||||
send_cfunc_ruby_array_varg,
|
||||
send_cfunc_argc_mismatch,
|
||||
send_cfunc_toomany_args,
|
||||
send_cfunc_tracing,
|
||||
send_iseq_tailcall,
|
||||
send_iseq_arity_error,
|
||||
send_iseq_only_keywords,
|
||||
send_iseq_complex_callee,
|
||||
send_not_implemented_method,
|
||||
send_getter_arity,
|
||||
send_se_cf_overflow,
|
||||
send_se_protected_check_failed,
|
||||
|
||||
traced_cfunc_return,
|
||||
|
||||
invokesuper_me_changed,
|
||||
invokesuper_block,
|
||||
|
||||
leave_se_interrupt,
|
||||
leave_interp_return,
|
||||
leave_start_pc_non_zero,
|
||||
|
||||
getivar_se_self_not_heap,
|
||||
getivar_idx_out_of_range,
|
||||
|
||||
setivar_se_self_not_heap,
|
||||
setivar_idx_out_of_range,
|
||||
setivar_val_heapobject,
|
||||
setivar_name_not_mapped,
|
||||
setivar_not_object,
|
||||
setivar_frozen,
|
||||
|
||||
oaref_argc_not_one,
|
||||
oaref_arg_not_fixnum,
|
||||
|
||||
opt_getinlinecache_miss,
|
||||
|
||||
binding_allocations,
|
||||
binding_set,
|
||||
|
||||
vm_insns_count,
|
||||
compiled_iseq_count,
|
||||
compiled_block_count,
|
||||
|
||||
invalidation_count,
|
||||
invalidate_method_lookup,
|
||||
invalidate_bop_redefined,
|
||||
invalidate_ractor_spawn,
|
||||
invalidate_constant_state_bump,
|
||||
invalidate_constant_ic_fill,
|
||||
|
||||
constant_state_bumps,
|
||||
|
||||
expandarray_splat,
|
||||
expandarray_postarg,
|
||||
expandarray_not_array,
|
||||
expandarray_rhs_too_small,
|
||||
|
||||
gbpp_block_param_modified,
|
||||
gbpp_block_handler_not_iseq,
|
||||
|
||||
// Member with known name for iterating over counters
|
||||
last_member
|
||||
)
|
||||
|
||||
#undef YJIT_DECLARE_COUNTERS
|
||||
|
||||
RUBY_EXTERN struct rb_yjit_runtime_counters yjit_runtime_counters;
|
||||
|
||||
#endif // YJIT_STATS
|
||||
|
||||
RUBY_EXTERN struct rb_yjit_options rb_yjit_opts;
|
||||
|
||||
VALUE *yjit_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx);
|
||||
int yjit_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc);
|
||||
void yjit_print_iseq(const rb_iseq_t *iseq);
|
||||
|
||||
void check_cfunc_dispatch(VALUE receiver, struct rb_callinfo *ci, void *callee, rb_callable_method_entry_t *compile_time_cme);
|
||||
|
||||
RBIMPL_ATTR_NODISCARD() bool assume_bop_not_redefined(block_t *block, int redefined_flag, enum ruby_basic_operators bop);
|
||||
void assume_method_lookup_stable(VALUE receiver_klass, const rb_callable_method_entry_t *cme, block_t *block);
|
||||
RBIMPL_ATTR_NODISCARD() bool assume_single_ractor_mode(block_t *block);
|
||||
void assume_stable_global_constant_state(block_t *block);
|
||||
static VALUE *yjit_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx);
|
||||
static int yjit_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc);
|
||||
static void yjit_print_iseq(const rb_iseq_t *iseq);
|
||||
|
||||
// this function *must* return passed exit_pc
|
||||
const VALUE *rb_yjit_count_side_exit_op(const VALUE *exit_pc);
|
||||
static const VALUE *yjit_count_side_exit_op(const VALUE *exit_pc);
|
||||
|
||||
void yjit_unlink_method_lookup_dependency(block_t *block);
|
||||
void yjit_block_assumptions_free(block_t *block);
|
||||
static void yjit_unlink_method_lookup_dependency(block_t *block);
|
||||
static void yjit_block_assumptions_free(block_t *block);
|
||||
|
||||
VALUE rb_yjit_code_page_alloc(void);
|
||||
code_page_t *rb_yjit_code_page_unwrap(VALUE cp_obj);
|
||||
|
|
32
yjit_utils.c
32
yjit_utils.c
|
@ -1,11 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "yjit_utils.h"
|
||||
#include "yjit_asm.h"
|
||||
// This file is a fragment of the yjit.o compilation unit. See yjit.c.
|
||||
|
||||
// Save caller-save registers on the stack before a C call
|
||||
void push_regs(codeblock_t *cb)
|
||||
static void
|
||||
push_regs(codeblock_t *cb)
|
||||
{
|
||||
push(cb, RAX);
|
||||
push(cb, RCX);
|
||||
|
@ -20,7 +17,8 @@ void push_regs(codeblock_t *cb)
|
|||
}
|
||||
|
||||
// Restore caller-save registers from the after a C call
|
||||
void pop_regs(codeblock_t *cb)
|
||||
static void
|
||||
pop_regs(codeblock_t *cb)
|
||||
{
|
||||
popfq(cb);
|
||||
pop(cb, R11);
|
||||
|
@ -34,12 +32,15 @@ void pop_regs(codeblock_t *cb)
|
|||
pop(cb, RAX);
|
||||
}
|
||||
|
||||
static void print_int_cfun(int64_t val)
|
||||
static void
|
||||
print_int_cfun(int64_t val)
|
||||
{
|
||||
fprintf(stderr, "%lld\n", (long long int)val);
|
||||
}
|
||||
|
||||
void print_int(codeblock_t *cb, x86opnd_t opnd)
|
||||
RBIMPL_ATTR_MAYBE_UNUSED()
|
||||
static void
|
||||
print_int(codeblock_t *cb, x86opnd_t opnd)
|
||||
{
|
||||
push_regs(cb);
|
||||
|
||||
|
@ -55,12 +56,15 @@ void print_int(codeblock_t *cb, x86opnd_t opnd)
|
|||
pop_regs(cb);
|
||||
}
|
||||
|
||||
static void print_ptr_cfun(void *val)
|
||||
static void
|
||||
print_ptr_cfun(void *val)
|
||||
{
|
||||
fprintf(stderr, "%p\n", val);
|
||||
}
|
||||
|
||||
void print_ptr(codeblock_t *cb, x86opnd_t opnd)
|
||||
RBIMPL_ATTR_MAYBE_UNUSED()
|
||||
static void
|
||||
print_ptr(codeblock_t *cb, x86opnd_t opnd)
|
||||
{
|
||||
assert (opnd.num_bits == 64);
|
||||
|
||||
|
@ -73,13 +77,15 @@ void print_ptr(codeblock_t *cb, x86opnd_t opnd)
|
|||
pop_regs(cb);
|
||||
}
|
||||
|
||||
static void print_str_cfun(const char *str)
|
||||
static void
|
||||
print_str_cfun(const char *str)
|
||||
{
|
||||
fprintf(stderr, "%s\n", str);
|
||||
}
|
||||
|
||||
// Print a constant string to stdout
|
||||
void print_str(codeblock_t *cb, const char *str)
|
||||
static void
|
||||
print_str(codeblock_t *cb, const char *str)
|
||||
{
|
||||
//as.comment("printStr(\"" ~ str ~ "\")");
|
||||
size_t len = strlen(str);
|
||||
|
|
15
yjit_utils.h
15
yjit_utils.h
|
@ -1,15 +0,0 @@
|
|||
#ifndef YJIT_UTILS_H
|
||||
#define YJIT_UTILS_H 1
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include "yjit_asm.h"
|
||||
|
||||
void push_regs(codeblock_t *cb);
|
||||
void pop_regs(codeblock_t *cb);
|
||||
void print_int(codeblock_t *cb, x86opnd_t opnd);
|
||||
void print_ptr(codeblock_t *cb, x86opnd_t opnd);
|
||||
void print_str(codeblock_t *cb, const char *str);
|
||||
|
||||
#endif // #ifndef YJIT_UTILS_H
|
Загрузка…
Ссылка в новой задаче