Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ jobs:
repository: ruby/ruby-bench
persist-credentials: false
path: ruby-bench
ref: 'a46e02b01a58ca74bb2ce055b4ea561cb372d1cd'

# If you want to skip failing benchmark, consider using `--excludes`.
# e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/zjit-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,7 @@ jobs:
persist-credentials: false
repository: ruby/ruby-bench
path: ruby-bench
ref: 'a46e02b01a58ca74bb2ce055b4ea561cb372d1cd'

# If you want to skip failing benchmark, consider using `--excludes`.
# e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/zjit-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ jobs:
repository: ruby/ruby-bench
persist-credentials: false
path: ruby-bench
ref: 'a46e02b01a58ca74bb2ce055b4ea561cb372d1cd'

# If you want to skip failing benchmark, consider using `--excludes`.
# e.g. `bench_opts: '--warmup=1 --bench=1 --excludes=railsbench,lobsters'`
Expand Down
80 changes: 0 additions & 80 deletions ext/-test-/postponed_job/postponed_job.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,38 +35,6 @@ pjob_callback(void *data)
rb_ary_push(ary, INT2FIX(counter));
}

static VALUE
pjob_register(VALUE self, VALUE obj)
{
counter = 0;
rb_postponed_job_register(0, pjob_callback, (void *)obj);
rb_gc_start();
counter++;
rb_gc_start();
counter++;
rb_gc_start();
counter++;
return self;
}

static void
pjob_one_callback(void *data)
{
VALUE ary = (VALUE)data;
Check_Type(ary, T_ARRAY);

rb_ary_push(ary, INT2FIX(1));
}

static VALUE
pjob_register_one(VALUE self, VALUE obj)
{
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
return self;
}

static VALUE
pjob_call_direct(VALUE self, VALUE obj)
{
Expand All @@ -83,48 +51,6 @@ pjob_call_direct(VALUE self, VALUE obj)

static void pjob_noop_callback(void *data) { }

static VALUE
pjob_register_one_same(VALUE self)
{
rb_gc_start();
int r1 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
int r2 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
int r3 = rb_postponed_job_register_one(0, pjob_noop_callback, NULL);
VALUE ary = rb_ary_new();
rb_ary_push(ary, INT2FIX(r1));
rb_ary_push(ary, INT2FIX(r2));
rb_ary_push(ary, INT2FIX(r3));
return ary;
}

#ifdef HAVE_PTHREAD_H
#include <pthread.h>

static void *
pjob_register_in_c_thread_i(void *obj)
{
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
rb_postponed_job_register_one(0, pjob_one_callback, (void *)obj);
return NULL;
}

static VALUE
pjob_register_in_c_thread(VALUE self, VALUE obj)
{
pthread_t thread;
if (pthread_create(&thread, NULL, pjob_register_in_c_thread_i, (void *)obj)) {
return Qfalse;
}

if (pthread_join(thread, NULL)) {
return Qfalse;
}

return Qtrue;
}
#endif

static void
pjob_preregistered_callback(void *data)
{
Expand Down Expand Up @@ -216,13 +142,7 @@ void
Init_postponed_job(VALUE self)
{
VALUE mBug = rb_define_module("Bug");
rb_define_module_function(mBug, "postponed_job_register", pjob_register, 1);
rb_define_module_function(mBug, "postponed_job_register_one", pjob_register_one, 1);
rb_define_module_function(mBug, "postponed_job_call_direct", pjob_call_direct, 1);
rb_define_module_function(mBug, "postponed_job_register_one_same", pjob_register_one_same, 0);
#ifdef HAVE_PTHREAD_H
rb_define_module_function(mBug, "postponed_job_register_in_c_thread", pjob_register_in_c_thread, 1);
#endif
rb_define_module_function(mBug, "postponed_job_preregister_and_call_with_sleep", pjob_preregister_and_call_with_sleep, 1);
rb_define_module_function(mBug, "postponed_job_preregister_and_call_without_sleep", pjob_preregister_and_call_without_sleep, 1);
rb_define_module_function(mBug, "postponed_job_preregister_multiple_times", pjob_preregister_multiple_times, 0);
Expand Down
7 changes: 6 additions & 1 deletion gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3601,7 +3601,12 @@ rb_gc_obj_optimal_size(VALUE obj)
}

case T_HASH:
return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
{
if (RB_OBJ_FROZEN(obj) && RHASH_AR_TABLE_P(obj)) {
return sizeof(struct RHash) + offsetof(ar_table, pairs) + RHASH_AR_TABLE_BOUND(obj) * sizeof(ar_table_pair);
}
return sizeof(struct RHash) + (RHASH_ST_TABLE_P(obj) ? sizeof(st_table) : sizeof(ar_table));
}

default:
return 0;
Expand Down
16 changes: 0 additions & 16 deletions hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -471,24 +471,8 @@ ar_set_entry(VALUE hash, unsigned int index, st_data_t key, st_data_t val, st_ha
#define RHASH_AR_TABLE_SIZE(h) (HASH_ASSERT(RHASH_AR_TABLE_P(h)), \
RHASH_AR_TABLE_SIZE_RAW(h))

#define RHASH_AR_TABLE_BOUND_RAW(h) \
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))

#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)

#define HASH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(HASH_DEBUG, expr, #expr)

static inline unsigned int
RHASH_AR_TABLE_BOUND(VALUE h)
{
HASH_ASSERT(RHASH_AR_TABLE_P(h));
const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
HASH_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
return bound;
}

#if HASH_DEBUG
#define hash_verify(hash) hash_verify_(hash, __FILE__, __LINE__)

Expand Down
53 changes: 0 additions & 53 deletions include/ruby/debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -754,59 +754,6 @@ rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_po
*/
void rb_postponed_job_trigger(rb_postponed_job_handle_t h);

/**
* Schedules the given `func` to be called with `data` when Ruby next checks for
* interrupts. If this function is called multiple times in between Ruby checking
* for interrupts, then `func` will be called only once with the `data` value from
* the first call to this function.
*
* Like `rb_postponed_job_trigger`, the context in which the job is called
* holds the GVL and can allocate Ruby objects.
*
* This method essentially has the same semantics as:
*
* ```
* rb_postponed_job_trigger(rb_postponed_job_preregister(func, data));
* ```
*
* @note Previous versions of Ruby promised that the (`func`, `data`) pairs would
* be executed as many times as they were registered with this function; in
* reality this was always subject to race conditions and this function no
* longer provides this guarantee. Instead, multiple calls to this function
* can be coalesced into a single execution of the passed `func`, with the
* most recent `data` registered at that time passed in.
*
* @deprecated This interface implies that arbitrarily many `func`'s can be enqueued
* over the lifetime of the program, whilst in reality the registration
* slots for postponed jobs are a finite resource. This is made clearer
* by the `rb_postponed_job_preregister` and `rb_postponed_job_trigger`
* functions, and a future version of Ruby might delete this function.
*
* @param[in] flags Unused and ignored.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
* @retval 0 Postponed job registration table is full. Failed.
* @retval 1 Registration succeeded.
* @post The passed job will run on the next interrupt check.
*/
RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);

/**
* Identical to `rb_postponed_job_register`
*
* @deprecated This is deprecated for the same reason as `rb_postponed_job_register`
*
* @param[in] flags Unused and ignored.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
* @retval 0 Postponed job registration table is full. Failed.
* @retval 1 Registration succeeded.
* @post The passed job will run on the next interrupt check.
*/
RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data);

/** @} */

/**
Expand Down
16 changes: 16 additions & 0 deletions internal/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,20 @@ RHASH_AR_TABLE_SIZE_RAW(VALUE h)
return (unsigned)ret;
}

#define RHASH_AR_TABLE_BOUND_RAW(h) \
((unsigned int)((RBASIC(h)->flags >> RHASH_AR_TABLE_BOUND_SHIFT) & \
(RHASH_AR_TABLE_BOUND_MASK >> RHASH_AR_TABLE_BOUND_SHIFT)))

#define RHASH_ST_TABLE_SET(h, s) rb_hash_st_table_set(h, s)
#define RHASH_TYPE(hash) (RHASH_AR_TABLE_P(hash) ? &objhash : RHASH_ST_TABLE(hash)->type)

static inline unsigned int
RHASH_AR_TABLE_BOUND(VALUE h)
{
RUBY_ASSERT(RHASH_AR_TABLE_P(h));
const unsigned int bound = RHASH_AR_TABLE_BOUND_RAW(h);
RUBY_ASSERT(bound <= RHASH_AR_TABLE_MAX_SIZE);
return bound;
}

#endif /* INTERNAL_HASH_H */
4 changes: 3 additions & 1 deletion iseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -3027,7 +3027,9 @@ rb_estimate_iv_count(VALUE klass, const rb_iseq_t * initialize_iseq)
attr_index_t count = (attr_index_t)iv_names.num_entries;

VALUE superclass = rb_class_superclass(klass);
count += RCLASS_MAX_IV_COUNT(superclass);
if (!NIL_P(superclass)) { // BasicObject doesn't have a superclass
count += RCLASS_MAX_IV_COUNT(superclass);
}

set_free_embedded_table(&iv_names);

Expand Down
35 changes: 0 additions & 35 deletions test/-ext-/postponed_job/test_postponed_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,39 +33,4 @@ def test_multiple_preregistration_with_new_data
assert_equal [3, 4], values
RUBY
end

def test_legacy_register
assert_separately([], __FILE__, __LINE__, <<-'RUBY')
require '-test-/postponed_job'
direct, registered = [], []

Bug.postponed_job_call_direct(direct)
Bug.postponed_job_register(registered)

assert_equal([0], direct)
assert_equal([3], registered)

Bug.postponed_job_register_one(ary = [])
assert_equal [1], ary
RUBY
end

def test_legacy_register_one_same
assert_separately([], __FILE__, __LINE__, <<-'RUBY')
require '-test-/postponed_job'
# Registering the same job three times should result in three of the same handle
handles = Bug.postponed_job_register_one_same
assert_equal [handles[0]], handles.uniq
RUBY
end

if Bug.respond_to?(:postponed_job_register_in_c_thread)
def test_legacy_register_in_c_thread
assert_separately([], __FILE__, __LINE__, <<-'RUBY')
require '-test-/postponed_job'
assert Bug.postponed_job_register_in_c_thread(ary = [])
assert_equal [1], ary
RUBY
end
end
end
14 changes: 14 additions & 0 deletions test/ruby/test_super.rb
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,20 @@ def initialize
assert_equal 2, inherited.test # it may read index=1 while it should be index=2
end

def test_define_initialize_in_basic_object
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
class ::BasicObject
alias_method :initialize, :initialize
def initialize
@bug = "[Bug #21992]"
end
end

assert_not_nil Object.new
end;
end

def test_super_in_basic_object
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
Expand Down
27 changes: 0 additions & 27 deletions vm_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1921,33 +1921,6 @@ rb_postponed_job_trigger(rb_postponed_job_handle_t h)
RUBY_VM_SET_POSTPONED_JOB_INTERRUPT(get_valid_ec(GET_VM()));
}


static int
pjob_register_legacy_impl(unsigned int flags, rb_postponed_job_func_t func, void *data)
{
/* We _know_ calling preregister from a signal handler like this is racy; what is
* and is not promised is very exhaustively documented in debug.h */
rb_postponed_job_handle_t h = rb_postponed_job_preregister(0, func, data);
if (h == POSTPONED_JOB_HANDLE_INVALID) {
return 0;
}
rb_postponed_job_trigger(h);
return 1;
}

int
rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data)
{
return pjob_register_legacy_impl(flags, func, data);
}

int
rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data)
{
return pjob_register_legacy_impl(flags, func, data);
}


void
rb_postponed_job_flush(rb_vm_t *vm)
{
Expand Down