This changes object_id from being based on the objects location in
memory (or a nearby memory location in the case of a conflict) to be
based on an always increasing number.
This number is a Ruby Integer which allows it to overflow the size of a
pointer without issue (very unlikely to happen in real programs
especially on 64-bit, but a nice guarantee).
This changes obj_to_id_tbl and id_to_obj_tbl to both be maps of Ruby
objects to Ruby objects (previously they were Ruby object to C integer)
which simplifies updating them after compaction as we can run them
through gc_update_table_refs.
Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
Ripper reuses parse.y for its implementation. Ripper changes the
grammar productions to sometimes return Ruby objects. This Ruby objects
are put in to the parser's stack, so they must be kept alive. This is
where the "mark_ary" comes in. The mark array ensures that Ruby objects
created and pushed on the stack during the course of parsing will stay
alive for the life of the parsing functions.
Unfortunately, Arrays do not prevent their contents from moving. If the
compactor runs, objects on the parser stack could move because the array
won't prevent them from moving. But the GC doesn't know about the
parser stack, so it can't update references in that stack (it will
update them in the array).
This commit changes the mark array to be an identity hash. Since the
identity hash relies on memory addresses for the definition of identity,
the GC will not allow keys in an identity hash to move. We can prevent
movement of objects in the parser stack by sticking them in an identity
hash.
Downstream C++ projects that compile with C++11 or newer and include
the generated config.h file issue compiler warnings. Both C and C++
compilers do string-literal token pasting regardless of whitespace
between the tokens to paste. C++ compilers since C++11 require such
spaces, to avoid ambiguity with the new style of string literals
introduced then. This change fixes such projects without affecting
core Ruby.
ISO/IEC 9899:1999 section 6.7.8 specifies the values of static
storage which are not explicitly initialized. According to that
these initializers can be omitted. Doing so improvoes future
compatibility against addition / deletion of the fields of this
struct.
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
We track recursion in order to not infinite loop in ==, inspect, and
similar methods by keeping a thread-local 1 or 2 level hash. This allows
us to track when we have seen the same object (ex. using inspect) or
same pair of objects (ex. using ==) in this stack before and to treat
that differently.
Previously both levels of this Hash used the object's memory_id as a key
(using object_id would be slow and wasteful). Unfortunately, prettyprint
(pp.rb) uses this thread local variable to "pretend" to be inspect and
inherit its same recursion behaviour.
This commit changes the top-level hash to be an identity hash and to use
objects as keys instead of their object_ids.
I'd like to have also converted the 2nd level hash to an ident hash, but
it would have prevented an optimization which avoids allocating a 2nd
level hash for only a single element, which we want to keep because it's
by far the most common case.
So the new format of this hash is:
{ object => true } (not paired)
{ lhs_object => rhs_object_memory_id } (paired, single object)
{ lhs_object => { rhs_object_memory_id => true, ... } } (paired, many objects)
We must also update pp.rb to match this (using identity hashes).
This commit is to attempt fixing this error:
http://ci.rvm.jp/results/trunk-gc-asserts@ruby-sky1/2353281
Each non-full heap_page struct contains a reference to the next page
that contains free slots. Compaction could fill any page, including
pages that happen to be linked to as "pages which contain free slots".
To fix this, we'll iterate each page, and rebuild the "free page list"
depending on the number of actual free slots on that page. If there are
no free slots on the page, we'll set the free_next pointer to NULL.
Finally we'll pop one page off the "free page list" and set it as the
"using page" for the next allocation.