Commit Graph

553 Commits

Author SHA1 Message Date
0x1eef 819156e678 task: return nil when given a nested call to Task.run
When you try to start an event loop inside an event loop,
the mruby process will SIGSEGV:

```ruby
Task.new { Task.run }
Task.run
```

This change turns the second call to `Task.run` into a noop
that returns nil instead.

Fix #6865
2026-05-27 23:10:09 -03:00
Yukihiro "Matz" Matsumoto d1608ba72e mruby.h: add MRB_API to mrb_const_cache_clear
The function is the symmetric counterpart of mrb_method_cache_clear
declared two lines above, but was added without MRB_API in
50bc8c6136. Both are VM-internal cache invalidators exposed in the
public header under the same #ifndef MRB_NO_*_CACHE pattern; make
their decoration consistent.

Reported by dearblue in #6826.

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-14 13:23:05 +09:00
Yukihiro "Matz" Matsumoto 6d2d31ac5f mruby.h: use MRB_INLINE for mrb_funcall_argv1 / mrb_funcall_argv2
These public convenience wrappers were declared with raw
`static inline`, while every other public inline helper in mruby.h
uses MRB_INLINE. MRB_INLINE expands to static inline, so this is a
spelling-only change for grep-consistency across the C API.

Reported by dearblue in #6827.

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-14 13:12:26 +09:00
Yukihiro "Matz" Matsumoto 575609f3b9 mruby.h: add mrb_funcall_argv1/argv2 inline helpers
mrb_funcall_id() always reserves a 16-element argv buffer on its
stack frame regardless of the actual argument count. The two new
static inline wrappers allocate exactly one or two argument slots,
saving 100-220 bytes of stack per call after inlining (the savings
depend on mrb_value size under the active boxing configuration).

close #5804

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-10 01:30:29 +09:00
Yukihiro "Matz" Matsumoto afc0753c1d symbol.c: add dynamic symbol limit (MRB_SYMBOL_MAX)
track dynamic (runtime-created) symbols separately from presyms,
inline symbols, and static C API symbols. raise RuntimeError when
the dynamic symbol count exceeds MRB_SYMBOL_MAX (default 4096).

this prevents DoS attacks via unbounded symbol creation (e.g.
"str".to_sym in a loop). presyms and inline symbols are not
counted toward the limit.

infrastructure for future symbol GC: sym_flags array tracks
per-symbol metadata (SYM_FL_DYNAMIC flag).

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 19:25:26 +09:00
Yukihiro "Matz" Matsumoto 50bc8c6136 vm.c: replace constant cache generation counter with direct invalidation
Remove the per-entry generation field and per-state generation
counter. Invalidation now clears entries directly, removing one
comparison from every OP_GETCONST hot path.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 19:25:21 +09:00
Yukihiro "Matz" Matsumoto 7675601b92 vm.c: add constant lookup cache with generation counter
Cache OP_GETCONST results in a global direct-mapped cache (64 entries)
keyed by (irep, sym). Invalidate all entries via a generation counter
bumped on mrb_const_set(), mrb_const_remove(), and
mrb_define_const_id(). ~10% faster on constant-heavy code; disabled
with MRB_NO_CONST_CACHE.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-23 19:25:20 +09:00
dearblue 0d00743a5f Define the typedef for mrb_state earlier
This improves consistency with other definitions.
2026-04-19 21:17:18 +09:00
Yukihiro "Matz" Matsumoto 8956c5abb5 mruby.h: include mruby/presym.h for all source files
Since presym is now mandatory, mruby.h includes presym.h so that
MRB_SYM() macros are available everywhere without explicit include.
Remove redundant #include <mruby/presym.h> from all source files.

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 16:50:58 +09:00
Yukihiro "Matz" Matsumoto 8d10056aff variable.c: add object shapes for MRB_TT_OBJECT IV storage
Introduce "object shapes" (hidden classes) that share IV key
layouts across objects with the same instance variable assignment
order. This eliminates per-object key storage overhead.

Memory savings: ~22% heap reduction for object-heavy workloads
(e.g., 150k objects with 2-6 IVs). Per-object: 40->24 bytes
for 2 IVs. Objects exceeding 16 IVs or using
remove_instance_variable fall back to traditional iv_tbl.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-27 08:29:46 +09:00
Yukihiro "Matz" Matsumoto 71cb3c2e3a class.c: allocate ROM table wrappers per mrb_state
ROM method tables used static mrb_mt_tbl variables shared
across the process. The next pointer in each wrapper was
mutated by mrb_mt_init_rom(), causing cross-state
contamination when multiple mrb_state instances existed.

Allocate mrb_mt_tbl wrappers per-state via mrb_malloc().
The const mrb_mt_entry[] arrays remain static and shared.
Wrappers are tracked in mrb->rom_mt and freed at mrb_close().

Remove MRB_MT_ROM_TAB macro; add MRB_MT_INIT_ROM macro that
auto-computes size and calls the new mrb_mt_init_rom().

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 22:24:31 +09:00
Yukihiro "Matz" Matsumoto ce8ce3f96d class.c: separate flags from symbol key in mrb_mt_entry
Add a dedicated uint32_t flags field to mrb_mt_entry instead of
packing flags into the lower bits of mrb_sym via MRB_MT_KEY().
The key field now stores the pure symbol ID with no shift.

On 64-bit, the flags field fills the alignment gap after mrb_sym,
so entry size remains 16 bytes (zero overhead). On 32-bit, entry
size grows from 8 to 12 bytes.

This eliminates the risk of symbol ID overflow from the 4-bit
shift, and the flags field can later store aspec (MRB_ARGS_*)
information that was previously discarded.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 07:57:02 +09:00
Yukihiro "Matz" Matsumoto b07518e85c parse.y: implement &nil in formal parameters
`&nil` is recently introduced in CRuby to explicitly declare that
a method does not accept a block. When a block is passed,
ArgumentError "no block accepted" is raised. This is analogous to
`**nil` for keyword arguments.

The noblock flag is encoded in bit 23 of OP_ENTER's aspec operand
(24=n1:m5:o5:r1:m5:k5:d1:b1), avoiding the need for a new opcode.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 16:54:17 +09:00
Yukihiro "Matz" Matsumoto e05bd8f806 symbol.c: use chunk-based pool for symbol string allocation
Replace per-symbol mrb_malloc() with a chunk-based string pool that
batches allocations into 4KB chunks. This reduces malloc call count
by ~12x (e.g. 909 vs 10,887 for 10k dynamic symbols) and eliminates
per-allocation malloc metadata overhead (~16 bytes/symbol).

Pool allocations are rounded up to even size to preserve LSB pointer
tagging used for literal detection.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:25 +09:00
dearblue 3ac682b2de Add the MRB_ENSURE() macro 2026-01-24 11:31:32 +09:00
HASUMI Hitoshi 0a21eef938 Fix mruby-task for PicoRuby Integration
With this PR, I can remove the original task.c in picoruby/picoruby and future development will be much easier.

## Add

### General

- C API functions exported with MRB_API for external integration:
  - mrb_execute_proc_synchronously() for synchronous proc execution
  - Task control APIs (mrb_create_task, mrb_suspend_task, mrb_resume_task, mrb_terminate_task, mrb_stop_task, mrb_task_value, mrb_task_status)
  - Task context management APIs for picoruby-sandbox (mrb_task_init_context, mrb_task_reset_context, mrb_task_proc_set)
  - Task.tick class method to get current tick count
- Comprehensive C API documentation with WASM integration examples

### For PicoRuby.wasm

- WASM/Emscripten support: Disable SIGALRM timer when __EMSCRIPTEN__ is defined, as JavaScript handles tick calls via setInterval
- Scheduler lock mechanism to prevent asynchronous task operations during synchronous execution (scheduler_lock counter in mrb_task_state)
- mrb_task_run_once() for single-step execution (event loop integration)

## Fix

### task.c
- Replace MRB_FIBER_TERMINATED with MRB_TASK_STOPPED just for clarity
- Allow suspending DORMANT and WAITING tasks in mrb_task_suspend (See comment in the source)
- Task context initialization by removing dummy callinfo push/pop

*NOTE*

With the dummy callinfo code that I deleted, IRB in PicoRuby ended SEGV.
If that code is mandatory, we need to discuss how to solve my problem.

### vm.c
- Handle MRB_TASK_CREATED status in VM's NORMAL_RETURN phase to properly stop tasks

----

These changes are necessary to make PicoRuby work.
Nevertheless, even with this patch, MicroRuby for Raspberry Pi Pico 2 is still unstable.
I would like to merge this PR anyway to make development easier by involving the PicoRuby community.
2026-01-11 17:07:04 +09:00
Yukihiro "Matz" Matsumoto 7fe5c2e260 gc.c: rename mrb_alloca() to mrb_temp_alloc() and fix memory leaks
rename mrb_alloca() to mrb_temp_alloc() for clearer naming - the new name
better describes its purpose as GC-managed temporary allocation. keep
mrb_alloca() as a macro alias for backward compatibility.

apply mrb_temp_alloc() to fix potential memory leaks in:
- mruby-strftime: if mrb_str_cat() raises, allocated buffers now cleaned by GC
- mruby-io File.readlink: if mrb_str_new() raises, buffer now cleaned by GC

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-08 08:23:51 +09:00
Yukihiro "Matz" Matsumoto 98c33acc75 mruby.h: fix build with MRB_NO_METHOD_CACHE
mrb_method_cache_clear() was called unconditionally from class.c and
state.c, but the function definition was guarded by MRB_NO_METHOD_CACHE.
This caused linker errors when building with MRB_NO_METHOD_CACHE defined.

Add empty macro definition when MRB_NO_METHOD_CACHE is defined, matching
the existing pattern used for mrb_mc_clear_by_class().

Co-authored-by: Claude <noreply@anthropic.com>
2025-12-22 13:55:42 +09:00
Yukihiro "Matz" Matsumoto 40b0cb98f7 mruby.h: add MRB_OPEN_FAILURE() macro and refactor MRB_OPEN_SUCCESS()
since all current uses check for failure (!MRB_OPEN_SUCCESS), add
MRB_OPEN_FAILURE() as the primary macro for better readability. define
MRB_OPEN_SUCCESS() in terms of MRB_OPEN_FAILURE() to avoid duplication
and optimize the common case. update all usage sites to use the clearer
MRB_OPEN_FAILURE() form.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-16 06:53:02 +09:00
Yukihiro "Matz" Matsumoto 05ffe0c441 mrb_open: return mrb_state with exc set on init failure
changed mrb_open() and mrb_open_core() to return mrb_state with mrb->exc
set (instead of NULL) when initialization fails. this allows callers to
programmatically inspect error details, which is essential for embedded
systems without stderr. return NULL only for true allocation failure.

added MRB_OPEN_SUCCESS(mrb) macro to check initialization success, since
mrb != NULL no longer guarantees success. updated all binary tools
(mruby, mirb, mrdb, mrbtest) to use new pattern: check MRB_OPEN_SUCCESS,
print exception details via mrb_print_error if available, then mrb_close.

mrb_core_init_protect now preserves exception in mrb->exc instead of
printing and clearing it, giving caller control over error handling.

breaking change: callers must use MRB_OPEN_SUCCESS(mrb) or check both
mrb != NULL && mrb->exc == NULL. old NULL-only checks will miss
initialization failures.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-13 19:10:46 +09:00
Yukihiro "Matz" Matsumoto f4fb41b528 kernel.c: regression on struct/array/hash == override with super; fix #6660
when overriding struct#==, array#==, or hash#== with super, the recursion
detection incorrectly treated the super call as a circular reference. this
was caused by commit 5ca2d442 which added recursion detection.

the fix introduces mrb_recursive_func_p that starts from ci[-2] instead of
ci[-1], skipping the immediate parent frame which may be a ruby override
calling super. equality methods (==, eql?) now use this function, while
inspect methods keep using mrb_recursive_method_p for immediate circular
reference detection.

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-12 10:25:37 +09:00
Yukihiro "Matz" Matsumoto 4499daf88e mruby.h: simplify task state definitions using fiber state aliases
remove MRB_TASK_CREATED and MRB_TASK_STOPPED from mrb_fiber_state enum
and define them as aliases to MRB_FIBER_CREATED and MRB_FIBER_TERMINATED.

this makes the relationship between tasks and fibers clearer and avoids
artificially extending the enum with semantically equivalent values.

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-11 10:47:40 +09:00
Yukihiro "Matz" Matsumoto 745e577b0e mruby-task: treat root context as main task
Implement main task wrapper following Fiber's pattern, where root context
is represented by a special task object. This matches PicoRuby behavior
where Task.current always returns a task object, even from root context.

The main task is lazy-allocated on first Task.current call from root,
stored in mrb->task.main_task, and has name "main", status RUNNING,
priority 0. It wraps the root context without allocating a separate
execution context.

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-09 16:22:25 +09:00
Yukihiro "Matz" Matsumoto a0655615c9 mruby-task: rename mrb_tcb to mrb_task for clarity
replace confusing "tcb" (task control block) terminology with clearer
"mrb_task" naming:
- struct mrb_tcb -> struct mrb_task
- update mrb_task_state to use mrb_task pointers
- rename internal functions to avoid naming conflicts:
  - mrb_task_new -> task_alloc
  - mrb_task_free (lifecycle) -> task_free
- update field names for clarity:
  - tcb_join -> join
  - task (ruby object) -> self
  - value (return value) -> result

this makes the code more readable and follows mruby naming conventions
like mrb_context, mrb_irep, etc.

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-08 23:55:20 +09:00
Yukihiro "Matz" Matsumoto dda60ca719 mruby-task: add core data structures to mrb_state
extend mrb_fiber_state enum with task-specific states:
- MRB_TASK_CREATED: task context initialized
- MRB_TASK_STOPPED: task execution finished

add mrb_task_state structure to mrb_state:
- task queues array (dormant, ready, waiting, suspended)
- tick counter for scheduling
- wakeup_tick for sleep timing
- switching flag for context switches

remove duplicate mrb_task_state definition from task.h since it is
now defined in include/mruby.h. all changes guarded by
MRB_USE_TASK_SCHEDULER for zero overhead when disabled.

Co-authored-by: Claude <noreply@anthropic.com>
2025-10-08 23:55:20 +09:00
Yukihiro "Matz" Matsumoto a217935e7d symbol.c: implement adaptive symbol table for memory efficiency
Replace fixed 256-element hash array in mrb_state with adaptive approach:
- Linear search for <=255 symbols (typical embedded use case)
- Hash table allocated on-demand when symbols exceed threshold
- Reduces mrb_state size by 1KB per instance (1068->36 bytes in symbol fields)
- Configurable threshold via MRB_SYMBOL_LINEAR_THRESHOLD in mrbconf.h

Co-authored-by: Claude <noreply@anthropic.com>
2025-08-14 10:53:08 +09:00
Yukihiro "Matz" Matsumoto 07b803e28a docs: replace xml-style markup with markdown in comments
Replace XML-style markup tags in comments with markdown equivalents:
- <code>...</code> to `...` (inline code)
- <tt>...</tt> to `...` (teletype/monospace)
- <i>...</i> to *...* (italics/emphasis)
- +...+ to `...` (parameter/variable references)

Updated 80+ files across core source, headers, mrbgems, and libraries
to use consistent markdown formatting in documentation comments.
Handled edge cases including special characters like <=> operators.

Co-authored-by: Atlassian Rovo Dev
2025-08-14 10:52:49 +09:00
Yukihiro "Matz" Matsumoto 95656c40ff state.c: optimize mrb_state initialization by deferring method cache clear
During mrb_state initialization, especially when defining core classes and methods,
the method cache is repeatedly cleared. This causes significant overhead in
scenarios like mrbtest where mrb_state is initialized multiple times.

This commit introduces a `bootstrapping` flag in `struct mrb_state`.
When this flag is TRUE (during mrb_open_core), method cache clears
triggered by `mrb_define_method_raw` and `include_module_at` are suppressed.
The cache is cleared only once at the very end of `mrb_open_core` after
all core methods are defined, and the flag is then set to FALSE.

This optimization significantly reduces the number of method cache clears
during initialization, improving performance for repeated mrb_state creations.

Co-authored-by: Gemini <gemini@google.com>
2025-07-11 10:09:38 +09:00
Yukihiro "Matz" Matsumoto 419c8ebfb2 hash.c: add recursion detection to prevent SystemStackError; fix #5531
Add generalized recursion detection system and integrate it into Hash#==
and Hash#eql? to prevent infinite recursion with mutually recursive hash
structures. Uses call stack inspection for minimal memory overhead.

Co-authored-by: Claude <noreply@anthropic.com>
2025-07-11 10:09:36 +09:00
John Bampton 383cd6a936 misc: fix spelling word case 2025-06-25 10:46:23 +10:00
Yukihiro "Matz" Matsumoto 5522c94bb3 mruby.h: remove mrb_allocf type
As a result, we removed (already obsoleted) `mrb_open_allocf()', and
made `mrb_open_core()` take no argument. [incompatible changes]
2025-05-10 08:59:18 +09:00
Yukihiro "Matz" Matsumoto 5c71681d82 allocf.c (mrb_basic_alloc_func): remove ud argument 2025-05-10 08:59:18 +09:00
Yukihiro "Matz" Matsumoto c3cc559dfc allocf.c: rename mrb_default_alloc to mrb_basic_alloc_func
Along with removing mrb_state first argument from the function. From
mruby 3.2, this function is *not* the default function, but the entry
point that can be redefined for the application. The function in
`src/allocf.c` is the default *implementation* (using malloc / realloc /
free) of the function.
2025-05-09 21:50:18 +09:00
Yukihiro "Matz" Matsumoto 0bdd529430 mruby.h: remove allocf and allocf_ud from mrb_state
This is preparation for memory allocation restructuring.
2025-05-09 18:13:28 +09:00
dearblue 3fd5e1c250 Fixed visibility at method definition
There was a problem with visibility state from proc that straddles a fiber or is independent.

Therefore, it has been changed to give priority to env objects, if any.
Also, added "separate module" flag to block traversal to a higher level env object.

Note that the "separate module" flag is now set when calling blocks with the `mrb_yield_with_class()` function.

fixed https://github.com/mruby/mruby/issues/6494
2025-04-11 21:36:26 +09:00
Yukihiro "Matz" Matsumoto 889f09f8b7 class.c: move visibility flags from classes/modules to callinfo 2025-03-07 17:17:50 +09:00
Yukihiro "Matz" Matsumoto ca20017ac9 class.c: implement mrb_define_private_method() 2025-03-07 17:17:36 +09:00
dearblue a981f5aed7 Add more const qualifier for RProc 2025-01-20 22:25:50 +09:00
Yukihiro "Matz" Matsumoto d13e6ff8c9 include/presym.h: MRB_GVSYM() for global variables is now available 2024-12-14 16:03:35 +09:00
Yukihiro "Matz" Matsumoto 49525fa207 mempool.c: renamed from pool.c
To avoid confusion with pools in irep, we renamed region-based memory
manager from pool to mempool.

- rename pool.c to mempool.c
- separate mempool.h
- rename all mrb_pool to mrb_mempool

So if someone is using pool.c functions (I suppose no one does though),
they need to rename all `mrb_pool` to `mrb_mempool` and include
`mruby/mempool.h` header at the top.
2024-10-31 14:06:10 +09:00
Yukihiro "Matz" Matsumoto d6fa7772a0 mruby.h (mrb_method_t): avoid unnamed union
It caused errors in the pedantic-mode of GCC.
2024-09-26 00:07:03 +09:00
dearblue ad576f1e75 Revert "Delegate the care of a directly given block from cipop() to cipush()"
This reverts commit ad2e626e7a.

Because of the changes made by #6282, the following code caused a problem.

```ruby
b = proc { break "BAD!" }
p self.tap { b.call }
# (expected)    => break from proc-closure (LocalJumpError)
# (after #6282) => "BAD!"
```

I revived the `mrb_callinfo::blk` field to fix this, but it did not overcome the following problem.

```ruby
def m(&b); b = b.clone; GC.start; b.call; end
p m { break "OK!" }
# (expected)    => "OK!"
# (revived blk) => break from proc-closure (LocalJumpError)
```
2024-06-30 21:01:45 +09:00
dearblue ad2e626e7a Delegate the care of a directly given block from cipop() to cipush()
Outlines:
  - Removed `mrb_callinfo::blk`
  - Added `mrb_callinfo::flags`
  - Added `MRB_CI_COMPANION_BLOCK` flag
2024-05-31 22:03:15 +09:00
dearblue a0526418ce Update documentation for mrb_top_run()
Also, add explanations for the `mrb_load_irep()` and `mrb_load_string()` families, which are indirect calls to `mrb_top_run()`.
2024-04-26 22:05:45 +09:00
dearblue 328eb71e52 Reorganize mrb_cache_entry and mrb_method_t types
The purpose is to remove the `mid` field from the `mrb_cache_entry` structure.
The resulting RAM requirement for the method cache is reduced from 5 words per entry to 4 words per entry for 32-bit CPUs.

The relevant changes are as follows:

  - Removed `MRB_USE_METHOD_T_STRUCT`.

    The `mrb_method_t` type is now always defined as a structure.

  - Include method IDs in `mrb_method_t`

    Change the `flags` member to `uint32_t`.
    The bitstring structure should be the same as the keys of the `mt` table in `class.c`.

I believe the impact on API compatibility with previous versions is minimal.
2024-03-30 18:19:26 +09:00
Yukihiro "Matz" Matsumoto 87b358a342 Including header files in include/* by <> 2024-03-26 13:59:59 +09:00
Yukihiro "Matz" Matsumoto 96fa3461f0 mruby.h: move integer hash function from khash.h 2024-03-26 13:59:58 +09:00
Yukihiro "Matz" Matsumoto aa0cb370a8 kernel.c (mrb_obj_is_instance_of): add const qualifier 2024-03-04 13:01:20 +09:00
dearblue ce8b2d4973 Added mrb_callinfo::u.keep_context for clarity 2024-02-24 21:32:11 +09:00
Yukihiro "Matz" Matsumoto c3f8227c6d mruby.h: adjust comment offset [ci skip] 2024-02-15 14:01:48 +09:00