This reverts commit 7ae25febbb.
CI runs with this change showed Dnscache was already Running on all
Windows jobs and Resolve-DnsName resolved "localhost" successfully,
yet Winsock getaddrinfo still failed. The service start and probe
had no effect on the failing tests, so they add noise without value.
Co-authored-by: Claude <noreply@anthropic.com>
This reverts commit a69d12aa54.
The diagnostic served its purpose: it isolated the failure to
Winsock's getaddrinfo for the "localhost" hostname. The permanent
fix (skip guard) is now in place, so remove the temporary probe.
Co-authored-by: Claude <noreply@anthropic.com>
Addrinfo.getaddrinfo("localhost", ...) and Addrinfo.foreach("localhost",
...) crash on GitHub Actions Windows runners (Windows Server 2022 and
2025, both mingw-gcc and MSVC). Diagnostic showed 127.0.0.1 as a
numeric literal resolves fine via Winsock getaddrinfo, but "localhost"
as a hostname returns WSAHOST_NOT_FOUND under every address family
(AF_INET, AF_INET6, AF_UNSPEC, nil). PowerShell Resolve-DnsName on
the same runner succeeds, so the failure is Winsock-specific rather
than OS-level. Earlier workarounds (Dnscache service start, hosts
file append) had no effect.
Skip both tests on Windows with the existing SocketTest.win? guard,
matching the pattern already used for Addrinfo.unix and
Addrinfo#afamily. Linux and macOS coverage is unaffected.
Co-authored-by: Claude <noreply@anthropic.com>
Addrinfo.getaddrinfo on the Windows CI runners fails for "localhost"
regardless of address family (diagnostic commit a69d12aa54 showed
127.0.0.1 literal resolves fine while "localhost" never does under
AF_INET, AF_INET6, AF_UNSPEC, or nil). That rules out the earlier
KB4057932/AF_INET hypothesis and points at the Dnscache service
being stopped on the runner image.
Start Dnscache if not already running (and set it to Automatic),
then Resolve-DnsName localhost to print the OS-level resolver view
to the log. Existing hosts file and diagnostic assert stay in place
so the single CI round exposes both the service state and its
effect on getaddrinfo.
Co-authored-by: Claude <noreply@anthropic.com>
Addrinfo.getaddrinfo("localhost", 53, AF_INET, SOCK_STREAM) crashes
on GitHub Actions Windows runners with WSAHOST_NOT_FOUND, while the
same call works on Linux and macOS. Earlier hypotheses (winsock link
missing; hosts file not populated) have been ruled out on CI.
Probe five variants in one run to isolate the failing condition:
numeric literal 127.0.0.1, localhost with AF_UNSPEC, localhost with
nil family, localhost with AF_INET6, and the original AF_INET path.
Results go to stdout via puts so they are visible in CI logs. This
commit is temporary and will be reverted once the real fix lands.
Co-authored-by: Claude <noreply@anthropic.com>
GitHub Actions Windows Server 2022/2025 runner images ship with the
localhost entries commented out in C:\Windows\System32\drivers\etc\hosts
and rely on the DNS Client service's built-in rule. That path is subject
to Microsoft KB4057932 (getaddrinfo fails with WSAHOST_NOT_FOUND after
an AF_INET6 negative cache), which makes Addrinfo.getaddrinfo("localhost",
53, AF_INET, ...) in mrbgems/mruby-socket/test/addrinfo.rb flaky on CI.
Prepend explicit 127.0.0.1/::1 localhost entries to the hosts file on
all three Windows CI jobs (two mingw-gcc matrix entries and Windows-VC)
before running the build, so the resolver avoids the DNS negative cache
path and returns the expected IPv4 address.
Co-authored-by: Claude <noreply@anthropic.com>
Commit be6413f0d86a ("mruby-task: migrate HAL to ports/ directories")
moved the Windows HAL source into mruby-task/ports/win/ but dropped
the linker.libraries declaration that previously lived in
hal-win-task/mrbgem.rake. Both mingw and MSVC builds now fail to link
task_hal.o/obj with undefined references to timeBeginPeriod,
timeEndPeriod, timeSetEvent, and timeKillEvent. Re-declare winmm
under a for_windows? guard.
Co-authored-by: Claude <noreply@anthropic.com>
Commit 9965f11cfe1c ("mruby-io: migrate HAL to ports/ directories")
moved the Windows HAL source into mruby-io/ports/win/ but dropped the
linker.libraries declaration that previously lived in
hal-win-io/mrbgem.rake. Both mingw and MSVC builds now fail to link
with undefined references to closesocket, WSAStartup, WSACleanup,
select, and WSAGetLastError referenced from io.c and io_hal.c.
Re-declare ws2_32 under a for_windows? guard.
Co-authored-by: Claude <noreply@anthropic.com>
Commit d9e107c801 ("mruby-socket: migrate HAL to ports/ directories")
moved the Windows HAL source into mruby-socket/ports/win/ but dropped
the linker.libraries declarations that previously lived in
hal-win-socket/mrbgem.rake. Both mingw and MSVC builds now fail to
link with undefined references to WSAStartup, socket, send, and other
Winsock APIs. Re-declare wsock32 and ws2_32 under a for_windows? guard.
Co-authored-by: Claude <noreply@anthropic.com>
Cover zero operands, power-of-2 fast path, negative operands,
balanced multi-limb pairs with a shared Fibonacci factor, highly
unbalanced pairs (to exercise the Euclidean fallback), and
Fibonacci neighbors (always coprime). Declare a test dependency
on mruby-numeric-ext since Integer#gcd is defined there.
Co-authored-by: Claude <noreply@anthropic.com>
Replace the classical Euclidean main loop (mpz_mod per iteration)
with Stein's binary GCD: subtract + factor out trailing 2s on
odd-maintained operands. Keep an mpz_mod fallback for heavily
unbalanced pairs (the smaller operand has at least two fewer limbs)
where one long division replaces many Stein subtracts.
The old loop allocated a temporary mpz_t every iteration to hold the
mod result; the Stein loop is allocation-free thanks to the in-place
paths in mpz_sub and mpz_div_2exp. This matches the "memory first"
priority and also happens to be faster on typical inputs because
mpz_mod's setup cost dominates when the quotient is small (the
classical Fibonacci-neighbor worst case).
Also add a small mpz_swap helper used by the new loop.
Benchmark (bin/mruby benchmark/bm_bigint_gcd.rb, median of 3):
case before after ratio
single-limb 42 ms 50 ms 1.19 (fast-path
unchanged;
noise)
fib(200) vs fib(201) 82 ms 23 ms 0.28
balanced ~700-bit shared 46 ms 32 ms 0.70
unbalanced big vs small 35 ms 28 ms 0.80
power-of-2 path 38 ms 42 ms 1.11 (fast-path
unchanged;
noise)
balanced ~2800-bit shared 19 ms 15 ms 0.79
Co-authored-by: Claude <noreply@anthropic.com>
The preceding comment claimed "Binary GCD (Stein's algorithm)",
but the multi-limb main loop is classical Euclidean using mpz_mod.
Only the prelude (factoring out common 2s, single-limb and
power-of-2 fast paths) is Stein-flavored. Describe what the code
actually does so readers are not misled.
Co-authored-by: Claude <noreply@anthropic.com>
Per gemini-code-assist review on #6790: the documentation still
showed the pre-#6790 union mrb_mt_ptr member order (proc first)
and the C99 designated-initializer form of MRB_MT_ENTRY. Update
both to match the merged code, and add a note explaining why func
must come first in the union.
Co-authored-by: Claude <noreply@anthropic.com>
Per gemini-code-assist review on #6791: replace member-by-member
assignment with C89/C++98-style positional aggregate initialization,
keeping the macro a single declaration and matching the existing
pool_storage initializer style in the same macro.
Co-authored-by: Claude <noreply@anthropic.com>
heapify() and heap_delete_root() call mrb_gc_protect() to guard a
C-local mrb_value across potential GC points inside sort_cmp().
They were missing the matching mrb_gc_arena_save/restore pair, so
each call leaked one arena slot. For O(n log n) heapify calls under
MRB_GC_FIXED_ARENA this overflows the 100-slot arena and raises
NoMemoryError, e.g. during Array#repeated_permutation tests.
Wrap each function body with mrb_gc_arena_save/restore, matching
the pattern already used in insertion_sort() above.
Co-authored-by: Claude <noreply@anthropic.com>
The mrb_match_data struct stores `source` and `regexp` as plain
mrb_value members of a C-allocated struct, which the GC does not
scan. Under MRB_GC_STRESS the source string could be collected
while the MatchData was still alive, causing md[0] to read freed
memory (observed as "\xff\xff\xff").
Also stash source and regexp as instance variables on the MatchData
object so they remain reachable via the object's iv_tbl during GC.
The C struct members continue to provide fast direct access, and
no other call sites need to change.
Co-authored-by: Claude <noreply@anthropic.com>
Remove early return of hardcoded 0 for zero floats. Instead, normalize
-0.0 to +0.0 and pass through mrb_byte_hash() for better distribution.
The previous second condition (f == -0.0) was dead code since IEEE 754
-0.0 == 0.0 is true.
Co-authored-by: Claude <noreply@anthropic.com>
Use FNV-1a (xor-then-multiply) instead of FNV-1 for better avalanche
in byte hashing. Strengthen the hash finalizer in mrb_obj_hash_code()
with multiply-xorshift to improve distribution for integer and symbol
keys with power-of-two table sizes.
Co-authored-by: Claude <noreply@anthropic.com>
Replace printf("%c", val) with pack("CCC") for outputting raw
bytes. printf("%c") with values >= 128 produces invalid UTF-8
on CRuby, corrupting the PPM output. Also remove unused
arguments from the "255\n" format string.
Co-authored-by: Claude <noreply@anthropic.com>
Add hw-adc gem with analog-to-digital conversion support:
- Common Ruby API with read, read_raw, and read_voltage
- ports/esp32/ using ESP-IDF ADC oneshot driver
- ports/rp2040/ using Pico SDK ADC hardware
Based on picoruby-adc by HASUMI Hitoshi.
Co-authored-by: Claude <noreply@anthropic.com>
Add hw-pwm gem with pulse width modulation support:
- Common Ruby API with frequency, duty, period_us, pulse_width_us
- ports/esp32/ using LEDC peripheral
- ports/rp2040/ using Pico SDK PWM hardware
Based on picoruby-pwm by HASUMI Hitoshi.
Co-authored-by: Claude <noreply@anthropic.com>
Add hw-spi gem with SPI communication support:
- Common Ruby API with write, read, and full-duplex transfer
- ports/esp32/ using ESP-IDF SPI master driver
- ports/rp2040/ using Pico SDK
Based on picoruby-spi by HASUMI Hitoshi.
Co-authored-by: Claude <noreply@anthropic.com>
Move hal-posix-task and hal-win-task into
mruby-task/ports/posix/ and mruby-task/ports/win/.
Remove HAL auto-detection logic from mrbgem.rake. Update
cosmopolitan.rb to use conf.ports :posix instead of explicit
hal-* gem references.
Co-authored-by: Claude <noreply@anthropic.com>
Move hal-posix-socket and hal-win-socket into
mruby-socket/ports/posix/ and mruby-socket/ports/win/.
Remove HAL auto-detection logic from mrbgem.rake.
Co-authored-by: Claude <noreply@anthropic.com>
Move hal-posix-dir and hal-win-dir into mruby-dir/ports/posix/
and mruby-dir/ports/win/. Remove HAL auto-detection logic from
mrbgem.rake.
Co-authored-by: Claude <noreply@anthropic.com>
Move hal-posix-io and hal-win-io into mruby-io/ports/posix/ and
mruby-io/ports/win/. Platform sources are now compiled
automatically based on conf.ports setting. Remove HAL
auto-detection logic from mrbgem.rake.
Co-authored-by: Claude <noreply@anthropic.com>
Move hw-esp32-uart and hw-rp2040-uart into hw-uart/ports/esp32/
and hw-uart/ports/rp2040/ using the new ports build system.
Co-authored-by: Claude <noreply@anthropic.com>
Move hw-esp32-gpio and hw-rp2040-gpio into hw-gpio/ports/esp32/
and hw-gpio/ports/rp2040/ using the new ports build system.
Co-authored-by: Claude <noreply@anthropic.com>
Move hw-esp32-i2c and hw-rp2040-i2c into hw-i2c/ports/esp32/
and hw-i2c/ports/rp2040/ using the new ports build system.
Platform sources are now compiled automatically based on
conf.ports setting. Separate platform gems are no longer needed.
Co-authored-by: Claude <noreply@anthropic.com>
Add conf.ports method to specify target platform tags (e.g.,
:esp32, :rp2040, :posix). Gems with matching ports/<name>/
directories will automatically compile those sources.
Host builds auto-detect :posix or :win when not explicitly set.
Cross builds require explicit specification. Existing gems
without ports/ directories are unaffected.
Co-authored-by: Claude <noreply@anthropic.com>
Add three new gems for UART serial communication:
- hw-uart: common Ruby API, C bindings, ring buffer, and HAL header
- hw-esp32-uart: ESP32 HAL using ESP-IDF UART driver with FreeRTOS
RX task
- hw-rp2040-uart: RP2040 HAL using Pico SDK with IRQ-driven RX
Co-authored-by: Claude <noreply@anthropic.com>
The HAL init/final functions were defined in hal-posix-io and
hal-win-io but never called. On Windows, hal-win-io performs
WSAStartup/WSACleanup in these functions, which was not being
invoked by mruby-io unlike other HAL gems (dir, socket, task).
Co-authored-by: Claude <noreply@anthropic.com>
Add three new gems for GPIO pin control:
- hw-gpio: common Ruby API, C bindings, and HAL header
- hw-esp32-gpio: ESP32 HAL using ESP-IDF GPIO driver
- hw-rp2040-gpio: RP2040 HAL using Pico SDK
Co-authored-by: Claude <noreply@anthropic.com>
Add three new gems for I2C communication:
- hw-i2c: common Ruby API, C bindings, and HAL header
- hw-esp32-i2c: ESP32 HAL using ESP-IDF I2C master driver
- hw-rp2040-i2c: RP2040 HAL using Pico SDK
The HAL API provides init, read, write, and atomic write_read
(repeated START) operations. Platform gems depend on hw-i2c
and are only compiled when explicitly included in build config.
Co-authored-by: Claude <noreply@anthropic.com>
Replace all int64_t, uint64_t, uint32_t, and int32_t with mrb_int
in the HAL struct, timeval, and function signatures. All values
originate from or end up as mrb_int at the Ruby layer. Also removes
dead overflow checks in callers and the stdint.h dependency from
io_hal.h.
Co-authored-by: Claude <noreply@anthropic.com>
int64_t was unnecessary; readlink(2) returns ssize_t (bounded by
PATH_MAX), and the Windows HAL just raises NotImplementedError.
Co-authored-by: Claude <noreply@anthropic.com>
Replace the inline switch with a separate fast_fmt_ok() function that
maps each format character to a validity code (0=invalid, 1=arg spec,
2=separator). Modern compilers generally lower this to a jump table,
so the per-character cost remains effectively O(1).
Keeping this as a switch (instead of a C99 array-index designator
lookup table) also lets the file compile cleanly as C++.
Co-authored-by: Claude <noreply@anthropic.com>
Skip the two-pass format scanning when the format string contains
only simple specifiers (o, S, i, n, z, b, f, A, H, c, s, a) with
optional '|' separator. Validates all specifiers before consuming
va_list to ensure safe fallback to the slow path.
Covers ~50% of all mrb_get_args call sites in the codebase (175
of 353). Reduces per-call argument parsing overhead by ~30-40%.
Co-authored-by: Claude <noreply@anthropic.com>
Pre-allocate visited array and thread lists at compile time and
reuse them across re_exec calls. A cache_in_use flag detects
re-entrancy and falls back to malloc when needed.
Eliminates 3 malloc + 3 free per NFA execution for the common
non-re-entrant case. Combined with the literal fast path, brings
literal match? from 4.7x to 2.5x vs CRuby.
Co-authored-by: Claude <noreply@anthropic.com>
Pure literal patterns (/hello/, /abc/) are detected at compile
time and matched using memchr+memcmp directly, completely
bypassing Pike VM setup (no malloc, no visited array, no thread
lists). Engine-only time drops from ~400ns to ~80ns.
Co-authored-by: Claude <noreply@anthropic.com>
Move the match loop for non-block gsub, sub, and scan from Ruby
to C. Key improvements:
- re_exec called directly in a loop without MatchData per match
- MatchData created only once (for $~ of the last match)
- Replacement \-escapes processed in C (apply_replacement)
- No intermediate string objects for pre_match/post_match
- Block variants remain in Ruby to avoid VM callbacks
Performance improvement (vs CRuby ratio):
gsub simple: 5.0x -> 2.9x
scan words: 5.8x -> 1.9x
Co-authored-by: Claude <noreply@anthropic.com>
Compute a 128-bit bitmap of bytes that could start a match.
For patterns like /cat|dog|fox/ the bitmap contains only {b,c,d,f},
skipping positions where no alternative can match. For /\d+/ only
{'0'-'9'} are set.
Used when no literal prefix is available (alternation, character
class patterns). Falls back gracefully when too many bytes match.
Key improvements vs CRuby ratio:
alternation miss: 9.5x -> 3.6x
\d+ medium string: 3.0x -> 1.4x
Co-authored-by: Claude <noreply@anthropic.com>
Move pool_copy inside each match condition so captures are only
copied for threads that advance to the next step, skipping the
copy for non-matching threads.
Co-authored-by: Claude <noreply@anthropic.com>
Extract the leading literal bytes from compiled bytecode and use
memchr + memcmp to skip positions where the prefix cannot match.
Both Pike VM and backtracking engine benefit.
For /needle/ in a 2006-char string: 29x faster (1.97s -> 0.07s),
now on par with CRuby/Oniguruma.
Co-authored-by: Claude <noreply@anthropic.com>
The flag is set not only for non-greedy quantifiers but also for
lookahead, lookbehind, and backreferences. The new name accurately
reflects its purpose: indicating that the backtracking engine is
required instead of the Pike VM.
Co-authored-by: Claude <noreply@anthropic.com>
Same pattern as the earlier gsub fix: collect parts in an array
and join at the end instead of repeated string concatenation.
Co-authored-by: Claude <noreply@anthropic.com>