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
2 changes: 1 addition & 1 deletion depend
Original file line number Diff line number Diff line change
Expand Up @@ -1401,7 +1401,6 @@ compile.$(OBJEXT): $(top_srcdir)/prism/pack.h
compile.$(OBJEXT): $(top_srcdir)/prism/parser.h
compile.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
compile.$(OBJEXT): $(top_srcdir)/prism/prism.h
compile.$(OBJEXT): $(top_srcdir)/prism/regexp.h
compile.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
compile.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
Expand Down Expand Up @@ -17727,6 +17726,7 @@ transcode.$(OBJEXT): $(hdrdir)/ruby/ruby.h
transcode.$(OBJEXT): $(top_srcdir)/internal/array.h
transcode.$(OBJEXT): $(top_srcdir)/internal/class.h
transcode.$(OBJEXT): $(top_srcdir)/internal/compilers.h
transcode.$(OBJEXT): $(top_srcdir)/internal/encoding.h
transcode.$(OBJEXT): $(top_srcdir)/internal/gc.h
transcode.$(OBJEXT): $(top_srcdir)/internal/inits.h
transcode.$(OBJEXT): $(top_srcdir)/internal/object.h
Expand Down
14 changes: 13 additions & 1 deletion encoding.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,16 @@ enc_registered(struct enc_table *enc_table, const char *name)
return -1;
}

int
rb_enc_registered(const char *name)
{
int idx;
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
idx = enc_registered(enc_table, name);
}
return idx;
}

void
rb_encdb_declare(const char *name)
{
Expand Down Expand Up @@ -1600,8 +1610,10 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
/* Already set */
overridden = TRUE;

int index = 0;
if (!NIL_P(encoding)) {
enc_check_encoding(encoding); // loads it if necessary. Needs to be done outside of VM lock.
index = rb_enc_to_index(rb_to_encoding(encoding));
}

GLOBAL_ENC_TABLE_LOCKING(enc_table) {
Expand All @@ -1619,7 +1631,7 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
(st_data_t)UNSPECIFIED_ENCODING);
}
else {
def->index = rb_enc_to_index(rb_to_encoding(encoding));
def->index = index;
def->enc = 0;
enc_alias_internal(enc_table, name, def->index);
}
Expand Down
33 changes: 30 additions & 3 deletions gc/default/default.c
Original file line number Diff line number Diff line change
Expand Up @@ -1853,7 +1853,10 @@ static struct heap_page *
heap_page_resurrect(rb_objspace_t *objspace)
{
struct heap_page *page = NULL;
if (objspace->empty_pages != NULL) {
if (objspace->empty_pages == NULL) {
GC_ASSERT(objspace->empty_pages_count == 0);
}
else {
GC_ASSERT(objspace->empty_pages_count > 0);
objspace->empty_pages_count--;
page = objspace->empty_pages;
Expand Down Expand Up @@ -1973,6 +1976,8 @@ heap_page_allocate_and_initialize(rb_objspace_t *objspace, rb_heap_t *heap)
if (page == NULL && objspace->heap_pages.allocatable_slots > 0) {
page = heap_page_allocate(objspace);
allocated = true;

GC_ASSERT(page != NULL);
}

if (page != NULL) {
Expand Down Expand Up @@ -2047,6 +2052,9 @@ heap_prepare(rb_objspace_t *objspace, rb_heap_t *heap)
/* If we still don't have a free page and not allowed to create a new page,
* we should start a new GC cycle. */
if (heap->free_pages == NULL) {
GC_ASSERT(objspace->empty_pages_count == 0);
GC_ASSERT(objspace->heap_pages.allocatable_slots == 0);

if (gc_start(objspace, GPR_FLAG_NEWOBJ) == FALSE) {
rb_memerror();
}
Expand Down Expand Up @@ -3922,10 +3930,29 @@ gc_sweep_continue(rb_objspace_t *objspace, rb_heap_t *sweep_heap)

for (int i = 0; i < HEAP_COUNT; i++) {
rb_heap_t *heap = &heaps[i];
if (!gc_sweep_step(objspace, heap)) {
if (heap == sweep_heap && objspace->empty_pages_count == 0 && objspace->heap_pages.allocatable_slots == 0) {
if (gc_sweep_step(objspace, heap)) {
GC_ASSERT(heap->free_pages != NULL);
}
else if (heap == sweep_heap) {
if (objspace->empty_pages_count > 0 || objspace->heap_pages.allocatable_slots > 0) {
/* [Bug #21548]
*
* If this heap is the heap we want to sweep, but we weren't able
* to free any slots, but we also either have empty pages or could
* allocate new pages, then we want to preemptively claim a page
* because it's possible that sweeping another heap will call
* gc_sweep_finish_heap, which may use up all of the
* empty/allocatable pages. If other heaps are not finished sweeping
* then we do not finish this GC and we will end up triggering a new
* GC cycle during this GC phase. */
heap_page_allocate_and_initialize(objspace, heap);

GC_ASSERT(heap->free_pages != NULL);
}
else {
/* Not allowed to create a new page so finish sweeping. */
gc_sweep_rest(objspace);
GC_ASSERT(gc_mode(objspace) == gc_mode_none);
break;
}
}
Expand Down
1 change: 1 addition & 0 deletions internal/encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ void rb_encdb_declare(const char *name);
void rb_enc_set_base(const char *name, const char *orig);
int rb_enc_set_dummy(int index);
void rb_enc_raw_set(VALUE obj, rb_encoding *enc);
int rb_enc_registered(const char *name);

PUREFUNC(int rb_data_is_encoding(VALUE obj));

Expand Down
8 changes: 4 additions & 4 deletions ractor_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,14 @@ ractor_port_init(VALUE rpv, rb_ractor_t *r)
* Returns a new Ractor::Port object.
*/
static VALUE
ractor_port_initialzie(VALUE self)
ractor_port_initialize(VALUE self)
{
return ractor_port_init(self, GET_RACTOR());
}

/* :nodoc: */
static VALUE
ractor_port_initialzie_copy(VALUE self, VALUE orig)
ractor_port_initialize_copy(VALUE self, VALUE orig)
{
struct ractor_port *dst = RACTOR_PORT_PTR(self);
struct ractor_port *src = RACTOR_PORT_PTR(orig);
Expand Down Expand Up @@ -1498,8 +1498,8 @@ Init_RactorPort(void)
{
rb_cRactorPort = rb_define_class_under(rb_cRactor, "Port", rb_cObject);
rb_define_alloc_func(rb_cRactorPort, ractor_port_alloc);
rb_define_method(rb_cRactorPort, "initialize", ractor_port_initialzie, 0);
rb_define_method(rb_cRactorPort, "initialize_copy", ractor_port_initialzie_copy, 1);
rb_define_method(rb_cRactorPort, "initialize", ractor_port_initialize, 0);
rb_define_method(rb_cRactorPort, "initialize_copy", ractor_port_initialize_copy, 1);

#if USE_RACTOR_SELECTOR
rb_init_ractor_selector();
Expand Down
19 changes: 19 additions & 0 deletions test/ruby/test_encoding.rb
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,23 @@ def test_ractor_lazy_load_encoding_concurrently
assert rs.empty?
end;
end

def test_ractor_set_default_external_string
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
$-w = nil
rs = []
7.times do |i|
rs << Ractor.new(i) do |i|
Encoding.default_external = "us-ascii"
end
end

while rs.any?
r, _obj = Ractor.select(*rs)
rs.delete(r)
end
assert rs.empty?
end;
end
end
46 changes: 46 additions & 0 deletions test/ruby/test_transcode.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2361,6 +2361,52 @@ def test_ractor_lazy_load_encoding_random
end;
end

def test_ractor_asciicompat_encoding_exists
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
rs = []
7.times do
rs << Ractor.new do
string = "ISO-2022-JP"
encoding = Encoding.find(string)
20_000.times do
Encoding::Converter.asciicompat_encoding(string)
Encoding::Converter.asciicompat_encoding(encoding)
end
end
end

while rs.any?
r, _obj = Ractor.select(*rs)
rs.delete(r)
end
assert rs.empty?
end;
end

def test_ractor_asciicompat_encoding_doesnt_exist
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
begin;
rs = []
NO_EXIST = "I".freeze
7.times do
rs << Ractor.new do
50.times do
if (val = Encoding::Converter.asciicompat_encoding(NO_EXIST))
raise "Got #{val}, expected nil"
end
end
end
end

while rs.any?
r, _obj = Ractor.select(*rs)
rs.delete(r)
end
assert rs.empty?
end;
end

private

def assert_conversion_both_ways_utf8(utf8, raw, encoding)
Expand Down
12 changes: 8 additions & 4 deletions test/ruby/test_zjit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1008,25 +1008,29 @@ def test
test
}

assert_compiles '1', %q{
# TODO(Shopify/ruby#716): Support spills and change to assert_compiles
assert_runs '1', %q{
def a(n1,n2,n3,n4,n5,n6,n7,n8,n9) = n1+n9
a(2,0,0,0,0,0,0,0,-1)
}

assert_compiles '0', %q{
# TODO(Shopify/ruby#716): Support spills and change to assert_compiles
assert_runs '0', %q{
def a(n1,n2,n3,n4,n5,n6,n7,n8) = n8
a(1,1,1,1,1,1,1,0)
}

# TODO(Shopify/ruby#716): Support spills and change to assert_compiles
# self param with spilled param
assert_compiles '"main"', %q{
assert_runs '"main"', %q{
def a(n1,n2,n3,n4,n5,n6,n7,n8) = self
a(1,0,0,0,0,0,0,0).to_s
}
end

def test_spilled_param_new_arary
assert_compiles '[:ok]', %q{
# TODO(Shopify/ruby#716): Support spills and change to assert_compiles
assert_runs '[:ok]', %q{
def a(n1,n2,n3,n4,n5,n6,n7,n8) = [n8]
a(0,0,0,0,0,0,0, :ok)
}
Expand Down
48 changes: 33 additions & 15 deletions transcode.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "internal/object.h"
#include "internal/string.h"
#include "internal/transcode.h"
#include "internal/encoding.h"
#include "ruby/encoding.h"
#include "vm_sync.h"

Expand Down Expand Up @@ -1826,7 +1827,9 @@ rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
st_table *table2;
struct asciicompat_encoding_t data = {0};

RB_VM_LOCKING() {
unsigned int lev;
RB_VM_LOCK_ENTER_LEV(&lev);
{
if (st_lookup(transcoder_table, (st_data_t)ascii_incompat_name, &v)) {
table2 = (st_table *)v;
/*
Expand All @@ -1839,12 +1842,25 @@ rb_econv_asciicompat_encoding(const char *ascii_incompat_name)
if (table2->num_entries == 1) {
data.ascii_incompat_name = ascii_incompat_name;
data.ascii_compat_name = NULL;
st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
if (rb_multi_ractor_p()) {
/*
* We need to unlock in case `load_transcoder_entry` actually loads the encoding
* and table2 could be inserted into when we unlock.
*/
st_table *dup_table2 = st_copy(table2);
RB_VM_LOCK_LEAVE_LEV(&lev);
st_foreach(dup_table2, asciicompat_encoding_i, (st_data_t)&data);
st_free_table(dup_table2);
RB_VM_LOCK_ENTER_LEV(&lev);
}
else {
st_foreach(table2, asciicompat_encoding_i, (st_data_t)&data);
}
}

}

}
RB_VM_LOCK_LEAVE_LEV(&lev);

return data.ascii_compat_name; // can be NULL
}
Expand Down Expand Up @@ -2989,10 +3005,16 @@ static rb_encoding *
make_encoding(const char *name)
{
rb_encoding *enc;
RB_VM_LOCKING() {
enc = rb_enc_find(name);
if (!enc)
enc = make_dummy_encoding(name);
enc = rb_enc_find(name);
if (!enc) {
RB_VM_LOCKING() {
if (rb_enc_registered(name)) {
enc = NULL;
}
else {
enc = make_dummy_encoding(name);
}
}
}
return enc;
}
Expand Down Expand Up @@ -3029,14 +3051,10 @@ econv_s_asciicompat_encoding(VALUE klass, VALUE arg)
VALUE enc = Qnil;

enc_arg(&arg, &arg_name, &arg_enc);

RB_VM_LOCKING() {
result_name = rb_econv_asciicompat_encoding(arg_name);

if (result_name) {
result_enc = make_encoding(result_name);
enc = rb_enc_from_encoding(result_enc);
}
result_name = rb_econv_asciicompat_encoding(arg_name);
if (result_name) {
result_enc = make_encoding(result_name);
enc = rb_enc_from_encoding(result_enc);
}
return enc;
}
Expand Down
12 changes: 12 additions & 0 deletions zjit/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::GetSpecialNumber { nth, state } => gen_getspecial_number(asm, *nth, &function.frame_state(*state)),
&Insn::IncrCounter(counter) => no_output!(gen_incr_counter(asm, counter)),
Insn::ObjToString { val, cd, state, .. } => gen_objtostring(jit, asm, opnd!(val), *cd, &function.frame_state(*state)),
&Insn::CheckInterrupts { state } => no_output!(gen_check_interrupts(jit, asm, &function.frame_state(state))),
Insn::ArrayExtend { .. }
| Insn::ArrayMax { .. }
| Insn::ArrayPush { .. }
Expand Down Expand Up @@ -674,6 +675,17 @@ fn gen_getspecial_number(asm: &mut Assembler, nth: u64, state: &FrameState) -> O
asm_ccall!(asm, rb_reg_nth_match, Opnd::Imm((nth >> 1).try_into().unwrap()), backref)
}

fn gen_check_interrupts(jit: &mut JITState, asm: &mut Assembler, state: &FrameState) {
// Check for interrupts
// see RUBY_VM_CHECK_INTS(ec) macro
asm_comment!(asm, "RUBY_VM_CHECK_INTS(ec)");
// Not checking interrupt_mask since it's zero outside finalize_deferred_heap_pages,
// signal_exec, or rb_postponed_job_flush.
let interrupt_flag = asm.load(Opnd::mem(32, EC, RUBY_OFFSET_EC_INTERRUPT_FLAG));
asm.test(interrupt_flag, interrupt_flag);
asm.jnz(side_exit(jit, state, SideExitReason::Interrupt));
}

/// Compile an interpreter entry block to be inserted into an ISEQ
fn gen_entry_prologue(asm: &mut Assembler, iseq: IseqPtr) {
asm_comment!(asm, "ZJIT entry point: {}", iseq_get_location(iseq, 0));
Expand Down
Loading