| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
| |
callable_method_entry() read/write method table structures so that
this function should be synchronized between Ractors.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Before this commit, iclasses were "shady", or not protected by write
barriers. Because of that, the GC needs to spend more time marking these
objects than otherwise.
Applications that make heavy use of modules should see reduction in GC
time as they have a significant number of live iclasses on the heap.
- Put logic for iclass method table ownership into a function
- Remove calls to WB_UNPROTECT and insert write barriers for iclasses
This commit relies on the following invariant: for any non oirigin
iclass `I`, `RCLASS_M_TBL(I) == RCLASS_M_TBL(RBasic(I)->klass)`. This
invariant did not hold prior to 98286e9 for classes and modules that
have prepended modules.
[Feature #16984]
|
|
|
|
|
|
|
|
|
|
| |
I'm trying to get a better understanding for rare crashes that happen on
ci:
- http://ci.rvm.jp/results/trunk_clang_10@silicon-docker/3101898
- http://ci.rvm.jp/results/trunk-test@ruby-sky1/2777695
Looking at the stack trace it looks like a type confusion possibly
induced by heap corruption. I'm hoping to verify this theory.
|
| |
|
| |
|
|
|
|
|
|
|
|
| |
Doing so modifies the class's method table, but not in a way that should
be detectable from Ruby, so it may be safe to avoid checking if the
class is frozen.
Fixes [Bug #11669]
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This fixes various issues when a module is included in or prepended
to a module or class, and then refined, or refined and then included
or prepended to a module or class.
Implement by renaming ensure_origin to rb_ensure_origin, making it
non-static, and calling it when refining a module.
Fix Module#initialize_copy to handle origins correctly. Previously,
Module#initialize_copy did not handle origins correctly. For example,
this code:
```ruby
module B; end
class A
def b; 2 end
prepend B
end
a = A.dup.new
class A
def b; 1 end
end
p a.b
```
Printed 1 instead of 2. This is because the super chain for
a.singleton_class was:
```
a.singleton_class
A.dup
B(iclass)
B(iclass origin)
A(origin) # not A.dup(origin)
```
The B iclasses would not be modified, so the includer entry would be
still be set to A and not A.dup.
This modifies things so that if the class/module has an origin,
all iclasses between the class/module and the origin are duplicated
and have the correct includer entry set, and the correct origin
is created.
This requires other changes to make sure all tests still pass:
* rb_undef_methods_from doesn't automatically handle classes with
origins, so pass it the origin for Comparable when undefing
methods in Complex. This fixed a failure in the Complex tests.
* When adding a method, the method cache was not cleared
correctly if klass has an origin. Clear the method cache for
the klass before switching to the origin of klass. This fixed
failures in the autoload tests related to overridding require,
without breaking the optimization tests. Also clear the method
cache for both the module and origin when removing a method.
* Module#include? is fixed to skip origin iclasses.
* Refinements are fixed to use the origin class of the module that
has an origin.
* RCLASS_REFINED_BY_ANY is removed as it was only used in a single
place and is no longer needed.
* Marshal#dump is fixed to skip iclass origins.
* rb_method_entry_make is fixed to handled overridden optimized
methods for modules that have origins.
Fixes [Bug #16852]
|
| |
|
|
|
|
|
|
|
|
|
|
| |
search_method() can return invalid method, but vm_defined() checks
it as valid method entry. This is why defined?(foo) if foo is undef'ed.
To solve this problem, check invalidation and return NULL.
[Bug #16669]
https://twitter.com/kamipo/status/1252881930103558144
Tests will be merged by nobu soon.
|
| |
|
|
|
| |
Correctly show defined class for aliases of aliases
|
|
|
|
|
|
|
|
| |
To invalidate cached method entry, existing method entry (ment)
is marked as invalidated and replace with copied ment. However,
complemented method entry (method entries in Module) should not
be set to Module's m_tbl.
[Bug #16669]
|
|
|
|
|
|
| |
Starting GCC 7, warnings about uninitialized variables are issued around
them. Such warnings could be false positives (all versions of clang do
not warn), but adding initializers there could never be bad things.
|
|
|
|
|
|
|
|
| |
See also
35eb12c06397e770392a41343cbffc4b204e15c9
6f5eb285077d9abf8f97056531996c58674b570c
687308cf0dab0af675e40da2b6ab8ccd5f77c072
b6a2d63eb3dbc31e110e8cb95e054dd71d49a611
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This patch contains several ideas:
(1) Disposable inline method cache (IMC) for race-free inline method cache
* Making call-cache (CC) as a RVALUE (GC target object) and allocate new
CC on cache miss.
* This technique allows race-free access from parallel processing
elements like RCU.
(2) Introduce per-Class method cache (pCMC)
* Instead of fixed-size global method cache (GMC), pCMC allows flexible
cache size.
* Caching CCs reduces CC allocation and allow sharing CC's fast-path
between same call-info (CI) call-sites.
(3) Invalidate an inline method cache by invalidating corresponding method
entries (MEs)
* Instead of using class serials, we set "invalidated" flag for method
entry itself to represent cache invalidation.
* Compare with using class serials, the impact of method modification
(add/overwrite/delete) is small.
* Updating class serials invalidate all method caches of the class and
sub-classes.
* Proposed approach only invalidate the method cache of only one ME.
See [Feature #16614] for more details.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Now, rb_call_info contains how to call the method with tuple of
(mid, orig_argc, flags, kwarg). Most of cases, kwarg == NULL and
mid+argc+flags only requires 64bits. So this patch packed
rb_call_info to VALUE (1 word) on such cases. If we can not
represent it in VALUE, then use imemo_callinfo which contains
conventional callinfo (rb_callinfo, renamed from rb_call_info).
iseq->body->ci_kw_size is removed because all of callinfo is VALUE
size (packed ci or a pointer to imemo_callinfo).
To access ci information, we need to use these functions:
vm_ci_mid(ci), _flag(ci), _argc(ci), _kwarg(ci).
struct rb_call_info_kw_arg is renamed to rb_callinfo_kwarg.
rb_funcallv_with_cc() and rb_method_basic_definition_p_with_cc()
is temporary removed because cd->ci should be marked.
|
|
|
|
|
|
| |
Starting clang 11, casts between pointer and (narrower-than-pointer) int
are now warned. However all such thing in our repository are guaranteed
safe. Let's suppress the warnings.
|
|
|
|
|
|
| |
VALUE and rb_serial_t do not agree with their width. We have to be
consistent. Assigning an rb_serial_t value to a VALUE variable is
practically a problem on a ILP32 environment.
|
|
|
|
|
| |
It is considered a mistake, because calling this method with no
arguments has no effect.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Methods and their definitions can be allocated/deallocated on-the-fly.
One pathological situation is when a method is deallocated then another
one is allocated immediately after that. Address of those old/new method
entries/definitions can be the same then, depending on underlying
malloc/free implementation.
So pointer comparison is insufficient. We have to check the contents.
To do so we introduce def->method_serial, which is an integer unique to
that specific method definition.
PS: Note that method_serial being uintptr_t rather than rb_serial_t is
intentional. This is because rb_serial_t can be bigger than a pointer
on a 32bit system (rb_serial_t is at least 64bit). In order to preserve
old packing of struct rb_call_cache, rb_serial_t is inappropriate.
|
|
|
|
|
|
|
|
|
|
|
| |
Previously every time a method was defined on a module, we would
recursively walk all subclasses to see if the module was included in a
class which the VM optimizes for (such as Integer#+).
For most method definitions we can tell immediately that this won't be
the case based on the method's name. To do this we just keep a hash with
method IDs of optimized methods and if our new method isn't in that list
we don't need to check subclasses at all.
|
|
|
|
|
| |
It's a Ruby bug if this ever happens check it as an assertion instead of
paying the cost of the check every time.
|
|
|
|
|
|
| |
We know that this is a heap-allocated object (a CLASS, MODULE, or
ICLASS) so we don't need to check if it is an immediate value. This
should be very slightly faster.
|
|
|
|
|
|
|
|
| |
Avoids genereating a "throwaway" sentinel class serial. There wasn't any
read harm in doing so (we're at no risk of exhaustion and there'd be no
measurable performance impact), but if feels cleaner that all class
serials actually end up assigned and used (especially now that we won't
overwrite them in a single method definition).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
rb_clear_method_cache_by_class calls rb_class_clear_method_cache
recursively on subclasses, where it will bump the class serial and clear
some other data (callable_m_tbl, and some mjit data).
Previously this could end up taking a long time to clear all the classes
if the module was included a few levels deep and especially if there
were multiple paths to it in the dependency tree (ie. a class includes
two modules which both include the same other module) as we end up
revisiting class/iclass/module objects multiple times.
This commit avoids revisiting the same object, by short circuiting when
revisit the same object. We can check this efficiently by comparing the
class serial of each object we visit with the next class serial at the
start. We know that any objects with a higher class serial have already
been visited.
|
|
|
|
|
|
| |
This is a top-level version of Module#ruby2_keywords.
It can be used for functions (top-level methods) that delegates
arguments. [Feature #16364]
|
| |
|
|
|
|
|
|
|
| |
These functions are used from within a compilation unit so we can
make them static, for better binary size. This changeset reduces
the size of generated ruby binary from 26,590,128 bytes to
26,584,472 bytes on my macihne.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Noticed that rb_method_basic_definition_p is frequently called.
Its callers include vm_caller_setup_args_block(),
rb_hash_default_value(), rb_num_neative_int_p(), and a lot more.
It seems worth caching the method resolution part. Majority of
rb_method_basic_definion_p() usages take fixed class and fixed
method id combinations.
Calculating -------------------------------------
ours trunk
so_matrix 2.379 2.115 i/s - 1.000 times in 0.420409s 0.472879s
Comparison:
so_matrix
ours: 2.4 i/s
trunk: 2.1 i/s - 1.12x slower
|
|
|
|
|
|
|
|
|
| |
inside method
Calling these methods without an argument does not have the
desired effect inside a method.
Fixes [Bug #13249]
|
|
|
|
|
|
|
|
| |
There are libraries that use define_method with argument splats
where they would like to pass keywords through the method. To
more easily allow such libraries to use ruby2_keywords to handle
backwards compatibility, it is necessary for ruby2_keywords to
support bmethods.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This reverts commits: 10d6a3aca7 8ba48c1b85 fba8627dc1 dd883de5ba
6c6a25feca 167e6b48f1 7cb96d41a5 3207979278 595b3c4fdd 1521f7cf89
c11c5e69ac cf33608203 3632a812c0 f56506be0d 86427a3219 .
The reason for the revert is that we observe ABA problem around
inline method cache. When a cache misshits, we search for a
method entry. And if the entry is identical to what was cached
before, we reuse the cache. But the commits we are reverting here
introduced situations where a method entry is freed, then the
identical memory region is used for another method entry. An
inline method cache cannot detect that ABA.
Here is a code that reproduce such situation:
```ruby
require 'prime'
class << Integer
alias org_sqrt sqrt
def sqrt(n)
raise
end
GC.stress = true
Prime.each(7*37){} rescue nil # <- Here we populate CC
class << Object.new; end
# These adjacent remove-then-alias maneuver
# frees a method entry, then immediately
# reuses it for another.
remove_method :sqrt
alias sqrt org_sqrt
end
Prime.each(7*37).to_a # <- SEGV
```
|
|
|
|
|
| |
method_def_location() expects that rb_method_attr_t::location
is 0 (Qfalse) or not.
|
|
|
|
|
|
|
|
|
|
|
| |
Now that we have eliminated most destructive operations over the
rb_method_entry_t / rb_callable_method_entry_t, let's make them
mostly immutabe and mark them const.
One exception is rb_export_method(), which destructively modifies
visibilities of method entries. I have left that operation as is
because I suspect that destructiveness is the nature of that
function.
|
|
|
|
|
|
| |
Tired of rb_method_entry_create(..., rb_method_definition_create(
..., &(rb_method_foo_t) {...})) maneuver. Provide a function that
does the thing to reduce copy&paste.
|
|
|
|
| |
Make things more immutable.
|
|
|
|
|
|
| |
The deleted function was to destructively overwrite existing method
entries, which is now considered to be a bad idea. Delete it, and
assign a newly created method entry instead.
|
|
|
|
|
| |
Instead of destructively write fields of method entries, create a
new entry and let it overwrite its owner.
|
|
|
|
|
|
|
| |
Before this changeset rb_method_definition_create only allocated a
memory region and we had to destructively initialize it later.
That is not a good design so we change the API to return a complete
struct instead.
|
|
|
|
|
|
|
|
|
|
|
| |
Did you know that C functions can return structs? That has been
true since the beginning, but not that very useful until C99. Now
that we can write compound literals, this feature is much easier
to use. By allowing struct-returning functions, some formerly big
functions can be split into smaller ones, like this changeset.
At least GCC is smart enough to inline the split functions back
into one. No performance penalty is observed.
|
|
|
|
|
|
| |
Most (if not all) of the fields of rb_method_definition_t are never
meant to be modified once after they are stored. Marking them const
makes it possible for compilers to warn on unintended modifications.
|
|
|
|
|
| |
Because rb_method_definition_t tracks its own complemented_count,
we no longer have to check it in rb_method_entry_t side.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This approach uses a flag bit on the final hash object in the regular splat,
as opposed to a previous approach that used a VM frame flag. The hash flag
approach is less invasive, and handles some cases that the VM frame flag
approach does not, such as saving the argument splat array and splatting it
later:
ruby2_keywords def foo(*args)
@args = args
bar
end
def bar
baz(*@args)
end
def baz(*args, **kw)
[args, kw]
end
foo(a:1) #=> [[], {a: 1}]
foo({a: 1}, **{}) #=> [[{a: 1}], {}]
foo({a: 1}) #=> 2.7: [[], {a: 1}] # and warning
foo({a: 1}) #=> 3.0: [[{a: 1}], {}]
It doesn't handle some cases that the VM frame flag handles, such as when
the final hash object is replaced using Hash#merge, but those cases are
probably less common and are unlikely to properly support keyword
argument separation.
Use ruby2_keywords to handle argument delegation in the delegate library.
|
|
|
|
|
|
|
|
|
|
| |
rb_vm_call_kw handles the tmp buffer for you.
Also, change method_missing so it also calls rb_vm_call_kw to
handle the kw_splat flag, instead of requiring callers to handle
kw_splat flag before calling method_missing. This may fix other
cases where method_missing is currently called without the kw_splat
being handled.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If defined in Ruby, dig would be defined as def dig(arg, *rest) end,
it would not use keywords. If the last dig argument was an empty
hash, it could be treated as keyword arguments by the next dig
method. Allow dig to pass along the empty keyword flag if called
with an empty keyword, to suppress the previous behavior and force
treating the hash as a positional argument and not keywords.
Also handle the case where dig calls method_missing, passing the
empty keyword flag to that as well.
This requires adding rb_check_funcall_with_hook_kw functions, so
that dig can specify how arguments are treated. It also adds
kw_splat arguments to a couple static functions.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is needed for C functions to call methods with keyword arguments.
This is a copy of rb_funcall_with_block with an extra argument for
the keyword flag.
There isn't a clean way to implement this that doesn't involve
changing a lot of function signatures, because rb_call doesn't
support a way to mark that the call has keyword arguments. So hack
this in using a CALL_PUBLIC_KW call_type, which we switch for
CALL_PUBLIC later in the call stack.
We do need to modify rm_vm_call0 to take an argument for whether
keyword arguments are used, since the call_type is no longer
available at that point. Use the passed in value to set the
appropriate keyword flag in both calling and ci_entry.
|
|
|
|
|
|
|
| |
We can check the function pointer passed to rb_define_private_method
like how we do so in rb_define_method. Doing so revealed some
problematic usages of rb_obj_dummy. They had to be split according
to their arity.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The rb_define_method function takes a pointer to ANYARGS-ed functions,
which in fact varies 18 different prototypes. We still need to
preserve ANYARGS for storages but why not check the consistencies if
possible.
Q&As:
Q: Where did the magic number "18" came from in the description above?
A: Count the case branch of vm_method.c:call_cfunc_invoker_func().
Note also that the 18 branches has lasted for at least 25 years.
See also 200e0ee2fd3c1c006c528874a88f684447215524.
Q: What is this __weakref__ thing?
A: That is a kind of function overloading mechanism that GCC provides.
In this case for instance rb_define_method0 is an alias of
rb_define_method, with a strong type.
Q: What is this __transparent_union__ thing?
A: That is another kind of function overloading mechanism that GCC
provides. In this case the attributed function pointer is either
VALUE(*)(int,VALUE*,VALUE) or VALUE(*)(int,const VALUE*,VALUE).
This is better than void* or ANYARGS because we can reject all
other possibilities than the two.
Q: What does this rb_define_method macro mean?
A: It selects appropriate alias of the rb_define_method function,
depending on the arity.
Q: Why the prototype change of rb_f_notimplement?
A: Function pointer to rb_f_notimplement is special cased in
vm_method.c:rb_add_method_cfunc(). That should be handled by the
__builtin_choose_expr chain inside of rb_define_method macro
expansion. In order to do so, comparison like (func ==
rb_f_notimplement) is inappropriate for __builtin_choose_expr's
expression (which must be a compile-time integer constant but the
address of rb_f_notimplement is not fixed until the linker). So
instead we are using __builtin_types_compatible_p, and in doing so
we need to distinguish rb_f_notimplement from others, by type.
|