We setup specializations for code with a primitive just like regular methods, but don't replace the executor. We use the special primitive_failed executor to check whether we have jitted versions and run them. If we would replace the default executor, we would end up with infinite recursion.
If weakrefs are kept alive because of finalizers, this means that people can access finalized objects if they use finalizers. This shouldn't happen and can cause problems, for example with therubyracer. This problem occured with therubyracer which resulted in an exception with the message "Data object has already been freed" because it expects the object to be usable if it can be referenced through a weakref.
Improves the new Richards benchmark with the following numbers: Before: === bin/rbx === #main(10000) 76.1 (±3.9%) i/s - 384 in 5.057462s After: === bin/rbx === #main(10000) 109.7 (±4.6%) i/s - 552 in 5.041215s
We also use the direct class for inline caches, so we want to use this consistently. This also makes it easier to improve check_serial so the JIT can create a better version of that. Another advantage is that this makes it easier to create direct jumps to specialized functions in the JIT.
This changes the JIT so we don't inline methods that aren't often called, allowing for more room in JIT'ted code for methods that are often called. It also changes to keep track of compiling explicitly instead of (ab)using the call_count for that. Resetting the call count had other effects such as disabling that method for future jitting that has adverse effects. On my system this shaves off around 1 - 2 seconds of a CI run.