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:
Alan Wu 2021-10-01 18:38:39 -04:00
Родитель 25eed28483
Коммит f6da559d5b
17 изменённых файлов: 642 добавлений и 1279 удалений

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++;

132
yjit.c Normal file
Просмотреть файл

@ -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
Просмотреть файл

@ -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

Просмотреть файл

@ -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);

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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

Просмотреть файл

@ -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]++;

Просмотреть файл

@ -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);

Просмотреть файл

@ -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);

Просмотреть файл

@ -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