Files
mruby-mruby/doc/mruby3.md
T
Yukihiro "Matz" Matsumoto dccd66f9ef Support Ruby3.0 keyword arguments.
The Difference

Since Ruby1.9, the keyword arguments were emulated by Ruby using the hash
object at the bottom of the arguments. But we have gradually moved toward
keyword arguments separated from normal (positinal) arguments.

At the same time, we value compatibility, so that Ruby3.0 keyword
arguments are somewhat compromise. Basically, keyword arguments are
separated from positional arguments, except when the method does not
take any formal keyword arguments, given keyword arguments (packed
in the hash object) are considered as the last argument.

And we also allow non symbol keys in the keyword arguments. In that
case, those keys are just passed in the `**` hash (or raise
`ArgumentError` for unknown keys).

The Instruction Changes

We have changed `OP_SEND` instruction. `OP_SEND` instruction used to
take 3 operands, the register, the symbol, the number of (positional)
arguments. The meaning of the third operand has been changed. It is now
considered as `n|(nk<<4)`, where `n` is the number of positional
arguments, and `nk` is the number of keyword arguments, both occupies
4 bits in the operand.

The number `15` in both `n` and `nk` means variable sized arguments are
packed in the object. Positional arguments will be packed in the array,
and keyword arguments will be packed in the hash object. That means
arguments more than 14 values are always packed in the object.

Arguments information for other instructions (`OP_SENDB` and `OP_SUPER`)
are also changed. It works as the third operand of `OP_SEND`. the
difference between `OP_SEND` and `OP_SENDB` is just trivial. It assigns
`nil` to the block hidden arguments (right after arguments).

The instruction `OP_SENDV` and `OP_SENDVB` are removed. Those
instructions are replaced by `OP_SEND` and `OP_SENDB` respectively with
the `15` (variable sized) argument information.

Calling Convention

When calling a method, the stack elements shall be in the order of the
receiver of the method, positional arguments, keyword arguments and the
block argument. If the number of positional or keyword arugument (`n` or
`nk`) is zero, corresponding arguments will be empty. So when `n=0` and
`nk=0` the stack layout (from bottom to top) will be:

+-----------------------+
| recv | block (or nil) |
+-----------------------+

The last elements `block` should be explicitly filled before `OP_SEND`
or assigned to `nil` by `OP_SENDB` internally. In other words, the
following have exactly same behavior:

OP_SENDB clears `block` implicitly:

```
OP_SENDB reg sym 0
```

OP_SEND clears `block` implicitly:

```
OP_LOADNIL  R2
OP_SEND     R2 sym 0
```

When calling a method with only positional arguments (n=0..14) without
keyword arguments, the stack layout will be like following:

+--------------------------------------------+
| recv | arg1 | ... | arg_n | block (or nil) |
+--------------------------------------------+

When calling a method with arguments packed in the array (n=15) which
means argument splat (*) is used in the actual arguments, or more than
14 arguments are passed the stack layout will be like following:

+-------------------------------+
| recv | array | block (or nil) |
+-------------------------------+

The number of the actual arguments is determined by the length of the
argument array.

When keyword arguments are given (nk>0), keyword arguments are passed
between positional arguments and the block argument. For example, when
we pass one positional argument `1` and one keyword argument `a: 2`,
the stack layout will be like:

+------------------------------------+
| recv | 1 | :a | 2 | block (or nil) |
+------------------------------------+

Note that keyword arguments consume `2*nk` elements in the stack when
`nk=0..14` (unpacked).

When calling a method with keyword arguments packed in the hash object
(nk=15) which means keyword argument splat (**) is used or more than
14 keyword arguments in the actual arguments, the stack layout will
be like:

+------------------------------+
| recv | hash | block (or nil) |
+------------------------------+

Note for mruby/c

When mruby/c authors try to support new keyword arguments, they need
to handle the new meaning of the argument information operand. If they
choose not to support keyword arguments in mruby/c, it just raise
error when `nk` (taken by `(c>>4)&0xf`) is not zero. And combine
`OP_SENDV` behavior with `OP_SEND` when `n` is `15`.

If they want to support keyword arguments seriously, contact me at
<matz@ruby.or.jp> or `@yukihiro_matz`. I can help you.
2021-10-12 20:16:36 +09:00

4.6 KiB

User visible changes in mruby3

Build System

build_config directory

Typical build configuration files are located in build_config directory. For examples:

  • default: the default configuration
  • host-gprof: compiles with gprof for performance tuning
  • host-m32: compiles in gcc 32bit mode on 64bit platforms
  • boxing: compiles all three boxing options
  • clang-asan: compiles with clang's Address Sanitizer

You can specify the build configuration file with the MRUBY_CONFIG environment variable (or CONFIG in short). If the value specified by MRUBY_CONFIG is not the path to the configuration file, build_config/${MRUBY_CONFIG}.rb is used. So you can specify it as rake MRUBY_CONFIG=boxing, for example.

Build Configuration Contribution

When you write a new build configuration description, please contribute. We welcome your contribution as a GitHub pull-request.

Language Changes

New Syntax

We have ported some new syntax from CRuby.

  • Single line pattern matching (12 => x); mruby matches only with local variables at the moment
  • Numbered block parameter (x.map{_1 * 2})
  • End-less def (def double(x) = x*2)

Configuration Options Changed

Renamed for consistency

Some configuration macro names are changed for consistency (use MRB_USE_XXX or MRB_NO_XXX).

mruby2 mruby3
MRB_ENABLE_ALL_SYMBOLS MRB_USE_ALL_SYMBOLS
MRB_ENABLE_CXX_ABI MRB_USE_CXX_ABI
MRB_ENABLE_CXX_EXCEPTION MRB_USE_CXX_EXCEPTION
MRB_ENABLE_DEBUG_HOOK MRB_USE_DEBUG_HOOK
MRB_DISABLE_DIRECT_THREADING MRB_NO_DIRECT_THREADING
MRB_DISABLE_STDIO MRB_NO_STDIO
MRB_METHOD_T_STRUCT MRB_USE_METHOD_T_STRUCT
MRB_USE_FLOAT MRB_USE_FLOAT32
MRB_WITHOUT_FLOAT MRB_NO_FLOAT
ENABLE_LINENOISE MRB_USE_LINENOISE
ENABLE_READLINE MRB_USE_READLINE
DISABLE_MIRB_UNDERSCORE MRB_NO_MIRB_UNDERSCORE
  • MRB_USE_FLOAT32 is changed from MRB_USE_FLOAT to make sure float here means using single precision float, and not the opposite of MRB_NO_FLOAT.
  • MRB_USE_METHOD_T_STRUCT uses struct version of mrb_method_t. More portable but consumes more memory. Turned on by default on 32bit platforms.
  • MRB_ prefix is added to those without.

MRB_NO_BOXING

Uses struct to represent mrb_value. Consumes more memory but easier to investigate the internal and to debug. It used to be default mrb_value representation. Now the default is MRB_WORD_BOXING.

MRB_WORD_BOXING

Pack mrb_value in an intptr_t integer. Consumes less memory compared to MRB_NO_BOXING especially on 32-bit platforms. Inlined integer size is 31 bits, so some mrb_int values does not fit in mrb_value. Those integers are allocated in the object heap as struct RInteger.

MRB_NAN_BOXING

Pack mrb_value in a floating-point number. Nothing changed from previous versions.

MRB_USE_MALLOC_TRIM

Call malloc_trim(0) from mrb_full_gc() if this macro is defined. If you are using glibc malloc, this macro could reduce memory consumption.

Command Line Program

bin/mruby (by mrbgems/mruby-bin-mruby)

The mruby3 now automatically detects *.mrb files without the -b switch. Therefore, it can be mixed with the *.rb file in combination with the -r switch and specified at the same time. Here's an example that works fine:

$ bin/mruby app.mrb
$ bin/mruby -r lib1.mrb -r lib2.rb app.rb
$ bin/mruby -r lib1.rb -r lib2.rb < app.mrb

Internal Changes

New Instructions

mruby3 introduces a few new instructions.

Instructions that load a 16/32-bit integer.

  • OP_LOADI16
  • OP_LOADI32

Instruction that unwinds jump table for rescue/ensure.

  • OP_JMPUW

Renamed from OP_RAISE

  • OP_RAISEIF

Removed Instructions

Instructions for old exception handling

  • OP_ONERR
  • OP_POPERR
  • OP_EPUSH
  • OP_EPOP

No more operand extension

  • OP_EXT1
  • OP_EXT2
  • OP_EXT3

Changed Instructions

Jump addresses used to be specified by absolute offset from the start of iseq. Now they are relative offset from the address of the next instruction.

Random now use xoshiro128++

For better and faster random number generation.

Preallocated Symbol

Preallocated symbols are interned at compile-time. They can be accessed via symbols macros (e.g. MRB_SYM()).

See Symbols.