mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
679ef34586
Previously YARV bytecode implemented constant caching by having a pair of instructions, opt_getinlinecache and opt_setinlinecache, wrapping a series of getconstant calls (with putobject providing supporting arguments). This commit replaces that pattern with a new instruction, opt_getconstant_path, handling both getting/setting the inline cache and fetching the constant on a cache miss. This is implemented by storing the full constant path as a null-terminated array of IDs inside of the IC structure. idNULL is used to signal an absolute constant reference. $ ./miniruby --dump=insns -e '::Foo::Bar::Baz' == disasm: #<ISeq:<main>@-e:1 (1,0)-(1,13)> (catch: FALSE) 0000 opt_getconstant_path <ic:0 ::Foo::Bar::Baz> ( 1)[Li] 0002 leave The motivation for this is that we had increasingly found the need to disassemble the instructions between the opt_getinlinecache and opt_setinlinecache in order to determine the constant we are fetching, or otherwise store metadata. This disassembly was done: * In opt_setinlinecache, to register the IC against the constant names it is using for granular invalidation. * In rb_iseq_free, to unregister the IC from the invalidation table. * In YJIT to find the position of a opt_getinlinecache instruction to invalidate it when the cache is populated * In YJIT to register the constant names being used for invalidation. With this change we no longe need disassemly for these (in fact rb_iseq_each is now unused), as the list of constant names being referenced is held in the IC. This should also make it possible to make more optimizations in the future. This may also reduce the size of iseqs, as previously each segment required 32 bytes (on 64-bit platforms) for each constant segment. This implementation only stores one ID per-segment. There should be no significant performance change between this and the previous implementation. Previously opt_getinlinecache was a "leaf" instruction, but it included a jump (almost always to a separate cache line). Now opt_getconstant_path is a non-leaf (it may raise/autoload/call const_missing) but it does not jump. These seem to even out.
72 lines
2.9 KiB
C
72 lines
2.9 KiB
C
#ifndef YJIT_H
|
|
#define YJIT_H 1
|
|
//
|
|
// This file contains definitions YJIT exposes to the CRuby codebase
|
|
//
|
|
|
|
#include "ruby/internal/config.h"
|
|
#include "ruby_assert.h" // for RUBY_DEBUG
|
|
#include "vm_core.h"
|
|
#include "method.h"
|
|
|
|
// YJIT_STATS controls whether to support runtime counters in generated code
|
|
// and in the interpreter.
|
|
#ifndef YJIT_STATS
|
|
# define YJIT_STATS RUBY_DEBUG
|
|
#endif
|
|
|
|
#if USE_YJIT
|
|
|
|
// We generate x86 or arm64 assembly
|
|
#if defined(_WIN32) ? defined(_M_AMD64) : (defined(__x86_64__) || defined(__aarch64__))
|
|
// x86_64 platforms without mingw/msys or x64-mswin
|
|
#else
|
|
# error YJIT unsupported platform
|
|
#endif
|
|
|
|
// Expose these as declarations since we are building YJIT.
|
|
bool rb_yjit_enabled_p(void);
|
|
unsigned rb_yjit_call_threshold(void);
|
|
void rb_yjit_invalidate_all_method_lookup_assumptions(void);
|
|
void rb_yjit_method_lookup_change(VALUE klass, ID mid);
|
|
void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme);
|
|
void rb_yjit_collect_vm_usage_insn(int insn);
|
|
void rb_yjit_collect_binding_alloc(void);
|
|
void rb_yjit_collect_binding_set(void);
|
|
bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec);
|
|
void rb_yjit_init(void);
|
|
void rb_yjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop);
|
|
void rb_yjit_constant_state_changed(ID id);
|
|
void rb_yjit_iseq_mark(void *payload);
|
|
void rb_yjit_iseq_update_references(void *payload);
|
|
void rb_yjit_iseq_free(void *payload);
|
|
void rb_yjit_before_ractor_spawn(void);
|
|
void rb_yjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx);
|
|
void rb_yjit_tracing_invalidate_all(void);
|
|
|
|
#else
|
|
// !USE_YJIT
|
|
// In these builds, YJIT could never be turned on. Provide dummy implementations.
|
|
|
|
static inline bool rb_yjit_enabled_p(void) { return false; }
|
|
static inline unsigned rb_yjit_call_threshold(void) { return UINT_MAX; }
|
|
static inline void rb_yjit_invalidate_all_method_lookup_assumptions(void) {}
|
|
static inline void rb_yjit_method_lookup_change(VALUE klass, ID mid) {}
|
|
static inline void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme) {}
|
|
static inline void rb_yjit_collect_vm_usage_insn(int insn) {}
|
|
static inline void rb_yjit_collect_binding_alloc(void) {}
|
|
static inline void rb_yjit_collect_binding_set(void) {}
|
|
static inline bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec) { return false; }
|
|
static inline void rb_yjit_init(void) {}
|
|
static inline void rb_yjit_bop_redefined(int redefined_flag, enum ruby_basic_operators bop) {}
|
|
static inline void rb_yjit_constant_state_changed(ID id) {}
|
|
static inline void rb_yjit_iseq_mark(void *payload) {}
|
|
static inline void rb_yjit_iseq_update_references(void *payload) {}
|
|
static inline void rb_yjit_iseq_free(void *payload) {}
|
|
static inline void rb_yjit_before_ractor_spawn(void) {}
|
|
static inline void rb_yjit_constant_ic_update(const rb_iseq_t *const iseq, IC ic, unsigned insn_idx) {}
|
|
static inline void rb_yjit_tracing_invalidate_all(void) {}
|
|
|
|
#endif // #if USE_YJIT
|
|
|
|
#endif // #ifndef YJIT_H
|