summaryrefslogtreecommitdiff
path: root/yjit_iface.c
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2021-10-26 16:57:30 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2021-12-01 12:45:59 -0800
commit157095b3a44d8b0130a532a0b7be3f5ac197111c (patch)
tree362d1b19c520ebf270b92921671dc5b312b2307c /yjit_iface.c
parent94ee88b38cf0a20666e3965f5c9c4d520cf02b22 (diff)
Mark JIT code as writeable / executable depending on the situation
Some platforms don't want memory to be marked as writeable and executable at the same time. When we write to the code block, we calculate the OS page that the buffer position maps to. Then we call `mprotect` to allow writes on that particular page. As an optimization, we cache the "last written" aligned page which allows us to amortize the cost of the `mprotect` call. In other words, sequential writes to the same page will only call `mprotect` on the page once. When we're done writing, we call `mprotect` on the entire JIT buffer. This means we don't need to keep track of which pages were marked as writeable, we let the OS take care of that. Co-authored-by: John Hawthorn <john@hawthorn.email>
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/5032
Diffstat (limited to 'yjit_iface.c')
-rw-r--r--yjit_iface.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/yjit_iface.c b/yjit_iface.c
index 8605a4162e..39967a89a9 100644
--- a/yjit_iface.c
+++ b/yjit_iface.c
@@ -478,7 +478,7 @@ rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec)
#if (OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE) && JIT_ENABLED
bool success = true;
RB_VM_LOCK_ENTER();
- // TODO: I think we need to stop all other ractors here
+ rb_vm_barrier();
// Compile a block version starting at the first instruction
uint8_t *code_ptr = gen_entry_point(iseq, 0, ec);
@@ -914,6 +914,8 @@ rb_yjit_iseq_mark(const struct rb_iseq_constant_body *body)
void
rb_yjit_iseq_update_references(const struct rb_iseq_constant_body *body)
{
+ rb_vm_barrier();
+
rb_darray_for(body->yjit_blocks, version_array_idx) {
rb_yjit_block_array_t version_array = rb_darray_get(body->yjit_blocks, version_array_idx);
@@ -947,6 +949,11 @@ rb_yjit_iseq_update_references(const struct rb_iseq_constant_body *body)
VALUE possibly_moved = rb_gc_location(object);
// Only write when the VALUE moves, to be CoW friendly.
if (possibly_moved != object) {
+ // Possibly unlock the page we need to update
+ cb_mark_position_writeable(cb, offset_to_value);
+
+ // Object could cross a page boundary, so unlock there as well
+ cb_mark_position_writeable(cb, offset_to_value + SIZEOF_VALUE - 1);
memcpy(value_address, &possibly_moved, SIZEOF_VALUE);
}
}
@@ -955,6 +962,8 @@ rb_yjit_iseq_update_references(const struct rb_iseq_constant_body *body)
//block->code_page = rb_gc_location(block->code_page);
}
}
+ cb_mark_all_executable(cb);
+ cb_mark_all_executable(ocb);
}
// Free the yjit resources associated with an iseq