diff --git a/compile.c b/compile.c index 7fd5f8e33d2d38..a7308c66b1b50e 100644 --- a/compile.c +++ b/compile.c @@ -358,6 +358,29 @@ static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NOD #define IS_INSN_ID(iobj, insn) (INSN_OF(iobj) == BIN(insn)) #define IS_NEXT_INSN_ID(link, insn) \ ((link)->next && IS_INSN((link)->next) && IS_INSN_ID((link)->next, insn)) +#define IS_NEXT_NEXT_INSN_ID(link, insn) \ + ((link)->next && IS_NEXT_INSN_ID((link)->next, insn)) + +static inline bool +IS_INDEPENDENT_INSN(LINK_ELEMENT *link) +{ + if (!IS_INSN(link)) { + return false; + } + + enum ruby_vminsn_type type = INSN_OF(link); + + return ( + type == BIN(putobject) || + type == BIN(putspecialobject) || + type == BIN(putnil) || + type == BIN(putself) || + type == BIN(duphash) || + type == BIN(getinstancevariable) || + type == BIN(getlocal) || + type == BIN(opt_getconstant_path) + ); +} /* error */ #if CPDEBUG > 0 @@ -1225,6 +1248,25 @@ ELEM_REMOVE(LINK_ELEMENT *elem) } } +/* + * elem1, elem2 => elem2, elem1 + */ +static void +ELEM_SWAP(LINK_ELEMENT *first, LINK_ELEMENT *second) +{ + RUBY_ASSERT(first->next == second); + RUBY_ASSERT(first == second->prev); + + first->prev->next = second; + second->next->prev = first; + + first->next = second->next; + second->next = first; + + second->prev = first->prev; + first->prev = second; +} + static LINK_ELEMENT * FIRST_ELEMENT(const LINK_ANCHOR *const anchor) { @@ -4253,6 +4295,24 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal } } + /* + * putself / (or any other independent instruction) + * putnil / (or any other independent instruction) + * swap + * => + * putnil / (or any other independent instruction) + * putself / (or any other independent instruction) + */ + if (IS_NEXT_NEXT_INSN_ID(&iobj->link, swap)) { + LINK_ELEMENT *first = &iobj->link; + LINK_ELEMENT *second = first->next; + LINK_ELEMENT *swap = second->next; + if (IS_INDEPENDENT_INSN(first) && IS_INDEPENDENT_INSN(second)) { + ELEM_REMOVE(swap); + ELEM_SWAP(first, second); + } + } + return COMPILE_OK; } diff --git a/doc/file/filesystem_modes.md b/doc/file/filesystem_modes.md new file mode 100644 index 00000000000000..33b69c386119e7 --- /dev/null +++ b/doc/file/filesystem_modes.md @@ -0,0 +1,282 @@ +# Filesystem Modes + +A filesystem entry has an integer _mode_ that specifies: + +- [Permissions][permissions]. +- [Special bits][special bits]. +- [File type][file type]. + +## Getting a Mode + +You can use method File::Stat#mode to get the mode of a filesystem entry. + +Each of these methods returns a File::Stat object for a given filesystem entry. +The first three follow symbolic links; the others don't: + +- File::stat. +- IO#stat. +- Pathname#stat. +- File::lstat. +- File#lstat. +- Pathname#lstat. + +Once you have the File::Stat object, you can fetch the mode for the entry: + +```ruby +File.stat('README.md').mode.to_s(8) # => "100664" +File.stat('doc/').mode.to_s(8) # => "40775" +``` + +On this page, we use a helper method to display a mode +in a convenient form, showing the mode both as an octal integer and a string. +If you're new to this page, it may be helpful +to read about the [helper method][helper method] now. + +## Setting a Mode + +The mode for an entry is initialized when the entry is created: + +```ruby +filepath = '/tmp/t.txt' +File.write(filepath, 'foo') +mode(filepath) # => "100664 -rw-rw-r--" +dirpath = '/tmp/bar' +Dir.mkdir(dirpath) +mode(dirpath) # => "040775 drwxrwxr-x" +File.unlink(filepath) +Dir.rmdir(dirpath) +``` + +You can use one of these methods to change the [permissions][permissions] +and [special bits][special bits] (but not the [file type][file type]): + +- File::chmod. +- FileUtils::chmod. +- FileUtils::chmod_R. +- File#chmod. +- Pathname#chmod. +- FileUtils#chmod. +- FileUtils#chmod_R. + +## Permissions + +A filesystem entry has permissions: + +- Read: whether the file or directory may be read, and by what processes. +- Write: whether the file of directory may be written, and by what processes. +- Execute/search: + + - File: whether the file may be _executed_, and by what processes. + - Directory: whether the directory may be _searched_, and by what processes. + +For a method that actually creates a file in the underlying filesystem +(as opposed to merely creating a File object), permissions may be specified; +the permissions may also be changed: + +```ruby +filepath = '/tmp/t.tmp' +File.new(filepath, 'w', 0755) +mode(filepath) # => "100755 -rwxr-xr-x" +File.chmod(0644, filepath) +mode(filepath) # => "100644 -rw-r--r--" +``` + +For a method that actually creates a directory in the underlying filesystem +(as opposed to merely creating a Dir object), permissions may be specified; +the permissions may also be changed: + +```ruby +dirpath = '/tmp/dir' +Dir.mkdir(dirpath, 0755) +mode(dirpath) # => "040755 drwxr-xr-x" +File.chmod(0644, dirpath) +mode(dirpath) # => "040644 drw-r--r--" +``` + +On non-Posix operating systems, permissions may include only read-only or read-write, +in which case, the remaining permission will resemble typical values. +On Windows, for instance, the default permissions are `0644`; +The only change that can be made is to make the file +read-only, which is reported as `0444`. + +### Directory and \File Permissions + +Permissions for directories and files include read and write permissions. + +The permissions in this table do not involve execute/search, +and so apply similarly to a directory or a file. + +| Octal | \String | Permissions | +|:-----:|---------------|------------------------------------------| +| `000` | `'---------'` | No permissions. | +| `400` | `'r--------'` | Owner read-only. | +| `600` | `'rw-------'` | Owner read-write. | +| `644` | `'rw-r--r--'` | Owner read-write; group/world read-only. | +| `664` | `'rw-rw-r--'` | Owner/group read-write; world read-only. | +| `666` | `'rw-rw-rw-'` | Owner/group/world read-write. | + +### \File Permissions + +Permissions for a file include execute permissions, +in addition to the read and write permissions seen above. + +The permissions in this table, applied to a file, specify execute permissions. + +| Octal | \String | Permissions | +|:--------:|---------------|--------------------------------------------------------------| +| `700` | `'rwx------'` | Owner read-write-execute. | +| `750` | `'rwxr-x---'` | Owner read-write-execute; group read-execute. | +| `755` | `'rwxr-xr-x'` | Owner read-write-execute; group read-execute; world execute. | +| `775` | `'rwxrwxr-x'` | Owner/group read-write-execute; world read-execute. | +| `777` | `'rwxrwxrwx'` | Owner/group/world read-write-execute. | + +### Directory Permissions + +Permissions for a directory include search permissions, +in addition to the read and write permissions seen above. + +The permissions in this table, applied to a directory, specify search permissions. + +| Octal | \String | Permissions | +|:------:|---------------|-----------------------------------------------------------| +| `700` | `'rwx------'` | Owner read-write-search. | +| `750` | `'rwxr-x---'` | Owner read-write-search; group read-search. | +| `755` | `'rwxr-xr-x'` | Owner read-write-search; group read-search; world search. | +| `775` | `'rwxrwxr-x'` | Owner/group read-write-search; world read-search. | +| `777` | `'rwxrwxrwx'` | Owner/group/world read-write-search. | + +## Special Bits + +The fourth octal digit in a mode represents its special bits: + +- Its low-order bit (`1000`) shows whether the [sticky bit][sticky bit] is set. +- The next bit (`2000`) shows whether the [setuid bit][setuid bit] is set. +- The next bit (`4000`) shows whether the [setgid bit][setgid bit] is set. + +| Octal | Meaning | +|:-------:|---------------------------| +| `0000` | None. | +| `1000` | Sticky. | +| `2000` | Setgid. | +| `3000` | Setgid + sticky. | +| `4000` | Setuid. | +| `5000` | Setuid + sticky. | +| `6000` | Setuid + setgid. | +| `7000` | Setuid + setgid + sticky. | + +Examples: + +```ruby +File.write(filepath, '') +File.chmod(00644, filepath) +mode(filepath) # => "100644 -rw-r--r--" # No special bits set. +File.chmod(01644, filepath) +mode(filepath) # => "101644 -rw-r--r-T" # 'T' shows that sticky bit is set. +File.chmod(02644, filepath) +mode(filepath) # => "102644 -rw-r-Sr--" # 'S' shows that setuid bit is set. +File.chmod(04644, filepath) +mode(filepath) # => "104644 -rwSr--r--" # 'S' shows that setgid bit is set. +File.chmod(07644, filepath) +mode(filepath) # => "107644 -rwSr-Sr-T" # All set. +``` + +In each case, if the execute bit is also set, +lowercase letters `'t'` and `'s'` are displayed instead of uppercase `'T'` and `'S'`: + +```ruby +File.chmod(00755, filepath) +mode(filepath) # => "100755 -rwxr-xr-x" +File.chmod(01755, filepath) +mode(filepath) # => "101755 -rwxr-xr-t" +File.chmod(02755, filepath) +mode(filepath) # => "102755 -rwxr-sr-x" +File.chmod(04755, filepath) +mode(filepath) # => "104755 -rwsr-xr-x" +File.chmod(07755, filepath) +mode(filepath) # => "107755 -rwsr-sr-t" +``` + +## \File Type + +The fifth and sixth octal digits in a mode represent a file type: + +| Octal | Character | \File Type | +|----------|:---------:|-------------------| +| `010000` | `'p'` | Pipe. | +| `020000` | `'c'` | Character device. | +| `040000` | `'d'` | Directory. | +| `060000` | `'b'` | Block device. | +| `100000` | `'-'` | Regular file. | +| `120000` | `'l'` | Symbolic link. | +| `140000` | `'s'` | \Socket. | + +Examples: + +```ruby +File.mkfifo('/tmp/pipe', 0666) +mode('/tmp/pipe') # => "010664 prw-rw-r--" # 01; pipe. +mode('/dev/tty') # => "020666 crw-rw-rw-" # 02; character device. +mode('doc/') # => "040775 drwxrwxr-x" # 04; directory. +mode('/dev/loop0') # => "060660 brw-rw----" # 06; block device. +mode('README.md') # => "100664 -rw-rw-r--" # 10; regular file. +File.symlink('lib', '/tmp/link') +mode('/tmp/link') # => "120777 lrwxrwxrwx" # 12; symbolic link. +require 'socket' +UNIXServer.new('/tmp/socket') +mode('/tmp/socket') # => "140775 srwxrwxr-x" # 14; socket. +File.unlink('/tmp/pipe', '/tmp/link' ,'/tmp/socket') +``` + +## Helper Method + +On this page, we use a helper method, `mode`, to show the mode information for a given path: + +```ruby +mode('README.md') # => "0100664 -rw-rw-r--" +mode('/etc') # => "0040755 drwxr-xr-x" +``` + +The [permissions][permissions] are expressed both in: + +- The trailing three digits of the octal value (e.g., `755`, `644`). + + - Left digit: owner permissions. + - Middle digit: group permissions. + - Right digit: world permissions. + +- The trailing nine characters of the string string value + (e.g., `'rwxr-xr-x'`, `'rw-r--r--'`). + + - Left three characters: owner permissions. + - Middle three characters: group permissions. + - Right three characters: world permissions. + +The [special bits][special bits] are expressed in the fourth digit. + +The [file type][file type] is expressed the fifth and sixth digits. + +For the code-curious: + +```ruby +# Return a string containing the mode (octal digits and character string) +# for the given path. +def mode(path) + # Get mode digits from File.lstat. + mode_digits = File.lstat(path).inspect.split(', ').select {|s| s.match('mode')}.first.split('=').last + # Format to size. + formatted_digits = "%06o" % mode_digits + # Get mode characters from ls command. + mode_characters = `ls -ld #{path}`.split(' ').first + # Return both. + "#{formatted_digits} #{mode_characters}" +end +``` + +[permissions]: #permissions +[special bits]: #special-bits +[file type]: #file-type +[helper method]: #helper-method + +[sticky bit]: https://en.wikipedia.org/wiki/Sticky_bit +[setuid bit]: https://en.wikipedia.org/wiki/Setuid +[setgid bit]: https://en.wikipedia.org/wiki/Setuid diff --git a/ext/io/console/depend b/ext/io/console/depend index a38e9ee96cb7b6..2729ec9a6c3c4d 100644 --- a/ext/io/console/depend +++ b/ext/io/console/depend @@ -4,12 +4,11 @@ console.o: console.c # AUTOGENERATED DEPENDENCIES END -win32_vk.inc: win32_vk.list +win32_vk.inc: win32_vk.list $(srcdir)/extract-vk.rb .list.inc: ( \ - $(RUBY) -e "ARGF.read.scan(/^\w+,\s*\KVK_\w+/){|n|puts(%Q[#ifndef #{n}\n# define #{n} UNDEFINED_VK\n#endif])}" \ - $< && \ + $(RUBY) $(srcdir)/extract-vk.rb $< && \ gperf --ignore-case -L ANSI-C -E -C -P -p -j1 -i 1 -g -o -t -K ofs -N console_win32_vk -k* $< \ | sed -f $(top_srcdir)/tool/gperf.sed \ ) > $(@F) diff --git a/iseq.c b/iseq.c index a88a5745f72635..a2e71a1d451183 100644 --- a/iseq.c +++ b/iseq.c @@ -479,13 +479,7 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating) * compile/invalidate). Iseqs are born shareable, so a multi-Ractor local GC * never traverses them. */ const bool jit_payload_lock_p = rb_gc_multi_objspace_p(); - bool jit_payload_p = false; -# if USE_YJIT - if (body->yjit_payload != NULL) jit_payload_p = true; -# endif -# if USE_ZJIT - if (body->zjit_payload != NULL) jit_payload_p = true; -# endif + bool jit_payload_p = body->jit_payload != NULL; #endif if (reference_updating) { #if USE_YJIT || USE_ZJIT @@ -493,19 +487,19 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating) if (jit_payload_lock_p) { RB_VM_LOCKING_NO_BARRIER() { # if USE_YJIT - rb_yjit_iseq_update_references(iseq); + if (rb_yjit_enabled_p) rb_yjit_iseq_update_references(iseq); # endif # if USE_ZJIT - rb_zjit_iseq_update_references(body->zjit_payload); + if (rb_zjit_enabled_p) rb_zjit_iseq_update_references(body->jit_payload); # endif } } else { # if USE_YJIT - rb_yjit_iseq_update_references(iseq); + if (rb_yjit_enabled_p) rb_yjit_iseq_update_references(iseq); # endif # if USE_ZJIT - rb_zjit_iseq_update_references(body->zjit_payload); + if (rb_zjit_enabled_p) rb_zjit_iseq_update_references(body->jit_payload); # endif } } @@ -519,19 +513,19 @@ rb_iseq_mark_and_move(rb_iseq_t *iseq, bool reference_updating) if (jit_payload_lock_p) { RB_VM_LOCKING_NO_BARRIER() { # if USE_YJIT - rb_yjit_iseq_mark(body->yjit_payload); + if (rb_yjit_enabled_p) rb_yjit_iseq_mark(body->jit_payload); # endif # if USE_ZJIT - rb_zjit_iseq_mark(body->zjit_payload); + if (rb_zjit_enabled_p) rb_zjit_iseq_mark(body->jit_payload); # endif } } else { # if USE_YJIT - rb_yjit_iseq_mark(body->yjit_payload); + if (rb_yjit_enabled_p) rb_yjit_iseq_mark(body->jit_payload); # endif # if USE_ZJIT - rb_zjit_iseq_mark(body->zjit_payload); + if (rb_zjit_enabled_p) rb_zjit_iseq_mark(body->jit_payload); # endif } } diff --git a/jit.c b/jit.c index d815fb909ccf2c..21a16a156e488c 100644 --- a/jit.c +++ b/jit.c @@ -611,6 +611,27 @@ rb_jit_vm_unlock(unsigned int *recursive_lock_level, const char *file, int line) rb_vm_lock_leave(recursive_lock_level, file, line); } +void * +rb_iseq_get_jit_payload(const rb_iseq_t *iseq) +{ + RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); + if (ISEQ_BODY(iseq)) { + return ISEQ_BODY(iseq)->jit_payload; + } + else { + return NULL; + } +} + +void +rb_iseq_set_jit_payload(const rb_iseq_t *iseq, void *payload) +{ + RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); + RUBY_ASSERT_ALWAYS(ISEQ_BODY(iseq)); + RUBY_ASSERT_ALWAYS(NULL == ISEQ_BODY(iseq)->jit_payload); + ISEQ_BODY(iseq)->jit_payload = payload; +} + void rb_iseq_reset_jit_func(const rb_iseq_t *iseq) { diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index fcfe49fa165959..b8f37ca7d80962 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -107,6 +107,8 @@ A \fBcreated_at\fR timestamp is read as UTC when it carries no time zone offset\ .IP "\(bu" 4 \fBcredential_store\fR (\fBBUNDLE_CREDENTIAL_STORE\fR): Experimental: store and read host credentials (the values otherwise set via \fBbundle config set \fR) in a credential store instead of the plain text config file\. Set it to \fBtrue\fR to use the operating system's native store (macOS Keychain, Linux Secret Service, Windows Credential Manager) when one is available on this platform, or to the name of a backend provided by a third\-party gem, such as \fB1password\fR\. Falls back to the config file when the store is unavailable or fails, warning that the credential was written in plain text\. Defaults to false\. Credentials already written to the config file are not migrated automatically; re\-run \fBbundle config set \fR with the setting enabled to move each one into the store\. Being experimental, the name and behavior of this setting may change in a future release\. .IP +The value is read in three ways\. An empty value and the false values Bundler takes everywhere else (\fBfalse\fR, \fBf\fR, \fBno\fR, \fBn\fR, \fB0\fR) turn the store off\. \fBtrue\fR, \fBt\fR, \fByes\fR, \fBy\fR, \fBon\fR and \fB1\fR select the native store\. Case does not matter for any of those\. Anything else is a backend name, taken as written, and only lowercase letters, digits, \fB_\fR and \fB\-\fR are recognized in one\. So \fBoff\fR names a backend rather than turning the store off, which \fBfalse\fR does\. +.IP A credential kept in the store is never printed back\. \fBbundle config get \fR and \fBbundle config list\fR name the key and say that its value lives in the credential store\. With \fB\-\-parseable\fR, such a key is left out entirely, since that output is meant to be read back by \fBbundle config set\fR\. A third\-party backend is not required to enumerate what it holds, so a credential kept in one may not be listed at all\. .IP The store belongs to the machine's user, not to a project, so \fB\-\-local\fR and \fB\-\-global\fR make no difference to where a credential is kept\. Setting a host's credential in one project changes it for every project on the machine, and unsetting it there removes it everywhere\. Protecting the store itself is the operating system's job, or that of whichever backend you selected\. diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 689d6227ca0d81..4e1c67e10d55e4 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -193,6 +193,14 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). setting enabled to move each one into the store. Being experimental, the name and behavior of this setting may change in a future release. + The value is read in three ways. An empty value and the false values + Bundler takes everywhere else (`false`, `f`, `no`, `n`, `0`) turn the + store off. `true`, `t`, `yes`, `y`, `on` and `1` select the native store. + Case does not matter for any of those. Anything else is a backend name, + taken as written, and only lowercase letters, digits, `_` and `-` are + recognized in one. So `off` names a backend rather than turning the store + off, which `false` does. + A credential kept in the store is never printed back. `bundle config get ` and `bundle config list` name the key and say that its value lives in the credential store. With `--parseable`, such a key is left out diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb index 0e4be4c7f91f8c..1d53fd84c6490d 100644 --- a/lib/bundler/plugin/index.rb +++ b/lib/bundler/plugin/index.rb @@ -176,11 +176,15 @@ def load_index(index_file, global = false) # older Bundler versions, which dumped empty hashes as a bare key. index = Gem::YAMLSerializer.load(data) || {} - @commands.merge!(index["commands"] || {}) - @hooks.merge!(index["hooks"] || {}) - @load_paths.merge!(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) }) - @plugin_paths.merge!(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) }) - @sources.merge!(index["sources"] || {}) unless global + escaping = escaping_plugins(index, base) + hooks = (index["hooks"] || {}).transform_values {|names| Array(names) - escaping } + + @commands.merge!(owned_by(index["commands"] || {}, escaping)) + # An event whose plugins all escaped is left out rather than merged in empty. + @hooks.merge!(hooks.reject {|_, names| names.empty? }) + @load_paths.merge!(named(transform_index_paths(index["load_paths"]) {|p| absolutize_path(p, base) }, escaping)) + @plugin_paths.merge!(named(transform_index_paths(index["plugin_paths"]) {|p| absolutize_path(p, base) }, escaping)) + @sources.merge!(owned_by(index["sources"] || {}, escaping)) unless global end end @@ -209,6 +213,41 @@ def base_for_index(global) global ? Plugin.global_root : Plugin.root end + # A relative path only means anything inside the root, so an entry that escapes is not one Bundler installed. + def escaping_plugins(index, base) + names = [] + + %w[load_paths plugin_paths].each do |key| + (index[key] || {}).each do |name, value| + escapes = Array(value).any? do |path| + !Pathname.new(path).absolute? && !contained_in?(absolutize_path(path, base), base) + end + + names << name if escapes + end + end + + names.uniq + end + + # Expanded here, not by the caller: what gets stored stays joined, because + # #installed_in_plugin_root? matches it against Plugin.root as written. + def contained_in?(path, base) + path = File.expand_path(path) + base = File.expand_path(base) + + path == base || path.start_with?("#{base}#{File::SEPARATOR}") + end + + # commands and sources are keyed by what they provide, load_paths and plugin_paths by the plugin. + def owned_by(mapping, names) + mapping.reject {|_, plugin| names.include?(plugin) } + end + + def named(mapping, names) + mapping.reject {|plugin, _| names.include?(plugin) } + end + def transform_index_paths(paths) return {} unless paths @@ -225,12 +264,9 @@ def relativize_path(path, base) pathname = Pathname.new(path) return path unless pathname.absolute? - base_path = Pathname.new(base) - if pathname == base_path || pathname.to_s.start_with?(base_path.to_s + File::SEPARATOR) - pathname.relative_path_from(base_path).to_s - else - path - end + return path unless contained_in?(pathname.to_s, base) + + pathname.relative_path_from(Pathname.new(base)).to_s end def absolutize_path(path, base) diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index e9a26172b7786a..02780bef730c79 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -465,17 +465,16 @@ def is_userinfo(value) value.include?(":") end - ## - # The Gem::CredentialStore instance to use, or nil when the - # `credential_store` setting is off. The value is `true`/`"true"` for this - # platform's native backend or a backend name such as `"1password"`. - # Guarded by a cheap lookup so reading and writing settings costs nothing - # extra when the setting is disabled. - # Kept separate from RubyGems so gem signout does not remove Bundler's # host credentials. CREDENTIAL_STORE_SERVICE = "bundler" + ## + # The Gem::CredentialStore for the spec #credential_store_spec returns, + # or nil when the setting is off or this RubyGems has no credential store. + # Guarded by a cheap lookup so reading and writing settings costs nothing + # extra when the setting is disabled. + def active_credential_store(host = nil) spec = credential_store_spec(host) return nil unless spec @@ -493,8 +492,13 @@ def credential_store_spec(host = nil) value = self[:credential_store] if value.nil? # An environment variable can carry bytes String#downcase would reject. - case value.to_s.b.downcase - when "", "false", "0", "no", "off", "f", "n" then nil + normalized = value.to_s.b.downcase + + # Tri-state, unlike a BOOL_KEYS setting, so #to_bool is only consulted + # for the false half. + return nil unless to_bool(normalized) + + case normalized when "true", "1", "yes", "on", "t", "y" then true else value.to_s end diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 6e6e180faa727e..e9cd2c6c355429 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -36,6 +36,7 @@ # +:ipv4_fallback_enabled+:: See #ipv4_fallback_enabled # +:global_gem_cache+:: See #global_gem_cache # +:use_psych+:: See #use_psych +# +:credential_store+:: See #credential_store # +:gemhome+:: See #home # +:gempath+:: See #path # +:sources+:: Sets Gem::sources @@ -763,13 +764,13 @@ def self.normalize_credentials_key(host) def self.deep_transform_config_keys!(config) config.transform_keys! do |k| - if k.match?(/\A:(.*)\Z/) + if k.match?(/\A:(.*)\z/) k[1..-1].to_sym - elsif k.include?("__") || k.match?(%r{/\Z}) + elsif k.include?("__") || k.end_with?("/") if k.is_a?(Symbol) - k.to_s.gsub(/__/,".").gsub(%r{/\Z}, "").to_sym + k.to_s.gsub(/__/,".").delete_suffix("/").to_sym else - k.dup.gsub(/__/,".").gsub(%r{/\Z}, "") + k.dup.gsub(/__/,".").delete_suffix("/") end else k @@ -778,11 +779,11 @@ def self.deep_transform_config_keys!(config) config.transform_values! do |v| if v.is_a?(String) - if v.match?(/\A:(.*)\Z/) + if v.match?(/\A:(.*)\z/) v[1..-1].to_sym - elsif v.match?(/\A[+-]?\d+\Z/) + elsif v.match?(/\A[+-]?\d+\z/) v.to_i - elsif v.match?(/\Atrue|false\Z/) + elsif v.match?(/\A(?:true|false)\z/) v == "true" elsif v.empty? nil @@ -852,10 +853,20 @@ def warn_credential_store_fallback alert_warning "Could not write the API key to the credential store, so it was written to #{credentials_path} in plain text." end - # Anything that reads as a boolean is one, so RUBYGEMS_CREDENTIAL_STORE=0 - # turns the store off rather than naming a backend gem "0". CREDENTIAL_STORE_OFF = %w[false 0 no off f n].freeze + private_constant :CREDENTIAL_STORE_OFF + CREDENTIAL_STORE_ON = %w[true 1 yes on t y].freeze + private_constant :CREDENTIAL_STORE_ON + + #-- + # Anything that reads as a boolean is one, so RUBYGEMS_CREDENTIAL_STORE=0 + # turns the store off rather than naming a backend gem "0". Both lists are + # this setting's own. Nothing on the way here turns `off` into a boolean, so + # a gemrc saying `off` arrives as a String just as the environment variable + # does. Bundler leaves `off` out of its half because every one of its + # boolean settings shares a single vocabulary that has never had it. Nothing + # here shares that constraint. def normalize_credential_store(value, default) # An environment variable can carry bytes String#downcase would reject. diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index d97c313da3020b..51745296a10c2f 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -346,17 +346,32 @@ def load_lockfile(lock_file) # :nodoc: # `gem install -g` lockfile can be parsed without a Bundler environment. previous_root = Bundler.instance_variable_get(:@root) Bundler.instance_variable_set(:@root, Pathname.new(File.expand_path(File.dirname(lock_file)))) + root_swapped = true + + # A PLUGIN SOURCE section otherwise sends Bundler::Plugin.from_lock looking + # for the plugin that handles it, which loads and runs that plugin's + # `plugins.rb`. Nothing here can use a plugin source anyway, so borrow the + # flag Bundler itself uses to keep lockfile parsing inert. + previous_gemfile_parse = Bundler::Plugin.instance_variable_get(:@gemfile_parse) + Bundler::Plugin.instance_variable_set(:@gemfile_parse, true) + gemfile_parse_swapped = true parser = Bundler::LockfileParser.new(File.read(lock_file), lockfile_path: lock_file) + locked_versions = {} + parser.specs.group_by(&:source).each do |source, specs| case source when Bundler::Source::Rubygems - remotes = source.remotes.map {|remote| Gem::Source.new(remote.to_s) } + # Bundler::Source::Rubygems stores remotes in reverse of the lockfile + # order (Bundler::Source::Rubygems#to_lock reverses them back), so + # restore the lockfile order here. + remotes = source.remotes.reverse.map {|remote| Gem::Source.new(remote.to_s) } remotes << Gem::Source.new(Gem::DEFAULT_HOST) if remotes.empty? lock_set = Gem::Resolver::LockSet.new(remotes) specs.each do |spec| added = lock_set.add(spec.name, spec.version.to_s, spec.platform) + locked_versions[spec.name] ||= spec.version spec.dependencies.each do |dep| added.each {|s| s.add_dependency dep } end @@ -373,6 +388,7 @@ def load_lockfile(lock_file) # :nodoc: source.revision, source.submodules || false ) + locked_versions[spec.name] ||= spec.version spec.dependencies.each {|dep| git_spec.add_dependency dep } end @sets << git_set @@ -380,6 +396,7 @@ def load_lockfile(lock_file) # :nodoc: vendor_set = Gem::Resolver::VendorSet.new specs.each do |spec| loaded = vendor_set.add_vendor_gem(spec.name, source.path.to_s) + locked_versions[spec.name] ||= loaded.version spec.dependencies.each {|dep| loaded.dependencies << dep } end @sets << vendor_set @@ -387,10 +404,21 @@ def load_lockfile(lock_file) # :nodoc: end parser.dependencies.each_value do |dep| - gem dep.name, *dep.requirement.as_list + requirements = dep.requirement.as_list + + # A dependency the lockfile ties to a source replaces whatever it asks + # for with the version that source resolved, the way the parser this + # replaced did. For a PATH section that is the version of the gemspec on + # disk, not the one the lockfile records. + if dep.source && (version = locked_versions[dep.name]) + requirements = [version] + end + + gem dep.name, *requirements end ensure - Bundler.instance_variable_set(:@root, previous_root) if defined?(previous_root) + Bundler.instance_variable_set(:@root, previous_root) if root_swapped + Bundler::Plugin.instance_variable_set(:@gemfile_parse, previous_gemfile_parse) if gemfile_parse_swapped end def pretty_print(q) # :nodoc: diff --git a/spec/bundler/bundler/plugin/index_spec.rb b/spec/bundler/bundler/plugin/index_spec.rb index b7f57d05b0ce3b..5214069107c979 100644 --- a/spec/bundler/bundler/plugin/index_spec.rb +++ b/spec/bundler/bundler/plugin/index_spec.rb @@ -238,6 +238,54 @@ expect(new_index.load_paths(plugin_name)).to eq([plugin_root.join(plugin_name, "lib").to_s]) end + it "ignores entries that climb out only after an interior parent reference" do + require "rubygems/yaml_serializer" + + escaping_index = { + "commands" => {}, + "hooks" => {}, + "load_paths" => { "escaping-plugin" => [File.join("escaping-plugin", "..", "..", "elsewhere", "lib")] }, + "plugin_paths" => { "escaping-plugin" => File.join("escaping-plugin", "..", "..", "elsewhere") }, + "sources" => {}, + } + + File.open(index.index_file, "w") {|f| f.puts Gem::YAMLSerializer.dump(escaping_index) } + + new_index = Index.new + + expect(new_index.installed?("escaping-plugin")).to be_nil + expect(new_index.load_paths("escaping-plugin")).to be_nil + end + + it "reads a leading tilde in a relative path literally" do + require "rubygems/yaml_serializer" + + plugin_root = Bundler::Plugin.root + + tilde_index = { + "commands" => {}, + "hooks" => {}, + "load_paths" => { plugin_name => [File.join("~nosuchuser", "lib")] }, + "plugin_paths" => { plugin_name => "~nosuchuser" }, + "sources" => {}, + } + + File.open(index.index_file, "w") {|f| f.puts Gem::YAMLSerializer.dump(tilde_index) } + + new_index = Index.new + expect(new_index.plugin_path(plugin_name)).to eq(plugin_root.join("~nosuchuser")) + expect(new_index.load_paths(plugin_name)).to eq([plugin_root.join("~nosuchuser", "lib").to_s]) + end + + it "keeps an absolute path that only looks like it is under the plugin root" do + escaping_path = File.join(Bundler::Plugin.root.to_s, "..", "..", "escaping-plugin") + + index.register_plugin("escaping-plugin", escaping_path, [File.join(escaping_path, "lib")], [], [], []) + + new_index = Index.new + expect(new_index.installed?("escaping-plugin")).to eq(escaping_path) + end + it "keeps paths outside the plugin root as absolute" do outside_path = tmp.join("outside", "external-plugin") FileUtils.mkdir_p(outside_path.join("lib")) @@ -251,6 +299,70 @@ expect(data["load_paths"]["external-plugin"]).to eq([outside_path.join("lib").to_s]) end + it "ignores entries whose relative paths climb out of the plugin root" do + require "rubygems/yaml_serializer" + + escaping_index = { + "commands" => { "escape" => "escaping-plugin" }, + "hooks" => { "before-eval" => ["escaping-plugin", plugin_name] }, + "load_paths" => { + "escaping-plugin" => ["../../elsewhere/lib"], + plugin_name => [File.join(plugin_name, "lib")], + }, + "plugin_paths" => { "escaping-plugin" => "../../elsewhere", plugin_name => plugin_name }, + "sources" => { "escape" => "escaping-plugin" }, + } + + File.open(index.index_file, "w") {|f| f.puts Gem::YAMLSerializer.dump(escaping_index) } + + new_index = Index.new + + expect(new_index.installed?("escaping-plugin")).to be_nil + expect(new_index.load_paths("escaping-plugin")).to be_nil + expect(new_index.command_plugin("escape")).to be_nil + expect(new_index.source_plugin("escape")).to be_nil + expect(new_index.hook_plugins("before-eval")).to eq([plugin_name]) + expect(new_index.installed?(plugin_name)).to eq(Bundler::Plugin.root.join(plugin_name).to_s) + end + + it "ignores entries whose load paths alone climb out of the plugin root" do + require "rubygems/yaml_serializer" + + escaping_index = { + "commands" => {}, + "hooks" => {}, + "load_paths" => { "escaping-plugin" => ["../../elsewhere/lib"] }, + "plugin_paths" => { "escaping-plugin" => "escaping-plugin" }, + "sources" => {}, + } + + File.open(index.index_file, "w") {|f| f.puts Gem::YAMLSerializer.dump(escaping_index) } + + new_index = Index.new + + expect(new_index.installed?("escaping-plugin")).to be_nil + expect(new_index.load_paths("escaping-plugin")).to be_nil + end + + it "drops hook events whose plugins all climb out of the plugin root" do + require "rubygems/yaml_serializer" + + escaping_index = { + "commands" => {}, + "hooks" => { "before-eval" => ["escaping-plugin"] }, + "load_paths" => { "escaping-plugin" => ["../../elsewhere/lib"] }, + "plugin_paths" => { "escaping-plugin" => "../../elsewhere" }, + "sources" => {}, + } + + File.open(index.index_file, "w") {|f| f.puts Gem::YAMLSerializer.dump(escaping_index) } + + new_index = Index.new + new_index.register_plugin("aplugin", lib_path("aplugin").to_s, [lib_path("aplugin").join("lib").to_s], [], [], []) + + expect(new_index.index_file.read).to_not include("before-eval") + end + it "reads legacy index files with absolute paths" do require "rubygems/yaml_serializer" diff --git a/spec/bundler/bundler/settings_spec.rb b/spec/bundler/bundler/settings_spec.rb index 42e3dca1280a7b..58027fd0b22ca1 100644 --- a/spec/bundler/bundler/settings_spec.rb +++ b/spec/bundler/bundler/settings_spec.rb @@ -275,6 +275,53 @@ end end + describe "#credential_store_spec" do + it "is off when the setting is unset" do + expect(settings.send(:credential_store_spec)).to be_nil + end + + it "reads the same false spellings as every other Bundler boolean" do + ["", "false", "FALSE", "f", "no", "n", "0"].each do |off| + settings.set_local "credential_store", off + + expect(settings.send(:credential_store_spec)).to be_nil, "#{off.inspect} should turn the store off" + end + end + + it "reads the boolean true spellings as this platform's native store" do + %w[true TRUE t yes y on 1].each do |on| + settings.set_local "credential_store", on + + expect(settings.send(:credential_store_spec)).to be(true), "#{on.inspect} should select the native store" + end + end + + it "reads anything else as a backend name, `off` included" do + %w[1password off 1Password].each do |name| + settings.set_local "credential_store", name + + expect(settings.send(:credential_store_spec)).to eq(name) + end + end + + it "lets a host override the global setting" do + settings.set_local "credential_store", "1password" + settings.set_local "credential_store.gemserver.example.org", "false" + + expect(settings.send(:credential_store_spec, "gemserver.example.org")).to be_nil + expect(settings.send(:credential_store_spec, "other.example.org")).to eq("1password") + end + + it "survives an undecodable environment variable" do + # #to_bool refuses these bytes too, not just String#downcase. + without_env_side_effects do + ENV["BUNDLE_CREDENTIAL_STORE"] = "\xff".dup.force_encoding("UTF-8") + + expect(settings.send(:credential_store_spec)).to eq(ENV["BUNDLE_CREDENTIAL_STORE"]) + end + end + end + describe "#credentials_for" do let(:uri) { Gem::URI("https://gemserver.example.org/") } let(:credentials) { "username:password" } diff --git a/test/prism/newline_test.rb b/test/prism/newline_test.rb index 0accd8af6d81d2..ed797db965619f 100644 --- a/test/prism/newline_test.rb +++ b/test/prism/newline_test.rb @@ -24,6 +24,7 @@ class NewlineTest < TestCase ruby/parser_test.rb ruby/ripper_test.rb ruby/ruby_parser_test.rb + ruby/parameters_signature_test.rb ] base = __dir__ diff --git a/test/rubygems/test_gem_config_file.rb b/test/rubygems/test_gem_config_file.rb index 9e8c48e05ddce6..2c33192a4b3a83 100644 --- a/test/rubygems/test_gem_config_file.rb +++ b/test/rubygems/test_gem_config_file.rb @@ -896,6 +896,20 @@ def test_accept_string_key assert_equal false, @cfg.verbose end + def test_gemrc_coerces_only_exact_boolean_spellings + File.open @temp_conf, "w" do |fp| + fp.puts ":credential_store: truestore" + fp.puts ":ssl_ca_cert: /home/me/certs-false" + fp.puts ":verbose: false" + end + + util_config_file + + assert_equal "truestore", @cfg.credential_store + assert_equal "/home/me/certs-false", @cfg.ssl_ca_cert + assert_equal false, @cfg.verbose + end + def test_load_ssl_verify_mode_from_config File.open @temp_conf, "w" do |fp| fp.puts ":ssl_verify_mode: 1" diff --git a/test/rubygems/test_gem_request_set.rb b/test/rubygems/test_gem_request_set.rb index 33054aa8e50cc7..8c8be04fb9f9a0 100644 --- a/test/rubygems/test_gem_request_set.rb +++ b/test/rubygems/test_gem_request_set.rb @@ -354,6 +354,7 @@ def test_load_gemdeps_with_lockfile_gem_section a (1) b (1) a (~> 1.0) + b (3-x86_64-linux) PLATFORMS #{Gem::Platform::RUBY} @@ -365,9 +366,56 @@ def test_load_gemdeps_with_lockfile_gem_section rs.load_gemdeps "gem.deps.rb" + assert_equal [dep("b")], rs.dependencies + + lock_set = rs.sets.find {|set| Gem::Resolver::LockSet === set } + refute_nil lock_set, "LockSet should be created from GEM section" + assert_equal %w[a-1 b-1 b-3], lock_set.specs.map(&:full_name).sort + + expected = [ + Gem::Platform::RUBY, + Gem::Platform::RUBY, + Gem::Platform.new("x86_64-linux"), + ] + + assert_equal expected, lock_set.specs.sort_by(&:full_name).map(&:platform) + + spec = lock_set.specs.find {|s| s.full_name == "b-1" } + + assert_equal [dep("a", "~> 1.0")], spec.dependencies + end + + def test_load_gemdeps_with_lockfile_gem_section_multiple_remotes + rs = Gem::RequestSet.new + + File.open "gem.deps.rb", "w" do |io| + io.puts 'gem "a"' + end + + File.open "gem.deps.rb.lock", "w" do |io| + io.puts <<~LOCKFILE + GEM + remote: https://gems.example/ + remote: https://other.example/ + specs: + a (2) + + PLATFORMS + #{Gem::Platform::RUBY} + + DEPENDENCIES + a + LOCKFILE + end + + rs.load_gemdeps "gem.deps.rb" + lock_set = rs.sets.find {|set| Gem::Resolver::LockSet === set } refute_nil lock_set, "LockSet should be created from GEM section" - assert_equal %w[a-1 b-1], lock_set.specs.map(&:full_name).sort + assert_equal %w[a-2], lock_set.specs.map(&:full_name) + + assert_equal %w[https://gems.example/ https://other.example/], + lock_set.specs.flat_map {|s| s.sources.map {|src| src.uri.to_s } } end def test_load_gemdeps_with_lockfile_git_section @@ -383,7 +431,9 @@ def test_load_gemdeps_with_lockfile_git_section remote: git://example/a.git revision: deadbeef specs: - a (1) + a (2) + b (>= 3) + c PLATFORMS #{Gem::Platform::RUBY} @@ -395,9 +445,42 @@ def test_load_gemdeps_with_lockfile_git_section rs.load_gemdeps "gem.deps.rb" + assert_equal [dep("a", "= 2")], rs.dependencies + git_set = rs.sets.find {|set| Gem::Resolver::GitSet === set } refute_nil git_set, "GitSet should be created from GIT section" - assert_includes git_set.specs.keys, "a" + assert_equal %w[a-2], git_set.specs.values.map(&:full_name) + + assert_equal [dep("b", ">= 3"), dep("c")], + git_set.specs.values.first.dependencies + end + + def test_load_gemdeps_with_lockfile_git_section_prerelease + rs = Gem::RequestSet.new + + File.open "gem.deps.rb", "w" do |io| + io.puts 'gem "a", :git => "git://example/a.git"' + end + + File.open "gem.deps.rb.lock", "w" do |io| + io.puts <<~LOCKFILE + GIT + remote: git://example/a.git + revision: deadbeef + specs: + a (1.0.0.pre1) + + PLATFORMS + #{Gem::Platform::RUBY} + + DEPENDENCIES + a! + LOCKFILE + end + + rs.load_gemdeps "gem.deps.rb" + + assert_equal [dep("a", "= 1.0.0.pre1")], rs.dependencies end def test_load_gemdeps_with_lockfile_path_section @@ -426,11 +509,149 @@ def test_load_gemdeps_with_lockfile_path_section rs.load_gemdeps "gem.deps.rb" + assert_equal [dep("a", "= 1")], rs.dependencies + vendor_set = rs.sets.find {|set| Gem::Resolver::VendorSet === set } refute_nil vendor_set, "VendorSet should be created from PATH section" assert_equal %w[a-1], vendor_set.specs.values.map(&:full_name) end + def test_load_gemdeps_with_lockfile_path_section_newer_than_lockfile + _, _, directory = vendor_gem "a", 2 + + rs = Gem::RequestSet.new + + File.open "gem.deps.rb", "w" do |io| + io.puts "gem \"a\", :path => #{directory.inspect}" + end + + File.open "gem.deps.rb.lock", "w" do |io| + io.puts <<~LOCKFILE + PATH + remote: #{directory} + specs: + a (1) + + PLATFORMS + #{Gem::Platform::RUBY} + + DEPENDENCIES + a! + LOCKFILE + end + + rs.load_gemdeps "gem.deps.rb" + + assert_equal [dep("a", "= 2")], rs.dependencies + + vendor_set = rs.sets.find {|set| Gem::Resolver::VendorSet === set } + assert_equal %w[a-2], vendor_set.specs.values.map(&:full_name) + assert_equal %w[a-2], vendor_set.find_all(dep("a", "= 2")).map(&:full_name) + end + + def test_load_lockfile_does_not_load_plugins_for_a_plugin_source_section + require "bundler" + require "bundler/plugin" + + plugin = File.join @tempdir, ".bundle", "plugin", "plugins", "example" + loaded = File.join @tempdir, "plugin-was-loaded" + + FileUtils.mkdir_p File.join(plugin, "lib") + + File.open File.join(@tempdir, "Gemfile"), "w" do |io| + io.puts 'source "https://rubygems.org"' + end + + File.open File.join(plugin, "plugins.rb"), "w" do |io| + io.puts "File.write #{loaded.dump}, \"loaded\"" + io.puts "class ExampleSource" + io.puts " include Bundler::Plugin::API::Source" + io.puts "end" + io.puts 'Bundler::Plugin::API.source("example_type", ExampleSource)' + end + + File.open File.join(@tempdir, ".bundle", "plugin", "index"), "w" do |io| + io.puts <<~INDEX + --- + commands: + hooks: + load_paths: + example: + - plugins/example/lib + plugin_paths: + example: plugins/example + sources: + example_type: example + INDEX + end + + File.open "gem.deps.rb.lock", "w" do |io| + io.puts <<~LOCKFILE + PLUGIN SOURCE + remote: https://gems.example/ + type: example_type + specs: + a (1) + + PLATFORMS + #{Gem::Platform::RUBY} + + DEPENDENCIES + a! + LOCKFILE + end + + Bundler::Plugin.reset! + + rs = Gem::RequestSet.new + rs.load_lockfile "gem.deps.rb.lock" + + assert_path_not_exist loaded + assert_equal [dep("a")], rs.dependencies + ensure + Bundler::Plugin.reset! + end + + def test_load_lockfile_keeps_bundler_root_when_it_cannot_be_swapped + require "bundler" + + previous_root = Bundler.instance_variable_get(:@root) + Bundler.instance_variable_set(:@root, Pathname.new(@tempdir)) + + rs = Gem::RequestSet.new + def rs.require(*) + raise LoadError + end + + assert_raise LoadError do + rs.load_lockfile "gem.deps.rb.lock" + end + + assert_equal Pathname.new(@tempdir), Bundler.instance_variable_get(:@root) + ensure + Bundler.instance_variable_set(:@root, previous_root) + end + + def test_load_lockfile_restores_bundler_root_when_parsing_fails + require "bundler" + + previous_root = Bundler.instance_variable_get(:@root) + Bundler.instance_variable_set(:@root, Pathname.new(File.join(@tempdir, "elsewhere"))) + + File.open "gem.deps.rb.lock", "w" do |io| + io.puts "<<<<<<< HEAD" + end + + assert_raise Bundler::LockfileError do + Gem::RequestSet.new.load_lockfile "gem.deps.rb.lock" + end + + assert_equal Pathname.new(File.join(@tempdir, "elsewhere")), + Bundler.instance_variable_get(:@root) + ensure + Bundler.instance_variable_set(:@root, previous_root) + end + def test_load_gemdeps_with_missing_lockfile rs = Gem::RequestSet.new diff --git a/vm_core.h b/vm_core.h index 5f316b90e147ed..8d3eba50200b7a 100644 --- a/vm_core.h +++ b/vm_core.h @@ -572,20 +572,14 @@ struct rb_iseq_constant_body { rb_jit_func_t jit_exception; // Number of calls on jit_exec_exception() long unsigned jit_exception_calls; + void *jit_payload; #endif #if USE_YJIT - // YJIT stores some data on each iseq. - void *yjit_payload; // Used to estimate how frequently this ISEQ gets called uint64_t yjit_calls_at_interv; #endif -#if USE_ZJIT - // ZJIT stores some data on each iseq. - void *zjit_payload; -#endif - // Hash of the source this iseq was compiled from, or 0 if it is // unavailable. A computed hash of 0 is remapped to another value, so // 0 never denotes a real hash. diff --git a/yjit.c b/yjit.c index 823ae30cfd19e4..2b6f1110275362 100644 --- a/yjit.c +++ b/yjit.c @@ -193,29 +193,6 @@ rb_full_cfunc_return(rb_execution_context_t *ec, VALUE return_value) ec->cfp->sp++; } -// TODO(alan): consider using an opaque pointer for the payload rather than a void pointer -void * -rb_iseq_get_yjit_payload(const rb_iseq_t *iseq) -{ - RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); - if (ISEQ_BODY(iseq)) { - return ISEQ_BODY(iseq)->yjit_payload; - } - else { - // Body is NULL when constructing the iseq. - return NULL; - } -} - -void -rb_iseq_set_yjit_payload(const rb_iseq_t *iseq, void *payload) -{ - RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); - RUBY_ASSERT_ALWAYS(ISEQ_BODY(iseq)); - RUBY_ASSERT_ALWAYS(NULL == ISEQ_BODY(iseq)->yjit_payload); - ISEQ_BODY(iseq)->yjit_payload = payload; -} - // This is defined only as a named struct inside rb_iseq_constant_body. // By giving it a separate typedef, we make it nameable by rust-bindgen. // Bindgen's temp/anon name isn't guaranteed stable. diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 1b1a833eed9216..28afb79144f7fc 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -242,7 +242,7 @@ fn main() { .allowlist_function("rb_object_shape_count") .allowlist_function("rb_ivar_get_at") .allowlist_function("rb_ivar_get_at_no_ractor_check") - .allowlist_function("rb_iseq_(get|set)_yjit_payload") + .allowlist_function("rb_iseq_(get|set)_jit_payload") .allowlist_function("rb_iseq_pc_at_idx") .allowlist_function("rb_iseq_opcode_at_pc") .allowlist_function("rb_jit_reserve_addr_space") diff --git a/yjit/src/core.rs b/yjit/src/core.rs index bdea7ccceeb8f3..0cc4ea7ce6870e 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -1806,7 +1806,7 @@ impl IseqPayload { /// Get the payload for an iseq. For safety it's up to the caller to ensure the returned `&mut` /// upholds aliasing rules and that the argument is a valid iseq. pub fn get_iseq_payload(iseq: IseqPtr) -> Option<&'static mut IseqPayload> { - let payload = unsafe { rb_iseq_get_yjit_payload(iseq) }; + let payload = unsafe { rb_iseq_get_jit_payload(iseq) }; let payload: *mut IseqPayload = payload.cast(); unsafe { payload.as_mut() } } @@ -1816,7 +1816,7 @@ pub fn get_or_create_iseq_payload(iseq: IseqPtr) -> &'static mut IseqPayload { type VoidPtr = *mut c_void; let payload_non_null = unsafe { - let payload = rb_iseq_get_yjit_payload(iseq); + let payload = rb_iseq_get_jit_payload(iseq); if payload.is_null() { // Increment the compiled iseq count incr_counter!(compiled_iseq_count); @@ -1827,7 +1827,7 @@ pub fn get_or_create_iseq_payload(iseq: IseqPtr) -> &'static mut IseqPayload { // We allocate in those cases anyways. let new_payload = IseqPayload::default(); let new_payload = Box::into_raw(Box::new(new_payload)); - rb_iseq_set_yjit_payload(iseq, new_payload as VoidPtr); + rb_iseq_set_jit_payload(iseq, new_payload as VoidPtr); new_payload } else { @@ -1904,7 +1904,7 @@ pub extern "C" fn rb_yjit_iseq_free(iseq: IseqPtr) { iseq_free_invariants(iseq); let payload = { - let payload = unsafe { rb_iseq_get_yjit_payload(iseq) }; + let payload = unsafe { rb_iseq_get_jit_payload(iseq) }; if payload.is_null() { // Nothing to free. return; @@ -2032,7 +2032,7 @@ pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) { /// This is a mirror of [rb_yjit_iseq_mark]. #[no_mangle] pub extern "C" fn rb_yjit_iseq_update_references(iseq: IseqPtr) { - let payload = unsafe { rb_iseq_get_yjit_payload(iseq) }; + let payload = unsafe { rb_iseq_get_jit_payload(iseq) }; let payload = if payload.is_null() { // Nothing to update. return; diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 7bfb386c907d88..143eef16e28ed8 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -1254,8 +1254,6 @@ extern "C" { ) -> VALUE; pub fn rb_c_method_tracing_currently_enabled(ec: *const rb_execution_context_t) -> bool; pub fn rb_full_cfunc_return(ec: *mut rb_execution_context_t, return_value: VALUE); - pub fn rb_iseq_get_yjit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void; - pub fn rb_iseq_set_yjit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void); pub fn rb_get_symbol_id(namep: VALUE) -> ID; pub fn rb_yjit_builtin_function(iseq: *const rb_iseq_t) -> *const rb_builtin_function; pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE; @@ -1403,6 +1401,8 @@ extern "C" { file: *const ::std::os::raw::c_char, line: ::std::os::raw::c_int, ); + pub fn rb_iseq_get_jit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void; + pub fn rb_iseq_set_jit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void); pub fn rb_iseq_reset_jit_func(iseq: *const rb_iseq_t); pub fn rb_jit_get_page_size() -> u32; pub fn rb_jit_reserve_addr_space(mem_size: u32) -> *mut u8; diff --git a/zjit.c b/zjit.c index 2dcb20b55422c8..e92eb26a409b3f 100644 --- a/zjit.c +++ b/zjit.c @@ -141,30 +141,6 @@ rb_zjit_iseq_insn_set(const rb_iseq_t *iseq, unsigned int insn_idx, enum ruby_vm ISEQ_BODY(iseq)->iseq_encoded[insn_idx] = (VALUE)insn_table[bare_insn]; } -// Get profiling information for ISEQ -void * -rb_iseq_get_zjit_payload(const rb_iseq_t *iseq) -{ - RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); - if (ISEQ_BODY(iseq)) { - return ISEQ_BODY(iseq)->zjit_payload; - } - else { - // Body is NULL when constructing the iseq. - return NULL; - } -} - -// Set profiling information for ISEQ -void -rb_iseq_set_zjit_payload(const rb_iseq_t *iseq, void *payload) -{ - RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq)); - RUBY_ASSERT_ALWAYS(ISEQ_BODY(iseq)); - RUBY_ASSERT_ALWAYS(NULL == ISEQ_BODY(iseq)->zjit_payload); - ISEQ_BODY(iseq)->zjit_payload = payload; -} - void rb_zjit_print_exception(void) { diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs index ceafd6bbb0ddbf..fe25d56f081a0a 100644 --- a/zjit/bindgen/src/main.rs +++ b/zjit/bindgen/src/main.rs @@ -303,7 +303,7 @@ fn main() { .allowlist_type("rb_iseq_type") .allowlist_type("rb_event_flag_t") .allowlist_function("rb_object_shape_count") - .allowlist_function("rb_iseq_(get|set)_zjit_payload") + .allowlist_function("rb_iseq_(get|set)_jit_payload") .allowlist_function("rb_iseq_pc_at_idx") .allowlist_function("rb_iseq_opcode_at_pc") .allowlist_function("rb_iseq_bare_opcode_at_pc") diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index a1b6da8e51c20f..ca22b04274281b 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -2450,8 +2450,6 @@ unsafe extern "C" { insn_idx: ::std::os::raw::c_uint, bare_insn: ruby_vminsn_type, ); - pub fn rb_iseq_get_zjit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void; - pub fn rb_iseq_set_zjit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void); pub fn rb_zjit_print_exception(); pub fn rb_zjit_singleton_class_p(klass: VALUE) -> bool; pub fn rb_zjit_defined_ivar(obj: VALUE, id: ID, pushval: VALUE) -> VALUE; @@ -2579,6 +2577,8 @@ unsafe extern "C" { file: *const ::std::os::raw::c_char, line: ::std::os::raw::c_int, ); + pub fn rb_iseq_get_jit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void; + pub fn rb_iseq_set_jit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void); pub fn rb_iseq_reset_jit_func(iseq: *const rb_iseq_t); pub fn rb_jit_get_page_size() -> u32; pub fn rb_jit_reserve_addr_space(mem_size: u32) -> *mut u8; diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs index 53b77e05601e31..842d0770ef855c 100644 --- a/zjit/src/hir/opt_tests.rs +++ b/zjit/src/hir/opt_tests.rs @@ -6125,15 +6125,15 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, C) - v11:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010) - v43:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008) + v42:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008) PatchPoint NoSingletonClass(C@0x1008) PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040) CheckInterrupts - Return v43 + Return v42 "); } @@ -6159,25 +6159,25 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, C) - v11:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) - v16:Fixnum[1] = Const Value(1) + v13:ClassSubclass[C@0x1008] = Const Value(VALUE(0x1008)) + v15:Fixnum[1] = Const Value(1) PatchPoint MethodRedefined(C@0x1008, new@0x1009, cme:0x1010) - v46:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008) + v45:ObjectSubclass[class_exact:C] = ObjectAllocClass C:VALUE(0x1008) PatchPoint NoSingletonClass(C@0x1008) PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040) - PushInlineFrame :initialize, v46 (0x1068), num_args=1 + PushInlineFrame :initialize, v45 (0x1068), num_args=1 PatchPoint SingleRactorMode - v64:CShape = LoadField v46, :shape_id@0x1090 - v65:CShape[0x1091] = GuardBitEquals v64, CShape(0x1091) recompile - StoreField v46, :@x@0x1092, v16 - WriteBarrier v46, v16 - v68:CShape[0x1093] = Const CShape(0x1093) - StoreField v46, :shape_id@0x1090, v68 + v63:CShape = LoadField v45, :shape_id@0x1090 + v64:CShape[0x1091] = GuardBitEquals v63, CShape(0x1091) recompile + StoreField v45, :@x@0x1092, v15 + WriteBarrier v45, v15 + v67:CShape[0x1093] = Const CShape(0x1093) + StoreField v45, :shape_id@0x1090, v67 CheckInterrupts PopInlineFrame - Return v46 + Return v45 "); } @@ -6198,15 +6198,15 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Object) - v11:ClassSubclass[Object@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[Object@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(Object@0x1008, new@0x1009, cme:0x1010) - v43:ObjectExact = ObjectAllocClass Object:VALUE(0x1008) + v42:ObjectExact = ObjectAllocClass Object:VALUE(0x1008) PatchPoint NoSingletonClass(Object@0x1008) PatchPoint MethodRedefined(Object@0x1008, initialize@0x1038, cme:0x1040) CheckInterrupts - Return v43 + Return v42 "); } @@ -6228,15 +6228,15 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Object) - v11:ClassSubclass[Object@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[Object@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(Object@0x1008, new@0x1009, cme:0x1010) - v43:ObjectExact = ObjectAllocClass Object:VALUE(0x1008) + v42:ObjectExact = ObjectAllocClass Object:VALUE(0x1008) PatchPoint NoSingletonClass(Object@0x1008) PatchPoint MethodRedefined(Object@0x1008, initialize@0x1038, cme:0x1040) CheckInterrupts - Return v43 + Return v42 "); } @@ -6262,28 +6262,28 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): - v10:BasicObject = GetConstantPath 0x1000 - v12:NilClass = Const Value(nil) - v15:CBool = IsMethodCFunc v10, :new - CondBranch v15, bb6(), bb4() + v10:NilClass = Const Value(nil) + v12:BasicObject = GetConstantPath 0x1000 + v14:CBool = IsMethodCFunc v12, :new + CondBranch v14, bb6(), bb4() bb6(): - v17:HeapBasicObject = ObjectAlloc v10 + v16:HeapBasicObject = ObjectAlloc v12 SideExit NoProfileSend recompile bb4(): PatchPoint NoSingletonClass(Factory@0x1010) PatchPoint MethodRedefined(Factory@0x1010, new@0x1018, cme:0x1020) - v42:ObjectSubclass[class_exact:Factory] = GuardType v10, ObjectSubclass[class_exact:Factory] recompile - PushInlineFrame :new, v42 (0x1048), num_args=0 + v41:ObjectSubclass[class_exact:Factory] = GuardType v12, ObjectSubclass[class_exact:Factory] recompile + PushInlineFrame :new, v41 (0x1048), num_args=0 + v48:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1070, Object) - v50:ClassSubclass[Object@0x1078] = Const Value(VALUE(0x1078)) - v52:NilClass = Const Value(nil) + v51:ClassSubclass[Object@0x1078] = Const Value(VALUE(0x1078)) PatchPoint MethodRedefined(Object@0x1078, new@0x1018, cme:0x1080) - v86:ObjectExact = ObjectAllocClass Object:VALUE(0x1078) + v84:ObjectExact = ObjectAllocClass Object:VALUE(0x1078) PatchPoint NoSingletonClass(Object@0x1078) PatchPoint MethodRedefined(Object@0x1078, initialize@0x10a8, cme:0x10b0) CheckInterrupts PopInlineFrame - Return v86 + Return v84 "); } @@ -6304,15 +6304,15 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, BasicObject) - v11:ClassSubclass[BasicObject@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[BasicObject@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(BasicObject@0x1008, new@0x1009, cme:0x1010) - v43:BasicObjectExact = ObjectAllocClass BasicObject:VALUE(0x1008) + v42:BasicObjectExact = ObjectAllocClass BasicObject:VALUE(0x1008) PatchPoint NoSingletonClass(BasicObject@0x1008) PatchPoint MethodRedefined(BasicObject@0x1008, initialize@0x1038, cme:0x1040) CheckInterrupts - Return v43 + Return v42 "); } @@ -6333,33 +6333,33 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Hash) - v11:ClassSubclass[Hash@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[Hash@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(Hash@0x1008, new@0x1009, cme:0x1010) - v43:HashExact = ObjectAllocClass Hash:VALUE(0x1008) + v42:HashExact = ObjectAllocClass Hash:VALUE(0x1008) PatchPoint NoSingletonClass(Hash@0x1008) PatchPoint MethodRedefined(Hash@0x1008, initialize@0x1038, cme:0x1040) - v47:Fixnum[0] = Const Value(0) - v96:Fixnum[0] = Const Value(0) - v97:NilClass = Const Value(nil) - PushInlineFrame :initialize, v43 (0x1068), num_args=1 - v63:TrueClass = Const Value(true) - v81:CPtr = GetEP 0 - v82:CUInt64 = LoadField v81, :VM_ENV_DATA_INDEX_FLAGS@0x1090 - v83:CBool = IsBlockParamModified v82 - CondBranch v83, bb11(), bb12() + v46:Fixnum[0] = Const Value(0) + v95:Fixnum[0] = Const Value(0) + v96:NilClass = Const Value(nil) + PushInlineFrame :initialize, v42 (0x1068), num_args=1 + v62:TrueClass = Const Value(true) + v80:CPtr = GetEP 0 + v81:CUInt64 = LoadField v80, :VM_ENV_DATA_INDEX_FLAGS@0x1090 + v82:CBool = IsBlockParamModified v81 + CondBranch v82, bb11(), bb12() bb11(): - v85:BasicObject = LoadField v81, :block@0x1091 - Jump bb13(v85) + v84:BasicObject = LoadField v80, :block@0x1091 + Jump bb13(v84) bb12(): - v87:BasicObject = GetBlockParam :block, l0, EP@4 - Jump bb13(v87) - bb13(v80:BasicObject): - v90:BasicObject = InvokeBuiltin rb_hash_init, v43, v47, v63, v63, v80 + v86:BasicObject = GetBlockParam :block, l0, EP@4 + Jump bb13(v86) + bb13(v79:BasicObject): + v89:BasicObject = InvokeBuiltin rb_hash_init, v42, v46, v62, v62, v79 CheckInterrupts PopInlineFrame - Return v43 + Return v42 "); assert_snapshot!(inspect("test"), @"{}"); } @@ -6381,15 +6381,15 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Array) - v11:ClassSubclass[Array@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) - v16:Fixnum[1] = Const Value(1) + v13:ClassSubclass[Array@0x1008] = Const Value(VALUE(0x1008)) + v15:Fixnum[1] = Const Value(1) PatchPoint MethodRedefined(Array@0x1008, new@0x1009, cme:0x1010) PatchPoint MethodRedefined(Class@0x1038, new@0x1009, cme:0x1010) - v54:BasicObject = CCallVariadic v11, :Array.new@0x1040, v16 + v53:BasicObject = CCallVariadic v13, :Array.new@0x1040, v15 CheckInterrupts - Return v54 + Return v53 "); } @@ -6410,17 +6410,17 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Set) - v11:ClassSubclass[Set@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[Set@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(Set@0x1008, new@0x1009, cme:0x1010) - v18:HeapBasicObject = ObjectAlloc v11 + v17:HeapBasicObject = ObjectAlloc v13 PatchPoint NoSingletonClass(Set@0x1008) PatchPoint MethodRedefined(Set@0x1008, initialize@0x1038, cme:0x1040) - v46:SetExact = GuardType v18, SetExact recompile - v47:BasicObject = CCallVariadic v46, :Set#initialize@0x1068 + v45:SetExact = GuardType v17, SetExact recompile + v46:BasicObject = CCallVariadic v45, :Set#initialize@0x1068 CheckInterrupts - Return v46 + Return v45 "); } @@ -6441,14 +6441,14 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, String) - v11:ClassSubclass[String@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) + v13:ClassSubclass[String@0x1008] = Const Value(VALUE(0x1008)) PatchPoint MethodRedefined(String@0x1008, new@0x1009, cme:0x1010) PatchPoint MethodRedefined(Class@0x1038, new@0x1009, cme:0x1010) - v51:BasicObject = CCallVariadic v11, :String.new@0x1040 + v50:BasicObject = CCallVariadic v13, :String.new@0x1040 CheckInterrupts - Return v51 + Return v50 "); } @@ -6469,18 +6469,18 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Regexp) - v11:ClassSubclass[Regexp@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) - v16:StringExact[VALUE(0x1010)] = Const Value(VALUE(0x1010)) - v17:StringExact = StringCopy v16 + v13:ClassSubclass[Regexp@0x1008] = Const Value(VALUE(0x1008)) + v15:StringExact[VALUE(0x1010)] = Const Value(VALUE(0x1010)) + v16:StringExact = StringCopy v15 PatchPoint MethodRedefined(Regexp@0x1008, new@0x1018, cme:0x1020) - v47:RegexpExact = ObjectAllocClass Regexp:VALUE(0x1008) + v46:RegexpExact = ObjectAllocClass Regexp:VALUE(0x1008) PatchPoint NoSingletonClass(Regexp@0x1008) PatchPoint MethodRedefined(Regexp@0x1008, initialize@0x1048, cme:0x1050) - v52:BasicObject = CCallVariadic v47, :Regexp#initialize@0x1078, v17 + v51:BasicObject = CCallVariadic v46, :Regexp#initialize@0x1078, v16 CheckInterrupts - Return v47 + Return v46 "); } @@ -21679,91 +21679,91 @@ mod hir_opt_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): + v10:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1000, Point) - v11:ClassSubclass[Point@0x1008] = Const Value(VALUE(0x1008)) - v13:NilClass = Const Value(nil) - v16:Fixnum[1] = Const Value(1) - v18:Fixnum[2] = Const Value(2) + v13:ClassSubclass[Point@0x1008] = Const Value(VALUE(0x1008)) + v15:Fixnum[1] = Const Value(1) + v17:Fixnum[2] = Const Value(2) PatchPoint MethodRedefined(Point@0x1008, new@0x1009, cme:0x1010) - v87:ObjectSubclass[class_exact:Point] = ObjectAllocClass Point:VALUE(0x1008) + v85:ObjectSubclass[class_exact:Point] = ObjectAllocClass Point:VALUE(0x1008) PatchPoint NoSingletonClass(Point@0x1008) PatchPoint MethodRedefined(Point@0x1008, initialize@0x1038, cme:0x1040) - PushInlineFrame :initialize, v87 (0x1068), num_args=2 + PushInlineFrame :initialize, v85 (0x1068), num_args=2 PatchPoint SingleRactorMode - v119:CShape = LoadField v87, :shape_id@0x1090 - v120:CShape[0x1091] = GuardBitEquals v119, CShape(0x1091) recompile - StoreField v87, :@x@0x1092, v16 - WriteBarrier v87, v16 - v123:CShape[0x1093] = Const CShape(0x1093) - StoreField v87, :shape_id@0x1090, v123 + v117:CShape = LoadField v85, :shape_id@0x1090 + v118:CShape[0x1091] = GuardBitEquals v117, CShape(0x1091) recompile + StoreField v85, :@x@0x1092, v15 + WriteBarrier v85, v15 + v121:CShape[0x1093] = Const CShape(0x1093) + StoreField v85, :shape_id@0x1090, v121 PatchPoint NoEPEscape(initialize) PatchPoint SingleRactorMode - StoreField v87, :@y@0x1094, v18 - WriteBarrier v87, v18 - v138:CShape[0x1095] = Const CShape(0x1095) - StoreField v87, :shape_id@0x1090, v138 + StoreField v85, :@y@0x1094, v17 + WriteBarrier v85, v17 + v136:CShape[0x1095] = Const CShape(0x1095) + StoreField v85, :shape_id@0x1090, v136 CheckInterrupts PopInlineFrame + v42:NilClass = Const Value(nil) PatchPoint StableConstantNames(0x1098, Point) - v44:ClassSubclass[Point@0x1008] = Const Value(VALUE(0x1008)) - v46:NilClass = Const Value(nil) - v49:Fixnum[1] = Const Value(1) - v51:Fixnum[2] = Const Value(2) + v45:ClassSubclass[Point@0x1008] = Const Value(VALUE(0x1008)) + v47:Fixnum[1] = Const Value(1) + v49:Fixnum[2] = Const Value(2) PatchPoint MethodRedefined(Point@0x1008, new@0x1009, cme:0x1010) - v97:ObjectSubclass[class_exact:Point] = ObjectAllocClass Point:VALUE(0x1008) + v95:ObjectSubclass[class_exact:Point] = ObjectAllocClass Point:VALUE(0x1008) PatchPoint NoSingletonClass(Point@0x1008) PatchPoint MethodRedefined(Point@0x1008, initialize@0x1038, cme:0x1040) - PushInlineFrame :initialize, v97 (0x1068), num_args=2 + PushInlineFrame :initialize, v95 (0x1068), num_args=2 PatchPoint SingleRactorMode - v159:CShape = LoadField v97, :shape_id@0x1090 - v160:CShape[0x1091] = GuardBitEquals v159, CShape(0x1091) recompile - StoreField v97, :@x@0x1092, v49 - WriteBarrier v97, v49 - v163:CShape[0x1093] = Const CShape(0x1093) - StoreField v97, :shape_id@0x1090, v163 + v157:CShape = LoadField v95, :shape_id@0x1090 + v158:CShape[0x1091] = GuardBitEquals v157, CShape(0x1091) recompile + StoreField v95, :@x@0x1092, v47 + WriteBarrier v95, v47 + v161:CShape[0x1093] = Const CShape(0x1093) + StoreField v95, :shape_id@0x1090, v161 PatchPoint NoEPEscape(initialize) PatchPoint SingleRactorMode - StoreField v97, :@y@0x1094, v51 - WriteBarrier v97, v51 - v178:CShape[0x1095] = Const CShape(0x1095) - StoreField v97, :shape_id@0x1090, v178 + StoreField v95, :@y@0x1094, v49 + WriteBarrier v95, v49 + v176:CShape[0x1095] = Const CShape(0x1095) + StoreField v95, :shape_id@0x1090, v176 CheckInterrupts PopInlineFrame PatchPoint NoSingletonClass(Point@0x1008) PatchPoint MethodRedefined(Point@0x1008, ==@0x10a0, cme:0x10a8) - PushInlineFrame :==, v87 (0x10d0), num_args=1 + PushInlineFrame :==, v85 (0x10d0), num_args=1 PatchPoint SingleRactorMode - v197:CShape = LoadField v87, :shape_id@0x1090 - v198:CShape[0x1095] = GuardBitEquals v197, CShape(0x1095) recompile - v199:BasicObject = LoadField v87, :@x@0x1092 + v195:CShape = LoadField v85, :shape_id@0x1090 + v196:CShape[0x1095] = GuardBitEquals v195, CShape(0x1095) recompile + v197:BasicObject = LoadField v85, :@x@0x1092 PatchPoint NoEPEscape(==) PatchPoint MethodRedefined(Point@0x1008, x@0x10f8, cme:0x1100) PatchPoint MethodRedefined(Integer@0x1128, ==@0x10a0, cme:0x1130) - v255:Fixnum = GuardType v199, Fixnum recompile - v257:BoolExact = FixnumEq v255, v49 - v210:CBool = Test v257 - v211:FalseClass = RefineType v257, Falsy - CondBranch v210, bb19(), bb18(v211) + v253:Fixnum = GuardType v197, Fixnum recompile + v255:BoolExact = FixnumEq v253, v47 + v208:CBool = Test v255 + v209:FalseClass = RefineType v255, Falsy + CondBranch v208, bb19(), bb18(v209) bb19(): PatchPoint SingleRactorMode - v218:CShape = LoadField v87, :shape_id@0x1090 - v219:CShape[0x1095] = GuardBitEquals v218, CShape(0x1095) recompile - v220:BasicObject = LoadField v87, :@y@0x1094 + v216:CShape = LoadField v85, :shape_id@0x1090 + v217:CShape[0x1095] = GuardBitEquals v216, CShape(0x1095) recompile + v218:BasicObject = LoadField v85, :@y@0x1094 PatchPoint NoEPEscape(==) PatchPoint NoSingletonClass(Point@0x1008) PatchPoint MethodRedefined(Point@0x1008, y@0x1158, cme:0x1160) - v262:CShape = LoadField v97, :shape_id@0x1090 - v263:CShape[0x1095] = GuardBitEquals v262, CShape(0x1095) recompile - v264:BasicObject = LoadField v97, :@y@0x1094 + v260:CShape = LoadField v95, :shape_id@0x1090 + v261:CShape[0x1095] = GuardBitEquals v260, CShape(0x1095) recompile + v262:BasicObject = LoadField v95, :@y@0x1094 PatchPoint MethodRedefined(Integer@0x1128, ==@0x10a0, cme:0x1130) - v267:Fixnum = GuardType v220, Fixnum recompile - v268:Fixnum = GuardType v264, Fixnum - v269:BoolExact = FixnumEq v267, v268 - Jump bb18(v269) - bb18(v232:BoolExact): + v265:Fixnum = GuardType v218, Fixnum recompile + v266:Fixnum = GuardType v262, Fixnum + v267:BoolExact = FixnumEq v265, v266 + Jump bb18(v267) + bb18(v230:BoolExact): CheckInterrupts PopInlineFrame - Return v232 + Return v230 "); } diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs index 4591ac70fbfd97..6c80b892d08d4f 100644 --- a/zjit/src/hir/tests.rs +++ b/zjit/src/hir/tests.rs @@ -2754,13 +2754,13 @@ pub(crate) mod hir_build_tests { v7:BasicObject = LoadArg :a@1 Jump bb3(v6, v7) bb3(v9:BasicObject, v10:BasicObject): - v16:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1008)) - v19:StaticSymbol[:b] = Const Value(VALUE(0x1010)) - v21:Fixnum[1] = Const Value(1) - v23:BasicObject = Send v16, :core#hash_merge_ptr, v10, v19, v21 # SendFallbackReason: Uncategorized(opt_send_without_block) - v25:BasicObject = Send v9, :foo, v23 # SendFallbackReason: Uncategorized(opt_send_without_block) + v15:ClassSubclass[VMFrozenCore] = Const Value(VALUE(0x1008)) + v18:StaticSymbol[:b] = Const Value(VALUE(0x1010)) + v20:Fixnum[1] = Const Value(1) + v22:BasicObject = Send v15, :core#hash_merge_ptr, v10, v18, v20 # SendFallbackReason: Uncategorized(opt_send_without_block) + v24:BasicObject = Send v9, :foo, v22 # SendFallbackReason: Uncategorized(opt_send_without_block) CheckInterrupts - Return v25 + Return v24 "); } @@ -2883,20 +2883,20 @@ pub(crate) mod hir_build_tests { v4:BasicObject = LoadArg :self@0 Jump bb3(v4) bb3(v6:BasicObject): - v10:BasicObject = GetConstantPath 0x1000 - v12:NilClass = Const Value(nil) - v15:CBool = IsMethodCFunc v10, :new - CondBranch v15, bb6(), bb4(v6, v12, v10) + v10:NilClass = Const Value(nil) + v12:BasicObject = GetConstantPath 0x1000 + v14:CBool = IsMethodCFunc v12, :new + CondBranch v14, bb6(), bb4(v6, v10, v12) bb6(): - v17:HeapBasicObject = ObjectAlloc v10 - v19:BasicObject = Send v17, :initialize # SendFallbackReason: Uncategorized(opt_send_without_block) - Jump bb5(v6, v17, v19) - bb4(v22:BasicObject, v23:NilClass, v24:BasicObject): - v27:BasicObject = Send v24, :new # SendFallbackReason: Uncategorized(opt_send_without_block) - Jump bb5(v22, v27, v23) - bb5(v30:BasicObject, v31:BasicObject, v32:BasicObject): - CheckInterrupts - Return v31 + v16:HeapBasicObject = ObjectAlloc v12 + v18:BasicObject = Send v16, :initialize # SendFallbackReason: Uncategorized(opt_send_without_block) + Jump bb5(v6, v16, v18) + bb4(v21:BasicObject, v22:NilClass, v23:BasicObject): + v26:BasicObject = Send v23, :new # SendFallbackReason: Uncategorized(opt_send_without_block) + Jump bb5(v21, v26, v22) + bb5(v29:BasicObject, v30:BasicObject, v31:BasicObject): + CheckInterrupts + Return v30 "); } diff --git a/zjit/src/payload.rs b/zjit/src/payload.rs index 51b6f4721bf40e..b10e97324afeac 100644 --- a/zjit/src/payload.rs +++ b/zjit/src/payload.rs @@ -110,7 +110,7 @@ pub fn get_or_create_iseq_payload_ptr(iseq: IseqPtr) -> *mut IseqPayload { type VoidPtr = *mut c_void; unsafe { - let payload = rb_iseq_get_zjit_payload(iseq); + let payload = rb_iseq_get_jit_payload(iseq); if payload.is_null() { // Allocate a new payload with Box and transfer ownership to the GC. // We drop the payload with Box::from_raw when the GC frees the ISEQ and calls us. @@ -118,7 +118,7 @@ pub fn get_or_create_iseq_payload_ptr(iseq: IseqPtr) -> *mut IseqPayload { // We allocate in those cases anyways. let new_payload = IseqPayload::new(); let new_payload = Box::into_raw(Box::new(new_payload)); - rb_iseq_set_zjit_payload(iseq, new_payload as VoidPtr); + rb_iseq_set_jit_payload(iseq, new_payload as VoidPtr); new_payload } else {