Commit graph

25 commits

Author SHA1 Message Date
Kazuhiro NISHIYAMA
04f07713d1
Fix typos [ci skip] 2021-12-25 10:33:49 +09:00
Alan Wu
ac5d6faea8
YJIT: Fix unexpected truncation when outputing VALUE
Previously, YJIT incorrectly discarded the upper 32 bits of the object
pointer when writing out VALUEs to setup default keyword arguments.

In addition to incorrectly truncating, the output pointers were not
properly tracked for handling GC compaction moving the referenced
objects.

YJIT previously attempted to encode a mov instruction with a memory
destination and a 64 bit immediate when there is no such encoding
possible in the ISA. Add an assert to mitigate not being able to
catch this at build time.
2021-12-14 19:47:42 -05:00
Alan Wu
26063d3954 YJIT: Initialize code buffer with PUSH DS
PUSH DS triggers the #UD processor exception in 64-bit mode, which the
OS translates to a SIGILL. Unlike INT3, this triggers the usual crash
reporter, which makes failures easier to notice. When there is a
debugger attached, the PUSH DS pauses execution just like INT3.
2021-12-05 10:26:35 -05:00
Alan Wu
f41b4d44f9 YJIT: Bounds check every byte in the assembler
Previously, YJIT assumed that basic blocks never consume more than
1 KiB of memory. This assumption does not hold for long Ruby methods
such as the one in the following:

```ruby
eval(<<RUBY)
def set_local_a_lot
  #{'_=0;'*0x40000}
end
RUBY

set_local_a_lot
```

For low `--yjit-exec-mem-size` values, one basic block could exhaust the
entire buffer.

Introduce a new field `codeblock_t::dropped_bytes` that the assembler
sets whenever it runs out of space. Check this field in
gen_single_block() to respond to out of memory situations and other
error conditions. This design avoids making the control flow graph of
existing code generation functions more complex.

Use POSIX shell in misc/test_yjit_asm.sh since bash is expanding
`0%/*/*` differently.

Co-authored-by: Aaron Patterson <tenderlove@ruby-lang.org>
2021-12-03 20:02:25 -05:00
Aaron Patterson
157095b3a4 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>
2021-12-01 12:45:59 -08:00
Alan Wu
91a9062626
YJIT: use shorter encoding for mov(r64,imm) when unambiguous (#5081)
* YJIT: use shorter encoding for mov(r64,imm) when unambiguous

Previously, for small constants such as `mov(RAX, imm_opnd(Qundef))`,
we emit an instruction with an 8-byte immediate. This form commonly
gets the `movabs` mnemonic.

In 64-bit mode, 32-bit operands get zero extended to 64-bit to fill the
register, so when the immediate is small enough, we can save 4 bytes by
using the `mov` variant that takes a 32-bit immediate and does a zero
extension.

Not implement with this change, there is an imm32 variant of `mov` that
does sign extension we could use. When the constant is negative, we
fallback to the `movabs` form.

In railsbench, this change yields roughly a 12% code size reduction for
the outlined block.

Co-authored-by: Jemma Issroff <jemmaissroff@gmail.com>

* [ci skip] comment edit. Please squash.

Co-authored-by: Jemma Issroff <jemmaissroff@gmail.com>
2021-11-05 15:44:29 -04:00
Maxime Chevalier-Boisvert
2421527d6e
YJIT code pages refactoring for code GC (#5073)
* New code page allocation logic

* Fix leaked globals

* Fix leaked symbols, yjit asm tests

* Make COUNTED_EXIT take a jit argument, so we can eliminate global ocb

* Remove extra whitespace

* Change block start_pos/end_pos to be pointers instead of uint32_t

* Change branch end_pos and start_pos to end_addr, start_addr
2021-11-04 16:05:41 -04:00
Alan Wu
6a9e2b3cc3 YJIT: Show GCC that the mmap probing loop runs at least once
Fixes:
    ./src/yjit_asm.c:196:8: warning: 'mem_block' may be used uninitialized [-Wmaybe-uninitialized]
2021-10-20 19:04:22 -04:00
Alan Wu
00be5846e4 Fix non RUBY_DEBUG build warnings
On non RUBY_DEBUG builds, assert() compiles to nothing and the compiler
warns about uninitialized variables in those code paths. Replace
those asserts with rb_bug() to fix the warnings and do the assert in
all builds. Since yjit_asm_tests.c compiles outside of Ruby, it needed
a distinct version of rb_bug().

Also put YJIT_STATS check for function delcaration that is only defined
in YJIT_STATS builds.
2021-10-20 18:19:43 -04:00
Alan Wu
f6da559d5b Put YJIT into a single compilation unit
For upstreaming, we want functions we export either prefixed with "rb_"
or made static. Historically we haven't been following this rule, so we
were "leaking" a lot of symbols as `make leak-globals` would tell us.

This change unifies everything YJIT into a single compilation unit,
yjit.o, and makes everything unprefixed static to pass `make leak-globals`.
This manual "unified build" setup is similar to that of vm.o.

Having everything in one compilation unit allows static functions to
be visible across YJIT files and removes the need for declarations in
headers in some cases. Unnecessary declarations were removed.

Other changes of note:
  - switched to MJIT_SYMBOL_EXPORT_BEGIN which indicates stuff as being
    off limits for native extensions
  - the first include of each YJIT file is change to be "internal.h"
  - undefined MAP_STACK before explicitly redefining it since it
    collide's with a definition in system headers. Consider renaming?
2021-10-20 18:19:42 -04:00
Alan Wu
f36a5a98c0 style: line break before "else" 2021-10-20 18:19:41 -04:00
Alan Wu
ec4998bd69 style: switch statements indent
Case labels get half an indent and the opening brace is on the same line
as "switch".
2021-10-20 18:19:41 -04:00
Alan Wu
a10cf74e5c style: align pointer "*" to the right 2021-10-20 18:19:41 -04:00
Maxime Chevalier-Boisvert
0385ca2e97 Try to break the code page refactoring into smaller steps 2021-10-20 18:19:41 -04:00
Jean Boussier
217f7cb16f Include errno message in mmap failure output
It might help figure out why it is failing.
2021-10-20 18:19:40 -04:00
Maxime Chevalier-Boisvert
350b686a2c First pass at code page GC object. 2021-10-20 18:19:37 -04:00
Maxime Chevalier-Boisvert
51c84f0033 Code page allocation code 2021-10-20 18:19:37 -04:00
Maxime Chevalier-Boisvert
6b5d26dc78 Implement basic encodings for xchg 2021-10-20 18:19:35 -04:00
Maxime Chevalier-Boisvert
5c2f74fc32 Fix encoding of test x86 instruction 2021-10-20 18:19:35 -04:00
Maxime Chevalier-Boisvert
cf2b508375 Try to alloc executable memory within rel32 range on Linux machines (#12)
* Use INT32_MIN, INT32_MAX, etc. constants in yjit_asm.c

* Print warning on stderr when code past rel32 jump range

* Fix preprocessor snafu

* Move rel32 warning into --yjit-stats

* Try to allocate within rel32 offset on Linux machines

* Update yjit_asm.c

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>

* On Linux, use sysconf to get the page size

Co-authored-by: Alan Wu <XrXr@users.noreply.github.com>
2021-10-20 18:19:34 -04:00
Maxime Chevalier-Boisvert
d1e9e4566f Update yjit_asm.c 2021-10-20 18:19:32 -04:00
Maxime Chevalier-Boisvert
3d53ee1761 Fill uninitialized memory with int3 2021-10-20 18:19:32 -04:00
Alan Wu
d03b7f77d4 Fix GCC warnings
Mostly unused and uninitialized warnings here and there
2021-10-20 18:19:32 -04:00
Dylan Thacker-Smith
4b80358e5d Fix condition in cb_align_pos which should return early when aligned 2021-10-20 18:19:32 -04:00
Jose Narvaez
4e2eb7695e Yet Another Ruby JIT!
Renaming uJIT to YJIT. AKA s/ujit/yjit/g.
2021-10-20 18:19:31 -04:00
Renamed from ujit_asm.c (Browse further)