mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7ac96912e9 |
@@ -5,29 +5,11 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
bundler-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
github-actions-dependencies:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
- package-ecosystem: "pre-commit"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
pre-commit-hooks:
|
||||
patterns:
|
||||
- "*"
|
||||
cooldown:
|
||||
default-days: 7
|
||||
|
||||
@@ -31,9 +31,7 @@ jobs:
|
||||
LD: ${{ matrix.cc }}
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Ruby version
|
||||
run: ruby -v
|
||||
- name: Compiler version
|
||||
@@ -46,13 +44,11 @@ jobs:
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Ruby version
|
||||
run: ruby -v
|
||||
- name: Cache cosmocc
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
uses: actions/cache@v5
|
||||
id: cache-cosmocc
|
||||
with:
|
||||
path: ~/cosmo
|
||||
@@ -74,9 +70,7 @@ jobs:
|
||||
MRUBY_CONFIG: ci/msvc
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Ruby version
|
||||
run: ruby -v
|
||||
- name: Build and test
|
||||
|
||||
@@ -18,16 +18,14 @@ jobs:
|
||||
language: ["actions"]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa # v4.36.0
|
||||
uses: github/codeql-action/analyze@v4
|
||||
with:
|
||||
category: "Security"
|
||||
|
||||
@@ -2,9 +2,6 @@ name: Coverage
|
||||
|
||||
on: [push]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
coverage:
|
||||
name: Coverage
|
||||
@@ -19,9 +16,7 @@ jobs:
|
||||
LDFLAGS: --coverage
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Ruby version
|
||||
run: ruby -v
|
||||
- name: Compiler version
|
||||
@@ -39,7 +34,7 @@ jobs:
|
||||
echo \`\`\`
|
||||
} > "$GITHUB_STEP_SUMMARY"
|
||||
- name: Upload coverage report
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: coverage-${{ github.sha }}
|
||||
path: coverage/
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
pull-requests: write
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
|
||||
- uses: actions/labeler@v6
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
sync-labels: true
|
||||
|
||||
@@ -11,9 +11,7 @@ jobs:
|
||||
name: Run ls-lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: ls-lint/action@02e380fe8733d499cbfc9e22276de5085508a5bd # v2.3.1
|
||||
- uses: actions/checkout@v6
|
||||
- uses: ls-lint/action@v2.3.1
|
||||
with:
|
||||
config: .github/linters/.ls-lint.yml
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@v7
|
||||
if: failure()
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
# https://github.com/j178/prek
|
||||
name: Manual hooks
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
pre-commit:
|
||||
name: Run pre-commit
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4
|
||||
with:
|
||||
install-only: true
|
||||
- name: Run manual pre-commit hooks
|
||||
run: prek run --color=always --all-files --hook-stage manual
|
||||
@@ -12,9 +12,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: j178/prek-action@bdca6f102f98e2b4c7029491a53dfd366469e33d # v2.0.4
|
||||
uses: actions/checkout@v6
|
||||
- uses: j178/prek-action@v1
|
||||
with:
|
||||
extra-args: --all-files
|
||||
- name: Run manual pre-commit hooks
|
||||
run: prek run --color=always --all-files --hook-stage manual
|
||||
|
||||
@@ -19,9 +19,7 @@ jobs:
|
||||
fail-fast: false
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref_name }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
uses: actions/checkout@v6
|
||||
- name: Builds
|
||||
id: builds
|
||||
run: |
|
||||
@@ -40,7 +38,7 @@ jobs:
|
||||
mv .sha256 "$packagename.sha256"
|
||||
)
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
draft: true
|
||||
prerelease: ${{ contains(github.ref_name, '-rc') }}
|
||||
|
||||
@@ -15,13 +15,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )"
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter/slim@9e863354e3ff62e0727d37183162c4a88873df41 # v8.6.0
|
||||
uses: super-linter/super-linter/slim@v8.5.0
|
||||
env:
|
||||
# VALIDATE_BASH_EXEC: true
|
||||
VALIDATE_DOCKERFILE_HADOLINT: true
|
||||
|
||||
+9
-22
@@ -3,7 +3,7 @@
|
||||
default_stages: [pre-commit, pre-push]
|
||||
default_language_version:
|
||||
python: python3
|
||||
node: 24.14.0
|
||||
node: 24.11.1
|
||||
minimum_pre_commit_version: "3.2.0"
|
||||
exclude: "^tools/lrama/"
|
||||
repos:
|
||||
@@ -15,9 +15,6 @@ repos:
|
||||
- id: check-hooks-apply
|
||||
name: run check-hooks-apply
|
||||
description: check hooks apply to the repository
|
||||
- id: check-useless-excludes
|
||||
name: run check-useless-excludes
|
||||
description: clean up unnecessary exclusion patterns
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: prettier
|
||||
@@ -27,16 +24,6 @@ repos:
|
||||
files: \.(md|ya?ml)$
|
||||
language: node
|
||||
additional_dependencies: ["prettier@3.7.4"]
|
||||
pass_filenames: false
|
||||
stages: [manual]
|
||||
- id: check-makefile-indentation
|
||||
name: check Makefiles are indented with tabs
|
||||
description: ensures that Makefiles are indented with tabs
|
||||
entry: ./scripts/check_makefiles_for_tabs.sh
|
||||
language: system
|
||||
files: "(?i)^makefile$"
|
||||
pass_filenames: true # <-- Crucial change: pass filenames to the script
|
||||
types: [file] # Ensure only regular files are passed, not directories
|
||||
stages: [manual]
|
||||
- id: check-zip-file-is-not-committed
|
||||
name: disallow zip files
|
||||
@@ -47,13 +34,13 @@ repos:
|
||||
track and have security implications. Please remove the zip file from the repository.
|
||||
files: \.zip$
|
||||
- repo: https://github.com/gitleaks/gitleaks
|
||||
rev: v8.30.1
|
||||
rev: v8.30.0
|
||||
hooks:
|
||||
- id: gitleaks
|
||||
name: run gitleaks
|
||||
description: detect hardcoded secrets with gitleaks
|
||||
- repo: https://github.com/oxipng/oxipng
|
||||
rev: v10.1.1
|
||||
rev: v10.0.0
|
||||
hooks:
|
||||
- id: oxipng
|
||||
name: run oxipng
|
||||
@@ -85,7 +72,7 @@ repos:
|
||||
- id: mixed-line-ending
|
||||
- id: trailing-whitespace
|
||||
- repo: https://github.com/Lucas-C/pre-commit-hooks
|
||||
rev: v1.5.6
|
||||
rev: v1.5.5
|
||||
hooks:
|
||||
- id: forbid-tabs
|
||||
name: run no-tabs checker
|
||||
@@ -97,19 +84,19 @@ repos:
|
||||
args: [--whitespaces-count, "2"]
|
||||
exclude: Makefile$
|
||||
- repo: https://github.com/rhysd/actionlint
|
||||
rev: v1.7.12
|
||||
rev: v1.7.9
|
||||
hooks:
|
||||
- id: actionlint
|
||||
name: run actionlint
|
||||
description: lint GitHub Actions workflow files
|
||||
- repo: https://github.com/codespell-project/codespell
|
||||
rev: v2.4.2
|
||||
rev: v2.4.1
|
||||
hooks:
|
||||
- id: codespell
|
||||
name: run codespell
|
||||
description: check spelling with codespell
|
||||
- repo: https://github.com/igorshubovych/markdownlint-cli
|
||||
rev: v0.48.0
|
||||
rev: v0.46.0
|
||||
hooks:
|
||||
- id: markdownlint
|
||||
name: run markdownlint
|
||||
@@ -118,7 +105,7 @@ repos:
|
||||
types: [markdown]
|
||||
files: \.md$
|
||||
- repo: https://github.com/rubocop/rubocop
|
||||
rev: v1.86.2
|
||||
rev: v1.81.7
|
||||
hooks:
|
||||
- id: rubocop
|
||||
name: run rubocop
|
||||
@@ -132,7 +119,7 @@ repos:
|
||||
name: run shellcheck
|
||||
description: check shell scripts with a static analysis tool
|
||||
- repo: https://github.com/adrienverge/yamllint
|
||||
rev: v1.38.0
|
||||
rev: v1.37.1
|
||||
hooks:
|
||||
- id: yamllint
|
||||
name: run yamllint
|
||||
|
||||
@@ -3,4 +3,3 @@ build
|
||||
coverage
|
||||
doc/internal/opcode.md
|
||||
tools/lrama
|
||||
.venv
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
# Authors of mruby (mruby developers)
|
||||
|
||||
## The List of Contributors sorted by number of commits (as of 2026-05-31 9d084b0)
|
||||
## The List of Contributors sorted by number of commits (as of 2026-03-02 02877f0)
|
||||
|
||||
7747 Yukihiro "Matz" Matsumoto (@matz)*
|
||||
749 dearblue (@dearblue)*
|
||||
7532 Yukihiro "Matz" Matsumoto (@matz)*
|
||||
712 dearblue (@dearblue)*
|
||||
587 KOBAYASHI Shuji (@shuujii)
|
||||
353 Daniel Bovensiepen (@bovi)*
|
||||
345 Takeshi Watanabe (@take-cheeze)*
|
||||
333 Masaki Muranaka (@monaka)
|
||||
266 John Bampton (@jbampton)
|
||||
255 John Bampton (@jbampton)
|
||||
234 Jun Hiroe (@suzukaze)
|
||||
228 Tomoyuki Sahara (@tsahara)*
|
||||
220 Cremno (@cremno)*
|
||||
209 Yuki Kurihara (@ksss)+
|
||||
146 Yasuhiro Matsumoto (@mattn)*
|
||||
144 Yasuhiro Matsumoto (@mattn)*
|
||||
113 Carson McDonald (@carsonmcdonald)
|
||||
104 Tomasz Pędraszewski (@dabroz)*
|
||||
83 Akira Yumiyama (@akiray03)*
|
||||
83 skandhas (@skandhas)
|
||||
80 Masamitsu MURASE (@masamitsu-murase)
|
||||
79 Hiroshi Mimaki (@mimaki)*
|
||||
73 Hiroshi Mimaki (@mimaki)*
|
||||
71 Tatsuhiko Kubo (@cubicdaiya)*
|
||||
71 Yuichiro MASUI (@masuidrive)
|
||||
62 Yuichiro Kaneko (@yui-knk)+
|
||||
@@ -36,10 +36,8 @@
|
||||
32 Masayoshi Takahashi (@takahashim)+
|
||||
31 MATSUMOTO Ryosuke (@matsumotory)*
|
||||
30 Nobuyoshi Nakada (@nobu)
|
||||
29 HASUMI Hitoshi (@hasumikin)
|
||||
26 Hoshiumi Arata (@hoshiumiarata)*
|
||||
25 Julian Aron Prenner (@furunkel)*
|
||||
23 leviongit (@leviongit)
|
||||
22 Clayton Smith (@clayton-shopify)
|
||||
22 Uchio Kondo (@udzura)*
|
||||
22 Zachary Scott (@zzak)*
|
||||
@@ -52,9 +50,10 @@
|
||||
18 Corey Powell (@IceDragon200)
|
||||
18 Hidetaka Takano (@TJ-Hidetaka-Takano)
|
||||
18 Jon Maken (@jonforums)+
|
||||
18 leviongit (@leviongit)
|
||||
18 mirichi (@mirichi)
|
||||
17 Mitchell Blank Jr (@mitchblank)*
|
||||
16 Hendrik (@Asmod4n)
|
||||
16 HASUMI Hitoshi (@hasumikin)
|
||||
16 bggd (@bggd)
|
||||
16 kano4 (@kano4)
|
||||
15 Felix Jones (@felixjones)*
|
||||
@@ -77,7 +76,7 @@
|
||||
11 RIZAL Reckordp (@Reckordp)+
|
||||
11 Seeker (@SeekingMeaning)
|
||||
11 takkaw (@takkaw)
|
||||
10 Chris Hasiński (@khasinski)
|
||||
10 Hendrik (@Asmod4n)
|
||||
10 Miura Hideki (@miura1729)
|
||||
10 Narihiro Nakamura (@authorNari)
|
||||
10 YAMAMOTO Masaya (pandax381)
|
||||
@@ -89,7 +88,6 @@
|
||||
8 Wataru Ashihara (@wataash)*
|
||||
7 Bhargava Shastry (@bshastry)*
|
||||
7 Kouichi Nakanishi (@keizo042)
|
||||
7 Paweł Świątkowski (@katafrakt)
|
||||
7 Rubyist (@expeditiousRubyist)
|
||||
7 Simon Génier (@simon-shopify)
|
||||
7 Terence Lee (@hone)
|
||||
@@ -103,6 +101,7 @@
|
||||
6 INOUE Yasuyuki (@yasuyuki)
|
||||
6 Junji Sawada (@junjis0203)
|
||||
6 Kenji Okimoto (@okkez)+
|
||||
6 Paweł Świątkowski (@katafrakt)
|
||||
6 Selman ULUG (@selman)
|
||||
6 Yusuke Endoh (@mame)*
|
||||
6 buty4649 (@buty4649)
|
||||
@@ -121,6 +120,7 @@
|
||||
5 dreamedge (@dreamedge)
|
||||
5 nkshigeru (@nkshigeru)
|
||||
5 xuejianqing (@joans321)
|
||||
4 Chris Hasiński (@khasinski)
|
||||
4 Dante Catalfamo (@dantecatalfamo)
|
||||
4 Goro Kikuchi (@gorogit)
|
||||
4 Herwin Weststrate (@herwinw)
|
||||
@@ -140,7 +140,6 @@
|
||||
4 Yuji Yamano (@yyamano)
|
||||
4 kurodash (@kurodash)*
|
||||
4 wanabe (@wanabe)*
|
||||
2 0x1eef (@0x1eef)
|
||||
3 Anton Davydov (@davydovanton)
|
||||
3 Aurora Nockert (@auroranockert)
|
||||
3 Carlo Prelz (@asfluido)*
|
||||
@@ -193,7 +192,6 @@
|
||||
2 Masahiro Wakame (@vvkame)+
|
||||
2 Minao Yamamoto (@tarosay)+
|
||||
2 Nihad Abbasov (@NARKOZ)
|
||||
2 Pete Kinnecom (@petekinnecom)
|
||||
2 Robert Mosolgo (@rmosolgo)
|
||||
2 Russel Hunter Yukawa (@rhykw)+
|
||||
2 Ryunosuke SATO (@tricknotes)
|
||||
@@ -222,7 +220,6 @@
|
||||
1 Colin MacKenzie IV (@sinisterchipmunk)
|
||||
1 Daehyub Kim (@lateau)
|
||||
1 Daniel Varga (@vargad)
|
||||
1 David Korczynski (@DavidKorczynski)
|
||||
1 Diamond Rivero (@diamant3)
|
||||
1 Edgar Boda-Majer (@eboda)
|
||||
1 Fangrui Song (@MaskRay)
|
||||
@@ -277,6 +274,7 @@
|
||||
1 Patrick Ellis (@pje)
|
||||
1 Patrick Pokatilo (@SHyx0rmZ)
|
||||
1 Pavel Evstigneev (@Paxa)+
|
||||
1 Pete Kinnecom (@petekinnecom)
|
||||
1 Piotr Usewicz (@pusewicz)
|
||||
1 Prayag Verma (@pra85)
|
||||
1 Ranmocy (@ranmocy)
|
||||
@@ -284,7 +282,6 @@
|
||||
1 Ryan Scott Lewis (@RyanScottLewis)
|
||||
1 Ryo Okubo (@syucream)
|
||||
1 SAkira a.k.a. Akira Suzuki (@sakisakira)
|
||||
1 SaekiMototsune (@saeki-mototsune)
|
||||
1 Santiago Rodriguez (@sanrodari)
|
||||
1 Satoh, Hiroh (@cho45)+
|
||||
1 Satoru Naba (@snaba)+
|
||||
@@ -328,7 +325,6 @@
|
||||
1 sbsoftware (@sbsoftware)
|
||||
1 ssmallkirby (@smallkirby)
|
||||
1 taku toyama (@tsuichu)
|
||||
1 vobloeb (@vobloeb)
|
||||
|
||||
`*` - Entries unified according to names and addresses
|
||||
`+` - Entries with names different from commits
|
||||
|
||||
@@ -48,7 +48,7 @@ PROJECT_NAME = mruby
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 4.0.0
|
||||
PROJECT_NUMBER = 3.4.0
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
coderay (1.1.3)
|
||||
rake (13.4.2)
|
||||
yard (0.9.44)
|
||||
rake (13.3.1)
|
||||
yard (0.9.38)
|
||||
yard-coderay (0.1.0)
|
||||
coderay
|
||||
yard
|
||||
|
||||
@@ -23,8 +23,6 @@ mruby now supports pattern matching (case/in) syntax:
|
||||
- Trailing comma in method definition parameters: `def foo(a, b,)` ([f78334b](https://github.com/mruby/mruby/commit/f78334b))
|
||||
- Array/Hash/String subclasses can now override `[]` and `[]=` methods ([#6675](https://github.com/mruby/mruby/pull/6675))
|
||||
- `OP_SETIDX` optimization for Array and Hash ([ddd8fe1](https://github.com/mruby/mruby/commit/ddd8fe1))
|
||||
- `case`/`in` without `else` now raises `NoMatchingPatternError` ([d8de35b](https://github.com/mruby/mruby/commit/d8de35b))
|
||||
- Allow compound statement in parenthesized argument context ([919cbd8](https://github.com/mruby/mruby/commit/919cbd8))
|
||||
|
||||
# Changes in C API
|
||||
|
||||
@@ -39,8 +37,6 @@ mruby now supports pattern matching (case/in) syntax:
|
||||
- `mrb_open()` returns mrb_state with exc set on init failure ([05ffe0c](https://github.com/mruby/mruby/commit/05ffe0c))
|
||||
- `mrb_utf8_to_buf()` for UTF-8 encoding consolidation ([7e28e68](https://github.com/mruby/mruby/commit/7e28e68))
|
||||
- `kh_is_end()` macro for safe khash iteration ([893cc75](https://github.com/mruby/mruby/commit/893cc75))
|
||||
- `mrb_bigint_p()` always defined regardless of bigint gem presence ([6c4a8c0](https://github.com/mruby/mruby/commit/6c4a8c0))
|
||||
- `RInteger` and `RFloat` added to `RVALUE` union ([13dbca0](https://github.com/mruby/mruby/commit/13dbca0))
|
||||
|
||||
# ROM Method Tables
|
||||
|
||||
@@ -80,7 +76,6 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
- Emscripten: use native WASM exception handling ([ca364e3](https://github.com/mruby/mruby/commit/ca364e3))
|
||||
- HAL (Hardware Abstraction Layer) for platform abstraction in mruby-io, mruby-socket, mruby-dir, mruby-task ([74ca22f](https://github.com/mruby/mruby/commit/74ca22f))
|
||||
- `MRUBY_MIRB_READLINE` environment variable to control readline library selection ([0aafb83](https://github.com/mruby/mruby/commit/0aafb83))
|
||||
- MSYS2 drive letter support in build script ([77f6ffe](https://github.com/mruby/mruby/commit/77f6ffe))
|
||||
- Inter-gem headers separated from external API headers ([#6671](https://github.com/mruby/mruby/pull/6671))
|
||||
|
||||
# Changes in mrbgems
|
||||
@@ -115,7 +110,6 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
## Other Gem Changes
|
||||
|
||||
- **_NOTE_**: `Hash#deconstruct_keys` removed for CRuby compatibility ([34b9412](https://github.com/mruby/mruby/commit/34b9412))
|
||||
- **mruby-enum-lazy**: Fix `Lazy#flat_map` to handle non-enumerable block return values ([#6765](https://github.com/mruby/mruby/pull/6765))
|
||||
- **mruby-array-ext**: Add `Array#find` and `Array#rfind` methods
|
||||
- **mruby-io**: Add `IO#putc` and `Kernel#putc` ([baff6e6](https://github.com/mruby/mruby/commit/baff6e6))
|
||||
- **mruby-random**: Replace xoshiro with PCG for better memory efficiency ([f1bab01](https://github.com/mruby/mruby/commit/f1bab01))
|
||||
@@ -131,8 +125,6 @@ mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
- Optimized masgn to generate literals directly into target registers ([fb5d966](https://github.com/mruby/mruby/commit/fb5d966))
|
||||
- Optimized splat of literal arrays in args/literals ([1cb8d73](https://github.com/mruby/mruby/commit/1cb8d73))
|
||||
- Early termination after too many parse errors ([510ebd7](https://github.com/mruby/mruby/commit/510ebd7))
|
||||
- Chunk array literals at 64 elements to reduce register pressure ([f98d641](https://github.com/mruby/mruby/commit/f98d641))
|
||||
- Chunk `%w()` and `%i()` literals to reduce register pressure ([62cf0dc](https://github.com/mruby/mruby/commit/62cf0dc))
|
||||
|
||||
# VM Optimizations
|
||||
|
||||
@@ -193,10 +185,6 @@ Other optimizations:
|
||||
- [#6705](https://github.com/mruby/mruby/issues/6705) Can't get outer class of an object in C
|
||||
- [#6713](https://github.com/mruby/mruby/issues/6713) mruby-polarssl not work
|
||||
- [#6720](https://github.com/mruby/mruby/issues/6720) Random float range: different behavior from CRuby
|
||||
- [#6722](https://github.com/mruby/mruby/issues/6722) RBreak size overflow on 32-bit platforms with MRB_NO_BOXING
|
||||
- [#6740](https://github.com/mruby/mruby/issues/6740) `%w()`/`%i()` register pressure with large literals
|
||||
- [#6741](https://github.com/mruby/mruby/issues/6741) `case`/`in` without `else` should raise `NoMatchingPatternError`
|
||||
- [#6760](https://github.com/mruby/mruby/issues/6760) `mrb_gc_unregister()` not removing all matching entries
|
||||
|
||||
# Merged Pull Requests
|
||||
|
||||
@@ -272,7 +260,6 @@ Other optimizations:
|
||||
- [#6589](https://github.com/mruby/mruby/pull/6589) Add pre-commit hook `check-zip-file-is-not-committed`
|
||||
- [#6591](https://github.com/mruby/mruby/pull/6591) mruby-eval fix license link in README
|
||||
- [#6593](https://github.com/mruby/mruby/pull/6593) README: Add Contributors Avatars, Star History, Table of Contents
|
||||
- [#6598](https://github.com/mruby/mruby/pull/6598) Fix heap buffer overflow in `#method_missing`
|
||||
- [#6599](https://github.com/mruby/mruby/pull/6599) pre-commit: run `markdown-link-check`, `oxipng`, `prettier` manually
|
||||
- [#6600](https://github.com/mruby/mruby/pull/6600) `dreamcast_shelf build config`: update to use KallistiOS wrappers
|
||||
- [#6601](https://github.com/mruby/mruby/pull/6601) fix: skip local build_config.rb when working in MRUBY_ROOT
|
||||
@@ -316,33 +303,6 @@ Other optimizations:
|
||||
- [#6716](https://github.com/mruby/mruby/pull/6716) Fixes identity for proc object
|
||||
- [#6717](https://github.com/mruby/mruby/pull/6717) Fix mruby-task: wrapping by critical section and setting initial task receiver
|
||||
- [#6718](https://github.com/mruby/mruby/pull/6718) Add installation instructions for conda and Homebrew
|
||||
- [#6723](https://github.com/mruby/mruby/pull/6723) Add `RInteger` and `RFloat` to `RVALUE`
|
||||
- [#6727](https://github.com/mruby/mruby/pull/6727) Language documentation: update wording of "overloading" section
|
||||
- [#6729](https://github.com/mruby/mruby/pull/6729) Simplifying dependency addition for gensym task
|
||||
- [#6730](https://github.com/mruby/mruby/pull/6730) Simplifying presym file generation actions
|
||||
- [#6733](https://github.com/mruby/mruby/pull/6733) Include `mruby/presym.h` for all source files
|
||||
- [#6734](https://github.com/mruby/mruby/pull/6734) Chunk array literals at 64 elements to reduce register pressure
|
||||
- [#6735](https://github.com/mruby/mruby/pull/6735) Prevent full recompilation without changes to presym file
|
||||
- [#6739](https://github.com/mruby/mruby/pull/6739) Fix MSYS2 build error with drive letters
|
||||
- [#6743](https://github.com/mruby/mruby/pull/6743) Chunk `%w()` and `%i()` literals to reduce register pressure
|
||||
- [#6744](https://github.com/mruby/mruby/pull/6744) Raise `NoMatchingPatternError` in `case`/`in` without `else`
|
||||
- [#6747](https://github.com/mruby/mruby/pull/6747) Correctly handle empty hash as default named argument
|
||||
- [#6749](https://github.com/mruby/mruby/pull/6749) Fix microcontroller profile
|
||||
- [#6750](https://github.com/mruby/mruby/pull/6750) Fix out-of-bounds read and divide-by-zero in `Array#product`
|
||||
- [#6752](https://github.com/mruby/mruby/pull/6752) Fix `attr_reader`-generated methods accepting extra arguments
|
||||
- [#6753](https://github.com/mruby/mruby/pull/6753) Further optimize `Array#product`
|
||||
- [#6754](https://github.com/mruby/mruby/pull/6754) Mark `attr_reader` procs as noarg
|
||||
- [#6755](https://github.com/mruby/mruby/pull/6755) Reload `ci` after `mrb_hash_delete_key()` in keyword argument handling
|
||||
- [#6756](https://github.com/mruby/mruby/pull/6756) Avoid impact of object modifications caused by `mrb_vm_exec()` calls
|
||||
- [#6758](https://github.com/mruby/mruby/pull/6758) Don't assign result of `mrb_funcall()` directly to `regs`
|
||||
- [#6759](https://github.com/mruby/mruby/pull/6759) Define `mrb_bigint_p()` always
|
||||
- [#6761](https://github.com/mruby/mruby/pull/6761) Fix `mrb_gc_unregister()` to remove all matching entries
|
||||
- [#6762](https://github.com/mruby/mruby/pull/6762) Write generated test C files atomically to avoid build race condition
|
||||
- [#6765](https://github.com/mruby/mruby/pull/6765) Fix `Lazy#flat_map` to handle non-enumerable block return values
|
||||
- [#6767](https://github.com/mruby/mruby/pull/6767) Allow compound statement in parenthesized argument context
|
||||
- [#6780](https://github.com/mruby/mruby/pull/6780) Fix `String#prepend` with self-referencing arguments
|
||||
- [#6781](https://github.com/mruby/mruby/pull/6781) Protect `sprintf` format string from mutation during callbacks
|
||||
- [#6783](https://github.com/mruby/mruby/pull/6783) Pin GitHub Actions workflows to commit hashes
|
||||
|
||||
# Security Fixes
|
||||
|
||||
@@ -360,8 +320,4 @@ Other optimizations:
|
||||
- Heap-use-after-free in insertion_sort ([099d2c47](https://github.com/mruby/mruby/commit/099d2c47))
|
||||
- Integer overflow in str_check_length ([6afff1c3](https://github.com/mruby/mruby/commit/6afff1c3))
|
||||
- Integer overflow in Integer#lcm ([070bef24](https://github.com/mruby/mruby/commit/070bef24))
|
||||
- Heap buffer overflow in `#method_missing` ([550d10a](https://github.com/mruby/mruby/commit/550d10a))
|
||||
- Out-of-bounds read and divide-by-zero in `Array#product` ([8441eaf](https://github.com/mruby/mruby/commit/8441eaf))
|
||||
- Heap buffer overflow in `String#prepend` with self-referencing arguments ([18ba026](https://github.com/mruby/mruby/commit/18ba026))
|
||||
- Use-after-free in `sprintf` via `to_s` callback mutating format string ([48fc422](https://github.com/mruby/mruby/commit/48fc422))
|
||||
- Multiple memory leak fixes in bigint, Set, Array, and Task gems
|
||||
|
||||
@@ -51,8 +51,6 @@ To get mruby, you can download the stable version 4.0.0 from the official mruby
|
||||
GitHub repository or clone the trunk of the mruby source tree with the "git
|
||||
clone" command. You can also install and compile mruby using [ruby-install](https://github.com/postmodern/ruby-install), [ruby-build](https://github.com/rbenv/ruby-build), [rvm](https://github.com/rvm/rvm), [conda](https://anaconda.org/channels/conda-forge/packages/mruby/overview) or [Homebrew](https://formulae.brew.sh/formula/mruby).
|
||||
|
||||
The release candidate version 4.0.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/4.0.0-rc3.zip](https://github.com/mruby/mruby/archive/4.0.0-rc3.zip)
|
||||
|
||||
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
|
||||
|
||||
The trunk of the mruby source tree can be checked out with the
|
||||
|
||||
@@ -292,7 +292,9 @@ class Scene
|
||||
r = rad.x / nsfs
|
||||
g = rad.y / nsfs
|
||||
b = rad.z / nsfs
|
||||
print([clamp(r), clamp(g), clamp(b)].pack("CCC"))
|
||||
printf("%c", clamp(r))
|
||||
printf("%c", clamp(g))
|
||||
printf("%c", clamp(b))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -301,7 +303,7 @@ end
|
||||
# File.open("ao.ppm", "w") do |fp|
|
||||
printf("P6\n")
|
||||
printf("%d %d\n", IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||
printf("255\n")
|
||||
printf("255\n", IMAGE_WIDTH, IMAGE_HEIGHT)
|
||||
Scene.new.render(IMAGE_WIDTH, IMAGE_HEIGHT, NSUBSAMPLES)
|
||||
# Scene.new.render(256, 256, 2)
|
||||
# end
|
||||
|
||||
@@ -30,7 +30,7 @@ MRuby::CrossBuild.new("ArduinoDue") do |conf|
|
||||
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(KHASH_INITIAL_SIZE=8)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
|
||||
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
|
||||
|
||||
@@ -16,7 +16,7 @@ MRuby::CrossBuild.new("RX630") do |conf|
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_USE_FLOAT32)
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(KHASH_INITIAL_SIZE=8)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
|
||||
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
|
||||
|
||||
@@ -27,7 +27,7 @@ MRuby::CrossBuild.new("chipKITMax32") do |conf|
|
||||
|
||||
#configuration for low memory environment
|
||||
cc.defines << %w(MRB_HEAP_PAGE_SIZE=64)
|
||||
cc.defines << %w(KHASH_INITIAL_SIZE=8)
|
||||
cc.defines << %w(KHASH_DEFAULT_SIZE=8)
|
||||
cc.defines << %w(MRB_GC_STRESS)
|
||||
#cc.defines << %w(MRB_NO_STDIO) #if you don't need stdio.
|
||||
#cc.defines << %w(POOL_PAGE_SIZE=1000) #effective only for use with mruby-eval
|
||||
|
||||
@@ -64,8 +64,10 @@ MRuby::Build.new do |conf|
|
||||
# APE binaries use .com extension
|
||||
conf.exts.executable = '.com'
|
||||
|
||||
# Cosmopolitan provides POSIX compatibility
|
||||
conf.ports :posix
|
||||
# Cosmopolitan provides POSIX compatibility, explicitly select POSIX HALs
|
||||
conf.gem core: 'hal-posix-io'
|
||||
conf.gem core: 'hal-posix-socket'
|
||||
conf.gem core: 'hal-posix-dir'
|
||||
|
||||
# Standard library
|
||||
conf.gembox 'stdlib'
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
MRuby::Build.new do |conf|
|
||||
# load specific toolchain settings
|
||||
conf.toolchain
|
||||
|
||||
# Use mrbgems
|
||||
# conf.gem 'examples/mrbgems/ruby_extension_example'
|
||||
# conf.gem 'examples/mrbgems/c_extension_example' do |g|
|
||||
# g.cc.flags << '-g' # append cflags in this gem
|
||||
# end
|
||||
# conf.gem 'examples/mrbgems/c_and_ruby_extension_example'
|
||||
# conf.gem :core => 'mruby-eval'
|
||||
# conf.gem :mgem => 'mruby-onig-regexp'
|
||||
# conf.gem :github => 'mattn/mruby-onig-regexp'
|
||||
# conf.gem :git => 'git@github.com:mattn/mruby-onig-regexp.git', :branch => 'master', :options => '-v'
|
||||
|
||||
# include the GEM box
|
||||
#conf.gembox 'default'
|
||||
|
||||
# C compiler settings
|
||||
# conf.cc do |cc|
|
||||
# cc.command = ENV['CC'] || 'gcc'
|
||||
# cc.flags = [ENV['CFLAGS'] || %w()]
|
||||
# cc.include_paths = ["#{root}/include"]
|
||||
# cc.defines = %w()
|
||||
# cc.option_include_path = %q[-I"%s"]
|
||||
# cc.option_define = '-D%s'
|
||||
# cc.compile_options = %Q[%{flags} -MMD -o "%{outfile}" -c "%{infile}"]
|
||||
# end
|
||||
|
||||
# mrbc settings
|
||||
# conf.mrbc do |mrbc|
|
||||
# mrbc.compile_options = "-g -B%{funcname} -o-" # The -g option is required for line numbers
|
||||
# end
|
||||
|
||||
# Linker settings
|
||||
# conf.linker do |linker|
|
||||
# linker.command = ENV['LD'] || 'gcc'
|
||||
# linker.flags = [ENV['LDFLAGS'] || []]
|
||||
# linker.flags_before_libraries = []
|
||||
# linker.libraries = %w()
|
||||
# linker.flags_after_libraries = []
|
||||
# linker.library_paths = []
|
||||
# linker.option_library = '-l%s'
|
||||
# linker.option_library_path = '-L%s'
|
||||
# linker.link_options = %Q[%{flags} -o "%{outfile}" %{objs} %{libs}]
|
||||
# end
|
||||
|
||||
# Archiver settings
|
||||
# conf.archiver do |archiver|
|
||||
# archiver.command = ENV['AR'] || 'ar'
|
||||
# archiver.archive_options = 'rs "%{outfile}" %{objs}'
|
||||
# end
|
||||
|
||||
# Parser generator settings
|
||||
# conf.yacc do |yacc|
|
||||
# yacc.command = ENV['YACC'] || 'bison'
|
||||
# yacc.compile_options = %q[-o "%{outfile}" "%{infile}"]
|
||||
# end
|
||||
|
||||
# gperf settings
|
||||
# conf.gperf do |gperf|
|
||||
# gperf.command = 'gperf'
|
||||
# gperf.compile_options = %q[-L ANSI-C -C -j1 -i 1 -o -t -N mrb_reserved_word -k"1,3,$" "%{infile}" > "%{outfile}"]
|
||||
# end
|
||||
|
||||
# file extensions
|
||||
# conf.exts do |exts|
|
||||
# exts.object = '.o'
|
||||
# exts.executable = '' # '.exe' if Windows
|
||||
# exts.library = '.a'
|
||||
# end
|
||||
|
||||
# file separator
|
||||
# conf.file_separator = '/'
|
||||
|
||||
# change library directory name from the default "lib" if necessary
|
||||
# conf.libdir_name = 'lib64'
|
||||
|
||||
# Turn on `enable_debug` for better debugging
|
||||
conf.enable_sanitizer 'address,undefined'
|
||||
conf.enable_debug
|
||||
conf.enable_bintest
|
||||
conf.enable_test
|
||||
conf.ports :glib
|
||||
conf.cc.defines << 'MRB_TASK_BUILD_DEMO'
|
||||
conf.gem core: 'mruby-task'
|
||||
conf.gem core: 'mruby-compiler'
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
MRuby::Build.new('host-cxx') do |conf|
|
||||
MRuby::Build.new do |conf|
|
||||
conf.toolchain
|
||||
|
||||
# include the default GEMs
|
||||
|
||||
@@ -13,8 +13,6 @@ MRuby::Build.new('host') do |conf|
|
||||
# Generate mruby debugger command (require mruby-eval)
|
||||
conf.gem :core => "mruby-bin-debugger"
|
||||
|
||||
# Regexp is included via stdlib.gembox
|
||||
|
||||
# test
|
||||
conf.enable_test
|
||||
# bintest
|
||||
|
||||
+20
-78
@@ -1,94 +1,36 @@
|
||||
# Build mruby with a shared libmruby.so (in addition to the usual
|
||||
# libmruby.a / executables).
|
||||
#
|
||||
# Produces (in build/host/lib/):
|
||||
# libmruby.a the static archive (as in the default build)
|
||||
# libmruby.so the shared library, with SONAME=libmruby.so.<MAJOR>.<MINOR>
|
||||
# libmruby.so.<MAJOR>.<MINOR> symlink to libmruby.so (matches SONAME)
|
||||
# libmruby.map linker version script (MRUBY_<RELEASE_NO>)
|
||||
#
|
||||
# Also produces the matching libmruby_core.so + symlink for completeness.
|
||||
#
|
||||
# Symbol versioning ties to MRUBY_RELEASE_NO (e.g. MRUBY_40000 for 4.0.0).
|
||||
# mruby has historically had ABI breaks between TEENY versions, so the
|
||||
# version tag uses the full release number rather than just MAJOR.MINOR.
|
||||
#
|
||||
# The shared library is built FROM the static archive via
|
||||
# `-Wl,--whole-archive`, so the existing static-build pipeline (including
|
||||
# the test infrastructure) is unaffected. Executables in build/host/bin
|
||||
# remain statically linked; distros that want dynamically-linked
|
||||
# executables can rebuild them against the .so.
|
||||
#
|
||||
# NOTE: gcc/clang only — VisualC++ support requires a separate config.
|
||||
|
||||
require "mruby/source"
|
||||
# NOTE: Currently, this configuration file does not support VisualC++!
|
||||
# Your help is needed!
|
||||
|
||||
MRuby::Build.new do |conf|
|
||||
# load specific toolchain settings
|
||||
conf.toolchain
|
||||
|
||||
# include the GEM box
|
||||
conf.gembox 'default'
|
||||
|
||||
# -fPIC so the static archive's contents can be linked into the .so.
|
||||
# C compiler settings
|
||||
conf.compilers.each do |cc|
|
||||
cc.flags << '-fPIC'
|
||||
end
|
||||
|
||||
conf.archiver do |archiver|
|
||||
archiver.command = cc.command
|
||||
archiver.archive_options = '-shared -o %{outfile} %{objs}'
|
||||
end
|
||||
|
||||
# file extensions
|
||||
conf.exts do |exts|
|
||||
exts.library = '.so'
|
||||
end
|
||||
|
||||
# file separator
|
||||
# conf.file_separator = '/'
|
||||
|
||||
# enable this if better compatibility with C++ is desired
|
||||
#conf.enable_cxx_exception
|
||||
|
||||
# Turn on `enable_debug` for better debugging
|
||||
conf.enable_debug
|
||||
conf.enable_bintest
|
||||
conf.enable_test
|
||||
end
|
||||
|
||||
# Add the shared-library targets as a post-build pass, so the default
|
||||
# static-build pipeline remains untouched.
|
||||
MRuby.each_target do
|
||||
next unless name == "host"
|
||||
|
||||
libdir = File.join(build_dir, libdir_name)
|
||||
vermap = File.join(build_dir, "libmruby.map")
|
||||
vertag = "MRUBY_#{MRuby::Source::MRUBY_RELEASE_NO}"
|
||||
|
||||
# Generate the version script eagerly — it has no .o dependencies and is
|
||||
# tiny enough that lazy generation isn't worth the rake plumbing.
|
||||
mkdir_p File.dirname(vermap)
|
||||
File.write(vermap, <<~MAP)
|
||||
#{vertag} {
|
||||
global: *;
|
||||
local: *;
|
||||
};
|
||||
MAP
|
||||
|
||||
major = MRuby::Source::MRUBY_RELEASE_MAJOR
|
||||
minor = MRuby::Source::MRUBY_RELEASE_MINOR
|
||||
|
||||
[
|
||||
[libmruby_static, "libmruby"],
|
||||
[libmruby_core_static, "libmruby_core"],
|
||||
].each do |archive, basename|
|
||||
so = File.join(libdir, "#{basename}.so")
|
||||
symlink = "#{so}.#{major}.#{minor}"
|
||||
soname = "#{basename}.so.#{major}.#{minor}"
|
||||
|
||||
# Build .so from the static archive via --whole-archive.
|
||||
file so => [archive, vermap] do |t|
|
||||
_pp "LD", so.relative_path
|
||||
sh "#{cc.command} -shared -fPIC -o #{so}" \
|
||||
" -Wl,-soname,#{soname}" \
|
||||
" -Wl,--version-script=#{vermap}" \
|
||||
" -Wl,--whole-archive #{archive} -Wl,--no-whole-archive" \
|
||||
" -lm"
|
||||
end
|
||||
products << so
|
||||
|
||||
# SONAME-matching symlink: needed so executables linked with -lmruby
|
||||
# (which embeds the SONAME as DT_NEEDED) can find the library at
|
||||
# runtime via standard search paths.
|
||||
file symlink => so do |t|
|
||||
_pp "LN", "#{symlink.relative_path} -> #{File.basename(so)}"
|
||||
rm_f symlink
|
||||
File.symlink(File.basename(so), symlink)
|
||||
end
|
||||
products << symlink
|
||||
end
|
||||
end
|
||||
|
||||
@@ -72,9 +72,7 @@ MRuby::CrossBuild.new("playstationportable") do |conf|
|
||||
conf.gem :core => "mruby-os-memsize"
|
||||
conf.gem :core => "mruby-proc-binding"
|
||||
conf.gem :core => "mruby-sleep"
|
||||
# Disabled until PSP-specific HALs are available; the POSIX HALs depend on
|
||||
# APIs that the PSP SDK does not fully provide.
|
||||
# conf.gem :core => "mruby-io"
|
||||
# conf.gem :core => "mruby-dir"
|
||||
# conf.gem :core => "mruby-socket"
|
||||
conf.gem :core => "mruby-io"
|
||||
conf.gem :core => "mruby-dir"
|
||||
#conf.gem :core => "mruby-socket" unsupported
|
||||
end
|
||||
|
||||
+30
-30
@@ -4,44 +4,44 @@
|
||||
|
||||
New to mruby? Start here:
|
||||
|
||||
| Document | Description |
|
||||
| -------------------------------------------- | -------------------------------------- |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [Getting Started](guides/getting-started.md) | Build mruby and run your first program |
|
||||
| [Language Features](guides/language.md) | Ruby subset supported by mruby |
|
||||
| [Limitations](limitations.md) | Behavioral differences from CRuby |
|
||||
| [Language Features](guides/language.md) | Ruby subset supported by mruby |
|
||||
| [Limitations](limitations.md) | Behavioral differences from CRuby |
|
||||
|
||||
## Guides (for embedders and gem authors)
|
||||
|
||||
### Embedding mruby in C
|
||||
|
||||
| Document | Description |
|
||||
| --------------------------------------- | ------------------------------------------------ |
|
||||
| [C API Reference](guides/capi.md) | Values, classes, methods, error handling, fibers |
|
||||
| [GC Arena](guides/gc-arena-howto.md) | Managing temporary objects in C extensions |
|
||||
| [Linking](guides/link.md) | Linking with `libmruby` |
|
||||
| [Amalgamation](guides/amalgamation.md) | Single-file build for easy integration |
|
||||
| [Precompiled Symbols](guides/symbol.md) | Compile-time symbol allocation |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [C API Reference](guides/capi.md) | Values, classes, methods, error handling, fibers |
|
||||
| [GC Arena](guides/gc-arena-howto.md) | Managing temporary objects in C extensions |
|
||||
| [Linking](guides/link.md) | Linking with `libmruby` |
|
||||
| [Amalgamation](guides/amalgamation.md) | Single-file build for easy integration |
|
||||
| [Precompiled Symbols](guides/symbol.md) | Compile-time symbol allocation |
|
||||
|
||||
### Building and Configuring
|
||||
|
||||
| Document | Description |
|
||||
| ---------------------------------------- | ------------------------------------------- |
|
||||
| [Compilation](guides/compile.md) | Build system, cross-compilation, toolchains |
|
||||
| [Build Configuration](guides/mrbconf.md) | Compile-time macros (`MRB_*` flags) |
|
||||
| [mrbgems](guides/mrbgems.md) | Creating and managing gems |
|
||||
| [Memory](guides/memory.md) | Allocator customization and heap regions |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [Compilation](guides/compile.md) | Build system, cross-compilation, toolchains |
|
||||
| [Build Configuration](guides/mrbconf.md) | Compile-time macros (`MRB_*` flags) |
|
||||
| [mrbgems](guides/mrbgems.md) | Creating and managing gems |
|
||||
| [Memory](guides/memory.md) | Allocator customization and heap regions |
|
||||
|
||||
### Tools
|
||||
|
||||
| Document | Description |
|
||||
| ----------------------------------------------- | ----------------------------------------------- |
|
||||
| [Debugger](guides/debugger.md) | Using `mrdb` for debugging |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [Debugger](guides/debugger.md) | Using `mrdb` for debugging |
|
||||
| [ROM Method Tables](guides/rom-method-table.md) | Read-only method tables for constrained devices |
|
||||
|
||||
### Reference
|
||||
|
||||
| Document | Description |
|
||||
| ------------------------------------- | ------------------ |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [Directory Structure](guides/hier.md) | Source tree layout |
|
||||
|
||||
## Internals (for mruby contributors)
|
||||
@@ -49,14 +49,14 @@ New to mruby? Start here:
|
||||
Start with [Architecture](internal/architecture.md) for an overview,
|
||||
then dive into the subsystem you need:
|
||||
|
||||
| Document | Description |
|
||||
| ----------------------------------------- | -------------------------------------------------- |
|
||||
| [Architecture](internal/architecture.md) | Overview of object model, VM, GC, compiler |
|
||||
| [Virtual Machine](internal/vm.md) | Dispatch loop, call frames, method lookup, fibers |
|
||||
| [Garbage Collector](internal/gc.md) | Tri-color marking, write barriers, generational GC |
|
||||
| [Compiler Pipeline](internal/compiler.md) | Parser, code generator, IRep, binary format |
|
||||
| [Opcodes](internal/opcode.md) | VM instruction set reference |
|
||||
| [Value Boxing](internal/boxing.md) | How `mrb_value` encodes types |
|
||||
| Document | Description |
|
||||
| -------- | ----------- |
|
||||
| [Architecture](internal/architecture.md) | Overview of object model, VM, GC, compiler |
|
||||
| [Virtual Machine](internal/vm.md) | Dispatch loop, call frames, method lookup, fibers |
|
||||
| [Garbage Collector](internal/gc.md) | Tri-color marking, write barriers, generational GC |
|
||||
| [Compiler Pipeline](internal/compiler.md) | Parser, code generator, IRep, binary format |
|
||||
| [Opcodes](internal/opcode.md) | VM instruction set reference |
|
||||
| [Value Boxing](internal/boxing.md) | How `mrb_value` encodes types |
|
||||
|
||||
## Release Notes
|
||||
|
||||
|
||||
@@ -73,14 +73,14 @@ The following gems work with amalgamation:
|
||||
- `mruby-enum-ext`, `mruby-compar-ext`
|
||||
- `mruby-error`, `mruby-math`, `mruby-struct`
|
||||
- `mruby-bigint`, `mruby-rational`, `mruby-complex`
|
||||
- `mruby-io` (with the active `ports/<name>/` HAL)
|
||||
- `mruby-task` (with the active `ports/<name>/` HAL)
|
||||
- `mruby-io` (with `hal-posix-io`)
|
||||
- `mruby-task` (with `hal-posix-task`)
|
||||
|
||||
### Platform-Dependent Gems
|
||||
|
||||
Gems that use a HAL (Hardware Abstraction Layer) include
|
||||
platform-specific code in the amalgamation. For example, if
|
||||
`mruby-io` selects its POSIX port on Linux, the generated `mruby.c`
|
||||
`mruby-io` selects `hal-posix-io` on Linux, the generated `mruby.c`
|
||||
contains POSIX-specific code and cannot be compiled on Windows.
|
||||
|
||||
If you need amalgamated files for multiple platforms, generate them
|
||||
|
||||
@@ -381,13 +381,6 @@ mrb_define_method(mrb, point, "initialize", point_init, MRB_ARGS_REQ(2));
|
||||
mrb_define_method(mrb, point, "x", point_x, MRB_ARGS_NONE());
|
||||
```
|
||||
|
||||
**Do not call into mruby from a `dfree` handler.** The handler runs
|
||||
from inside GC sweep; allocating Ruby objects, calling
|
||||
`mrb_funcall`, `mrb_yield`, raising exceptions, or otherwise
|
||||
re-entering the VM can trigger a recursive GC that revisits the
|
||||
same object and causes double-free. Keep `dfree` to `mrb_free` /
|
||||
plain C cleanup of the wrapped data only.
|
||||
|
||||
## Exception Handling
|
||||
|
||||
### Raising Exceptions
|
||||
|
||||
@@ -40,7 +40,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
|
||||
|
||||
```bash
|
||||
$ mrdb --version
|
||||
mruby 4.0.0 (2026-04-20)
|
||||
mruby 3.4.0 (2025-04-20)
|
||||
```
|
||||
|
||||
## 2.2 Basic Operation
|
||||
|
||||
+87
-87
@@ -205,11 +205,11 @@ mruby's numeric type sizes depend on the boxing mode and platform.
|
||||
|
||||
### Integer
|
||||
|
||||
| Configuration | Range |
|
||||
| -------------------------------------- | ---------------- |
|
||||
| Configuration | Range |
|
||||
| ------------- | ----- |
|
||||
| 64-bit word boxing (default on 64-bit) | roughly +/- 2^62 |
|
||||
| 32-bit word boxing (default on 32-bit) | roughly +/- 2^30 |
|
||||
| NaN boxing (64-bit only) | -2^31 to 2^31-1 |
|
||||
| NaN boxing (64-bit only) | -2^31 to 2^31-1 |
|
||||
|
||||
Integer overflow raises a `RangeError` unless the `mruby-bigint` gem
|
||||
is included, in which case integers automatically promote to
|
||||
@@ -235,32 +235,32 @@ With word boxing on 64-bit, many float values are stored inline
|
||||
|
||||
These classes are always available in mruby (no gem required):
|
||||
|
||||
| Class | Notes |
|
||||
| ------------- | -------------------------------------- |
|
||||
| Object | Base class for all objects |
|
||||
| Module | Module definition and mixin |
|
||||
| Class | Class definition and instantiation |
|
||||
| NilClass | Singleton `nil` |
|
||||
| TrueClass | Singleton `true` |
|
||||
| FalseClass | Singleton `false` |
|
||||
| Integer | Fixed-precision integer |
|
||||
| Float | Floating-point (unless `MRB_NO_FLOAT`) |
|
||||
| Symbol | Interned identifier |
|
||||
| String | Mutable byte string |
|
||||
| Array | Ordered collection |
|
||||
| Hash | Key-value mapping |
|
||||
| Range | Interval representation |
|
||||
| Proc | Closure / callable object |
|
||||
| Exception | Exception hierarchy root |
|
||||
| StandardError | Common error base |
|
||||
| Class | Notes |
|
||||
| ----- | ----- |
|
||||
| Object | Base class for all objects |
|
||||
| Module | Module definition and mixin |
|
||||
| Class | Class definition and instantiation |
|
||||
| NilClass | Singleton `nil` |
|
||||
| TrueClass | Singleton `true` |
|
||||
| FalseClass | Singleton `false` |
|
||||
| Integer | Fixed-precision integer |
|
||||
| Float | Floating-point (unless `MRB_NO_FLOAT`) |
|
||||
| Symbol | Interned identifier |
|
||||
| String | Mutable byte string |
|
||||
| Array | Ordered collection |
|
||||
| Hash | Key-value mapping |
|
||||
| Range | Interval representation |
|
||||
| Proc | Closure / callable object |
|
||||
| Exception | Exception hierarchy root |
|
||||
| StandardError | Common error base |
|
||||
|
||||
### Core Modules
|
||||
|
||||
| Module | Notes |
|
||||
| ---------- | ----------------------------------------- |
|
||||
| Kernel | Core methods (`puts`, `p`, `raise`, etc.) |
|
||||
| Comparable | Comparison operators via `<=>` |
|
||||
| Enumerable | Collection iteration methods |
|
||||
| Module | Notes |
|
||||
| ------ | ----- |
|
||||
| Kernel | Core methods (`puts`, `p`, `raise`, etc.) |
|
||||
| Comparable | Comparison operators via `<=>` |
|
||||
| Enumerable | Collection iteration methods |
|
||||
|
||||
## Standard Library (via gemboxes)
|
||||
|
||||
@@ -270,70 +270,70 @@ gembox provides the class or feature you need:
|
||||
|
||||
### Classes and Modules
|
||||
|
||||
| Class/Module | Gembox | Gem |
|
||||
| --------------------- | ---------- | ----------------- |
|
||||
| Fiber | stdlib | mruby-fiber |
|
||||
| Enumerator | stdlib | mruby-enumerator |
|
||||
| Enumerator::Lazy | stdlib | mruby-enum-lazy |
|
||||
| Set | stdlib | mruby-set |
|
||||
| ObjectSpace | stdlib | mruby-objectspace |
|
||||
| Time | stdlib-ext | mruby-time |
|
||||
| Struct | stdlib-ext | mruby-struct |
|
||||
| Data | stdlib-ext | mruby-data |
|
||||
| Random | stdlib-ext | mruby-random |
|
||||
| IO, File | stdlib-io | mruby-io |
|
||||
| Socket | stdlib-io | mruby-socket |
|
||||
| Dir | stdlib-io | mruby-dir |
|
||||
| Errno | stdlib-io | mruby-errno |
|
||||
| Math | math | mruby-math |
|
||||
| Rational | math | mruby-rational |
|
||||
| Complex | math | mruby-complex |
|
||||
| Bigint | math | mruby-bigint |
|
||||
| Method, UnboundMethod | metaprog | mruby-method |
|
||||
| Class/Module | Gembox | Gem |
|
||||
| ------------ | ------ | --- |
|
||||
| Fiber | stdlib | mruby-fiber |
|
||||
| Enumerator | stdlib | mruby-enumerator |
|
||||
| Enumerator::Lazy | stdlib | mruby-enum-lazy |
|
||||
| Set | stdlib | mruby-set |
|
||||
| ObjectSpace | stdlib | mruby-objectspace |
|
||||
| Time | stdlib-ext | mruby-time |
|
||||
| Struct | stdlib-ext | mruby-struct |
|
||||
| Data | stdlib-ext | mruby-data |
|
||||
| Random | stdlib-ext | mruby-random |
|
||||
| IO, File | stdlib-io | mruby-io |
|
||||
| Socket | stdlib-io | mruby-socket |
|
||||
| Dir | stdlib-io | mruby-dir |
|
||||
| Errno | stdlib-io | mruby-errno |
|
||||
| Math | math | mruby-math |
|
||||
| Rational | math | mruby-rational |
|
||||
| Complex | math | mruby-complex |
|
||||
| Bigint | math | mruby-bigint |
|
||||
| Method, UnboundMethod | metaprog | mruby-method |
|
||||
|
||||
### Methods and Features
|
||||
|
||||
| Feature | Gembox | Gem |
|
||||
| ----------------------------- | ---------- | ------------------ |
|
||||
| `catch`/`throw` | stdlib | mruby-catch |
|
||||
| `Kernel#sprintf`, `String#%` | stdlib-ext | mruby-sprintf |
|
||||
| `Array#pack`, `String#unpack` | stdlib-ext | mruby-pack |
|
||||
| `Kernel#rand` | stdlib-ext | mruby-random |
|
||||
| `Kernel#eval` | metaprog | mruby-eval |
|
||||
| `Kernel#binding` | metaprog | mruby-binding |
|
||||
| `Proc#binding` | metaprog | mruby-proc-binding |
|
||||
| Runtime compiler | metaprog | mruby-compiler |
|
||||
| Feature | Gembox | Gem |
|
||||
| ------- | ------ | --- |
|
||||
| `catch`/`throw` | stdlib | mruby-catch |
|
||||
| `Kernel#sprintf`, `String#%` | stdlib-ext | mruby-sprintf |
|
||||
| `Array#pack`, `String#unpack` | stdlib-ext | mruby-pack |
|
||||
| `Kernel#rand` | stdlib-ext | mruby-random |
|
||||
| `Kernel#eval` | metaprog | mruby-eval |
|
||||
| `Kernel#binding` | metaprog | mruby-binding |
|
||||
| `Proc#binding` | metaprog | mruby-proc-binding |
|
||||
| Runtime compiler | metaprog | mruby-compiler |
|
||||
|
||||
### Core Class Extensions
|
||||
|
||||
The `stdlib` gembox also extends built-in classes with additional
|
||||
methods. These are included by default:
|
||||
|
||||
| Extension | Examples |
|
||||
| ----------------------- | ---------------------------------------------- |
|
||||
| Array extensions | `#dig`, `#union`, `#difference` |
|
||||
| Hash extensions | `#dig`, `#transform_keys`, `#transform_values` |
|
||||
| String extensions | `#encode`, `#bytes`, `#chars` |
|
||||
| Numeric extensions | `Integer#digits`, `Integer#pow` |
|
||||
| Comparable extensions | `#clamp` |
|
||||
| Enumerable extensions | `#sort_by`, `#min_by`, `#max_by`, `#tally` |
|
||||
| Range extensions | `#size`, `#cover?` |
|
||||
| Proc extensions | `#<<`, `#>>` (composition) |
|
||||
| Symbol extensions | `#to_proc` |
|
||||
| Object extensions | `#then`, `#yield_self` |
|
||||
| Kernel extensions | `#__method__` |
|
||||
| Class/Module extensions | `Module#name` |
|
||||
| Extension | Examples |
|
||||
| --------- | -------- |
|
||||
| Array extensions | `#dig`, `#union`, `#difference` |
|
||||
| Hash extensions | `#dig`, `#transform_keys`, `#transform_values` |
|
||||
| String extensions | `#encode`, `#bytes`, `#chars` |
|
||||
| Numeric extensions | `Integer#digits`, `Integer#pow` |
|
||||
| Comparable extensions | `#clamp` |
|
||||
| Enumerable extensions | `#sort_by`, `#min_by`, `#max_by`, `#tally` |
|
||||
| Range extensions | `#size`, `#cover?` |
|
||||
| Proc extensions | `#<<`, `#>>` (composition) |
|
||||
| Symbol extensions | `#to_proc` |
|
||||
| Object extensions | `#then`, `#yield_self` |
|
||||
| Kernel extensions | `#__method__` |
|
||||
| Class/Module extensions | `Module#name` |
|
||||
|
||||
### Gembox Summary
|
||||
|
||||
| Gembox | Contents | Notes |
|
||||
| ------------ | --------------------------------------------- | -------------------------------------------- |
|
||||
| `stdlib` | Core class extensions, Fiber, Enumerator, Set | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `stdlib-ext` | Time, Struct, Data, Random, sprintf, pack | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `stdlib-io` | IO, File, Dir, Socket, Errno | Requires stdio |
|
||||
| `math` | Math, Rational, Complex, Bigint | Works with `MRB_NO_STDIO` |
|
||||
| `metaprog` | eval, binding, Method, compiler | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `default` | All of the above + CLI tools | Full installation |
|
||||
| Gembox | Contents | Notes |
|
||||
| ------ | -------- | ----- |
|
||||
| `stdlib` | Core class extensions, Fiber, Enumerator, Set | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `stdlib-ext` | Time, Struct, Data, Random, sprintf, pack | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `stdlib-io` | IO, File, Dir, Socket, Errno | Requires stdio |
|
||||
| `math` | Math, Rational, Complex, Bigint | Works with `MRB_NO_STDIO` |
|
||||
| `metaprog` | eval, binding, Method, compiler | Works with `MRB_NO_STDIO` and `MRB_NO_FLOAT` |
|
||||
| `default` | All of the above + CLI tools | Full installation |
|
||||
|
||||
## Key Differences from CRuby
|
||||
|
||||
@@ -416,15 +416,15 @@ differently on 32-bit or NaN boxing configurations.
|
||||
|
||||
Key compile-time macros that affect language behavior:
|
||||
|
||||
| Macro | Effect |
|
||||
| -------------------- | ---------------------------------- |
|
||||
| `MRB_NO_FLOAT` | Remove all float support |
|
||||
| `MRB_USE_FLOAT32` | Use 32-bit float instead of double |
|
||||
| `MRB_UTF8_STRING` | Enable UTF-8 string handling |
|
||||
| `MRB_INT32` | Force 32-bit integer |
|
||||
| `MRB_INT64` | Force 64-bit integer |
|
||||
| `MRB_STR_LENGTH_MAX` | Max string length (default 1MB) |
|
||||
| `MRB_ARY_LENGTH_MAX` | Max array length (default 2^17) |
|
||||
| Macro | Effect |
|
||||
| ----- | ------ |
|
||||
| `MRB_NO_FLOAT` | Remove all float support |
|
||||
| `MRB_USE_FLOAT32` | Use 32-bit float instead of double |
|
||||
| `MRB_UTF8_STRING` | Enable UTF-8 string handling |
|
||||
| `MRB_INT32` | Force 32-bit integer |
|
||||
| `MRB_INT64` | Force 64-bit integer |
|
||||
| `MRB_STR_LENGTH_MAX` | Max string length (default 1MB) |
|
||||
| `MRB_ARY_LENGTH_MAX` | Max array length (default 2^17) |
|
||||
|
||||
See [mrbconf.md](mrbconf.md) for the complete list of configuration
|
||||
macros.
|
||||
|
||||
@@ -202,10 +202,10 @@ any other heap page. The only differences are:
|
||||
The page size is controlled by `MRB_HEAP_PAGE_SIZE` (default: 1024 slots).
|
||||
Each page occupies:
|
||||
|
||||
| Platform | Slot size | Page size (approx) |
|
||||
| -------- | --------- | ------------------ |
|
||||
| 64-bit | 40 bytes | ~41 KB |
|
||||
| 32-bit | 24 bytes | ~25 KB |
|
||||
| Platform | Slot size | Page size (approx) |
|
||||
|----------|-----------|---------------------|
|
||||
| 64-bit | 40 bytes | ~41 KB |
|
||||
| 32-bit | 24 bytes | ~25 KB |
|
||||
|
||||
To estimate pages for a given buffer: `pages = buffer_size / sizeof(mrb_heap_page)`.
|
||||
Each page provides `MRB_HEAP_PAGE_SIZE` object slots.
|
||||
|
||||
@@ -233,10 +233,10 @@ end
|
||||
- Specifies 4th argument(`argc`) max value of `mrb_funcall`.
|
||||
- Raises `ArgumentError` when the `argc` argument is bigger then this value `mrb_funcall`.
|
||||
|
||||
`KHASH_INITIAL_SIZE`
|
||||
`KHASH_DEFAULT_SIZE`
|
||||
|
||||
- Default value is `32`.
|
||||
- Specifies initial size of khash table bucket.
|
||||
- Specifies default size of khash table bucket.
|
||||
- Used in `kh_init_ ## name` function.
|
||||
|
||||
`MRB_NO_METHOD_CACHE`
|
||||
@@ -272,7 +272,7 @@ deployment targets. Define one of the following:
|
||||
`MRB_CONSTRAINED_BASELINE_PROFILE`
|
||||
|
||||
- For micro controllers.
|
||||
- Enables `MRB_NO_METHOD_CACHE`, reduces `KHASH_INITIAL_SIZE` to `16`,
|
||||
- Enables `MRB_NO_METHOD_CACHE`, reduces `KHASH_DEFAULT_SIZE` to `16`,
|
||||
and `MRB_HEAP_PAGE_SIZE` to `256`.
|
||||
|
||||
`MRB_BASELINE_PROFILE`
|
||||
|
||||
@@ -172,8 +172,6 @@ The maximal GEM structure looks like this:
|
||||
|
|
||||
+- src/ <- Source for C extension
|
||||
|
|
||||
+- ports/<name>/ <- Platform-specific C sources (see Platform Ports)
|
||||
|
|
||||
+- tools/ <- Source for Executable (in C)
|
||||
|
|
||||
+- test/ <- Test code (Ruby)
|
||||
@@ -184,8 +182,6 @@ contains C/C++ files to extend mruby. The `include` directory contains C/C++ hea
|
||||
files. The `test` directory contains C/C++ and pure Ruby files for testing purposes
|
||||
which will be used by `mrbtest`. `mrbgem.rake` contains the specification
|
||||
to compile C and Ruby files. `README.md` is a short description of your GEM.
|
||||
The optional `ports/<name>/` directories hold platform-specific C sources
|
||||
selected at build time; see [Platform Ports](#platform-ports-ports) below.
|
||||
|
||||
## Build process
|
||||
|
||||
@@ -336,64 +332,6 @@ end
|
||||
**NOTE**: Using the `build_settings` method will cause GEM's all build command settings
|
||||
directly written in the block passed to `MRuby::Gem::Specification.new` to be ignored.
|
||||
|
||||
## Platform Ports (ports/)
|
||||
|
||||
A gem may ship platform-specific C sources under `ports/<name>/`
|
||||
subdirectories. The build configuration selects which port name(s)
|
||||
are active via `conf.ports`, and each gem compiles the sources of
|
||||
the first matching `ports/<name>/` it ships:
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
conf.toolchain
|
||||
conf.ports :posix # selects ports/posix/ across all gems
|
||||
end
|
||||
```
|
||||
|
||||
`conf.ports` accepts multiple names as a fallback chain. Each gem
|
||||
picks the first directory in the list that exists on its side:
|
||||
|
||||
```ruby
|
||||
conf.ports :rp2040, :posix # try rp2040 per-gem, else posix
|
||||
```
|
||||
|
||||
Host builds auto-detect `:posix` or `:win` when `conf.ports` is
|
||||
not set. Sources outside `ports/` (i.e. `src/`) are always
|
||||
compiled regardless of the port selection.
|
||||
|
||||
### External HAL Provider Gems
|
||||
|
||||
A third-party gem may replace another gem's bundled port at build
|
||||
time. A gem whose name matches `hal-<short>-<conf>` is recognized
|
||||
as the external HAL provider for the target gem whose name's last
|
||||
`-`-separated segment is `<short>`. For example, `hal-task-glib`
|
||||
overrides the HAL of `mruby-task`; `hal-io-uring` would override
|
||||
`mruby-io`. The HAL provider must depend on its target so it can
|
||||
`#include` the target's HAL header:
|
||||
|
||||
```ruby
|
||||
MRuby::Gem::Specification.new('hal-task-glib') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'Your Name'
|
||||
spec.summary = 'GLib HAL for mruby-task'
|
||||
spec.add_dependency 'mruby-task', core: 'mruby-task'
|
||||
# src/ contains the HAL implementation
|
||||
end
|
||||
```
|
||||
|
||||
When a matching HAL provider gem is present in the build, the
|
||||
target gem's `ports/<conf.ports>/` sources are dropped from the
|
||||
build automatically. The HAL provider's own sources supply the
|
||||
implementation instead, avoiding duplicate symbol errors at link
|
||||
time. Loading two gems that match the same `hal-<short>-*`
|
||||
prefix is a build error.
|
||||
|
||||
The naming convention is the only signal -- no spec attribute,
|
||||
no `add_dependency` flag is required. A gem author who wants to
|
||||
contribute an additional bundled port upstream sends a PR adding
|
||||
`<target-gem>/ports/<name>/`; a gem author who prefers to ship
|
||||
out of tree publishes a `hal-<short>-<conf>` gem instead.
|
||||
|
||||
## C Extension
|
||||
|
||||
mruby can be extended with C. This is possible by using the C API to
|
||||
|
||||
@@ -117,8 +117,8 @@ Defined in `include/mruby/class.h`:
|
||||
|
||||
```c
|
||||
union mrb_mt_ptr {
|
||||
mrb_func_t func; /* first member: see MRB_MT_ENTRY note */
|
||||
const struct RProc *proc;
|
||||
mrb_func_t func;
|
||||
};
|
||||
|
||||
typedef struct mrb_mt_entry {
|
||||
@@ -139,12 +139,9 @@ typedef struct mrb_mt_tbl {
|
||||
|
||||
```c
|
||||
/* ROM table entry: 3rd param is MRB_ARGS_*() optionally OR'd with
|
||||
MRB_MT_PRIVATE. The macro OR's in MRB_MT_FUNC automatically.
|
||||
`func` must be the first member of `union mrb_mt_ptr` so that
|
||||
positional initialization works on legacy C++ compilers that do
|
||||
not accept C99 designated initializers. */
|
||||
MRB_MT_PRIVATE. The macro OR's in MRB_MT_FUNC automatically. */
|
||||
#define MRB_MT_ENTRY(fn, sym, flags) \
|
||||
{ { (fn) }, (sym), (flags) | MRB_MT_FUNC }
|
||||
{ { .func = (fn) }, (sym), (flags) | MRB_MT_FUNC }
|
||||
|
||||
/* Extract aspec from combined flags */
|
||||
#define MRB_MT_ASPEC(flags) ((mrb_aspec)((flags) & 0xffffff))
|
||||
|
||||
@@ -31,17 +31,17 @@ struct RBasic (8 bytes on 64-bit)
|
||||
|
||||
All object structs embed this header via `MRB_OBJECT_HEADER`:
|
||||
|
||||
| Struct | Ruby Type | Extra Fields |
|
||||
| ------------ | ---------------- | ---------------------------------- |
|
||||
| `RObject` | Object instances | `iv` (instance variables) |
|
||||
| `RClass` | Class/Module | `iv`, `mt` (method table), `super` |
|
||||
| `RString` | String | embedded or heap buffer, length |
|
||||
| `RArray` | Array | embedded or heap buffer, length |
|
||||
| `RHash` | Hash | hash table or k-v array |
|
||||
| `RProc` | Proc/Lambda | `irep` or C function, environment |
|
||||
| `RData` | C data wrapper | `void *data`, `mrb_data_type` |
|
||||
| `RFiber` | Fiber | `mrb_context` |
|
||||
| `RException` | Exception | `iv` |
|
||||
| Struct | Ruby Type | Extra Fields |
|
||||
| ------ | --------- | ------------ |
|
||||
| `RObject` | Object instances | `iv` (instance variables) |
|
||||
| `RClass` | Class/Module | `iv`, `mt` (method table), `super` |
|
||||
| `RString` | String | embedded or heap buffer, length |
|
||||
| `RArray` | Array | embedded or heap buffer, length |
|
||||
| `RHash` | Hash | hash table or k-v array |
|
||||
| `RProc` | Proc/Lambda | `irep` or C function, environment |
|
||||
| `RData` | C data wrapper | `void *data`, `mrb_data_type` |
|
||||
| `RFiber` | Fiber | `mrb_context` |
|
||||
| `RException` | Exception | `iv` |
|
||||
|
||||
Immediate values (Integer, Symbol, `true`, `false`, `nil`) are encoded
|
||||
directly in `mrb_value` without heap allocation. The encoding depends on
|
||||
@@ -111,52 +111,52 @@ See [compiler.md](compiler.md) for detailed compiler internals,
|
||||
|
||||
### Core (`src/`)
|
||||
|
||||
| File | Responsibility |
|
||||
| ------------- | ---------------------------------------------- |
|
||||
| `vm.c` | Bytecode dispatch loop, method invocation |
|
||||
| `state.c` | `mrb_state` init/close, irep management |
|
||||
| `gc.c` | Garbage collector (mark-sweep, incremental) |
|
||||
| `class.c` | Class/module definition, method tables |
|
||||
| `object.c` | Core object operations |
|
||||
| `variable.c` | Instance/class/global variables, object shapes |
|
||||
| `proc.c` | Proc/Lambda/closure handling |
|
||||
| `array.c` | Array implementation |
|
||||
| `string.c` | String implementation (embedded, shared, heap) |
|
||||
| `hash.c` | Hash implementation (open addressing) |
|
||||
| `numeric.c` | Integer/Float arithmetic |
|
||||
| `symbol.c` | Symbol table and interning |
|
||||
| `range.c` | Range implementation |
|
||||
| `error.c` | Exception creation, raise, backtrace |
|
||||
| `kernel.c` | Kernel module methods |
|
||||
| `load.c` | `.mrb` bytecode loading |
|
||||
| `dump.c` | Bytecode serialization (write `.mrb`) |
|
||||
| `print.c` | Print/puts/p output |
|
||||
| `backtrace.c` | Stack trace generation |
|
||||
| File | Responsibility |
|
||||
| ---- | -------------- |
|
||||
| `vm.c` | Bytecode dispatch loop, method invocation |
|
||||
| `state.c` | `mrb_state` init/close, irep management |
|
||||
| `gc.c` | Garbage collector (mark-sweep, incremental) |
|
||||
| `class.c` | Class/module definition, method tables |
|
||||
| `object.c` | Core object operations |
|
||||
| `variable.c` | Instance/class/global variables, object shapes |
|
||||
| `proc.c` | Proc/Lambda/closure handling |
|
||||
| `array.c` | Array implementation |
|
||||
| `string.c` | String implementation (embedded, shared, heap) |
|
||||
| `hash.c` | Hash implementation (open addressing) |
|
||||
| `numeric.c` | Integer/Float arithmetic |
|
||||
| `symbol.c` | Symbol table and interning |
|
||||
| `range.c` | Range implementation |
|
||||
| `error.c` | Exception creation, raise, backtrace |
|
||||
| `kernel.c` | Kernel module methods |
|
||||
| `load.c` | `.mrb` bytecode loading |
|
||||
| `dump.c` | Bytecode serialization (write `.mrb`) |
|
||||
| `print.c` | Print/puts/p output |
|
||||
| `backtrace.c` | Stack trace generation |
|
||||
|
||||
### Compiler (`mrbgems/mruby-compiler/core/`)
|
||||
|
||||
| File | Responsibility |
|
||||
| ----------- | ------------------------------- |
|
||||
| `parse.y` | Yacc grammar → AST |
|
||||
| `y.tab.c` | Generated parser (from parse.y) |
|
||||
| `codegen.c` | AST → bytecode (irep) |
|
||||
| `node.h` | AST node type definitions |
|
||||
| File | Responsibility |
|
||||
| ---- | -------------- |
|
||||
| `parse.y` | Yacc grammar → AST |
|
||||
| `y.tab.c` | Generated parser (from parse.y) |
|
||||
| `codegen.c` | AST → bytecode (irep) |
|
||||
| `node.h` | AST node type definitions |
|
||||
|
||||
### Key Headers (`include/mruby/`)
|
||||
|
||||
| Header | Contents |
|
||||
| ------------ | ------------------------------------- |
|
||||
| `mruby.h` | `mrb_state`, core API declarations |
|
||||
| `value.h` | `mrb_value`, type enums, value macros |
|
||||
| `object.h` | `RBasic`, `RObject`, object header |
|
||||
| `class.h` | `RClass`, method table types |
|
||||
| `string.h` | `RString`, string macros |
|
||||
| `array.h` | `RArray`, array macros |
|
||||
| `hash.h` | `RHash`, hash API |
|
||||
| `data.h` | `RData`, C data wrapping |
|
||||
| `irep.h` | `mrb_irep`, bytecode structures |
|
||||
| `compile.h` | Compiler context, `mrb_load_string` |
|
||||
| `boxing_*.h` | Value boxing implementations |
|
||||
| Header | Contents |
|
||||
| ------ | -------- |
|
||||
| `mruby.h` | `mrb_state`, core API declarations |
|
||||
| `value.h` | `mrb_value`, type enums, value macros |
|
||||
| `object.h` | `RBasic`, `RObject`, object header |
|
||||
| `class.h` | `RClass`, method table types |
|
||||
| `string.h` | `RString`, string macros |
|
||||
| `array.h` | `RArray`, array macros |
|
||||
| `hash.h` | `RHash`, hash API |
|
||||
| `data.h` | `RData`, C data wrapping |
|
||||
| `irep.h` | `mrb_irep`, bytecode structures |
|
||||
| `compile.h` | Compiler context, `mrb_load_string` |
|
||||
| `boxing_*.h` | Value boxing implementations |
|
||||
|
||||
## mrbgems System
|
||||
|
||||
|
||||
+10
-10
@@ -77,16 +77,16 @@ No boxing represents `mrb_value` by the C struct with `type` and the value union
|
||||
|
||||
## Comparison
|
||||
|
||||
| Property | Word Boxing | NaN Boxing | No Boxing |
|
||||
| ---------------------- | ----------------- | ---------------- | -------------------- |
|
||||
| `mrb_value` size | 1 word (4/8 byte) | 8 bytes | 2 words (8/16 bytes) |
|
||||
| Default on | most platforms | (manual opt-in) | `host-debug` |
|
||||
| Macro | `MRB_WORD_BOXING` | `MRB_NAN_BOXING` | `MRB_NO_BOXING` |
|
||||
| Inline integers | yes (31/63 bit) | yes (32 bit) | yes (full width) |
|
||||
| Inline floats (64-bit) | yes (rotation) | yes (native) | yes (struct field) |
|
||||
| Inline floats (32-bit) | no (heap RFloat) | yes (native) | yes (struct field) |
|
||||
| Pointer size limit | none | 48 bits | none |
|
||||
| Debugger friendly | no | no | yes |
|
||||
| Property | Word Boxing | NaN Boxing | No Boxing |
|
||||
| ---------------------- | ------------------ | ------------------ | -------------------- |
|
||||
| `mrb_value` size | 1 word (4/8 byte) | 8 bytes | 2 words (8/16 bytes) |
|
||||
| Default on | most platforms | (manual opt-in) | `host-debug` |
|
||||
| Macro | `MRB_WORD_BOXING` | `MRB_NAN_BOXING` | `MRB_NO_BOXING` |
|
||||
| Inline integers | yes (31/63 bit) | yes (32 bit) | yes (full width) |
|
||||
| Inline floats (64-bit) | yes (rotation) | yes (native) | yes (struct field) |
|
||||
| Inline floats (32-bit) | no (heap RFloat) | yes (native) | yes (struct field) |
|
||||
| Pointer size limit | none | 48 bits | none |
|
||||
| Debugger friendly | no | no | yes |
|
||||
|
||||
## ABI Compatibility
|
||||
|
||||
|
||||
+59
-59
@@ -40,18 +40,18 @@ file: `mrbgems/mruby-compiler/core/parse.y`.
|
||||
|
||||
The parser maintains extensive state in `mrb_parser_state`:
|
||||
|
||||
- **lstate**: current lexer state (EXPR_BEG, EXPR_END, EXPR_ARG,
|
||||
EXPR_DOT, EXPR_FNAME, etc.). Controls how tokens like `+`/`-`
|
||||
- **lstate**: current lexer state (EXPR\_BEG, EXPR\_END, EXPR\_ARG,
|
||||
EXPR\_DOT, EXPR\_FNAME, etc.). Controls how tokens like `+`/`-`
|
||||
are interpreted (sign vs operator) and whether newlines are
|
||||
significant.
|
||||
- **locals**: stack of local variable lists (one per scope), stored
|
||||
as cons-lists of symbols.
|
||||
- **lex_strterm**: string/heredoc parsing state for handling nested
|
||||
- **lex\_strterm**: string/heredoc parsing state for handling nested
|
||||
interpolation.
|
||||
- **cond_stack**, **cmdarg_stack**: bit stacks tracking
|
||||
- **cond\_stack**, **cmdarg\_stack**: bit stacks tracking
|
||||
conditional and command argument contexts.
|
||||
- **tree**: root AST node after successful parse.
|
||||
- **error_buffer**: accumulated parse errors.
|
||||
- **error\_buffer**: accumulated parse errors.
|
||||
|
||||
### AST Nodes
|
||||
|
||||
@@ -123,10 +123,10 @@ reuse temporaries within an expression.
|
||||
Instructions are emitted via helper functions:
|
||||
|
||||
- `genop_0(opcode)`: no operands
|
||||
- `genop_1(opcode, a)`: one operand (auto-extends with OP_EXT1
|
||||
- `genop_1(opcode, a)`: one operand (auto-extends with OP\_EXT1
|
||||
if a > 255)
|
||||
- `genop_2(opcode, a, b)`: two operands (auto-extends with
|
||||
OP_EXT1/2/3 as needed)
|
||||
OP\_EXT1/2/3 as needed)
|
||||
- `genop_3(opcode, a, b, c)`: three operands
|
||||
- `genop_W(opcode, a)`: 24-bit operand
|
||||
- `genop_2S(opcode, a, b)`: one 8-bit + one 16-bit operand
|
||||
@@ -176,14 +176,14 @@ mrb_irep
|
||||
|
||||
Pool entries store constants referenced by instructions:
|
||||
|
||||
| Type | Tag | Description |
|
||||
| ---------------- | --- | ------------------------------- |
|
||||
| `IREP_TT_STR` | 0 | Dynamic string (heap allocated) |
|
||||
| `IREP_TT_SSTR` | 2 | Static string (read-only) |
|
||||
| `IREP_TT_INT32` | 1 | 32-bit integer |
|
||||
| `IREP_TT_INT64` | 3 | 64-bit integer |
|
||||
| `IREP_TT_FLOAT` | 5 | Floating-point number |
|
||||
| `IREP_TT_BIGINT` | 7 | Arbitrary-precision integer |
|
||||
| Type | Tag | Description |
|
||||
| ---- | --- | ----------- |
|
||||
| `IREP_TT_STR` | 0 | Dynamic string (heap allocated) |
|
||||
| `IREP_TT_SSTR` | 2 | Static string (read-only) |
|
||||
| `IREP_TT_INT32` | 1 | 32-bit integer |
|
||||
| `IREP_TT_INT64` | 3 | 64-bit integer |
|
||||
| `IREP_TT_FLOAT` | 5 | Floating-point number |
|
||||
| `IREP_TT_BIGINT` | 7 | Arbitrary-precision integer |
|
||||
|
||||
The code generator deduplicates pool entries: identical strings
|
||||
and equal numeric values share the same pool index.
|
||||
@@ -209,28 +209,28 @@ During exception unwinding, handlers are searched in reverse order
|
||||
Standard instructions use 8-bit operands. When a value exceeds
|
||||
255, extension prefixes widen operands to 16 bits:
|
||||
|
||||
| Prefix | Effect |
|
||||
| --------- | --------------------------------- |
|
||||
| `OP_EXT1` | First operand (a) becomes 16-bit |
|
||||
| Prefix | Effect |
|
||||
| ------ | ------ |
|
||||
| `OP_EXT1` | First operand (a) becomes 16-bit |
|
||||
| `OP_EXT2` | Second operand (b) becomes 16-bit |
|
||||
| `OP_EXT3` | Both a and b become 16-bit |
|
||||
| `OP_EXT3` | Both a and b become 16-bit |
|
||||
|
||||
Instruction formats:
|
||||
|
||||
| Format | Layout | Size |
|
||||
| ------ | ----------------------------- | ------- |
|
||||
| Z | opcode only | 1 byte |
|
||||
| B | opcode + a(8) | 2 bytes |
|
||||
| BB | opcode + a(8) + b(8) | 3 bytes |
|
||||
| BBB | opcode + a(8) + b(8) + c(8) | 4 bytes |
|
||||
| BS | opcode + a(8) + b(16) | 4 bytes |
|
||||
| BSS | opcode + a(8) + b(16) + c(16) | 6 bytes |
|
||||
| S | opcode + a(16) | 3 bytes |
|
||||
| W | opcode + a(24) | 4 bytes |
|
||||
| Format | Layout | Size |
|
||||
| ------ | ------ | ---- |
|
||||
| Z | opcode only | 1 byte |
|
||||
| B | opcode + a(8) | 2 bytes |
|
||||
| BB | opcode + a(8) + b(8) | 3 bytes |
|
||||
| BBB | opcode + a(8) + b(8) + c(8) | 4 bytes |
|
||||
| BS | opcode + a(8) + b(16) | 4 bytes |
|
||||
| BSS | opcode + a(8) + b(16) + c(16) | 6 bytes |
|
||||
| S | opcode + a(16) | 3 bytes |
|
||||
| W | opcode + a(24) | 4 bytes |
|
||||
|
||||
See [opcode.md](opcode.md) for the full instruction table.
|
||||
|
||||
## OP_ENTER: Argument Specification
|
||||
## OP\_ENTER: Argument Specification
|
||||
|
||||
`OP_ENTER` encodes a method's argument layout in a 24-bit value
|
||||
(W format). The bit fields are defined by the `MRB_ARGS_*` macros:
|
||||
@@ -258,16 +258,16 @@ string interning for common symbols.
|
||||
Generated by `lib/mruby/presym.rb`, the presym table maps symbol
|
||||
names to compile-time constants:
|
||||
|
||||
| Macro | Example | Symbol |
|
||||
| ----------------- | --------------------- | ------------- |
|
||||
| `MRB_SYM(name)` | `MRB_SYM(initialize)` | `:initialize` |
|
||||
| `MRB_SYM_B(name)` | `MRB_SYM_B(map)` | `:map!` |
|
||||
| `MRB_SYM_Q(name)` | `MRB_SYM_Q(nil)` | `:nil?` |
|
||||
| `MRB_SYM_E(name)` | `MRB_SYM_E(name)` | `:name=` |
|
||||
| `MRB_OPSYM(op)` | `MRB_OPSYM(add)` | `:+` |
|
||||
| `MRB_IVSYM(name)` | `MRB_IVSYM(name)` | `:@name` |
|
||||
| `MRB_CVSYM(name)` | `MRB_CVSYM(count)` | `:@@count` |
|
||||
| `MRB_GVSYM(name)` | `MRB_GVSYM(stdout)` | `:$stdout` |
|
||||
| Macro | Example | Symbol |
|
||||
| ----- | ------- | ------ |
|
||||
| `MRB_SYM(name)` | `MRB_SYM(initialize)` | `:initialize` |
|
||||
| `MRB_SYM_B(name)` | `MRB_SYM_B(map)` | `:map!` |
|
||||
| `MRB_SYM_Q(name)` | `MRB_SYM_Q(nil)` | `:nil?` |
|
||||
| `MRB_SYM_E(name)` | `MRB_SYM_E(name)` | `:name=` |
|
||||
| `MRB_OPSYM(op)` | `MRB_OPSYM(add)` | `:+` |
|
||||
| `MRB_IVSYM(name)` | `MRB_IVSYM(name)` | `:@name` |
|
||||
| `MRB_CVSYM(name)` | `MRB_CVSYM(count)` | `:@@count` |
|
||||
| `MRB_GVSYM(name)` | `MRB_GVSYM(stdout)` | `:$stdout` |
|
||||
|
||||
## Binary Format (.mrb)
|
||||
|
||||
@@ -299,25 +299,25 @@ mrbc -Boutput source.rb # C array format
|
||||
|
||||
## Compilation Limits
|
||||
|
||||
| Limit | Value |
|
||||
| ---------------------- | ----------------------------- |
|
||||
| Max nesting depth | 256 (`MRB_CODEGEN_LEVEL_MAX`) |
|
||||
| Max local variables | 255 (uint16 `nlocals`) |
|
||||
| Max symbols per irep | 65535 |
|
||||
| Max operand (standard) | 255 (8-bit) |
|
||||
| Max operand (extended) | 65535 (16-bit) |
|
||||
| Limit | Value |
|
||||
| ----- | ----- |
|
||||
| Max nesting depth | 256 (`MRB_CODEGEN_LEVEL_MAX`) |
|
||||
| Max local variables | 255 (uint16 `nlocals`) |
|
||||
| Max symbols per irep | 65535 |
|
||||
| Max operand (standard) | 255 (8-bit) |
|
||||
| Max operand (extended) | 65535 (16-bit) |
|
||||
|
||||
## Source Files
|
||||
|
||||
| File | Contents |
|
||||
| --------------------------------------- | ------------------------- |
|
||||
| `mrbgems/mruby-compiler/core/parse.y` | Lrama/Bison grammar |
|
||||
| `mrbgems/mruby-compiler/core/y.tab.c` | Generated parser |
|
||||
| `mrbgems/mruby-compiler/core/codegen.c` | Code generator |
|
||||
| `mrbgems/mruby-compiler/core/node.h` | AST node types |
|
||||
| `include/mruby/irep.h` | IRep structure definition |
|
||||
| `include/mruby/compile.h` | Compiler context API |
|
||||
| `include/mruby/ops.h` | Opcode definitions |
|
||||
| `src/load.c` | Binary format loader |
|
||||
| `src/dump.c` | Binary format writer |
|
||||
| `lib/mruby/presym.rb` | Presym table generator |
|
||||
| File | Contents |
|
||||
| ---- | -------- |
|
||||
| `mrbgems/mruby-compiler/core/parse.y` | Lrama/Bison grammar |
|
||||
| `mrbgems/mruby-compiler/core/y.tab.c` | Generated parser |
|
||||
| `mrbgems/mruby-compiler/core/codegen.c` | Code generator |
|
||||
| `mrbgems/mruby-compiler/core/node.h` | AST node types |
|
||||
| `include/mruby/irep.h` | IRep structure definition |
|
||||
| `include/mruby/compile.h` | Compiler context API |
|
||||
| `include/mruby/ops.h` | Opcode definitions |
|
||||
| `src/load.c` | Binary format loader |
|
||||
| `src/dump.c` | Binary format writer |
|
||||
| `lib/mruby/presym.rb` | Presym table generator |
|
||||
|
||||
+35
-165
@@ -26,12 +26,12 @@ pauses.
|
||||
Every heap-allocated object has a color stored in
|
||||
`RBasic::gc_color` (3 bits):
|
||||
|
||||
| Color | Value | Meaning |
|
||||
| -------------- | ------ | ------------------------------------ |
|
||||
| White (A or B) | 1 or 2 | Unmarked, candidate for collection |
|
||||
| Gray | 0 | Marked, but children not yet scanned |
|
||||
| Black | 4 | Fully marked and scanned |
|
||||
| Red | 7 | Static/ROM object, never collected |
|
||||
| Color | Value | Meaning |
|
||||
| ----- | ----- | ------- |
|
||||
| White (A or B) | 1 or 2 | Unmarked, candidate for collection |
|
||||
| Gray | 0 | Marked, but children not yet scanned |
|
||||
| Black | 4 | Fully marked and scanned |
|
||||
| Red | 7 | Static/ROM object, never collected |
|
||||
|
||||
The GC uses two white types (A and B) in a flip-flop scheme. At the
|
||||
start of each GC cycle, the meaning of "current white" is flipped by
|
||||
@@ -107,7 +107,7 @@ The GC operates as a three-state machine:
|
||||
GC_STATE_ROOT --> GC_STATE_MARK --> GC_STATE_SWEEP --> GC_STATE_ROOT
|
||||
```
|
||||
|
||||
### Root Scan (GC_STATE_ROOT)
|
||||
### Root Scan (GC\_STATE\_ROOT)
|
||||
|
||||
Marks objects directly reachable from the VM:
|
||||
|
||||
@@ -121,7 +121,7 @@ Marks objects directly reachable from the VM:
|
||||
|
||||
After root scanning, the white color is flipped.
|
||||
|
||||
### Incremental Marking (GC_STATE_MARK)
|
||||
### Incremental Marking (GC\_STATE\_MARK)
|
||||
|
||||
Gray objects are popped from the gray stack and their children
|
||||
marked. Each step processes a limited number of objects:
|
||||
@@ -131,15 +131,13 @@ limit = (GC_STEP_SIZE / 100) * step_ratio
|
||||
```
|
||||
|
||||
With default `step_ratio = 200` and `GC_STEP_SIZE = 1024`, the
|
||||
limit is 2048 objects per step. After each step, `gc_debt` is
|
||||
decremented by the actual number of objects processed, so larger
|
||||
steps repay more debt.
|
||||
limit is 2048 objects per step.
|
||||
|
||||
When the gray stack is exhausted, the final marking phase re-marks
|
||||
the arena and global variables to catch objects created during
|
||||
marking, then transitions to sweep.
|
||||
|
||||
### Sweep (GC_STATE_SWEEP)
|
||||
### Sweep (GC\_STATE\_SWEEP)
|
||||
|
||||
Iterates through heap pages. For each object:
|
||||
|
||||
@@ -275,7 +273,7 @@ From Ruby: `GC.generational_mode = true/false`.
|
||||
`mrb_obj_alloc()` is the core allocation function:
|
||||
|
||||
1. If `MRB_GC_STRESS` is defined, run a full GC
|
||||
2. Increment `gc->gc_debt`; if positive, run `mrb_incremental_gc()`
|
||||
2. If `gc->live >= gc->threshold`, run `mrb_incremental_gc()`
|
||||
3. Ensure arena has space (`gc_arena_keep`)
|
||||
4. Pop an object from the freelist of `gc->free_heaps`
|
||||
5. If no free pages, allocate a new page (`add_heap`)
|
||||
@@ -301,43 +299,18 @@ The object's type is set to `MRB_TT_FREE` after freeing.
|
||||
|
||||
## Triggering GC
|
||||
|
||||
### Debt Model
|
||||
### Automatic
|
||||
|
||||
GC uses a **debt-based feedback model** to balance allocation
|
||||
rate against collection work. The key field is `gc->gc_debt`
|
||||
(signed integer):
|
||||
|
||||
- **Negative** = credit (GC is ahead, no collection needed)
|
||||
- **Zero** = balanced
|
||||
- **Positive** = debt (allocation outpacing collection, GC runs)
|
||||
|
||||
Each object allocation increments `gc_debt` by 1. When debt
|
||||
goes positive, `mrb_incremental_gc()` runs. Each incremental
|
||||
step decrements debt by `GC_STEP_SIZE` (1024), giving credit
|
||||
for many future allocations.
|
||||
|
||||
When a GC cycle completes, credit is calculated from
|
||||
`interval_ratio`:
|
||||
GC runs automatically when `gc->live >= gc->threshold` during
|
||||
object allocation. After each cycle:
|
||||
|
||||
```text
|
||||
credit = (live_after_mark / 100) * interval_ratio - live_after_mark
|
||||
threshold = (live_after_mark / 100) * interval_ratio
|
||||
minimum: GC_STEP_SIZE (1024)
|
||||
gc_debt = -credit
|
||||
```
|
||||
|
||||
With default `interval_ratio = 200` and 1000 live objects:
|
||||
`credit = (1000/100)*200 - 1000 = 1000`, so approximately 1000
|
||||
allocations can occur before the next GC cycle begins.
|
||||
|
||||
### Malloc Pressure
|
||||
|
||||
When `gc->malloc_threshold` is set (non-zero), the GC also
|
||||
tracks bytes allocated through `mrb_realloc_simple()` in
|
||||
`gc->malloc_increase`. When `malloc_increase` exceeds
|
||||
`malloc_threshold`, the counter resets and an incremental GC
|
||||
step runs. This captures memory pressure from large buffers
|
||||
(e.g., long strings) that would otherwise be invisible to the
|
||||
object-count-based debt model.
|
||||
With default `interval_ratio = 200`, GC triggers when live objects
|
||||
roughly double.
|
||||
|
||||
### Manual
|
||||
|
||||
@@ -352,136 +325,33 @@ From Ruby: `GC.start`.
|
||||
|
||||
### Compile-Time
|
||||
|
||||
| Macro | Default | Description |
|
||||
| ------------------------------ | ------- | --------------------------------------- |
|
||||
| `MRB_HEAP_PAGE_SIZE` | 1024 | Objects per heap page |
|
||||
| `MRB_GRAY_STACK_SIZE` | 1024 | Gray stack capacity |
|
||||
| `MRB_GC_ARENA_SIZE` | 100 | Arena size (fixed mode) or initial size |
|
||||
| `MRB_GC_FIXED_ARENA` | off | Use fixed-size arena |
|
||||
| `MRB_GC_TURN_OFF_GENERATIONAL` | off | Disable generational mode |
|
||||
| `MRB_GC_STRESS` | off | Full GC on every allocation (debug) |
|
||||
| `MRB_GC_STATS` | off | Enable GC statistics counters |
|
||||
| `MRB_USE_MALLOC_TRIM` | off | Call `malloc_trim()` after full GC |
|
||||
| Macro | Default | Description |
|
||||
| ----- | ------- | ----------- |
|
||||
| `MRB_HEAP_PAGE_SIZE` | 1024 | Objects per heap page |
|
||||
| `MRB_GRAY_STACK_SIZE` | 1024 | Gray stack capacity |
|
||||
| `MRB_GC_ARENA_SIZE` | 100 | Arena size (fixed mode) or initial size |
|
||||
| `MRB_GC_FIXED_ARENA` | off | Use fixed-size arena |
|
||||
| `MRB_GC_TURN_OFF_GENERATIONAL` | off | Disable generational mode |
|
||||
| `MRB_GC_STRESS` | off | Full GC on every allocation (debug) |
|
||||
| `MRB_USE_MALLOC_TRIM` | off | Call `malloc_trim()` after full GC |
|
||||
|
||||
### Runtime
|
||||
|
||||
From Ruby code:
|
||||
|
||||
```ruby
|
||||
GC.interval_ratio = 200 # controls debt credit after GC cycle
|
||||
GC.step_ratio = 200 # objects per incremental step
|
||||
GC.step_limit = 0 # 0=unlimited, >0=absolute step cap
|
||||
GC.malloc_threshold = 0 # 0=disabled, >0=bytes to trigger GC
|
||||
GC.interval_ratio = 200 # threshold = live * ratio / 100
|
||||
GC.step_ratio = 200 # objects per incremental step
|
||||
GC.generational_mode = true
|
||||
GC.start # force full GC
|
||||
GC.enable # re-enable GC
|
||||
GC.disable # disable GC
|
||||
GC.start # force full GC
|
||||
GC.enable # re-enable GC
|
||||
GC.disable # disable GC
|
||||
```
|
||||
|
||||
### GC Statistics
|
||||
|
||||
`GC.stat` returns a Hash with GC state and statistics:
|
||||
|
||||
```ruby
|
||||
GC.stat
|
||||
# => {
|
||||
# :live => 5432, # live object count
|
||||
# :debt => -1024, # GC debt (negative=credit, positive=behind)
|
||||
# :state => 0, # 0=root, 1=marking, 2=sweeping
|
||||
# :generational => true, # generational mode enabled
|
||||
# :full => false, # major GC in progress
|
||||
# :step_limit => 0, # current step limit setting
|
||||
# :malloc_increase => 8192, # malloc bytes since last cycle
|
||||
# :malloc_threshold => 0, # current malloc threshold setting
|
||||
# }
|
||||
```
|
||||
|
||||
With `MRB_GC_STATS` enabled, additional keys are available:
|
||||
|
||||
```ruby
|
||||
# :total => 15, # total GC invocations
|
||||
# :minor => 12, # minor GC count
|
||||
# :major => 3, # major GC count
|
||||
```
|
||||
|
||||
### Tuning Guide
|
||||
|
||||
**`interval_ratio`** (default 200): Controls how many allocations
|
||||
occur between GC cycles. Higher values reduce GC frequency but
|
||||
increase peak memory. The debt credit after each cycle is
|
||||
`(live_after_mark / 100) * interval_ratio - live_after_mark`.
|
||||
|
||||
**`step_ratio`** (default 200): Controls how much work each
|
||||
incremental step performs. Higher values make each step larger,
|
||||
reducing total GC overhead but increasing individual pause times.
|
||||
|
||||
**`step_limit`** (default 0, unlimited): Caps the maximum work
|
||||
per incremental step regardless of `step_ratio`. Useful for
|
||||
real-time applications that need bounded pause times. The
|
||||
effective step size is `min(step_ratio calculation, step_limit)`.
|
||||
|
||||
**`malloc_threshold`** (default 0, disabled): Triggers GC when
|
||||
cumulative `malloc`/`realloc` bytes exceed this threshold. Useful
|
||||
when applications allocate large buffers (strings, data objects)
|
||||
that create memory pressure without proportional object count
|
||||
increase.
|
||||
|
||||
### Practical Tuning Examples
|
||||
|
||||
**Allocation-heavy workloads** (many short-lived Procs, closures,
|
||||
blocks): GC sweep dominates because of high object churn. Increase
|
||||
`interval_ratio` to reduce GC frequency:
|
||||
|
||||
```ruby
|
||||
GC.interval_ratio = 400 # ~12% faster than default (200)
|
||||
```
|
||||
|
||||
Higher values (400-600) reduce sweep overhead at the cost of more
|
||||
dead objects accumulating before collection. Values above 600 show
|
||||
diminishing returns. Peak memory usage increases temporarily, but
|
||||
live object count after GC remains the same.
|
||||
|
||||
**CPU-intensive workloads** (numeric computation, recursive methods
|
||||
with no object allocation): GC parameters have negligible impact
|
||||
because GC rarely runs. No tuning needed.
|
||||
|
||||
**Real-time or latency-sensitive** applications: Use `step_limit`
|
||||
to bound pause times:
|
||||
|
||||
```ruby
|
||||
GC.step_limit = 256 # cap incremental step to 256 objects
|
||||
```
|
||||
|
||||
This makes GC pauses more predictable but increases total GC
|
||||
overhead (more steps needed per cycle).
|
||||
|
||||
**Large buffer workloads** (reading files, building long strings):
|
||||
Set `malloc_threshold` to trigger GC when buffer allocations
|
||||
accumulate, even if object count is low:
|
||||
|
||||
```ruby
|
||||
GC.malloc_threshold = 1024 * 1024 # trigger GC per ~1MB allocated
|
||||
```
|
||||
|
||||
### Diagnosing GC Overhead
|
||||
|
||||
Use `GC.stat` to monitor GC behavior at runtime:
|
||||
|
||||
```ruby
|
||||
s = GC.stat
|
||||
puts "live objects: #{s[:live]}"
|
||||
puts "GC debt: #{s[:debt]}" # positive = GC is behind
|
||||
puts "GC state: #{s[:state]}" # 0=idle, 1=marking, 2=sweeping
|
||||
```
|
||||
|
||||
If `debt` is frequently positive during performance-critical
|
||||
sections, increase `interval_ratio`. If memory usage is too high,
|
||||
decrease it.
|
||||
|
||||
## Source Files
|
||||
|
||||
| File | Contents |
|
||||
| -------------------- | --------------------------------- |
|
||||
| `src/gc.c` | GC implementation |
|
||||
| File | Contents |
|
||||
| ---- | -------- |
|
||||
| `src/gc.c` | GC implementation (~1400 lines) |
|
||||
| `include/mruby/gc.h` | `mrb_gc` structure, public GC API |
|
||||
| `include/mruby.h` | Arena save/restore macros |
|
||||
| `include/mruby.h` | Arena save/restore macros |
|
||||
|
||||
+19
-19
@@ -97,12 +97,12 @@ return n + 1 (skip self)
|
||||
|
||||
### Call Context Info (cci)
|
||||
|
||||
| Value | Name | Meaning |
|
||||
| ----- | --------------- | ------------------------------------- |
|
||||
| 0 | `CINFO_NONE` | Normal VM-to-VM call |
|
||||
| 1 | `CINFO_DIRECT` | Explicit VM call (block, lambda.call) |
|
||||
| 2 | `CINFO_SKIP` | Skip frame in stack traces |
|
||||
| 3 | `CINFO_RESUMED` | Fiber resumed (stop execution) |
|
||||
| Value | Name | Meaning |
|
||||
| ----- | ---- | ------- |
|
||||
| 0 | `CINFO_NONE` | Normal VM-to-VM call |
|
||||
| 1 | `CINFO_DIRECT` | Explicit VM call (block, lambda.call) |
|
||||
| 2 | `CINFO_SKIP` | Skip frame in stack traces |
|
||||
| 3 | `CINFO_RESUMED` | Fiber resumed (stop execution) |
|
||||
|
||||
## Dispatch Loop
|
||||
|
||||
@@ -241,13 +241,13 @@ correctness.
|
||||
|
||||
### Proc Types
|
||||
|
||||
| Flag | Meaning |
|
||||
| ------------------- | ------------------------------ |
|
||||
| `MRB_PROC_CFUNC_FL` | C function (not irep-based) |
|
||||
| `MRB_PROC_STRICT` | Lambda (strict argument check) |
|
||||
| `MRB_PROC_ORPHAN` | No environment attachment |
|
||||
| `MRB_PROC_ENVSET` | Has captured environment |
|
||||
| `MRB_PROC_SCOPE` | Defines a new variable scope |
|
||||
| Flag | Meaning |
|
||||
| ---- | ------- |
|
||||
| `MRB_PROC_CFUNC_FL` | C function (not irep-based) |
|
||||
| `MRB_PROC_STRICT` | Lambda (strict argument check) |
|
||||
| `MRB_PROC_ORPHAN` | No environment attachment |
|
||||
| `MRB_PROC_ENVSET` | Has captured environment |
|
||||
| `MRB_PROC_SCOPE` | Defines a new variable scope |
|
||||
|
||||
## Fiber Switching
|
||||
|
||||
@@ -317,9 +317,9 @@ ensuring the incremental GC correctly tracks live references.
|
||||
|
||||
## Source Files
|
||||
|
||||
| File | Contents |
|
||||
| ----------------------- | ---------------------------------------------- |
|
||||
| `src/vm.c` | Dispatch loop, method invocation (~1900 lines) |
|
||||
| `include/mruby.h` | `mrb_state`, `mrb_callinfo`, `mrb_context` |
|
||||
| `include/mruby/proc.h` | `RProc`, `REnv` structures |
|
||||
| `include/mruby/throw.h` | `MRB_TRY`/`MRB_CATCH` macros |
|
||||
| File | Contents |
|
||||
| ---- | -------- |
|
||||
| `src/vm.c` | Dispatch loop, method invocation (~1900 lines) |
|
||||
| `include/mruby.h` | `mrb_state`, `mrb_callinfo`, `mrb_context` |
|
||||
| `include/mruby/proc.h` | `RProc`, `REnv` structures |
|
||||
| `include/mruby/throw.h` | `MRB_TRY`/`MRB_CATCH` macros |
|
||||
|
||||
+9
-168
@@ -15,23 +15,6 @@ This document is collecting these limitations.
|
||||
This document does not contain a complete list of limitations.
|
||||
Please help to improve it by submitting your findings.
|
||||
|
||||
## Features provided by mrbgems
|
||||
|
||||
Many Ruby features that CRuby builds into its core are provided by
|
||||
mrbgems in mruby. Which features are actually available depends on
|
||||
which mrbgems are linked into the build. The `default.gembox` and
|
||||
`stdlib.gembox` cover the common cases, but a minimal build can omit
|
||||
familiar features such as `Kernel#binding` (provided by
|
||||
`mruby-binding`), `Kernel#catch`/`throw` (by `mruby-catch`),
|
||||
`Enumerable` extensions, `Comparable`, IO, regular expressions, and
|
||||
many more.
|
||||
|
||||
This is by design rather than a limitation per se. When porting Ruby
|
||||
code to mruby, a `NoMethodError` or `NameError` often means "the gem
|
||||
providing this feature is not linked in" rather than "mruby does not
|
||||
support it." Adding the relevant gem to the build configuration is
|
||||
usually enough.
|
||||
|
||||
## `Kernel.raise` in rescue clause
|
||||
|
||||
`Kernel.raise` without arguments does not raise the current exception within
|
||||
@@ -150,6 +133,12 @@ The re-defined `+` operator does not accept any arguments.
|
||||
`'ab'`
|
||||
Behavior of the operator wasn't changed.
|
||||
|
||||
## `Kernel#binding` is not supported without mruby-binding gem
|
||||
|
||||
`Kernel#binding` method requires the `mruby-binding` gem (included
|
||||
in the `metaprog` gembox). Without this gem, `binding` is not
|
||||
available.
|
||||
|
||||
## `nil?` redefinition in conditional expressions
|
||||
|
||||
Redefinition of `nil?` is ignored in conditional expressions.
|
||||
@@ -285,11 +274,11 @@ enabled with the `MRB_UTF8_STRING` compile flag.
|
||||
|
||||
Integer size depends on the value boxing configuration:
|
||||
|
||||
| Configuration | Integer range |
|
||||
| ----------------------------- | ---------------- |
|
||||
| Configuration | Integer range |
|
||||
| ------------- | ------------- |
|
||||
| Word boxing, 64-bit (default) | roughly +/- 2^62 |
|
||||
| Word boxing, 32-bit (default) | roughly +/- 2^30 |
|
||||
| NaN boxing (64-bit only) | -2^31 to 2^31-1 |
|
||||
| NaN boxing (64-bit only) | -2^31 to 2^31-1 |
|
||||
|
||||
Code relying on 64-bit integer precision may behave differently
|
||||
across configurations. The `mruby-bigint` gem provides
|
||||
@@ -301,151 +290,3 @@ arbitrary-precision integers when included.
|
||||
(included in the `stdlib` gembox). Even with the gem,
|
||||
`ObjectSpace.each_object` has limited functionality compared
|
||||
to CRuby.
|
||||
|
||||
## No Implicit Type Conversion (`to_int`, `to_str`, `to_ary`, ...)
|
||||
|
||||
mruby does not perform implicit type conversion through methods
|
||||
like `to_int`, `to_str`, `to_ary`, or `to_hash`. CRuby uses these
|
||||
to let user-defined classes duck-type as built-in types — for
|
||||
example `Array#[]` calls `to_int` on its argument, `String#+` calls
|
||||
`to_str`, and multiple assignment calls `to_ary` on its right-hand
|
||||
side. mruby's built-in operations require the actual built-in type
|
||||
and do not consult these conversion methods.
|
||||
|
||||
```ruby
|
||||
class MyInt; def to_int; 42; end; end
|
||||
class MyStr; def to_str; "x"; end; end
|
||||
class MyAry; def to_ary; [1,2,3]; end; end
|
||||
```
|
||||
|
||||
#### CRuby
|
||||
|
||||
```
|
||||
[1,2,3][MyInt.new] # => nil (to_int called -> ary[42])
|
||||
"a" + MyStr.new # => "ax" (to_str called)
|
||||
a, b, c = MyAry.new # => a=1, b=2, c=3 (to_ary called)
|
||||
```
|
||||
|
||||
#### mruby
|
||||
|
||||
```
|
||||
[1,2,3][MyInt.new] # TypeError
|
||||
"a" + MyStr.new # TypeError
|
||||
a, b, c = MyAry.new # a=<MyAry obj>, b=nil, c=nil (treated as single value)
|
||||
```
|
||||
|
||||
Identity versions of `to_int`, `to_str`, `to_sym`, and `to_hash`
|
||||
remain defined on the corresponding built-in types so that
|
||||
`respond_to?(:to_str)`-style checks work for built-in instances.
|
||||
`Float#to_int` and `Array#to_ary` are intentionally not defined.
|
||||
|
||||
Explicit conversion methods (`to_i`, `to_s`, `to_a`) work as in
|
||||
CRuby and are called by features such as string interpolation and
|
||||
the splat operator (`*obj`).
|
||||
|
||||
This is a deliberate trade-off: implicit conversion forces every
|
||||
coercion site to go through method dispatch and can silently mask
|
||||
type-mismatch bugs.
|
||||
|
||||
## Nested `def` in Singleton-Method Context
|
||||
|
||||
`def` written inside a singleton method (`def self.foo`) is placed
|
||||
on a different class in mruby than in CRuby. CRuby registers the
|
||||
inner method as an instance method of the lexical enclosing class.
|
||||
mruby registers it as a method of the enclosing receiver's
|
||||
singleton class, which makes it visible as a class method of the
|
||||
enclosing class.
|
||||
|
||||
```ruby
|
||||
class SomeClass
|
||||
def self.class_method
|
||||
def nested; 'nested!'; end
|
||||
end
|
||||
end
|
||||
SomeClass.class_method
|
||||
```
|
||||
|
||||
#### CRuby
|
||||
|
||||
```
|
||||
SomeClass.nested # NoMethodError
|
||||
SomeClass.new.nested # => "nested!" (instance method)
|
||||
```
|
||||
|
||||
#### mruby
|
||||
|
||||
```
|
||||
SomeClass.nested # => "nested!" (class method)
|
||||
SomeClass.new.nested # NoMethodError
|
||||
```
|
||||
|
||||
Writing nested `def` like this is unusual; this difference rarely
|
||||
surfaces in practical code.
|
||||
|
||||
## `Proc#dup` / `Proc#clone` is Always Orphan
|
||||
|
||||
A `dup` or `clone` of a block given to a method is always treated as
|
||||
an orphan block in mruby — calling it raises `LocalJumpError` if the
|
||||
block contains `break` or `return`. CRuby is finer-grained: the copy
|
||||
inherits the orphan status of its original, so the copy only becomes
|
||||
orphan once the original yielding method returns.
|
||||
|
||||
```ruby
|
||||
def m(&b)
|
||||
b.dup
|
||||
end
|
||||
|
||||
x = m { break 1 }
|
||||
x.call
|
||||
```
|
||||
|
||||
#### CRuby
|
||||
|
||||
```
|
||||
LocalJumpError # raised only after m returns; if called inside m,
|
||||
# the dup is still a live block
|
||||
```
|
||||
|
||||
#### mruby
|
||||
|
||||
```
|
||||
LocalJumpError # always raised — the dup is orphan from the moment
|
||||
# it is created
|
||||
```
|
||||
|
||||
mruby's stricter rule keeps `RProc` from needing a back-pointer to
|
||||
the original block (which would also enlarge the GC mark set).
|
||||
|
||||
## `Class#initialize` Can Be Re-Invoked
|
||||
|
||||
CRuby raises `TypeError: already initialized class` when `initialize`
|
||||
is invoked on a class that has already been set up. mruby's
|
||||
`Class#initialize` has no such guard — invoking it on an existing
|
||||
class through `__send__`, `send`, or `UnboundMethod#bind_call`
|
||||
silently succeeds. The superclass argument is ignored in this case,
|
||||
so the call cannot rewrite the class hierarchy; only the block (if
|
||||
any) is evaluated with the class as receiver.
|
||||
|
||||
```ruby
|
||||
Klass = Class.new
|
||||
Klass.__send__(:initialize) {}
|
||||
```
|
||||
|
||||
#### CRuby
|
||||
|
||||
```
|
||||
TypeError: already initialized class
|
||||
```
|
||||
|
||||
#### mruby
|
||||
|
||||
```
|
||||
The block is evaluated in the context of Klass; no error is raised.
|
||||
The superclass is not changed even when one is passed as an argument.
|
||||
```
|
||||
|
||||
`Module#initialize` is re-callable in both implementations, so this
|
||||
divergence is `Class`-specific. Adding the CRuby check would require
|
||||
an additional flag bit on every `RClass`; mruby leaves the bit
|
||||
unspent because no destructive side effects are possible through
|
||||
this path.
|
||||
|
||||
-367
@@ -1,367 +0,0 @@
|
||||
# User visible changes in `mruby4.0` from `mruby3.4`
|
||||
|
||||
"**_NOTE_**:" are changes to be aware of.
|
||||
|
||||
# The language
|
||||
|
||||
## Pattern Matching
|
||||
|
||||
mruby now supports pattern matching (case/in) syntax:
|
||||
|
||||
- Basic pattern matching with `case`/`in` syntax ([dadfac6](https://github.com/mruby/mruby/commit/dadfac6))
|
||||
- Array pattern matching ([ec67fd9](https://github.com/mruby/mruby/commit/ec67fd9))
|
||||
- Hash pattern matching ([2147263](https://github.com/mruby/mruby/commit/2147263))
|
||||
- Find pattern matching (`[*pre, target, *post]`) ([6c4d98b](https://github.com/mruby/mruby/commit/6c4d98b))
|
||||
- Pin operator (`^variable`) ([1de6340](https://github.com/mruby/mruby/commit/1de6340))
|
||||
- Guard clauses (`if`/`unless` conditions) ([07ac110](https://github.com/mruby/mruby/commit/07ac110))
|
||||
- One-line pattern matching (`expr in pattern`) ([e76ce24](https://github.com/mruby/mruby/commit/e76ce24))
|
||||
- Brace-less hash pattern support ([e8096bf](https://github.com/mruby/mruby/commit/e8096bf))
|
||||
|
||||
## Other Language Changes
|
||||
|
||||
- `&nil` in formal parameters to explicitly opt out of block arguments ([b07518e](https://github.com/mruby/mruby/commit/b07518e))
|
||||
- Trailing comma in method definition parameters: `def foo(a, b,)` ([f78334b](https://github.com/mruby/mruby/commit/f78334b))
|
||||
- Array/Hash/String subclasses can now override `[]` and `[]=` methods ([#6675](https://github.com/mruby/mruby/pull/6675))
|
||||
- `OP_SETIDX` optimization for Array and Hash ([ddd8fe1](https://github.com/mruby/mruby/commit/ddd8fe1))
|
||||
- `case`/`in` without `else` now raises `NoMatchingPatternError` ([d8de35b](https://github.com/mruby/mruby/commit/d8de35b))
|
||||
- Allow compound statement in parenthesized argument context ([919cbd8](https://github.com/mruby/mruby/commit/919cbd8))
|
||||
|
||||
# Changes in C API
|
||||
|
||||
- **_NOTE_**: `mrb_alloca()` renamed to `mrb_temp_alloc()` ([7fe5c2e](https://github.com/mruby/mruby/commit/7fe5c2e))
|
||||
- **_NOTE_**: `mruby/ext/io.h` renamed to `mruby/io.h` ([2813f79](https://github.com/mruby/mruby/commit/2813f79))
|
||||
- `mrb_gc_add_region()` for contiguous heap region support ([072855a](https://github.com/mruby/mruby/commit/072855a))
|
||||
- `mrb_class_outer()` to get the outer class/module ([3a1b771](https://github.com/mruby/mruby/commit/3a1b771))
|
||||
- `MRB_ENSURE()` macro for exception-safe cleanup ([3ac682b](https://github.com/mruby/mruby/commit/3ac682b))
|
||||
- `mrb_time_get_tm()` for accessing struct tm ([daaaafe](https://github.com/mruby/mruby/commit/daaaafe))
|
||||
- `MRB_OPEN_FAILURE()` macro for checking mrb_open result ([40b0cb9](https://github.com/mruby/mruby/commit/40b0cb9))
|
||||
- `mrb_print_error()` now handles NULL gracefully ([8e50a45](https://github.com/mruby/mruby/commit/8e50a45))
|
||||
- `mrb_open()` returns mrb_state with exc set on init failure ([05ffe0c](https://github.com/mruby/mruby/commit/05ffe0c))
|
||||
- `mrb_utf8_to_buf()` for UTF-8 encoding consolidation ([7e28e68](https://github.com/mruby/mruby/commit/7e28e68))
|
||||
- `kh_is_end()` macro for safe khash iteration ([893cc75](https://github.com/mruby/mruby/commit/893cc75))
|
||||
- `mrb_bigint_p()` always defined regardless of bigint gem presence ([6c4a8c0](https://github.com/mruby/mruby/commit/6c4a8c0))
|
||||
- `RInteger` and `RFloat` added to `RVALUE` union ([13dbca0](https://github.com/mruby/mruby/commit/13dbca0))
|
||||
|
||||
# ROM Method Tables
|
||||
|
||||
All built-in classes and most extension gems now use read-only method
|
||||
tables stored in `.rodata` instead of heap-allocated hash tables. Method
|
||||
definitions no longer consume heap memory, significantly reducing memory
|
||||
footprint for embedded use.
|
||||
|
||||
Core classes converted: BasicObject, Object, Module, Class, Kernel,
|
||||
String, Array, Hash, Numeric, Integer, Float, NilClass, TrueClass,
|
||||
FalseClass, Range, Symbol, Exception, Proc.
|
||||
|
||||
Extension gems converted: mruby-string-ext, mruby-array-ext, mruby-set,
|
||||
mruby-struct, mruby-class-ext, mruby-numeric-ext, mruby-random,
|
||||
mruby-kernel-ext, mruby-complex, mruby-rational, mruby-io, mruby-socket,
|
||||
mruby-method, mruby-metaprog, mruby-time, mruby-hash-ext, mruby-proc-ext,
|
||||
mruby-symbol-ext, mruby-range-ext, mruby-object-ext.
|
||||
|
||||
# GC and Memory
|
||||
|
||||
- **_NOTE_**: `MRB_NO_PRESYM` removed; presym is now always enabled ([81689045](https://github.com/mruby/mruby/commit/81689045))
|
||||
- Replace `gcnext` gray linked list with fixed-size gray stack, reducing per-object overhead ([31fea170](https://github.com/mruby/mruby/commit/31fea170))
|
||||
- `mrb_gc_add_region()` for providing contiguous memory buffers as GC heap pages ([072855a](https://github.com/mruby/mruby/commit/072855a))
|
||||
- Chunk-based pool for symbol string allocation ([e05bd8f](https://github.com/mruby/mruby/commit/e05bd8f))
|
||||
- Reduce `IV_INITIAL_SIZE` from 4 to 2 ([6bd1f51](https://github.com/mruby/mruby/commit/6bd1f51))
|
||||
- Lossless float encoding using rotation in word boxing ([b6148c8](https://github.com/mruby/mruby/commit/b6148c8))
|
||||
- Lossless rotation encoding for 32-bit float32 word boxing ([14a5cfb](https://github.com/mruby/mruby/commit/14a5cfb))
|
||||
- Consolidated irep allocation for .mrb loading ([74fb045](https://github.com/mruby/mruby/commit/74fb045))
|
||||
- Object shapes (hidden classes) for `MRB_TT_OBJECT` IV storage, sharing key layouts across objects with the same instance variable assignment order ([8d10056](https://github.com/mruby/mruby/commit/8d10056))
|
||||
|
||||
# Build & Configuration
|
||||
|
||||
- **_NOTE_**: `MRB_WORDBOX_NO_FLOAT_TRUNCATE` renamed to `MRB_WORDBOX_NO_INLINE_FLOAT` (old name still works) ([59e1fe2](https://github.com/mruby/mruby/commit/59e1fe2))
|
||||
- **_NOTE_**: `MRB_INT64` on 32-bit now requires `MRB_NO_BOXING` (other boxing modes cannot guarantee alignment for heap-allocated 64-bit integers) ([eaaa66b](https://github.com/mruby/mruby/commit/eaaa66b))
|
||||
- Amalgamation support via `rake amalgam` task ([d995ca2](https://github.com/mruby/mruby/commit/d995ca2))
|
||||
- New Platform: Cosmopolitan Libc ([#6681](https://github.com/mruby/mruby/pull/6681))
|
||||
- Emscripten: use native WASM exception handling ([ca364e3](https://github.com/mruby/mruby/commit/ca364e3))
|
||||
- HAL (Hardware Abstraction Layer) for platform abstraction in mruby-io, mruby-socket, mruby-dir, mruby-task ([74ca22f](https://github.com/mruby/mruby/commit/74ca22f))
|
||||
- `MRUBY_MIRB_READLINE` environment variable to control readline library selection ([0aafb83](https://github.com/mruby/mruby/commit/0aafb83))
|
||||
- MSYS2 drive letter support in build script ([77f6ffe](https://github.com/mruby/mruby/commit/77f6ffe))
|
||||
- Inter-gem headers separated from external API headers ([#6671](https://github.com/mruby/mruby/pull/6671))
|
||||
|
||||
# Changes in mrbgems
|
||||
|
||||
## New Gems
|
||||
|
||||
- **mruby-task**: Cooperative multitasking with preemptive scheduling ([ae0d7a0](https://github.com/mruby/mruby/commit/ae0d7a0))
|
||||
- **mruby-benchmark**: Benchmarking gem ([2f40f3d](https://github.com/mruby/mruby/commit/2f40f3d))
|
||||
- **mruby-strftime**: Time#strftime implementation ([b31e22f](https://github.com/mruby/mruby/commit/b31e22f))
|
||||
|
||||
## mruby-bin-mirb Improvements
|
||||
|
||||
- Custom multi-line editor replacing readline ([527018c](https://github.com/mruby/mruby/commit/527018c))
|
||||
- Syntax highlighting for keywords, strings, result values, hash key symbols ([624272b](https://github.com/mruby/mruby/commit/624272b), [1713d4a](https://github.com/mruby/mruby/commit/1713d4a))
|
||||
- Automatic light/dark theme detection via OSC 11 ([db4c8d9](https://github.com/mruby/mruby/commit/db4c8d9))
|
||||
- Tab completion support ([2f15282](https://github.com/mruby/mruby/commit/2f15282))
|
||||
- Colored output for prompts and errors ([b36e0b4](https://github.com/mruby/mruby/commit/b36e0b4))
|
||||
- Auto-indentation and auto-dedent ([d52f318](https://github.com/mruby/mruby/commit/d52f318), [e901b6d](https://github.com/mruby/mruby/commit/e901b6d))
|
||||
- Command history with Up/Down navigation ([5f85c1b](https://github.com/mruby/mruby/commit/5f85c1b))
|
||||
- Line numbers in multi-line prompts ([5a3f0e2](https://github.com/mruby/mruby/commit/5a3f0e2))
|
||||
- UTF-8 multibyte character support ([4a97da3](https://github.com/mruby/mruby/commit/4a97da3))
|
||||
|
||||
## mruby-bigint Improvements
|
||||
|
||||
- Toom-3 multiplication for large numbers ([99620804](https://github.com/mruby/mruby/commit/99620804))
|
||||
- Karatsuba multiplication for medium-sized numbers ([85e81072](https://github.com/mruby/mruby/commit/85e81072))
|
||||
- Balance multiplication for asymmetric operands ([0220ec2b](https://github.com/mruby/mruby/commit/0220ec2b))
|
||||
- Divide-and-conquer optimization for `to_s` ([990ff90f](https://github.com/mruby/mruby/commit/990ff90f))
|
||||
- Consolidated mpn layer for low-level limb operations ([9ef3362f](https://github.com/mruby/mruby/commit/9ef3362f))
|
||||
- Always use 32-bit limbs by default ([c747c77f](https://github.com/mruby/mruby/commit/c747c77f))
|
||||
|
||||
## Other Gem Changes
|
||||
|
||||
- **_NOTE_**: `Hash#deconstruct_keys` removed for CRuby compatibility ([34b9412](https://github.com/mruby/mruby/commit/34b9412))
|
||||
- **mruby-enum-lazy**: Fix `Lazy#flat_map` to handle non-enumerable block return values ([#6765](https://github.com/mruby/mruby/pull/6765))
|
||||
- **mruby-array-ext**: Add `Array#find` and `Array#rfind` methods
|
||||
- **mruby-io**: Add `IO#putc` and `Kernel#putc` ([baff6e6](https://github.com/mruby/mruby/commit/baff6e6))
|
||||
- **mruby-random**: Replace xoshiro with PCG for better memory efficiency ([f1bab01](https://github.com/mruby/mruby/commit/f1bab01))
|
||||
- **mruby-compiler**: Variable-sized AST nodes for reduced memory usage
|
||||
- **mruby-compiler**: `no_return_value` context flag for script optimization ([613b03a](https://github.com/mruby/mruby/commit/613b03a))
|
||||
- `initialize_copy` and `respond_to_missing?` defined as private ([#6708](https://github.com/mruby/mruby/pull/6708))
|
||||
- Struct keyword argument initialization ([#6574](https://github.com/mruby/mruby/pull/6574))
|
||||
|
||||
# Compiler Improvements
|
||||
|
||||
- Variable-sized AST nodes for reduced memory consumption ([821b989](https://github.com/mruby/mruby/commit/821b989))
|
||||
- Pattern matching bytecode optimizations ([21d4135](https://github.com/mruby/mruby/commit/21d4135))
|
||||
- Optimized masgn to generate literals directly into target registers ([fb5d966](https://github.com/mruby/mruby/commit/fb5d966))
|
||||
- Optimized splat of literal arrays in args/literals ([1cb8d73](https://github.com/mruby/mruby/commit/1cb8d73))
|
||||
- Early termination after too many parse errors ([510ebd7](https://github.com/mruby/mruby/commit/510ebd7))
|
||||
- Chunk array literals at 64 elements to reduce register pressure ([f98d641](https://github.com/mruby/mruby/commit/f98d641))
|
||||
- Chunk `%w()` and `%i()` literals to reduce register pressure ([62cf0dc](https://github.com/mruby/mruby/commit/62cf0dc))
|
||||
|
||||
# VM Optimizations
|
||||
|
||||
New super-instructions that fuse common opcode sequences to reduce bytecode size and improve performance:
|
||||
|
||||
- `OP_SEND0`/`OP_SSEND0`: Zero-argument method call, avoiding argument count setup ([9123ef4](https://github.com/mruby/mruby/commit/9123ef4))
|
||||
- `OP_TDEF`/`OP_SDEF`: Fused method definition combining TCLASS/SCLASS+METHOD+DEF into single instruction, saving 4 bytes per method ([8d4f47e](https://github.com/mruby/mruby/commit/8d4f47e))
|
||||
- `OP_GETIDX0`: Fast path for `array[0]` and `Array#first` access ([680f7ec](https://github.com/mruby/mruby/commit/680f7ec))
|
||||
- `OP_ADDILV`/`OP_SUBILV`: Local variable increment/decrement fusion for `i += n` patterns ([43f64b9](https://github.com/mruby/mruby/commit/43f64b9))
|
||||
- `OP_RETSELF`: Single-byte instruction for `return self` pattern ([a71db8c](https://github.com/mruby/mruby/commit/a71db8c))
|
||||
- `OP_RETNIL`: Single-byte instruction for `return nil` pattern ([64e30bf](https://github.com/mruby/mruby/commit/64e30bf))
|
||||
- `OP_RETTRUE`/`OP_RETFALSE`: Single-byte instructions for `return true`/`return false` patterns ([0b15727](https://github.com/mruby/mruby/commit/0b15727))
|
||||
- `OP_MATCHERR`: Pattern matching error with conditional execution ([944168a](https://github.com/mruby/mruby/commit/944168a))
|
||||
- `OP_BLKCALL`: Direct block call for `yield`, bypassing method dispatch (13-17% faster) ([3aa2872](https://github.com/mruby/mruby/commit/3aa2872))
|
||||
|
||||
Other optimizations:
|
||||
|
||||
- 1.5x stack growth instead of linear growth for reduced reallocations ([f7988c93](https://github.com/mruby/mruby/commit/f7988c93))
|
||||
- Skip keyword argument hash duplication ([5970e350](https://github.com/mruby/mruby/commit/5970e350))
|
||||
|
||||
# Fixed GitHub Issues
|
||||
|
||||
- [#5531](https://github.com/mruby/mruby/issues/5531) Hash recursion detection
|
||||
- [#6506](https://github.com/mruby/mruby/issues/6506) Constant lookup in singleton class
|
||||
- [#6507](https://github.com/mruby/mruby/issues/6507) tally multi-values
|
||||
- [#6508](https://github.com/mruby/mruby/issues/6508) Enumerable#sum index
|
||||
- [#6509](https://github.com/mruby/mruby/issues/6509) scope_new nregs initialization
|
||||
- [#6515](https://github.com/mruby/mruby/issues/6515) y.tab.c in repository
|
||||
- [#6516](https://github.com/mruby/mruby/issues/6516) Private backquote
|
||||
- [#6554](https://github.com/mruby/mruby/issues/6554) Socket private #initialize
|
||||
- [#6570](https://github.com/mruby/mruby/issues/6570) instance_eval crash
|
||||
- [#6613](https://github.com/mruby/mruby/issues/6613) const_added hook during bootstrapping
|
||||
- [#6635](https://github.com/mruby/mruby/issues/6635), [#6636](https://github.com/mruby/mruby/issues/6636) Colon3 constant lookup
|
||||
- [#6637](https://github.com/mruby/mruby/issues/6637) arm64 mingw64 builtin setjmp/longjmp
|
||||
- [#6642](https://github.com/mruby/mruby/issues/6642) Task segfault when sleep called from C
|
||||
- [#6645](https://github.com/mruby/mruby/issues/6645) Set memory leak from double initialization
|
||||
- [#6646](https://github.com/mruby/mruby/issues/6646) IO#gets negative length
|
||||
- [#6647](https://github.com/mruby/mruby/issues/6647) IO#ungetc buffer overflow
|
||||
- [#6648](https://github.com/mruby/mruby/issues/6648) sprintf buffer overread
|
||||
- [#6649](https://github.com/mruby/mruby/issues/6649) Array#sort! use-after-realloc
|
||||
- [#6650](https://github.com/mruby/mruby/issues/6650) Array#fill validation
|
||||
- [#6652](https://github.com/mruby/mruby/issues/6652) Array comparison use-after-realloc
|
||||
- [#6657](https://github.com/mruby/mruby/issues/6657) Exception handling for ||= on class variables
|
||||
- [#6659](https://github.com/mruby/mruby/issues/6659) Super with keyword arguments
|
||||
- [#6660](https://github.com/mruby/mruby/issues/6660) Regression on struct/array/hash == override with super
|
||||
- [#6662](https://github.com/mruby/mruby/issues/6662) Array set operations use-after-free
|
||||
- [#6664](https://github.com/mruby/mruby/issues/6664) Set#flatten memory leak
|
||||
- [#6666](https://github.com/mruby/mruby/issues/6666) Regexp literal with encoding
|
||||
- [#6668](https://github.com/mruby/mruby/issues/6668) Method#== for aliased methods and comparison bug
|
||||
- [#6671](https://github.com/mruby/mruby/issues/6671) Separate inter-gem headers from external API headers
|
||||
- [#6674](https://github.com/mruby/mruby/issues/6674) Document pattern matching limitations
|
||||
- [#6675](https://github.com/mruby/mruby/issues/6675) Allow Hash#[] to be aliased again
|
||||
- [#6687](https://github.com/mruby/mruby/issues/6687) Expand MRB_SYM/MRB_GVSYM support for symbols with special characters
|
||||
- [#6698](https://github.com/mruby/mruby/issues/6698) Bigint tests fail on architectures other than x86_64 and i386
|
||||
- [#6701](https://github.com/mruby/mruby/issues/6701) Heap-use-after-free in mrb_vm_exec involving mruby-rational / mruby-bigint
|
||||
- [#6702](https://github.com/mruby/mruby/issues/6702) mruby-bigint doesn't compile in C++ project
|
||||
- [#6704](https://github.com/mruby/mruby/issues/6704) Heap-buffer-overflow in mrb_vm_exec via malformed source code
|
||||
- [#6705](https://github.com/mruby/mruby/issues/6705) Can't get outer class of an object in C
|
||||
- [#6713](https://github.com/mruby/mruby/issues/6713) mruby-polarssl not work
|
||||
- [#6720](https://github.com/mruby/mruby/issues/6720) Random float range: different behavior from CRuby
|
||||
- [#6722](https://github.com/mruby/mruby/issues/6722) RBreak size overflow on 32-bit platforms with MRB_NO_BOXING
|
||||
- [#6740](https://github.com/mruby/mruby/issues/6740) `%w()`/`%i()` register pressure with large literals
|
||||
- [#6741](https://github.com/mruby/mruby/issues/6741) `case`/`in` without `else` should raise `NoMatchingPatternError`
|
||||
- [#6760](https://github.com/mruby/mruby/issues/6760) `mrb_gc_unregister()` not removing all matching entries
|
||||
|
||||
# Merged Pull Requests
|
||||
|
||||
- [#6418](https://github.com/mruby/mruby/pull/6418) Add `ls-lint` with GitHub Actions
|
||||
- [#6492](https://github.com/mruby/mruby/pull/6492) fix a typo, update specs
|
||||
- [#6493](https://github.com/mruby/mruby/pull/6493) Fix TYPO in memory.md
|
||||
- [#6495](https://github.com/mruby/mruby/pull/6495) Remove `MRB_ENDIAN_LOHI()` that is no longer in use
|
||||
- [#6497](https://github.com/mruby/mruby/pull/6497) gha: update `build.yml` try `windows-2025` image
|
||||
- [#6498](https://github.com/mruby/mruby/pull/6498) Clean up and standardize the pre-commit config
|
||||
- [#6501](https://github.com/mruby/mruby/pull/6501) Update pre-commit Node.js version to `v22.14.0 LTS`
|
||||
- [#6502](https://github.com/mruby/mruby/pull/6502) pre-commit: update prettier to the latest version
|
||||
- [#6503](https://github.com/mruby/mruby/pull/6503) misc: fix typos
|
||||
- [#6505](https://github.com/mruby/mruby/pull/6505) mrbgems: fix spelling
|
||||
- [#6510](https://github.com/mruby/mruby/pull/6510) Fixed class method visibility via `module_function`
|
||||
- [#6511](https://github.com/mruby/mruby/pull/6511) Exclude the external project "lrama" from pre-commit
|
||||
- [#6513](https://github.com/mruby/mruby/pull/6513) mruby 3.4.0 released
|
||||
- [#6517](https://github.com/mruby/mruby/pull/6517) core/codegen.c: remove unneeded duplicate semicolon
|
||||
- [#6518](https://github.com/mruby/mruby/pull/6518) Change mrbc_args.flags bit width from 2 to 3
|
||||
- [#6519](https://github.com/mruby/mruby/pull/6519) Add `tools/lrama` to `.prettierignore`
|
||||
- [#6520](https://github.com/mruby/mruby/pull/6520) pre-commit: autoupdate and update node LTS version
|
||||
- [#6521](https://github.com/mruby/mruby/pull/6521) Add codespell config file `.codespellrc`
|
||||
- [#6522](https://github.com/mruby/mruby/pull/6522) gha: label more files
|
||||
- [#6523](https://github.com/mruby/mruby/pull/6523) add `rand(Range)` and unify implementations of `Random#rand` and `Kernel#rand`
|
||||
- [#6524](https://github.com/mruby/mruby/pull/6524) Fix Kernel#p when no argument
|
||||
- [#6525](https://github.com/mruby/mruby/pull/6525) Skip adding empty input to mirb history
|
||||
- [#6526](https://github.com/mruby/mruby/pull/6526) Add build config for Luckfox Pico embedded SBC
|
||||
- [#6528](https://github.com/mruby/mruby/pull/6528) misc: fix spelling
|
||||
- [#6530](https://github.com/mruby/mruby/pull/6530) Revert "class.c (find_visibility_scope): when callinfo returns, \*ep == NULL; #6512"
|
||||
- [#6531](https://github.com/mruby/mruby/pull/6531) Improve method table performance by rehashing at 75% load factor
|
||||
- [#6532](https://github.com/mruby/mruby/pull/6532) Reverted method table optimizations to prioritize memory savings
|
||||
- [#6533](https://github.com/mruby/mruby/pull/6533) Fix calling `extended` callback
|
||||
- [#6534](https://github.com/mruby/mruby/pull/6534) Add descriptive comment to mrb_read_float function
|
||||
- [#6535](https://github.com/mruby/mruby/pull/6535) Added descriptive comments for functions/macros in src/mempool.c
|
||||
- [#6536](https://github.com/mruby/mruby/pull/6536) Add descriptive comments to public functions in src/debug.c
|
||||
- [#6537](https://github.com/mruby/mruby/pull/6537) Updated comments in `cdump.c` to remove the `@brief` tag
|
||||
- [#6539](https://github.com/mruby/mruby/pull/6539) Add descriptive comments for functions in src/load.c
|
||||
- [#6540](https://github.com/mruby/mruby/pull/6540) Add descriptive comments to MRB_API functions in object.c
|
||||
- [#6541](https://github.com/mruby/mruby/pull/6541) Add descriptive comments for MRB_API functions in src/array.c
|
||||
- [#6542](https://github.com/mruby/mruby/pull/6542) Add descriptive comments to MRB_API functions in src/symbol.c
|
||||
- [#6543](https://github.com/mruby/mruby/pull/6543) Add descriptive comments to several functions in src/dump.c
|
||||
- [#6544](https://github.com/mruby/mruby/pull/6544) Fix build strings that must be mutable
|
||||
- [#6545](https://github.com/mruby/mruby/pull/6545) Add descriptive comments for MRB_API functions in src/class.c
|
||||
- [#6548](https://github.com/mruby/mruby/pull/6548) Add descriptive comments to MRB_API functions in src/etc.c
|
||||
- [#6549](https://github.com/mruby/mruby/pull/6549) Add descriptive comments to kernel functions
|
||||
- [#6550](https://github.com/mruby/mruby/pull/6550) Add descriptive comments for MRB_API functions in src/proc.c
|
||||
- [#6551](https://github.com/mruby/mruby/pull/6551) Add descriptive comments for MRB_API functions in src/state.c
|
||||
- [#6552](https://github.com/mruby/mruby/pull/6552) Fix: Correct placement of comments in src/variable.c
|
||||
- [#6553](https://github.com/mruby/mruby/pull/6553) Add descriptive comments for MRB_API functions in src/vm.c
|
||||
- [#6555](https://github.com/mruby/mruby/pull/6555) `mrb_mt_foreach()` needs to update the pointer at each loop
|
||||
- [#6556](https://github.com/mruby/mruby/pull/6556) `iv_foreach()` needs to update the pointer at each loop
|
||||
- [#6560](https://github.com/mruby/mruby/pull/6560) Refactor: Improve Set GC marking and freeing
|
||||
- [#6561](https://github.com/mruby/mruby/pull/6561) pre-commit updates and fix prettier entrypoint
|
||||
- [#6562](https://github.com/mruby/mruby/pull/6562) misc: fix spelling word case
|
||||
- [#6563](https://github.com/mruby/mruby/pull/6563) pre-commit add rubocop with one rule spaces for indentation
|
||||
- [#6564](https://github.com/mruby/mruby/pull/6564) Remove jumanjihouse pre-commit hooks no longer maintained
|
||||
- [#6565](https://github.com/mruby/mruby/pull/6565) Rubocop: fix target Ruby version; add two more cops; fix lint error
|
||||
- [#6566](https://github.com/mruby/mruby/pull/6566) Removed unreferenced variables in `CrossBuild#run_bintest`
|
||||
- [#6567](https://github.com/mruby/mruby/pull/6567) Avoid array object creation in `cmd_bin` method in bintest
|
||||
- [#6568](https://github.com/mruby/mruby/pull/6568) mruby-bin-debugger depends on mruby-bin-mrbc in bintest
|
||||
- [#6569](https://github.com/mruby/mruby/pull/6569) sed s/Mruby/MRuby/g
|
||||
- [#6571](https://github.com/mruby/mruby/pull/6571) Update limitations.md to add behavior on small hash
|
||||
- [#6572](https://github.com/mruby/mruby/pull/6572) Add Claude Code GitHub Workflow
|
||||
- [#6573](https://github.com/mruby/mruby/pull/6573) pre-commit fixes and updates
|
||||
- [#6574](https://github.com/mruby/mruby/pull/6574) Support initializing structs via keyword arguments
|
||||
- [#6575](https://github.com/mruby/mruby/pull/6575) Fix typo in file time methods
|
||||
- [#6581](https://github.com/mruby/mruby/pull/6581) Merge `mrb_obj_iv_inspect()` into `mrb_obj_inspect()`
|
||||
- [#6582](https://github.com/mruby/mruby/pull/6582) Stricter type tag in `mrb_obj_alloc()`
|
||||
- [#6583](https://github.com/mruby/mruby/pull/6583) Add fallback to local build_config.rb before using default configuration
|
||||
- [#6585](https://github.com/mruby/mruby/pull/6585) Fix typo in mruby3.2 docs
|
||||
- [#6586](https://github.com/mruby/mruby/pull/6586) Makefile: refactor add docs and add command line `help` target
|
||||
- [#6587](https://github.com/mruby/mruby/pull/6587) Add Set#hash tests
|
||||
- [#6588](https://github.com/mruby/mruby/pull/6588) Add CodeQL Analysis for GitHub Actions
|
||||
- [#6589](https://github.com/mruby/mruby/pull/6589) Add pre-commit hook `check-zip-file-is-not-committed`
|
||||
- [#6591](https://github.com/mruby/mruby/pull/6591) mruby-eval fix license link in README
|
||||
- [#6593](https://github.com/mruby/mruby/pull/6593) README: Add Contributors Avatars, Star History, Table of Contents
|
||||
- [#6598](https://github.com/mruby/mruby/pull/6598) Fix heap buffer overflow in `#method_missing`
|
||||
- [#6599](https://github.com/mruby/mruby/pull/6599) pre-commit: run `markdown-link-check`, `oxipng`, `prettier` manually
|
||||
- [#6600](https://github.com/mruby/mruby/pull/6600) `dreamcast_shelf build config`: update to use KallistiOS wrappers
|
||||
- [#6601](https://github.com/mruby/mruby/pull/6601) fix: skip local build_config.rb when working in MRUBY_ROOT
|
||||
- [#6602](https://github.com/mruby/mruby/pull/6602) Improved iseq annotations for `new` and `!=`
|
||||
- [#6604](https://github.com/mruby/mruby/pull/6604) pre-commit config updates
|
||||
- [#6607](https://github.com/mruby/mruby/pull/6607) fix bigint on raspberry pi
|
||||
- [#6610](https://github.com/mruby/mruby/pull/6610) Extract golden ratio prime into constant
|
||||
- [#6614](https://github.com/mruby/mruby/pull/6614) Fix uninitialized variable in io_gets causing segmentation fault
|
||||
- [#6617](https://github.com/mruby/mruby/pull/6617) Fix various minor problems and speed up build
|
||||
- [#6618](https://github.com/mruby/mruby/pull/6618) Stop generating unnecessary C++ files in mruby-bin-mruby
|
||||
- [#6621](https://github.com/mruby/mruby/pull/6621) Set up all GEMS before mruby core tasks definition
|
||||
- [#6624](https://github.com/mruby/mruby/pull/6624) Fixed wrong `MRuby::Build.current` at the top level of `mrbgem.rake`
|
||||
- [#6628](https://github.com/mruby/mruby/pull/6628) Revert `File.absolute_path` logic
|
||||
- [#6629](https://github.com/mruby/mruby/pull/6629) pre-commit update
|
||||
- [#6631](https://github.com/mruby/mruby/pull/6631) Revert "Rakefile: make the whole thing parallel unless SERIAL=1"
|
||||
- [#6633](https://github.com/mruby/mruby/pull/6633) Fix a heap-buffer-overflow in str strip! methods
|
||||
- [#6643](https://github.com/mruby/mruby/pull/6643) Fix crash caused by an incorrect node type check in `codegen_masgn`
|
||||
- [#6651](https://github.com/mruby/mruby/pull/6651) Address stack-use-after-return in the mruby bigint implementation
|
||||
- [#6653](https://github.com/mruby/mruby/pull/6653) Improve HAL-related components for MinGW
|
||||
- [#6655](https://github.com/mruby/mruby/pull/6655) Preventing Memory Leaks in `Array#__combination_init`
|
||||
- [#6656](https://github.com/mruby/mruby/pull/6656) Fix integer overflow in allocation size calculation
|
||||
- [#6663](https://github.com/mruby/mruby/pull/6663) Added the `kh_is_end()` macro function
|
||||
- [#6665](https://github.com/mruby/mruby/pull/6665) Fixed use-after-free with `Set#join`
|
||||
- [#6670](https://github.com/mruby/mruby/pull/6670) Arranging VM dispatch macros
|
||||
- [#6673](https://github.com/mruby/mruby/pull/6673) Adjust broken license links; clean up Markdown
|
||||
- [#6677](https://github.com/mruby/mruby/pull/6677) gha: run pre-commit with `--color=always`
|
||||
- [#6678](https://github.com/mruby/mruby/pull/6678) Put ls-lint and pre-commit in separate workflow files
|
||||
- [#6679](https://github.com/mruby/mruby/pull/6679) pre-commit autoupdate; update node and prettier
|
||||
- [#6681](https://github.com/mruby/mruby/pull/6681) Add Cosmopolitan Libc build configuration
|
||||
- [#6689](https://github.com/mruby/mruby/pull/6689) docs: fix pre-commit manual hooks; fix link
|
||||
- [#6694](https://github.com/mruby/mruby/pull/6694) Fix mirb build under Cosmopolitan
|
||||
- [#6695](https://github.com/mruby/mruby/pull/6695) Dependabot: add a cooldown period for new releases
|
||||
- [#6696](https://github.com/mruby/mruby/pull/6696) Fix parse error with required kwargs and omitted parens
|
||||
- [#6699](https://github.com/mruby/mruby/pull/6699) Fix mruby-task for PicoRuby Integration
|
||||
- [#6700](https://github.com/mruby/mruby/pull/6700) Fix float/double pack/unpack on s390x
|
||||
- [#6706](https://github.com/mruby/mruby/pull/6706) Refactor task class to use symbol IDs
|
||||
- [#6708](https://github.com/mruby/mruby/pull/6708) `initialize_copy` and `respond_to_missing?` defined as private
|
||||
- [#6709](https://github.com/mruby/mruby/pull/6709) Add the `MRB_ENSURE()` macro
|
||||
- [#6711](https://github.com/mruby/mruby/pull/6711) Fix out of bounds read and write in IO.select
|
||||
- [#6714](https://github.com/mruby/mruby/pull/6714) Fix OP_DEBUG operand type and add NULL check for debug_op_hook
|
||||
- [#6716](https://github.com/mruby/mruby/pull/6716) Fixes identity for proc object
|
||||
- [#6717](https://github.com/mruby/mruby/pull/6717) Fix mruby-task: wrapping by critical section and setting initial task receiver
|
||||
- [#6718](https://github.com/mruby/mruby/pull/6718) Add installation instructions for conda and Homebrew
|
||||
- [#6723](https://github.com/mruby/mruby/pull/6723) Add `RInteger` and `RFloat` to `RVALUE`
|
||||
- [#6727](https://github.com/mruby/mruby/pull/6727) Language documentation: update wording of "overloading" section
|
||||
- [#6729](https://github.com/mruby/mruby/pull/6729) Simplifying dependency addition for gensym task
|
||||
- [#6730](https://github.com/mruby/mruby/pull/6730) Simplifying presym file generation actions
|
||||
- [#6733](https://github.com/mruby/mruby/pull/6733) Include `mruby/presym.h` for all source files
|
||||
- [#6734](https://github.com/mruby/mruby/pull/6734) Chunk array literals at 64 elements to reduce register pressure
|
||||
- [#6735](https://github.com/mruby/mruby/pull/6735) Prevent full recompilation without changes to presym file
|
||||
- [#6739](https://github.com/mruby/mruby/pull/6739) Fix MSYS2 build error with drive letters
|
||||
- [#6743](https://github.com/mruby/mruby/pull/6743) Chunk `%w()` and `%i()` literals to reduce register pressure
|
||||
- [#6744](https://github.com/mruby/mruby/pull/6744) Raise `NoMatchingPatternError` in `case`/`in` without `else`
|
||||
- [#6747](https://github.com/mruby/mruby/pull/6747) Correctly handle empty hash as default named argument
|
||||
- [#6749](https://github.com/mruby/mruby/pull/6749) Fix microcontroller profile
|
||||
- [#6750](https://github.com/mruby/mruby/pull/6750) Fix out-of-bounds read and divide-by-zero in `Array#product`
|
||||
- [#6752](https://github.com/mruby/mruby/pull/6752) Fix `attr_reader`-generated methods accepting extra arguments
|
||||
- [#6753](https://github.com/mruby/mruby/pull/6753) Further optimize `Array#product`
|
||||
- [#6754](https://github.com/mruby/mruby/pull/6754) Mark `attr_reader` procs as noarg
|
||||
- [#6755](https://github.com/mruby/mruby/pull/6755) Reload `ci` after `mrb_hash_delete_key()` in keyword argument handling
|
||||
- [#6756](https://github.com/mruby/mruby/pull/6756) Avoid impact of object modifications caused by `mrb_vm_exec()` calls
|
||||
- [#6758](https://github.com/mruby/mruby/pull/6758) Don't assign result of `mrb_funcall()` directly to `regs`
|
||||
- [#6759](https://github.com/mruby/mruby/pull/6759) Define `mrb_bigint_p()` always
|
||||
- [#6761](https://github.com/mruby/mruby/pull/6761) Fix `mrb_gc_unregister()` to remove all matching entries
|
||||
- [#6762](https://github.com/mruby/mruby/pull/6762) Write generated test C files atomically to avoid build race condition
|
||||
- [#6765](https://github.com/mruby/mruby/pull/6765) Fix `Lazy#flat_map` to handle non-enumerable block return values
|
||||
- [#6767](https://github.com/mruby/mruby/pull/6767) Allow compound statement in parenthesized argument context
|
||||
- [#6780](https://github.com/mruby/mruby/pull/6780) Fix `String#prepend` with self-referencing arguments
|
||||
- [#6781](https://github.com/mruby/mruby/pull/6781) Protect `sprintf` format string from mutation during callbacks
|
||||
- [#6783](https://github.com/mruby/mruby/pull/6783) Pin GitHub Actions workflows to commit hashes
|
||||
|
||||
# Security Fixes
|
||||
|
||||
- Buffer overflow in bigint uadd ([3f2611e](https://github.com/mruby/mruby/commit/3f2611e))
|
||||
- Stack buffer overflow in Montgomery reduction ([edce0a3](https://github.com/mruby/mruby/commit/edce0a3))
|
||||
- Buffer overflow in pack_uu encoding ([2993302](https://github.com/mruby/mruby/commit/2993302))
|
||||
- Buffer overflow in IO#ungetc ([01ab2ff](https://github.com/mruby/mruby/commit/01ab2ff))
|
||||
- Heap-buffer-overflow in pattern alternation codegen ([eea9e30](https://github.com/mruby/mruby/commit/eea9e30))
|
||||
- Out of bounds read and write in IO.select ([44831711](https://github.com/mruby/mruby/commit/44831711))
|
||||
- Off-by-one in bounds check for symbol names and pool strings in load.c ([b3b8c01](https://github.com/mruby/mruby/commit/b3b8c01))
|
||||
- Use-after-free in Set operations ([a6b55e7](https://github.com/mruby/mruby/commit/a6b55e7))
|
||||
- Use-after-free in Array set operations ([729b84c](https://github.com/mruby/mruby/commit/729b84c))
|
||||
- Use-after-free in Set#join ([0e653eb](https://github.com/mruby/mruby/commit/0e653eb))
|
||||
- Use-after-realloc in Array#sort! ([eb39897](https://github.com/mruby/mruby/commit/eb39897))
|
||||
- Heap-use-after-free in insertion_sort ([099d2c47](https://github.com/mruby/mruby/commit/099d2c47))
|
||||
- Integer overflow in str_check_length ([6afff1c3](https://github.com/mruby/mruby/commit/6afff1c3))
|
||||
- Integer overflow in Integer#lcm ([070bef24](https://github.com/mruby/mruby/commit/070bef24))
|
||||
- Heap buffer overflow in `#method_missing` ([550d10a](https://github.com/mruby/mruby/commit/550d10a))
|
||||
- Out-of-bounds read and divide-by-zero in `Array#product` ([8441eaf](https://github.com/mruby/mruby/commit/8441eaf))
|
||||
- Heap buffer overflow in `String#prepend` with self-referencing arguments ([18ba026](https://github.com/mruby/mruby/commit/18ba026))
|
||||
- Use-after-free in `sprintf` via `to_s` callback mutating format string ([48fc422](https://github.com/mruby/mruby/commit/48fc422))
|
||||
- Multiple memory leak fixes in bigint, Set, Array, and Task gems
|
||||
+4
-11
@@ -138,8 +138,8 @@
|
||||
/* turn off generational GC by default */
|
||||
//#define MRB_GC_TURN_OFF_GENERATIONAL
|
||||
|
||||
/* initial size of khash table bucket */
|
||||
//#define KHASH_INITIAL_SIZE 32
|
||||
/* default size of khash table bucket */
|
||||
//#define KHASH_DEFAULT_SIZE 32
|
||||
|
||||
/* allocated memory address alignment */
|
||||
//#define POOL_ALIGNMENT 4
|
||||
@@ -172,13 +172,6 @@
|
||||
#define MRB_SYMBOL_LINEAR_THRESHOLD 256
|
||||
#endif
|
||||
|
||||
/* Maximum number of dynamic symbols (created at runtime via to_sym etc.)
|
||||
Presyms, inline symbols, and mrb_intern_static symbols are excluded.
|
||||
Set to 0 to disable the limit. */
|
||||
#ifndef MRB_SYMBOL_MAX
|
||||
#define MRB_SYMBOL_MAX 4096
|
||||
#endif
|
||||
|
||||
/* obsolete configurations */
|
||||
#if defined(DISABLE_STDIO) || defined(MRB_DISABLE_STDIO)
|
||||
# define MRB_NO_STDIO
|
||||
@@ -215,8 +208,8 @@
|
||||
# define MRB_NO_METHOD_CACHE
|
||||
# endif
|
||||
|
||||
# ifndef KHASH_INITIAL_SIZE
|
||||
# define KHASH_INITIAL_SIZE 16
|
||||
# ifndef KHASH_DEFAULT_SIZE
|
||||
# define KHASH_DEFAULT_SIZE 16
|
||||
# endif
|
||||
|
||||
# ifndef MRB_HEAP_PAGE_SIZE
|
||||
|
||||
+9
-54
@@ -113,8 +113,6 @@
|
||||
|
||||
#include "mrbconf.h"
|
||||
|
||||
typedef struct mrb_state mrb_state;
|
||||
|
||||
#include <mruby/common.h>
|
||||
#include <mruby/value.h>
|
||||
#include <mruby/gc.h>
|
||||
@@ -158,6 +156,8 @@ typedef uint32_t mrb_aspec;
|
||||
|
||||
typedef struct mrb_irep mrb_irep;
|
||||
|
||||
struct mrb_state;
|
||||
|
||||
#ifndef MRB_FIXED_STATE_ATEXIT_STACK_SIZE
|
||||
#define MRB_FIXED_STATE_ATEXIT_STACK_SIZE 5
|
||||
#endif
|
||||
@@ -224,7 +224,7 @@ mrb_static_assert_powerof2(MRB_METHOD_CACHE_SIZE);
|
||||
* @param self The self object
|
||||
* @return [mrb_value] The function's return value
|
||||
*/
|
||||
typedef mrb_value (*mrb_func_t)(mrb_state *mrb, mrb_value self);
|
||||
typedef mrb_value (*mrb_func_t)(struct mrb_state *mrb, mrb_value self);
|
||||
|
||||
typedef struct {
|
||||
uint32_t flags; /* method flags (no symbol packed) */
|
||||
@@ -243,26 +243,9 @@ struct mrb_cache_entry {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef MRB_CONST_CACHE_SIZE
|
||||
# undef MRB_NO_CONST_CACHE
|
||||
mrb_static_assert_powerof2(MRB_CONST_CACHE_SIZE);
|
||||
#else
|
||||
/* default constant cache size: 64 */
|
||||
/* cache size needs to be power of 2 */
|
||||
# define MRB_CONST_CACHE_SIZE (1<<6)
|
||||
#endif
|
||||
|
||||
#ifndef MRB_NO_CONST_CACHE
|
||||
struct mrb_const_cache_entry {
|
||||
const struct mrb_irep *irep;
|
||||
mrb_sym sym;
|
||||
mrb_value value;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mrb_jmpbuf;
|
||||
|
||||
typedef void (*mrb_atexit_func)(mrb_state*);
|
||||
typedef void (*mrb_atexit_func)(struct mrb_state*);
|
||||
|
||||
#ifdef MRB_USE_TASK_SCHEDULER
|
||||
struct mrb_task;
|
||||
@@ -274,12 +257,10 @@ typedef struct mrb_task_state {
|
||||
volatile mrb_bool switching; /* Context switch pending flag */
|
||||
struct mrb_task *main_task; /* Main task wrapper for root context */
|
||||
uint8_t scheduler_lock; /* Lock counter for synchronous execution */
|
||||
mrb_bool loop_running; /* Active mrb_task_run loop flag */
|
||||
mrb_bool exception_as_result; /* Return unhandled task exceptions as values */
|
||||
} mrb_task_state;
|
||||
#endif
|
||||
|
||||
struct mrb_state {
|
||||
typedef struct mrb_state {
|
||||
struct mrb_jmpbuf *jmp;
|
||||
|
||||
struct mrb_context *c;
|
||||
@@ -316,28 +297,22 @@ struct mrb_state {
|
||||
struct mrb_cache_entry cache[MRB_METHOD_CACHE_SIZE];
|
||||
#endif
|
||||
|
||||
#ifndef MRB_NO_CONST_CACHE
|
||||
struct mrb_const_cache_entry const_cache[MRB_CONST_CACHE_SIZE];
|
||||
#endif
|
||||
|
||||
mrb_sym symidx;
|
||||
const char **symtbl;
|
||||
uint8_t *sym_flags; /* per-symbol flags (SYM_FL_*) */
|
||||
size_t symcapa;
|
||||
struct mrb_sym_hash_table *symhash;
|
||||
void *sym_pool;
|
||||
mrb_sym dynamic_sym_count; /* count of dynamic (GC-candidate) symbols */
|
||||
#ifndef MRB_USE_ALL_SYMBOLS
|
||||
char symbuf[8]; /* buffer for small symbol names */
|
||||
#endif
|
||||
|
||||
#ifdef MRB_USE_DEBUG_HOOK
|
||||
void (*code_fetch_hook)(mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
|
||||
void (*debug_op_hook)(mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
|
||||
void (*code_fetch_hook)(struct mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
|
||||
void (*debug_op_hook)(struct mrb_state* mrb, const struct mrb_irep *irep, const mrb_code *pc, mrb_value *regs);
|
||||
#endif
|
||||
|
||||
#ifdef MRB_BYTECODE_DECODE_OPTION
|
||||
mrb_code (*bytecode_decoder)(mrb_state* mrb, mrb_code code);
|
||||
mrb_code (*bytecode_decoder)(struct mrb_state* mrb, mrb_code code);
|
||||
#endif
|
||||
|
||||
struct RClass *eException_class;
|
||||
@@ -364,7 +339,7 @@ struct mrb_state {
|
||||
#ifdef MRB_USE_TASK_SCHEDULER
|
||||
mrb_task_state task; /* Task scheduler state */
|
||||
#endif
|
||||
};
|
||||
} mrb_state;
|
||||
|
||||
/**
|
||||
* Defines a new class.
|
||||
@@ -1184,21 +1159,6 @@ MRB_API mrb_value mrb_funcall_id(mrb_state *mrb, mrb_value val, mrb_sym mid, mrb
|
||||
* @see mrb_funcall
|
||||
*/
|
||||
MRB_API mrb_value mrb_funcall_argv(mrb_state *mrb, mrb_value val, mrb_sym name, mrb_int argc, const mrb_value *argv);
|
||||
/*
|
||||
* Convenience wrappers for `mrb_funcall_argv` with a fixed argument count.
|
||||
* Avoids the 16-slot fixed argv buffer used by the variadic `mrb_funcall_id`.
|
||||
*/
|
||||
MRB_INLINE mrb_value
|
||||
mrb_funcall_argv1(mrb_state *mrb, mrb_value val, mrb_sym name, mrb_value a1)
|
||||
{
|
||||
return mrb_funcall_argv(mrb, val, name, 1, &a1);
|
||||
}
|
||||
MRB_INLINE mrb_value
|
||||
mrb_funcall_argv2(mrb_state *mrb, mrb_value val, mrb_sym name, mrb_value a1, mrb_value a2)
|
||||
{
|
||||
const mrb_value argv[] = { a1, a2 };
|
||||
return mrb_funcall_argv(mrb, val, name, 2, argv);
|
||||
}
|
||||
/**
|
||||
* Call existing Ruby functions with a block.
|
||||
*/
|
||||
@@ -1324,11 +1284,6 @@ MRB_API void mrb_method_cache_clear(mrb_state *mrb);
|
||||
#else
|
||||
#define mrb_method_cache_clear(mrb) ((void)0)
|
||||
#endif
|
||||
#ifndef MRB_NO_CONST_CACHE
|
||||
MRB_API void mrb_const_cache_clear(mrb_state *mrb);
|
||||
#else
|
||||
#define mrb_const_cache_clear(mrb) ((void)0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Check if mrb_open() failed
|
||||
|
||||
+2
-24
@@ -20,17 +20,7 @@ typedef struct mrb_shared_array {
|
||||
mrb_value *ptr;
|
||||
} mrb_shared_array;
|
||||
|
||||
/* On 32-bit platforms whose ABI gives 8-byte members 8-byte alignment
|
||||
(ARM, MIPS, xtensa, ...), an embedded mrb_value array forces 8-byte
|
||||
alignment of the inner union, padding the heap-form layout and
|
||||
inflating struct size past the 5-word RVALUE limit. Disable embedding
|
||||
whenever mrb_value contains an 8-byte aligned member: nan-boxing
|
||||
(uint64_t), or no-boxing with int64_t/double inside the union. */
|
||||
#if defined(MRB_32BIT) && \
|
||||
(defined(MRB_NAN_BOXING) || \
|
||||
(defined(MRB_NO_BOXING) && \
|
||||
(!defined(MRB_USE_FLOAT32) || defined(MRB_INT64)))) && \
|
||||
!defined(MRB_ARY_NO_EMBED)
|
||||
#if defined(MRB_32BIT) && defined(MRB_NO_BOXING) && (!defined(MRB_USE_FLOAT32) || defined(MRB_INT64)) && !defined(MRB_ARY_NO_EMBED)
|
||||
# define MRB_ARY_NO_EMBED
|
||||
#endif
|
||||
|
||||
@@ -67,7 +57,7 @@ struct RArray {
|
||||
#define ARY_UNSET_EMBED_FLAG(a) (void)0
|
||||
#define ARY_EMBED_LEN(a) 0
|
||||
#define ARY_SET_EMBED_LEN(a,len) (void)0
|
||||
#define ARY_EMBED_PTR(a) ((mrb_value*)NULL)
|
||||
#define ARY_EMBED_PTR(a) 0
|
||||
#else
|
||||
#define MRB_ARY_EMBED_MASK 7
|
||||
#define ARY_EMBED_P(a) ((a)->flags & MRB_ARY_EMBED_MASK)
|
||||
@@ -81,7 +71,6 @@ struct RArray {
|
||||
#define ARY_PTR(a) (ARY_EMBED_P(a)?ARY_EMBED_PTR(a):(a)->as.heap.ptr)
|
||||
#define RARRAY_LEN(a) ARY_LEN(RARRAY(a))
|
||||
#define RARRAY_PTR(a) ARY_PTR(RARRAY(a))
|
||||
#define RARRAY_GETMEM(a, ptr, len) ARY_GETMEM(RARRAY(a), ptr, len)
|
||||
#define ARY_SET_LEN(a,n) do {\
|
||||
if (ARY_EMBED_P(a)) {\
|
||||
mrb_assert((n) <= MRB_ARY_EMBED_LEN_MAX); \
|
||||
@@ -95,17 +84,6 @@ struct RArray {
|
||||
#define ARY_SHARED_P(a) ((a)->flags & MRB_ARY_SHARED)
|
||||
#define ARY_SET_SHARED_FLAG(a) ((a)->flags |= MRB_ARY_SHARED)
|
||||
#define ARY_UNSET_SHARED_FLAG(a) ((a)->flags &= ~MRB_ARY_SHARED)
|
||||
#define ARY_GETMEM(a, ptr, len) do { \
|
||||
struct RArray *MRB_UNIQNAME(_a_) = (a); \
|
||||
if (ARY_EMBED_P(MRB_UNIQNAME(_a_))) { \
|
||||
(len) = ARY_EMBED_LEN(MRB_UNIQNAME(_a_)); \
|
||||
(ptr) = ARY_EMBED_PTR(MRB_UNIQNAME(_a_)); \
|
||||
} \
|
||||
else { \
|
||||
(len) = MRB_UNIQNAME(_a_)->as.heap.len; \
|
||||
(ptr) = MRB_UNIQNAME(_a_)->as.heap.ptr; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
MRB_API void mrb_ary_modify(mrb_state*, struct RArray*);
|
||||
MRB_API mrb_value mrb_ary_dup(mrb_state*, mrb_value ary);
|
||||
|
||||
@@ -103,8 +103,7 @@ mrb_unboxed_type(mrb_value o)
|
||||
{
|
||||
if (!mrb_float_p(o) && mrb_nb_tt(o) == MRB_NANBOX_TT_OBJECT && o.u != 0) {
|
||||
return ((struct RBasic*)(uintptr_t)o.u)->tt;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return MRB_TT_FALSE;
|
||||
}
|
||||
}
|
||||
@@ -151,7 +150,7 @@ mrb_nan_boxing_value_int(mrb_value v)
|
||||
#define SET_TRUE_VALUE(r) NANBOX_SET_MISC_VALUE(r, MRB_TT_TRUE, 1)
|
||||
#define SET_BOOL_VALUE(r,b) NANBOX_SET_MISC_VALUE(r, (b) ? MRB_TT_TRUE : MRB_TT_FALSE, 1)
|
||||
#ifdef MRB_INT64
|
||||
MRB_API mrb_value mrb_boxing_int_value(mrb_state*, mrb_int);
|
||||
MRB_API mrb_value mrb_boxing_int_value(struct mrb_state*, mrb_int);
|
||||
#define SET_INT_VALUE(mrb, r, n) ((r) = mrb_boxing_int_value(mrb, n))
|
||||
#else
|
||||
#define SET_INT_VALUE(mrb, r, n) SET_FIXNUM_VALUE(r, n)
|
||||
|
||||
@@ -165,11 +165,11 @@ mrb_val_union(mrb_value v)
|
||||
return x;
|
||||
}
|
||||
|
||||
MRB_API mrb_value mrb_word_boxing_cptr_value(mrb_state*, void*);
|
||||
MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*);
|
||||
#ifndef MRB_NO_FLOAT
|
||||
MRB_API mrb_value mrb_word_boxing_float_value(mrb_state*, mrb_float);
|
||||
MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float);
|
||||
#endif
|
||||
MRB_API mrb_value mrb_boxing_int_value(mrb_state*, mrb_int);
|
||||
MRB_API mrb_value mrb_boxing_int_value(struct mrb_state*, mrb_int);
|
||||
|
||||
#if WORDBOX_IMMEDIATE_MASK == 0x3
|
||||
#define mrb_immediate_p(o) ((o).w & WORDBOX_IMMEDIATE_MASK || (o).w <= MRB_Qundef)
|
||||
@@ -266,11 +266,9 @@ mrb_unboxed_type(mrb_value o)
|
||||
{
|
||||
if (mrb_nil_p(o)) {
|
||||
return MRB_TT_FALSE;
|
||||
}
|
||||
else if ((o.w & WORDBOX_IMMEDIATE_MASK) == 0) {
|
||||
} else if ((o.w & WORDBOX_IMMEDIATE_MASK) == 0) {
|
||||
return mrb_val_union(o).bp->tt;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
return MRB_TT_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,13 +100,10 @@ void mrb_mc_clear_by_class(mrb_state *mrb, struct RClass* c);
|
||||
typedef int (mrb_mt_foreach_func)(mrb_state*,mrb_sym,mrb_method_t,void*);
|
||||
MRB_API void mrb_mt_foreach(mrb_state*, struct RClass*, mrb_mt_foreach_func*, void*);
|
||||
|
||||
/* ROM method table types for static method registration.
|
||||
* NOTE: `func` is kept as the first union member so that positional
|
||||
* aggregate initialization in MRB_MT_ENTRY works without C99
|
||||
* designated initializers (required for legacy C++ compilers). */
|
||||
/* ROM method table types for static method registration */
|
||||
union mrb_mt_ptr {
|
||||
mrb_func_t func;
|
||||
const struct RProc *proc;
|
||||
mrb_func_t func;
|
||||
};
|
||||
|
||||
/* entry combining function pointer, symbol key, and flags */
|
||||
@@ -131,7 +128,7 @@ typedef struct mrb_mt_tbl {
|
||||
|
||||
/* ROM table entry: 3rd param is MRB_ARGS_*() optionally OR'd with MRB_MT_PRIVATE. */
|
||||
#define MRB_MT_ENTRY(fn, sym, flags) \
|
||||
{ { (fn) }, (sym), (flags) | MRB_MT_FUNC }
|
||||
{ { .func = (fn) }, (sym), (flags) | MRB_MT_FUNC }
|
||||
#define MRB_MT_ASPEC(flags) ((mrb_aspec)((flags) & 0xffffff))
|
||||
|
||||
/* "removed" tombstone: MRB_MT_FUNC flag set with NULL function pointer.
|
||||
|
||||
@@ -134,7 +134,6 @@ struct mrb_parser_state {
|
||||
mrb_sym* filename_table;
|
||||
uint16_t filename_table_length;
|
||||
uint16_t current_filename_index;
|
||||
uint16_t prev_file_lineno; /* saved lineno before partial_hook file switch */
|
||||
|
||||
/* Variable-sized node management */
|
||||
mrb_ast_node *nvars;
|
||||
|
||||
+6
-27
@@ -37,14 +37,7 @@ MRB_API mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value st
|
||||
#define mrb_exc_new_lit(mrb, c, lit) mrb_exc_new_str(mrb, c, mrb_str_new_lit(mrb, lit))
|
||||
MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, const char *fmt, ...);
|
||||
|
||||
/* On 32-bit platforms whose ABI gives uint64_t/double 8-byte alignment
|
||||
(ARM, MIPS, PowerPC, xtensa, ...), embedding mrb_value directly in
|
||||
RBreak forces 8-byte alignment that pushes the struct past the 5-word
|
||||
RVALUE budget via padding. Store the value bits as a uint32_t array
|
||||
(4-byte aligned) to dodge that padding. Word-boxing's mrb_value is
|
||||
just a uintptr_t with no over-alignment, and 64-bit platforms have no
|
||||
alignment gap to begin with, so neither needs the workaround. */
|
||||
#if defined(MRB_64BIT) || defined(MRB_WORD_BOXING)
|
||||
#if defined(MRB_NAN_BOXING) || defined(MRB_WORD_BOXING) || defined(MRB_64BIT)
|
||||
#undef MRB_USE_RBREAK_VALUE_UNION
|
||||
#else
|
||||
#define MRB_USE_RBREAK_VALUE_UNION 1
|
||||
@@ -52,8 +45,7 @@ MRB_API mrb_noreturn void mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_va
|
||||
|
||||
/*
|
||||
* flags:
|
||||
* 0..7: enum mrb_vtype (only when MRB_USE_RBREAK_VALUE_UNION and
|
||||
* !MRB_NAN_BOXING; nan-boxing encodes the type in the bits)
|
||||
* 0..7: enum mrb_vtype (only when defined MRB_USE_RBREAK_VALUE_UNION)
|
||||
* 8..10: RBREAK_TAGs in src/vm.c (otherwise, set to 0)
|
||||
*/
|
||||
struct RBreak {
|
||||
@@ -61,11 +53,11 @@ struct RBreak {
|
||||
uintptr_t ci_break_index; // The top-level ci index to break. One before the return destination.
|
||||
#ifndef MRB_USE_RBREAK_VALUE_UNION
|
||||
mrb_value val;
|
||||
#elif defined(MRB_NAN_BOXING)
|
||||
/* nan-boxing: mrb_value is a single 64-bit word (type encoded in NaN bits) */
|
||||
uint32_t value[sizeof(mrb_value) / sizeof(uint32_t)];
|
||||
#else
|
||||
/* no-boxing: store only the union bits; tt goes in flags */
|
||||
/* Store value as uint32_t words instead of union mrb_value_union
|
||||
to avoid 8-byte alignment of int64_t/double on 32-bit platforms
|
||||
(e.g., ARM, MIPS, PowerPC) which would inflate struct size beyond
|
||||
the 5-word RVALUE limit due to padding. */
|
||||
uint32_t value[sizeof(union mrb_value_union) / sizeof(uint32_t)];
|
||||
#endif
|
||||
};
|
||||
@@ -73,19 +65,6 @@ struct RBreak {
|
||||
#ifndef MRB_USE_RBREAK_VALUE_UNION
|
||||
#define mrb_break_value_get(brk) ((brk)->val)
|
||||
#define mrb_break_value_set(brk, v) ((brk)->val = v)
|
||||
#elif defined(MRB_NAN_BOXING)
|
||||
static inline mrb_value
|
||||
mrb_break_value_get(struct RBreak *brk)
|
||||
{
|
||||
mrb_value val;
|
||||
memcpy(&val, brk->value, sizeof(val));
|
||||
return val;
|
||||
}
|
||||
static inline void
|
||||
mrb_break_value_set(struct RBreak *brk, mrb_value val)
|
||||
{
|
||||
memcpy(brk->value, &val, sizeof(val));
|
||||
}
|
||||
#else
|
||||
#define RBREAK_VALUE_TT_MASK ((1 << 8) - 1)
|
||||
static inline mrb_value
|
||||
|
||||
+9
-15
@@ -14,12 +14,15 @@
|
||||
*/
|
||||
MRB_BEGIN_DECL
|
||||
|
||||
|
||||
struct mrb_state;
|
||||
|
||||
#define MRB_EACH_OBJ_OK 0
|
||||
#define MRB_EACH_OBJ_BREAK 1
|
||||
typedef int (mrb_each_object_callback)(mrb_state *mrb, struct RBasic *obj, void *data);
|
||||
void mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, void *data);
|
||||
typedef int (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data);
|
||||
void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data);
|
||||
size_t mrb_objspace_page_slot_size(void);
|
||||
MRB_API void mrb_free_context(mrb_state *mrb, struct mrb_context *c);
|
||||
MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c);
|
||||
|
||||
#ifndef MRB_GC_ARENA_SIZE
|
||||
#define MRB_GC_ARENA_SIZE 100
|
||||
@@ -45,7 +48,7 @@ typedef struct mrb_gc {
|
||||
mrb_bool gray_overflow:1; /* gray stack overflowed; needs heap rescan */
|
||||
size_t live; /* count of live objects */
|
||||
size_t live_after_mark; /* old generation objects */
|
||||
mrb_int gc_debt; /* <0:credit, >0:needs GC */
|
||||
size_t threshold; /* threshold to start GC */
|
||||
size_t oldgen_threshold; /* threshold to kick major GC */
|
||||
mrb_gc_state state; /* current state of gc */
|
||||
int interval_ratio;
|
||||
@@ -56,9 +59,6 @@ typedef struct mrb_gc {
|
||||
mrb_bool generational :1; /* generational GC mode */
|
||||
mrb_bool full :1; /* major GC mode */
|
||||
mrb_bool out_of_memory :1; /* out-of-memory error occurred */
|
||||
size_t step_limit; /* 0=unlimited, >0=absolute step cap */
|
||||
size_t malloc_increase; /* malloc bytes since last GC cycle */
|
||||
size_t malloc_threshold; /* 0=disabled, >0=bytes to trigger GC */
|
||||
|
||||
#ifdef MRB_GC_FIXED_ARENA
|
||||
struct RBasic *arena[MRB_GC_ARENA_SIZE]; /* GC protection array */
|
||||
@@ -67,16 +67,10 @@ typedef struct mrb_gc {
|
||||
int arena_capa; /* size of protection array */
|
||||
#endif
|
||||
int arena_idx;
|
||||
|
||||
#ifdef MRB_GC_STATS
|
||||
uint32_t gc_total_count; /* total GC invocations */
|
||||
uint32_t minor_gc_count; /* minor GC count */
|
||||
uint32_t major_gc_count; /* major GC count */
|
||||
#endif
|
||||
} mrb_gc;
|
||||
|
||||
MRB_API mrb_bool mrb_object_dead_p(mrb_state *mrb, struct RBasic *object);
|
||||
MRB_API int mrb_gc_add_region(mrb_state *mrb, void *start, size_t size);
|
||||
MRB_API mrb_bool mrb_object_dead_p(struct mrb_state *mrb, struct RBasic *object);
|
||||
MRB_API int mrb_gc_add_region(struct mrb_state *mrb, void *start, size_t size);
|
||||
|
||||
#define MRB_GC_RED 7
|
||||
|
||||
|
||||
@@ -279,7 +279,4 @@ mrb_value mrb_bint_abs(mrb_state *mrb, mrb_value x);
|
||||
void mrb_task_mark_all(mrb_state *mrb);
|
||||
#endif
|
||||
|
||||
/* Internal object allocation without type validation (gc.c) */
|
||||
struct RBasic* mrb_obj_alloc_core(mrb_state*, enum mrb_vtype, struct RClass*);
|
||||
|
||||
#endif /* MRUBY_INTERNAL_H */
|
||||
|
||||
@@ -20,7 +20,7 @@ enum irep_pool_type {
|
||||
IREP_TT_SSTR = 2, /* string (static) */
|
||||
IREP_TT_INT32 = 1, /* 32-bit integer */
|
||||
IREP_TT_INT64 = 3, /* 64-bit integer */
|
||||
IREP_TT_BIGINT = 7, /* big integer */
|
||||
IREP_TT_BIGINT = 7, /* big integer (not yet supported) */
|
||||
IREP_TT_FLOAT = 5, /* float (double/float) */
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ typedef uint32_t khint_t;
|
||||
typedef khint_t khiter_t;
|
||||
|
||||
#ifndef KHASH_INITIAL_SIZE
|
||||
# define KHASH_INITIAL_SIZE 32
|
||||
# define KHASH_INITIAL_SIZE 8
|
||||
#endif
|
||||
#define KHASH_MIN_SIZE 8
|
||||
#define KHASH_SMALL_LIMIT 4
|
||||
|
||||
@@ -102,60 +102,6 @@ struct RProc {
|
||||
#define MRB_PROC_ALIAS 8192
|
||||
#define MRB_PROC_ALIAS_P(p) (((p)->flags & MRB_PROC_ALIAS) != 0)
|
||||
|
||||
/* Compressed aspec for cfunc procs (13 bits in RProc.flags).
|
||||
* Uses free bits 0-6 and 14-19 to store a compressed argument spec.
|
||||
* Layout: block(0) kdict(1) key(2-3) post(4-5) rest(6) opt(14-16) req(17-19)
|
||||
* Field widths are smaller than the full 24-bit aspec: req/opt max 7, post/key max 3.
|
||||
* Values exceeding the compressed range are clamped and rest is forced to 1. */
|
||||
#define MRB_PROC_CASPEC_MASK 0xfc07fu /* bits 0-6 and 14-19 */
|
||||
|
||||
static inline uint32_t
|
||||
mrb_proc_compress_aspec(mrb_aspec aspec)
|
||||
{
|
||||
uint32_t req = MRB_ASPEC_REQ(aspec);
|
||||
uint32_t opt = MRB_ASPEC_OPT(aspec);
|
||||
uint32_t rest = MRB_ASPEC_REST(aspec);
|
||||
uint32_t post = MRB_ASPEC_POST(aspec);
|
||||
uint32_t key = MRB_ASPEC_KEY(aspec);
|
||||
uint32_t kdict = MRB_ASPEC_KDICT(aspec);
|
||||
uint32_t block = MRB_ASPEC_BLOCK(aspec);
|
||||
|
||||
if (req > 7 || opt > 7 || post > 3 || key > 3) {
|
||||
if (req > 7) req = 7;
|
||||
if (opt > 7) opt = 7;
|
||||
if (post > 3) post = 3;
|
||||
if (key > 3) key = 3;
|
||||
rest = 1;
|
||||
}
|
||||
|
||||
return block | (kdict << 1) | (key << 2) | (post << 4) | (rest << 6)
|
||||
| (opt << 14) | (req << 17);
|
||||
}
|
||||
|
||||
static inline mrb_aspec
|
||||
mrb_proc_decompress_caspec(uint32_t flags)
|
||||
{
|
||||
return (((flags >> 17) & 0x7) << 18) /* req */
|
||||
| (((flags >> 14) & 0x7) << 13) /* opt */
|
||||
| (((flags >> 6) & 0x1) << 12) /* rest */
|
||||
| (((flags >> 4) & 0x3) << 7) /* post */
|
||||
| (((flags >> 2) & 0x3) << 2) /* key */
|
||||
| (((flags >> 1) & 0x1) << 1) /* kdict */
|
||||
| (flags & 0x1); /* block */
|
||||
}
|
||||
|
||||
static inline void
|
||||
mrb_proc_set_cfunc_aspec(struct RProc *p, mrb_aspec aspec)
|
||||
{
|
||||
p->flags &= ~(MRB_PROC_NOARG | MRB_PROC_CASPEC_MASK);
|
||||
if (aspec == 0) {
|
||||
p->flags |= MRB_PROC_NOARG;
|
||||
}
|
||||
else {
|
||||
p->flags |= mrb_proc_compress_aspec(aspec);
|
||||
}
|
||||
}
|
||||
|
||||
#define mrb_proc_ptr(v) ((struct RProc*)(mrb_ptr(v)))
|
||||
|
||||
struct RProc *mrb_proc_new(mrb_state*, const mrb_irep*);
|
||||
|
||||
@@ -342,16 +342,6 @@ MRB_API const char *mrb_string_value_cstr(mrb_state *mrb, mrb_value *str);
|
||||
*/
|
||||
MRB_API mrb_value mrb_str_dup(mrb_state *mrb, mrb_value str);
|
||||
|
||||
/**
|
||||
* Returns a frozen string object.
|
||||
* The string will be duplicated and frozen if it is not already frozen.
|
||||
*
|
||||
* @param mrb The current mruby state.
|
||||
* @param str An original Ruby string.
|
||||
* @return [mrb_value] Ruby frozen string.
|
||||
*/
|
||||
MRB_API mrb_value mrb_str_dup_frozen(mrb_state *mrb, mrb_value str);
|
||||
|
||||
/**
|
||||
* Returns a symbol from a passed in Ruby string.
|
||||
*
|
||||
|
||||
@@ -55,6 +55,8 @@ typedef uint8_t mrb_bool;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
struct mrb_state;
|
||||
|
||||
#if defined _MSC_VER && _MSC_VER < 1800
|
||||
# define PRIo64 "llo"
|
||||
# define PRId64 "lld"
|
||||
@@ -314,11 +316,7 @@ struct RCptr {
|
||||
#endif
|
||||
#define mrb_test(o) mrb_bool(o)
|
||||
#ifndef mrb_bigint_p
|
||||
#ifdef MRB_USE_BIGINT
|
||||
#define mrb_bigint_p(o) (mrb_type(o) == MRB_TT_BIGINT)
|
||||
#else
|
||||
#define mrb_bigint_p(o) FALSE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
@@ -328,7 +326,7 @@ struct RCptr {
|
||||
*/
|
||||
#ifndef MRB_NO_FLOAT
|
||||
MRB_INLINE mrb_value
|
||||
mrb_float_value(mrb_state *mrb, mrb_float f)
|
||||
mrb_float_value(struct mrb_state *mrb, mrb_float f)
|
||||
{
|
||||
mrb_value v;
|
||||
(void) mrb;
|
||||
@@ -338,7 +336,7 @@ mrb_float_value(mrb_state *mrb, mrb_float f)
|
||||
#endif
|
||||
|
||||
MRB_INLINE mrb_value
|
||||
mrb_cptr_value(mrb_state *mrb, void *p)
|
||||
mrb_cptr_value(struct mrb_state *mrb, void *p)
|
||||
{
|
||||
mrb_value v;
|
||||
(void) mrb;
|
||||
@@ -350,7 +348,7 @@ mrb_cptr_value(mrb_state *mrb, void *p)
|
||||
* Returns an integer in Ruby.
|
||||
*/
|
||||
MRB_INLINE mrb_value
|
||||
mrb_int_value(mrb_state *mrb, mrb_int i)
|
||||
mrb_int_value(struct mrb_state *mrb, mrb_int i)
|
||||
{
|
||||
mrb_value v;
|
||||
SET_INT_VALUE(mrb, v, i);
|
||||
|
||||
@@ -80,7 +80,7 @@ MRB_BEGIN_DECL
|
||||
/*
|
||||
* Release year.
|
||||
*/
|
||||
#define MRUBY_RELEASE_YEAR 2026
|
||||
#define MRUBY_RELEASE_YEAR 2025
|
||||
|
||||
/*
|
||||
* Release month.
|
||||
|
||||
@@ -41,7 +41,7 @@ module MRuby
|
||||
allocf.c
|
||||
readnum.c
|
||||
readint.c
|
||||
fp_uscale.c
|
||||
readfloat.c
|
||||
state.c
|
||||
symbol.c
|
||||
class.c
|
||||
@@ -66,6 +66,7 @@ module MRuby
|
||||
cdump.c
|
||||
codedump.c
|
||||
print.c
|
||||
fmt_fp.c
|
||||
debug.c
|
||||
etc.c
|
||||
version.c
|
||||
|
||||
+1
-26
@@ -81,7 +81,7 @@ module MRuby
|
||||
include LoadGems
|
||||
attr_accessor :name, :bins, :exts, :file_separator, :build_dir, :gem_clone_dir, :defines, :libdir_name
|
||||
attr_reader :products, :libmruby_core_objs, :libmruby_objs, :gems, :toolchains, :presym, :mrbc_build, :gem_dir_to_repo_url
|
||||
attr_reader :install_excludes, :port_names
|
||||
attr_reader :install_excludes
|
||||
|
||||
alias libmruby libmruby_objs
|
||||
|
||||
@@ -138,7 +138,6 @@ module MRuby
|
||||
@mrbcfile_external = false
|
||||
@internal = internal
|
||||
@toolchains = []
|
||||
@port_names = nil
|
||||
@gem_dir_to_repo_url = {}
|
||||
|
||||
# Add lambda instead of string because libdir_name or lib may be changed by user configuration
|
||||
@@ -184,30 +183,6 @@ module MRuby
|
||||
@enable_debug = true
|
||||
end
|
||||
|
||||
# Set target port names for this build.
|
||||
# Each gem compiles the first matching ports/<name>/ directory;
|
||||
# later names in the list act as fallbacks for gems that don't
|
||||
# ship a port for the earlier names.
|
||||
# conf.ports :esp32
|
||||
# conf.ports :rp2040, :posix # use rp2040 if available, else posix
|
||||
def ports(*names)
|
||||
@port_names = names.map { |n| n.to_s }
|
||||
end
|
||||
|
||||
# Returns the effective port names for this build.
|
||||
# If not explicitly set, auto-detects :posix or :win for host builds.
|
||||
def effective_ports
|
||||
return @port_names if @port_names
|
||||
if kind_of?(MRuby::CrossBuild)
|
||||
[]
|
||||
elsif ENV['OS'] == 'Windows_NT' ||
|
||||
('A'..'Z').any? { |v| Dir.exist?("#{v}:") }
|
||||
['win']
|
||||
else
|
||||
['posix']
|
||||
end
|
||||
end
|
||||
|
||||
def disable_lock
|
||||
@enable_lock = false
|
||||
end
|
||||
|
||||
@@ -343,21 +343,16 @@ module MRuby
|
||||
opt = @compile_options % {funcname: funcname}
|
||||
opt << " -S" if cdump
|
||||
opt << " -s" if static
|
||||
# Have mrbc write to a private tempfile (-o) instead of stdout (-o-)
|
||||
# to avoid pipe-inheritance races with parallel rake on Windows MinGW,
|
||||
# where unrelated _pp build-progress lines from sibling workers can
|
||||
# leak into the captured stdout and corrupt the generated C file.
|
||||
tmpout = "#{out.path}.#{funcname}.mrbcout"
|
||||
opt = opt.sub(/\s-o-(?=\s|\z)/, %Q[ -o "#{filename tmpout}"])
|
||||
cmd = %["#{filename @command}" #{opt} #{filename(infiles).map{|f| %["#{f}"]}.join(' ')}]
|
||||
puts cmd if Rake.verbose
|
||||
unless system(cmd)
|
||||
rm_f tmpout
|
||||
IO.popen(cmd, 'r') do |io|
|
||||
out.puts io.read
|
||||
end
|
||||
# if mrbc execution fail, drop the file
|
||||
unless $?.success?
|
||||
rm_f out.path
|
||||
fail "Command failed with status (#{$?.exitstatus}): [#{cmd[0,42]}...]"
|
||||
end
|
||||
out.write File.binread(tmpout)
|
||||
rm_f tmpout
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+1
-56
@@ -25,7 +25,6 @@ module MRuby
|
||||
alias :author= :authors=
|
||||
|
||||
attr_accessor :rbfiles, :objs
|
||||
attr_reader :port_objs
|
||||
attr_writer :test_objs, :test_rbfiles
|
||||
attr_accessor :test_args, :test_preload
|
||||
|
||||
@@ -44,7 +43,6 @@ module MRuby
|
||||
def initialize(name, &block)
|
||||
@name = name
|
||||
@initializer = block
|
||||
@post_user_config = nil
|
||||
@version = "0.0.0"
|
||||
@dependencies = []
|
||||
@conflicts = []
|
||||
@@ -61,22 +59,6 @@ module MRuby
|
||||
@rbfiles = Dir.glob("#{@dir}/mrblib/**/*.rb").sort
|
||||
@objs = srcs_to_objs("src")
|
||||
|
||||
# Add platform-specific sources from the first matching
|
||||
# ports/<name>/ directory. effective_ports is a fallback
|
||||
# chain: later names act as defaults for gems that don't ship
|
||||
# a port for the earlier names. These objs are tracked
|
||||
# separately so List#resolve_external_hal! can drop them when
|
||||
# an external HAL provider (gem named hal-<short>-*) is loaded.
|
||||
@port_objs = []
|
||||
build.effective_ports.each do |port|
|
||||
port_dir = "#{@dir}/ports/#{port}"
|
||||
if File.directory?(port_dir)
|
||||
@port_objs = srcs_to_objs("ports/#{port}")
|
||||
@objs += @port_objs
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@test_preload = nil # 'test/assert.rb'
|
||||
@test_args = {}
|
||||
@skip_test = false
|
||||
@@ -103,7 +85,6 @@ module MRuby
|
||||
build.libmruby_objs << @objs
|
||||
|
||||
instance_eval(&@build_config_initializer) if @build_config_initializer
|
||||
instance_eval(&@post_user_config) if @post_user_config
|
||||
|
||||
repo_url = build.gem_dir_to_repo_url[dir]
|
||||
build.locks[repo_url]['version'] = version if repo_url
|
||||
@@ -128,8 +109,7 @@ module MRuby
|
||||
if build.kind_of?(MRuby::CrossBuild)
|
||||
return %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target)
|
||||
elsif build.kind_of?(MRuby::Build)
|
||||
return ('A'..'Z').to_a.any? { |vol| Dir.exist?("#{vol}:") } ||
|
||||
('a'..'z').to_a.any? { |vol| Dir.exist?("/#{vol}/") }
|
||||
return ('A'..'Z').to_a.any? { |vol| Dir.exist?("#{vol}:") }
|
||||
end
|
||||
return false
|
||||
end
|
||||
@@ -213,19 +193,6 @@ module MRuby
|
||||
end
|
||||
end
|
||||
|
||||
# Register a block that runs after the user's `build.gem` block has
|
||||
# been processed. Intended for gem authors to fill in defaults that
|
||||
# depend on user-supplied configuration (e.g. auto-detect a library
|
||||
# only if the user didn't specify which to use).
|
||||
#
|
||||
# Initialization order:
|
||||
# 1. block in `MRuby::Gem::Specification.new` (gem author)
|
||||
# 2. block in `build.gem` (user's build_config)
|
||||
# 3. block in `post_user_config` (gem author, this hook)
|
||||
def post_user_config(&block)
|
||||
@post_user_config = block
|
||||
end
|
||||
|
||||
def build_settings(&blk)
|
||||
@build_settings = blk
|
||||
end
|
||||
@@ -462,28 +429,6 @@ module MRuby
|
||||
self.each(&:setup)
|
||||
gemset = self.setup_dependencies(build).keys.sort
|
||||
end until gemset == gemset_prev
|
||||
resolve_external_hal!
|
||||
end
|
||||
|
||||
# A gem named `hal-<short>-<conf>` is treated as the external
|
||||
# HAL provider for the gem whose name's last `-`-separated
|
||||
# segment is <short> (e.g., hal-task-glib provides the HAL for
|
||||
# mruby-task). The target gem's ports/* sources are dropped
|
||||
# from its object list -- the matching gem supplies the
|
||||
# implementation. Two or more matches is a build error.
|
||||
def resolve_external_hal!
|
||||
each do |target|
|
||||
next if target.port_objs.nil? || target.port_objs.empty?
|
||||
short = target.name.split('-').last
|
||||
pattern = /\Ahal-#{Regexp.escape(short)}-.+\z/
|
||||
overriders = select { |g| g != target && g.name =~ pattern }
|
||||
next if overriders.empty?
|
||||
if overriders.size > 1
|
||||
fail "Multiple HAL providers for '#{target.name}': " +
|
||||
overriders.map(&:name).join(", ")
|
||||
end
|
||||
target.objs.reject! { |o| target.port_objs.include?(o) }
|
||||
end
|
||||
end
|
||||
|
||||
def setup_build
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
MRuby::Gem::Specification.new('hal-posix-dir') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = 'mruby developers'
|
||||
spec.summary = 'POSIX HAL for mruby-dir (Linux, macOS, BSD, Unix)'
|
||||
|
||||
spec.add_dependency 'mruby-dir', core: 'mruby-dir'
|
||||
end
|
||||
@@ -173,3 +173,21 @@ mrb_hal_dir_final(mrb_state *mrb)
|
||||
(void)mrb;
|
||||
/* No cleanup needed for POSIX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_posix_dir_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-dir gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_posix_dir_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_dir_final called from mruby-dir */
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
MRuby::Gem::Specification.new('hal-posix-io') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'POSIX HAL for mruby-io (Linux, macOS, BSD, Unix)'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-io automatically
|
||||
spec.add_dependency 'mruby-io', core: 'mruby-io'
|
||||
end
|
||||
@@ -67,25 +67,25 @@ convert_stat(const struct stat *src, mrb_io_stat *dst)
|
||||
#undef st_mtime
|
||||
#undef st_ctime
|
||||
|
||||
dst->st_dev = (mrb_int)src->st_dev;
|
||||
dst->st_ino = (mrb_int)src->st_ino;
|
||||
dst->st_mode = (mrb_int)src->st_mode;
|
||||
dst->st_nlink = (mrb_int)src->st_nlink;
|
||||
dst->st_uid = (mrb_int)src->st_uid;
|
||||
dst->st_gid = (mrb_int)src->st_gid;
|
||||
dst->st_rdev = (mrb_int)src->st_rdev;
|
||||
dst->st_size = (mrb_int)src->st_size;
|
||||
dst->st_atime = (mrb_int)atime_val;
|
||||
dst->st_mtime = (mrb_int)mtime_val;
|
||||
dst->st_ctime = (mrb_int)ctime_val;
|
||||
dst->st_dev = (uint64_t)src->st_dev;
|
||||
dst->st_ino = (uint64_t)src->st_ino;
|
||||
dst->st_mode = (uint32_t)src->st_mode;
|
||||
dst->st_nlink = (uint32_t)src->st_nlink;
|
||||
dst->st_uid = (uint32_t)src->st_uid;
|
||||
dst->st_gid = (uint32_t)src->st_gid;
|
||||
dst->st_rdev = (uint64_t)src->st_rdev;
|
||||
dst->st_size = (int64_t)src->st_size;
|
||||
dst->st_atime = (int64_t)atime_val;
|
||||
dst->st_mtime = (int64_t)mtime_val;
|
||||
dst->st_ctime = (int64_t)ctime_val;
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
|
||||
dst->st_blksize = (mrb_int)src->st_blksize;
|
||||
dst->st_blksize = (int64_t)src->st_blksize;
|
||||
#else
|
||||
dst->st_blksize = 512;
|
||||
#endif
|
||||
#ifdef HAVE_STRUCT_STAT_ST_BLOCKS
|
||||
dst->st_blocks = (mrb_int)src->st_blocks;
|
||||
dst->st_blocks = (int64_t)src->st_blocks;
|
||||
#else
|
||||
dst->st_blocks = (dst->st_size + 511) / 512;
|
||||
#endif
|
||||
@@ -135,14 +135,14 @@ mrb_hal_io_lstat(mrb_state *mrb, const char *path, mrb_io_stat *st)
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_io_chmod(mrb_state *mrb, const char *path, mrb_int mode)
|
||||
mrb_hal_io_chmod(mrb_state *mrb, const char *path, uint32_t mode)
|
||||
{
|
||||
(void)mrb;
|
||||
return chmod(path, (mode_t)mode);
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_hal_io_umask(mrb_state *mrb, mrb_int mask)
|
||||
uint32_t
|
||||
mrb_hal_io_umask(mrb_state *mrb, int32_t mask)
|
||||
{
|
||||
mode_t old;
|
||||
(void)mrb;
|
||||
@@ -155,11 +155,11 @@ mrb_hal_io_umask(mrb_state *mrb, mrb_int mask)
|
||||
else {
|
||||
old = umask((mode_t)mask);
|
||||
}
|
||||
return (mrb_int)old;
|
||||
return (uint32_t)old;
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_io_ftruncate(mrb_state *mrb, int fd, mrb_int length)
|
||||
mrb_hal_io_ftruncate(mrb_state *mrb, int fd, int64_t length)
|
||||
{
|
||||
(void)mrb;
|
||||
return ftruncate(fd, (off_t)length);
|
||||
@@ -200,11 +200,14 @@ mrb_hal_io_symlink(mrb_state *mrb, const char *target, const char *linkpath)
|
||||
return symlink(target, linkpath);
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_readlink(mrb_state *mrb, const char *path, char *buf, size_t bufsize)
|
||||
{
|
||||
ssize_t rc;
|
||||
(void)mrb;
|
||||
return (mrb_int)readlink(path, buf, bufsize);
|
||||
|
||||
rc = readlink(path, buf, bufsize);
|
||||
return (int64_t)rc;
|
||||
}
|
||||
|
||||
char*
|
||||
@@ -259,7 +262,7 @@ mrb_hal_io_gethome(mrb_state *mrb, const char *username)
|
||||
*/
|
||||
|
||||
int
|
||||
mrb_hal_io_open(mrb_state *mrb, const char *path, int flags, mrb_int mode)
|
||||
mrb_hal_io_open(mrb_state *mrb, const char *path, int flags, uint32_t mode)
|
||||
{
|
||||
int fd;
|
||||
(void)mrb;
|
||||
@@ -289,23 +292,30 @@ mrb_hal_io_close(mrb_state *mrb, int fd)
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_read(mrb_state *mrb, int fd, void *buf, size_t count)
|
||||
{
|
||||
ssize_t n;
|
||||
(void)mrb;
|
||||
return (mrb_int)read(fd, buf, count);
|
||||
|
||||
n = read(fd, buf, count);
|
||||
return (int64_t)n;
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_write(mrb_state *mrb, int fd, const void *buf, size_t count)
|
||||
{
|
||||
ssize_t n;
|
||||
(void)mrb;
|
||||
return (mrb_int)write(fd, buf, count);
|
||||
|
||||
n = write(fd, buf, count);
|
||||
return (int64_t)n;
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_hal_io_lseek(mrb_state *mrb, int fd, mrb_int offset, int whence)
|
||||
int64_t
|
||||
mrb_hal_io_lseek(mrb_state *mrb, int fd, int64_t offset, int whence)
|
||||
{
|
||||
off_t pos;
|
||||
int posix_whence;
|
||||
(void)mrb;
|
||||
|
||||
@@ -319,7 +329,8 @@ mrb_hal_io_lseek(mrb_state *mrb, int fd, mrb_int offset, int whence)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (mrb_int)lseek(fd, (off_t)offset, posix_whence);
|
||||
pos = lseek(fd, (off_t)offset, posix_whence);
|
||||
return (int64_t)pos;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -571,3 +582,21 @@ mrb_hal_io_final(mrb_state *mrb)
|
||||
(void)mrb;
|
||||
/* No special cleanup needed for POSIX */
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_posix_io_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-io gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_posix_io_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_io_final called from mruby-io */
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
MRuby::Gem::Specification.new('hal-posix-socket') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'POSIX HAL for mruby-socket (Linux, macOS, BSD, Unix)'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-socket automatically
|
||||
spec.add_dependency 'mruby-socket', core: 'mruby-socket'
|
||||
end
|
||||
+15
-33
@@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
#include <mruby.h>
|
||||
#include <mruby/array.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/class.h>
|
||||
#include <mruby/error.h>
|
||||
@@ -21,7 +20,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
@@ -43,16 +41,6 @@ mrb_hal_socket_final(mrb_state *mrb)
|
||||
/* No cleanup needed for POSIX sockets */
|
||||
}
|
||||
|
||||
/*
|
||||
* Error Handling
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_socket_set_errno_from_last_error(void)
|
||||
{
|
||||
/* POSIX socket calls already set errno on failure; nothing to do. */
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket Control Operations
|
||||
*/
|
||||
@@ -150,26 +138,20 @@ mrb_hal_socket_unix_path(mrb_state *mrb, const char *sockaddr, size_t socklen)
|
||||
return mrb_str_new_cstr(mrb, ((const struct sockaddr_un*)sockaddr)->sun_path);
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_hal_socket_ip_address_list(mrb_state *mrb)
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_posix_socket_gem_init(mrb_state *mrb)
|
||||
{
|
||||
struct ifaddrs *ifap = NULL;
|
||||
if (getifaddrs(&ifap) != 0) {
|
||||
mrb_sys_fail(mrb, "getifaddrs");
|
||||
}
|
||||
mrb_value ary = mrb_ary_new(mrb);
|
||||
int arena_idx = mrb_gc_arena_save(mrb);
|
||||
for (struct ifaddrs *ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
|
||||
if (ifa->ifa_addr == NULL) continue;
|
||||
socklen_t salen;
|
||||
switch (ifa->ifa_addr->sa_family) {
|
||||
case AF_INET: salen = sizeof(struct sockaddr_in); break;
|
||||
case AF_INET6: salen = sizeof(struct sockaddr_in6); break;
|
||||
default: continue;
|
||||
}
|
||||
mrb_ary_push(mrb, ary, mrb_str_new(mrb, (const char*)ifa->ifa_addr, salen));
|
||||
mrb_gc_arena_restore(mrb, arena_idx);
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return ary;
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-socket gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_posix_socket_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_socket_final called from mruby-socket */
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
# hal-posix-task
|
||||
|
||||
POSIX Hardware Abstraction Layer (HAL) implementation for mruby-task.
|
||||
|
||||
## Description
|
||||
|
||||
Provides timer and interrupt support for the mruby-task cooperative scheduler on POSIX-compliant platforms. Uses `SIGALRM` and `setitimer()` for periodic timer ticks, and `sigprocmask()` for interrupt protection.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- Linux
|
||||
- macOS
|
||||
- BSD (FreeBSD, OpenBSD, NetBSD)
|
||||
- Other POSIX-compliant Unix systems
|
||||
|
||||
## Requirements
|
||||
|
||||
- POSIX-compliant operating system
|
||||
- Signal support (`SIGALRM`, `sigaction`, `sigprocmask`)
|
||||
- Timer support (`setitimer`, `ITIMER_REAL`)
|
||||
|
||||
## Usage
|
||||
|
||||
### Explicit HAL Selection (Recommended)
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
# ... other configuration ...
|
||||
|
||||
# Specify POSIX HAL - automatically brings in mruby-task
|
||||
conf.gem core: 'hal-posix-task'
|
||||
end
|
||||
```
|
||||
|
||||
### Auto-detection (Development)
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
# ... other configuration ...
|
||||
|
||||
# Auto-detects and selects hal-posix-task on POSIX platforms
|
||||
conf.gem core: 'mruby-task'
|
||||
end
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Timer Mechanism
|
||||
|
||||
- Uses `setitimer(ITIMER_REAL, ...)` to generate periodic `SIGALRM` signals
|
||||
- Timer interval configured by `MRB_TICK_UNIT` (default: 4ms)
|
||||
- Signal handler calls `mrb_tick()` for all registered VM instances
|
||||
|
||||
### Interrupt Protection
|
||||
|
||||
- Critical sections protected using `sigprocmask()` to block `SIGALRM`
|
||||
- Prevents race conditions during task queue modifications
|
||||
- Supports nested critical sections through signal masking
|
||||
|
||||
### Multi-VM Support
|
||||
|
||||
- Supports up to `MRB_TASK_MAX_VMS` concurrent mruby VM instances (default: 8)
|
||||
- Single shared timer ticks all registered VMs
|
||||
- Per-VM task counters optimize timer usage (timer disabled when idle)
|
||||
|
||||
### Timer Optimization
|
||||
|
||||
The implementation dynamically enables/disables the timer based on task state:
|
||||
|
||||
- **Timer enabled** when: Multiple ready tasks OR any waiting tasks exist
|
||||
- **Timer disabled** when: Single task or all tasks dormant/suspended
|
||||
- Reduces CPU usage and power consumption when scheduler is idle
|
||||
|
||||
## Configuration
|
||||
|
||||
Override these macros in your build config if needed:
|
||||
|
||||
```ruby
|
||||
conf.gem core: 'hal-posix-task' do |spec|
|
||||
# Custom tick interval (10ms instead of default 4ms)
|
||||
spec.build.defines << 'MRB_TICK_UNIT=10'
|
||||
|
||||
# Custom timeslice (5 ticks instead of default 3)
|
||||
spec.build.defines << 'MRB_TIMESLICE_TICK_COUNT=5'
|
||||
|
||||
# More concurrent VMs (16 instead of default 8)
|
||||
spec.build.defines << 'MRB_TASK_MAX_VMS=16'
|
||||
end
|
||||
```
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- `SIGALRM` conflicts with other code using the same signal
|
||||
- Timer resolution limited by platform (typically 1-10ms)
|
||||
- Signal delivery may be delayed under heavy system load
|
||||
- Not suitable for hard real-time requirements
|
||||
|
||||
## See Also
|
||||
|
||||
- `mruby-task` - Core task scheduler
|
||||
- `hal-win-task` - Windows HAL implementation
|
||||
- Task scheduler documentation: `mrbgems/mruby-task/README.md`
|
||||
@@ -0,0 +1,8 @@
|
||||
MRuby::Gem::Specification.new('hal-posix-task') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = 'mruby developers'
|
||||
spec.summary = 'POSIX HAL for mruby-task (Linux, macOS, BSD, Unix)'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-task automatically
|
||||
spec.add_dependency 'mruby-task', core: 'mruby-task'
|
||||
end
|
||||
@@ -232,3 +232,21 @@ mrb_hal_task_final(mrb_state *mrb)
|
||||
(void)mrb;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization (empty - HAL functions called by mruby-task)
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_posix_task_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-task gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_posix_task_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_task_final called from mruby-task */
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
MRuby::Gem::Specification.new('hal-win-dir') do |spec|
|
||||
spec.license = 'MIT and MIT-like license'
|
||||
spec.authors = ['mruby developers', 'Kevlin Henney']
|
||||
spec.summary = 'Windows HAL for mruby-dir'
|
||||
|
||||
spec.add_dependency 'mruby-dir', core: 'mruby-dir'
|
||||
end
|
||||
@@ -214,3 +214,36 @@ mrb_hal_dir_final(mrb_state *mrb)
|
||||
(void)mrb;
|
||||
/* No cleanup needed for Windows */
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_win_dir_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-dir gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_win_dir_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_dir_final called from mruby-dir */
|
||||
}
|
||||
|
||||
/*
|
||||
** Portions derived from dirent.c by Kevlin Henney:
|
||||
**
|
||||
** Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
|
||||
**
|
||||
** Permission to use, copy, modify, and distribute this software and its
|
||||
** documentation for any purpose is hereby granted without fee, provided
|
||||
** that this copyright and permissions notice appear in all copies and
|
||||
** derivatives.
|
||||
**
|
||||
** This software is supplied "as is" without express or implied warranty.
|
||||
**
|
||||
** But that said, if there are any problems please get in touch.
|
||||
*/
|
||||
@@ -0,0 +1,11 @@
|
||||
MRuby::Gem::Specification.new('hal-win-io') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Windows HAL for mruby-io (Windows, MinGW)'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-io automatically
|
||||
spec.add_dependency 'mruby-io', core: 'mruby-io'
|
||||
|
||||
# Link Windows socket library
|
||||
spec.linker.libraries << "ws2_32"
|
||||
end
|
||||
@@ -34,17 +34,17 @@
|
||||
static void
|
||||
convert_stat(const struct _stat64 *src, mrb_io_stat *dst)
|
||||
{
|
||||
dst->st_dev = (mrb_int)src->st_dev;
|
||||
dst->st_ino = (mrb_int)src->st_ino;
|
||||
dst->st_mode = (mrb_int)src->st_mode;
|
||||
dst->st_nlink = (mrb_int)src->st_nlink;
|
||||
dst->st_dev = (uint64_t)src->st_dev;
|
||||
dst->st_ino = (uint64_t)src->st_ino;
|
||||
dst->st_mode = (uint32_t)src->st_mode;
|
||||
dst->st_nlink = (uint32_t)src->st_nlink;
|
||||
dst->st_uid = 0; /* Windows doesn't have Unix-style UIDs */
|
||||
dst->st_gid = 0; /* Windows doesn't have Unix-style GIDs */
|
||||
dst->st_rdev = (mrb_int)src->st_rdev;
|
||||
dst->st_size = (mrb_int)src->st_size;
|
||||
dst->st_atime = (mrb_int)src->st_atime;
|
||||
dst->st_mtime = (mrb_int)src->st_mtime;
|
||||
dst->st_ctime = (mrb_int)src->st_ctime;
|
||||
dst->st_rdev = (uint64_t)src->st_rdev;
|
||||
dst->st_size = (int64_t)src->st_size;
|
||||
dst->st_atime = (int64_t)src->st_atime;
|
||||
dst->st_mtime = (int64_t)src->st_mtime;
|
||||
dst->st_ctime = (int64_t)src->st_ctime;
|
||||
dst->st_blksize = 512;
|
||||
dst->st_blocks = (dst->st_size + 511) / 512;
|
||||
}
|
||||
@@ -114,14 +114,14 @@ mrb_hal_io_lstat(mrb_state *mrb, const char *path, mrb_io_stat *st)
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_io_chmod(mrb_state *mrb, const char *path, mrb_int mode)
|
||||
mrb_hal_io_chmod(mrb_state *mrb, const char *path, uint32_t mode)
|
||||
{
|
||||
(void)mrb;
|
||||
return _chmod(path, (int)mode);
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_hal_io_umask(mrb_state *mrb, mrb_int mask)
|
||||
uint32_t
|
||||
mrb_hal_io_umask(mrb_state *mrb, int32_t mask)
|
||||
{
|
||||
int old;
|
||||
(void)mrb;
|
||||
@@ -134,14 +134,14 @@ mrb_hal_io_umask(mrb_state *mrb, mrb_int mask)
|
||||
else {
|
||||
old = _umask((int)mask);
|
||||
}
|
||||
return (mrb_int)old;
|
||||
return (uint32_t)old;
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_io_ftruncate(mrb_state *mrb, int fd, mrb_int length)
|
||||
mrb_hal_io_ftruncate(mrb_state *mrb, int fd, int64_t length)
|
||||
{
|
||||
(void)mrb;
|
||||
return _chsize_s(fd, (__int64)length);
|
||||
return _chsize_s(fd, length);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -207,7 +207,7 @@ mrb_hal_io_symlink(mrb_state *mrb, const char *target, const char *linkpath)
|
||||
return -1; /* not reached */
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_readlink(mrb_state *mrb, const char *path, char *buf, size_t bufsize)
|
||||
{
|
||||
(void)path;
|
||||
@@ -280,7 +280,7 @@ mrb_hal_io_gethome(mrb_state *mrb, const char *username)
|
||||
*/
|
||||
|
||||
int
|
||||
mrb_hal_io_open(mrb_state *mrb, const char *path, int flags, mrb_int mode)
|
||||
mrb_hal_io_open(mrb_state *mrb, const char *path, int flags, uint32_t mode)
|
||||
{
|
||||
int fd;
|
||||
(void)mrb;
|
||||
@@ -306,23 +306,30 @@ mrb_hal_io_close(mrb_state *mrb, int fd)
|
||||
return _close(fd);
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_read(mrb_state *mrb, int fd, void *buf, size_t count)
|
||||
{
|
||||
int n;
|
||||
(void)mrb;
|
||||
return (mrb_int)_read(fd, buf, (unsigned int)count);
|
||||
|
||||
n = _read(fd, buf, (unsigned int)count);
|
||||
return (int64_t)n;
|
||||
}
|
||||
|
||||
mrb_int
|
||||
int64_t
|
||||
mrb_hal_io_write(mrb_state *mrb, int fd, const void *buf, size_t count)
|
||||
{
|
||||
int n;
|
||||
(void)mrb;
|
||||
return (mrb_int)_write(fd, buf, (unsigned int)count);
|
||||
|
||||
n = _write(fd, buf, (unsigned int)count);
|
||||
return (int64_t)n;
|
||||
}
|
||||
|
||||
mrb_int
|
||||
mrb_hal_io_lseek(mrb_state *mrb, int fd, mrb_int offset, int whence)
|
||||
int64_t
|
||||
mrb_hal_io_lseek(mrb_state *mrb, int fd, int64_t offset, int whence)
|
||||
{
|
||||
__int64 pos;
|
||||
int win_whence;
|
||||
(void)mrb;
|
||||
|
||||
@@ -336,7 +343,8 @@ mrb_hal_io_lseek(mrb_state *mrb, int fd, mrb_int offset, int whence)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (mrb_int)_lseeki64(fd, (__int64)offset, win_whence);
|
||||
pos = _lseeki64(fd, (__int64)offset, win_whence);
|
||||
return (int64_t)pos;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -618,3 +626,21 @@ mrb_hal_io_final(mrb_state *mrb)
|
||||
/* Cleanup Winsock */
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_win_io_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-io gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_win_io_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_io_final called from mruby-io */
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
MRuby::Gem::Specification.new('hal-win-socket') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.author = 'mruby developers'
|
||||
spec.summary = 'Windows HAL for mruby-socket (Windows, MinGW)'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-socket automatically
|
||||
spec.add_dependency 'mruby-socket', core: 'mruby-socket'
|
||||
|
||||
# Link Windows socket libraries
|
||||
spec.linker.libraries << "wsock32"
|
||||
spec.linker.libraries << "ws2_32"
|
||||
end
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
** socket_hal.c - Windows HAL implementation for mruby-socket
|
||||
**
|
||||
** See Copyright Notice in mruby.h
|
||||
**
|
||||
** Windows implementation for socket operations using Winsock APIs.
|
||||
** Supported platforms: Windows, MinGW
|
||||
*/
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501 // need Windows XP or later
|
||||
#endif
|
||||
|
||||
#include <mruby.h>
|
||||
#include <mruby/string.h>
|
||||
#include <mruby/class.h>
|
||||
#include <mruby/error.h>
|
||||
#include "socket_hal.h"
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <windows.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Socket HAL Initialization/Finalization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_socket_init(mrb_state *mrb)
|
||||
{
|
||||
WSADATA wsaData;
|
||||
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
if (result != NO_ERROR) {
|
||||
mrb_raise(mrb, mrb_class_get_id(mrb, MRB_SYM(RuntimeError)), "WSAStartup failed");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_socket_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
WSACleanup();
|
||||
}
|
||||
|
||||
/*
|
||||
* Socket Control Operations
|
||||
*/
|
||||
|
||||
int
|
||||
mrb_hal_socket_set_nonblock(mrb_state *mrb, int fd, int nonblock)
|
||||
{
|
||||
(void)mrb;
|
||||
u_long mode = nonblock ? 1 : 0;
|
||||
int result = ioctlsocket(fd, FIONBIO, &mode);
|
||||
if (result != NO_ERROR) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Address Conversion Functions
|
||||
*/
|
||||
|
||||
const char*
|
||||
mrb_hal_socket_inet_ntop(int af, const void *src, char *dst, size_t size)
|
||||
{
|
||||
if (af == AF_INET) {
|
||||
struct sockaddr_in in = {0};
|
||||
in.sin_family = AF_INET;
|
||||
memcpy(&in.sin_addr, src, sizeof(struct in_addr));
|
||||
if (getnameinfo((struct sockaddr*)&in, sizeof(struct sockaddr_in),
|
||||
dst, (DWORD)size, NULL, 0, NI_NUMERICHOST) == 0) {
|
||||
return dst;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
else if (af == AF_INET6) {
|
||||
struct sockaddr_in6 in = {0};
|
||||
in.sin6_family = AF_INET6;
|
||||
memcpy(&in.sin6_addr, src, sizeof(struct in6_addr));
|
||||
if (getnameinfo((struct sockaddr*)&in, sizeof(struct sockaddr_in6),
|
||||
dst, (DWORD)size, NULL, 0, NI_NUMERICHOST) == 0) {
|
||||
return dst;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_socket_inet_pton(int af, const char *src, void *dst)
|
||||
{
|
||||
struct addrinfo hints = {0};
|
||||
hints.ai_family = af;
|
||||
hints.ai_flags = AI_NUMERICHOST;
|
||||
|
||||
struct addrinfo *res;
|
||||
if (getaddrinfo(src, NULL, &hints, &res) != 0) {
|
||||
return 0; /* Invalid address */
|
||||
}
|
||||
|
||||
if (res == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (af == AF_INET && res->ai_family == AF_INET) {
|
||||
memcpy(dst, &((struct sockaddr_in*)res->ai_addr)->sin_addr, sizeof(struct in_addr));
|
||||
freeaddrinfo(res);
|
||||
return 1;
|
||||
}
|
||||
else if (af == AF_INET6 && res->ai_family == AF_INET6) {
|
||||
memcpy(dst, &((struct sockaddr_in6*)res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
|
||||
freeaddrinfo(res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
freeaddrinfo(res);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Platform-Specific Socket Features
|
||||
*/
|
||||
|
||||
mrb_value
|
||||
mrb_hal_socket_sockaddr_un(mrb_state *mrb, const char *path, size_t pathlen)
|
||||
{
|
||||
(void)path;
|
||||
(void)pathlen;
|
||||
mrb_raise(mrb, mrb_class_get_id(mrb, MRB_SYM(NotImplementedError)),
|
||||
"sockaddr_un unsupported on Windows");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
int
|
||||
mrb_hal_socket_socketpair(mrb_state *mrb, int domain, int type, int protocol, int sv[2])
|
||||
{
|
||||
(void)mrb;
|
||||
(void)domain;
|
||||
(void)type;
|
||||
(void)protocol;
|
||||
(void)sv;
|
||||
/* socketpair is not supported on Windows */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_hal_socket_unix_path(mrb_state *mrb, const char *sockaddr, size_t socklen)
|
||||
{
|
||||
(void)sockaddr;
|
||||
(void)socklen;
|
||||
mrb_raise(mrb, mrb_class_get_id(mrb, MRB_SYM(NotImplementedError)),
|
||||
"unix_path unsupported on Windows");
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_win_socket_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-socket gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_win_socket_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_socket_final called from mruby-socket */
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
# hal-win-task
|
||||
|
||||
Windows Hardware Abstraction Layer (HAL) implementation for mruby-task.
|
||||
|
||||
## Description
|
||||
|
||||
Provides timer and interrupt support for the mruby-task cooperative scheduler on Windows platforms. Uses multimedia timer (`timeSetEvent`/`timeKillEvent`) for periodic timer ticks, and `CRITICAL_SECTION` for interrupt protection.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
- Windows 7 and later
|
||||
- Windows Server 2008 R2 and later
|
||||
- All versions with multimedia timer support
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows operating system
|
||||
- Multimedia timer API (`winmm.lib`)
|
||||
- Visual C++, MinGW, or compatible compiler
|
||||
|
||||
## Usage
|
||||
|
||||
### Explicit HAL Selection (Recommended)
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
# ... other configuration ...
|
||||
|
||||
# Specify Windows HAL - automatically brings in mruby-task
|
||||
conf.gem core: 'hal-win-task'
|
||||
end
|
||||
```
|
||||
|
||||
### Auto-detection (Development)
|
||||
|
||||
```ruby
|
||||
MRuby::Build.new do |conf|
|
||||
# ... other configuration ...
|
||||
|
||||
# Auto-detects and selects hal-win-task on Windows platforms
|
||||
conf.gem core: 'mruby-task'
|
||||
end
|
||||
```
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Timer Mechanism
|
||||
|
||||
- Uses Windows multimedia timer (`timeSetEvent`) for periodic callbacks
|
||||
- Timer interval configured by `MRB_TICK_UNIT` (default: 4ms)
|
||||
- `TIME_KILL_SYNCHRONOUS` flag ensures clean timer shutdown
|
||||
- Requests 1ms timer resolution via `timeBeginPeriod(1)`
|
||||
|
||||
### Interrupt Protection
|
||||
|
||||
- Critical sections protected using `CRITICAL_SECTION` objects
|
||||
- Prevents race conditions during task queue modifications
|
||||
- `EnterCriticalSection`/`LeaveCriticalSection` used for mutual exclusion
|
||||
- Supports nested critical sections (automatic lock counting)
|
||||
|
||||
### Multi-VM Support
|
||||
|
||||
- Supports up to `MRB_TASK_MAX_VMS` concurrent mruby VM instances (default: 8)
|
||||
- Single shared timer ticks all registered VMs
|
||||
- Per-VM task counters optimize timer usage (timer disabled when idle)
|
||||
- Interlocked operations (`InterlockedIncrement`/`InterlockedDecrement`) for thread safety
|
||||
|
||||
### Timer Optimization
|
||||
|
||||
The implementation dynamically enables/disables the timer based on task state:
|
||||
|
||||
- **Timer enabled** when: Multiple ready tasks OR any waiting tasks exist
|
||||
- **Timer disabled** when: Single task or all tasks dormant/suspended
|
||||
- Reduces CPU usage and power consumption when scheduler is idle
|
||||
|
||||
## Configuration
|
||||
|
||||
Override these macros in your build config if needed:
|
||||
|
||||
```ruby
|
||||
conf.gem core: 'hal-win-task' do |spec|
|
||||
# Custom tick interval (10ms instead of default 4ms)
|
||||
spec.build.defines << 'MRB_TICK_UNIT=10'
|
||||
|
||||
# Custom timeslice (5 ticks instead of default 3)
|
||||
spec.build.defines << 'MRB_TIMESLICE_TICK_COUNT=5'
|
||||
|
||||
# More concurrent VMs (16 instead of default 8)
|
||||
spec.build.defines << 'MRB_TASK_MAX_VMS=16'
|
||||
end
|
||||
```
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Timer resolution typically limited to 1-2ms even with `timeBeginPeriod(1)`
|
||||
- Multimedia timers consume system resources (kernel timer objects)
|
||||
- Timer callbacks execute in separate thread context (handled internally)
|
||||
- Not suitable for hard real-time requirements
|
||||
- May interfere with other multimedia applications requesting different timer resolutions
|
||||
|
||||
## See Also
|
||||
|
||||
- `mruby-task` - Core task scheduler
|
||||
- `hal-posix-task` - POSIX/Unix HAL implementation
|
||||
- Task scheduler documentation: `mrbgems/mruby-task/README.md`
|
||||
|
||||
## Build Notes
|
||||
|
||||
The `winmm` library is automatically linked by the gem specification. No additional linker configuration is needed.
|
||||
@@ -0,0 +1,11 @@
|
||||
MRuby::Gem::Specification.new('hal-win-task') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = 'mruby developers'
|
||||
spec.summary = 'Windows HAL for mruby-task'
|
||||
|
||||
# HAL gem depends on feature gem - brings in mruby-task automatically
|
||||
spec.add_dependency 'mruby-task', core: 'mruby-task'
|
||||
|
||||
# Windows multimedia timer library
|
||||
spec.linker.libraries << 'winmm'
|
||||
end
|
||||
@@ -167,3 +167,21 @@ mrb_hal_task_final(mrb_state *mrb)
|
||||
LeaveCriticalSection(&irq_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Gem initialization (empty - HAL functions called by mruby-task)
|
||||
*/
|
||||
|
||||
void
|
||||
mrb_hal_win_task_gem_init(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* HAL interface functions are called by mruby-task gem */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hal_win_task_gem_final(mrb_state *mrb)
|
||||
{
|
||||
(void)mrb;
|
||||
/* Cleanup handled by mrb_hal_task_final called from mruby-task */
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
# hw-adc - ADC peripheral interface for mruby
|
||||
|
||||
This gem provides the `ADC` class for reading analog input from
|
||||
mruby. It is designed for embedded platforms such as ESP32 and
|
||||
RP2040.
|
||||
|
||||
## Architecture
|
||||
|
||||
Platform-specific HAL implementations are in `ports/` directories:
|
||||
|
||||
- `ports/esp32/` - ESP32 using ESP-IDF ADC oneshot driver
|
||||
- `ports/rp2040/` - RP2040 using Pico SDK ADC hardware
|
||||
|
||||
## Build Configuration
|
||||
|
||||
```ruby
|
||||
MRuby::CrossBuild.new('esp32') do |conf|
|
||||
conf.ports :esp32
|
||||
conf.gem core: 'hw-adc'
|
||||
end
|
||||
```
|
||||
|
||||
## Ruby API
|
||||
|
||||
### ADC.new
|
||||
|
||||
```ruby
|
||||
adc = ADC.new(pin)
|
||||
```
|
||||
|
||||
- `pin` - ADC-capable GPIO pin number (Integer)
|
||||
- Raises `ArgumentError` if the pin is not valid for ADC
|
||||
|
||||
### ADC#read / ADC#read_voltage
|
||||
|
||||
Read the analog value as voltage (Float).
|
||||
|
||||
```ruby
|
||||
voltage = adc.read # => 1.65
|
||||
voltage = adc.read_voltage # same
|
||||
```
|
||||
|
||||
### ADC#read_raw
|
||||
|
||||
Read the raw ADC value (Integer, typically 0-4095 for 12-bit).
|
||||
|
||||
```ruby
|
||||
raw = adc.read_raw # => 2048
|
||||
```
|
||||
|
||||
### ADC#input
|
||||
|
||||
Returns the ADC input channel number assigned during initialization.
|
||||
|
||||
## HAL Interface
|
||||
|
||||
To add support for a new platform, create a `ports/<name>/`
|
||||
directory and implement the following C functions declared in
|
||||
`<mruby/adc.h>`:
|
||||
|
||||
```c
|
||||
int mrb_adc_init(uint8_t pin);
|
||||
uint32_t mrb_adc_read_raw(uint8_t input);
|
||||
float mrb_adc_read_voltage(uint8_t input);
|
||||
```
|
||||
|
||||
- `mrb_adc_init` returns the input channel number (>= 0) on
|
||||
success, negative on error
|
||||
- `input` parameter for read functions is the value returned by
|
||||
`mrb_adc_init`
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef MRUBY_ADC_H
|
||||
#define MRUBY_ADC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* HAL functions - implemented in ports/<platform>/adc.c */
|
||||
int mrb_adc_init(uint8_t pin);
|
||||
uint32_t mrb_adc_read_raw(uint8_t input);
|
||||
float mrb_adc_read_voltage(uint8_t input);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MRUBY_ADC_H */
|
||||
@@ -1,5 +0,0 @@
|
||||
MRuby::Gem::Specification.new('hw-adc') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = ['HASUMI Hitoshi', 'mruby developers']
|
||||
spec.summary = 'ADC peripheral interface'
|
||||
end
|
||||
@@ -1,7 +0,0 @@
|
||||
class ADC
|
||||
def initialize(pin)
|
||||
@input = __init(pin)
|
||||
end
|
||||
|
||||
attr_reader :input
|
||||
end
|
||||
@@ -1,147 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include "esp_adc/adc_oneshot.h"
|
||||
#include <mruby/adc.h>
|
||||
|
||||
#define VOLTAGE_MAX 3.3f
|
||||
#define RESOLUTION 4095
|
||||
#define UNIT_NUM 2
|
||||
|
||||
static adc_oneshot_unit_handle_t adc_handles[UNIT_NUM];
|
||||
static bool adc_initialized;
|
||||
|
||||
static adc_unit_t
|
||||
pin_to_unit(uint8_t pin)
|
||||
{
|
||||
switch (pin) {
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
case 0: case 1: case 2: case 3: case 4:
|
||||
return ADC_UNIT_1;
|
||||
case 5:
|
||||
return ADC_UNIT_2;
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
case 32: case 33: case 34: case 35: case 36: case 39:
|
||||
return ADC_UNIT_1;
|
||||
case 0: case 2: case 4: case 12: case 13: case 14: case 15:
|
||||
case 25: case 26: case 27:
|
||||
return ADC_UNIT_2;
|
||||
#elif (CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2)
|
||||
case 1: case 2: case 3: case 4: case 5:
|
||||
case 6: case 7: case 8: case 9: case 10:
|
||||
return ADC_UNIT_1;
|
||||
case 11: case 12: case 13: case 14: case 15:
|
||||
case 16: case 17: case 18: case 19: case 20:
|
||||
return ADC_UNIT_2;
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static adc_channel_t
|
||||
pin_to_channel(uint8_t pin)
|
||||
{
|
||||
switch (pin) {
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
case 0: return ADC_CHANNEL_0;
|
||||
case 1: return ADC_CHANNEL_1;
|
||||
case 2: return ADC_CHANNEL_2;
|
||||
case 3: return ADC_CHANNEL_3;
|
||||
case 4: return ADC_CHANNEL_4;
|
||||
case 5: return ADC_CHANNEL_0;
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
case 36: return ADC_CHANNEL_0;
|
||||
case 39: return ADC_CHANNEL_3;
|
||||
case 32: return ADC_CHANNEL_4;
|
||||
case 33: return ADC_CHANNEL_5;
|
||||
case 34: return ADC_CHANNEL_6;
|
||||
case 35: return ADC_CHANNEL_7;
|
||||
case 4: return ADC_CHANNEL_0;
|
||||
case 0: return ADC_CHANNEL_1;
|
||||
case 2: return ADC_CHANNEL_2;
|
||||
case 15: return ADC_CHANNEL_3;
|
||||
case 13: return ADC_CHANNEL_4;
|
||||
case 12: return ADC_CHANNEL_5;
|
||||
case 14: return ADC_CHANNEL_6;
|
||||
case 27: return ADC_CHANNEL_7;
|
||||
case 25: return ADC_CHANNEL_8;
|
||||
case 26: return ADC_CHANNEL_9;
|
||||
#elif (CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32S2)
|
||||
case 1: return ADC_CHANNEL_0;
|
||||
case 2: return ADC_CHANNEL_1;
|
||||
case 3: return ADC_CHANNEL_2;
|
||||
case 4: return ADC_CHANNEL_3;
|
||||
case 5: return ADC_CHANNEL_4;
|
||||
case 6: return ADC_CHANNEL_5;
|
||||
case 7: return ADC_CHANNEL_6;
|
||||
case 8: return ADC_CHANNEL_7;
|
||||
case 9: return ADC_CHANNEL_8;
|
||||
case 10: return ADC_CHANNEL_9;
|
||||
case 11: return ADC_CHANNEL_0;
|
||||
case 12: return ADC_CHANNEL_1;
|
||||
case 13: return ADC_CHANNEL_2;
|
||||
case 14: return ADC_CHANNEL_3;
|
||||
case 15: return ADC_CHANNEL_4;
|
||||
case 16: return ADC_CHANNEL_5;
|
||||
case 17: return ADC_CHANNEL_6;
|
||||
case 18: return ADC_CHANNEL_7;
|
||||
case 19: return ADC_CHANNEL_8;
|
||||
case 20: return ADC_CHANNEL_9;
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
init_units(void)
|
||||
{
|
||||
adc_unit_t units[] = { ADC_UNIT_1, ADC_UNIT_2 };
|
||||
for (int i = 0; i < UNIT_NUM; i++) {
|
||||
adc_oneshot_unit_init_cfg_t cfg = {
|
||||
.unit_id = units[i],
|
||||
.ulp_mode = ADC_ULP_MODE_DISABLE,
|
||||
};
|
||||
if (adc_oneshot_new_unit(&cfg, &adc_handles[i]) != ESP_OK)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
mrb_adc_init(uint8_t pin)
|
||||
{
|
||||
if (!adc_initialized) {
|
||||
if (init_units() != 0) return -1;
|
||||
adc_initialized = true;
|
||||
}
|
||||
|
||||
int ch = pin_to_channel(pin);
|
||||
if (ch < 0) return -1;
|
||||
|
||||
adc_unit_t unit = pin_to_unit(pin);
|
||||
if (unit < 0 || unit >= UNIT_NUM) return -1;
|
||||
|
||||
adc_oneshot_chan_cfg_t cfg = {
|
||||
.atten = ADC_ATTEN_DB_12,
|
||||
.bitwidth = ADC_BITWIDTH_DEFAULT,
|
||||
};
|
||||
if (adc_oneshot_config_channel(adc_handles[unit], ch, &cfg) != ESP_OK)
|
||||
return -1;
|
||||
|
||||
return (int)pin;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mrb_adc_read_raw(uint8_t input)
|
||||
{
|
||||
adc_unit_t unit = pin_to_unit(input);
|
||||
int ch = pin_to_channel(input);
|
||||
int raw = 0;
|
||||
if (unit >= 0 && unit < UNIT_NUM)
|
||||
adc_oneshot_read(adc_handles[unit], ch, &raw);
|
||||
return (uint32_t)raw;
|
||||
}
|
||||
|
||||
float
|
||||
mrb_adc_read_voltage(uint8_t input)
|
||||
{
|
||||
return (float)mrb_adc_read_raw(input) * VOLTAGE_MAX / RESOLUTION;
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include "hardware/adc.h"
|
||||
#include <mruby/adc.h>
|
||||
|
||||
#define VOLTAGE_MAX 3.3f
|
||||
#define RESOLUTION 4095
|
||||
#define TEMP_INPUT 4
|
||||
|
||||
static bool adc_initialized;
|
||||
|
||||
int
|
||||
mrb_adc_init(uint8_t pin)
|
||||
{
|
||||
if (!adc_initialized) {
|
||||
adc_init();
|
||||
adc_initialized = true;
|
||||
}
|
||||
|
||||
uint input;
|
||||
switch (pin) {
|
||||
case 26: input = 0; break;
|
||||
case 27: input = 1; break;
|
||||
case 28: input = 2; break;
|
||||
case 29: input = 3; break;
|
||||
default: return -1;
|
||||
}
|
||||
adc_gpio_init(pin);
|
||||
return (int)input;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
mrb_adc_read_raw(uint8_t input)
|
||||
{
|
||||
adc_select_input(input);
|
||||
return (uint32_t)adc_read();
|
||||
}
|
||||
|
||||
float
|
||||
mrb_adc_read_voltage(uint8_t input)
|
||||
{
|
||||
adc_select_input(input);
|
||||
return (float)adc_read() * VOLTAGE_MAX / RESOLUTION;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/presym.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/adc.h>
|
||||
|
||||
/* ADC#__init(pin) */
|
||||
static mrb_value
|
||||
mrb_adc_m_init(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
int input = mrb_adc_init((uint8_t)pin);
|
||||
if (input < 0) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid ADC pin");
|
||||
}
|
||||
return mrb_fixnum_value(input);
|
||||
}
|
||||
|
||||
/* ADC#read_raw */
|
||||
static mrb_value
|
||||
mrb_adc_m_read_raw(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int input = mrb_integer(mrb_iv_get(mrb, self, MRB_IVSYM(input)));
|
||||
return mrb_fixnum_value(mrb_adc_read_raw((uint8_t)input));
|
||||
}
|
||||
|
||||
/* ADC#read_voltage (also aliased as read) */
|
||||
static mrb_value
|
||||
mrb_adc_m_read_voltage(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int input = mrb_integer(mrb_iv_get(mrb, self, MRB_IVSYM(input)));
|
||||
return mrb_float_value(mrb, (mrb_float)mrb_adc_read_voltage((uint8_t)input));
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hw_adc_gem_init(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *cls = mrb_define_class_id(mrb, MRB_SYM(ADC), mrb->object_class);
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(__init), mrb_adc_m_init, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(read_raw), mrb_adc_m_read_raw, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(read_voltage), mrb_adc_m_read_voltage, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(read), mrb_adc_m_read_voltage, MRB_ARGS_NONE());
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hw_adc_gem_final(mrb_state *mrb)
|
||||
{
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
# hw-gpio - GPIO peripheral interface for mruby
|
||||
|
||||
This gem provides the `GPIO` class for controlling general-purpose
|
||||
input/output pins from mruby.
|
||||
It is designed for embedded platforms such as ESP32 and RP2040.
|
||||
|
||||
## Architecture
|
||||
|
||||
Platform-specific HAL implementations are in `ports/` directories:
|
||||
|
||||
- `ports/esp32/` - ESP32 using ESP-IDF GPIO driver
|
||||
- `ports/rp2040/` - RP2040 using Pico SDK
|
||||
|
||||
The build system automatically compiles matching port sources based
|
||||
on `conf.ports` setting.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
```ruby
|
||||
# For ESP32
|
||||
MRuby::CrossBuild.new('esp32') do |conf|
|
||||
conf.ports :esp32
|
||||
conf.gem core: 'hw-gpio'
|
||||
end
|
||||
|
||||
# For RP2040
|
||||
MRuby::CrossBuild.new('rp2040') do |conf|
|
||||
conf.ports :rp2040
|
||||
conf.gem core: 'hw-gpio'
|
||||
end
|
||||
```
|
||||
|
||||
## Ruby API
|
||||
|
||||
### Constants (direction/mode flags)
|
||||
|
||||
These flags can be combined with bitwise OR.
|
||||
|
||||
| Flag | Value | Description |
|
||||
| ------------------ | ------ | -------------------------- |
|
||||
| `GPIO::IN` | `0x01` | Input mode |
|
||||
| `GPIO::OUT` | `0x02` | Output mode |
|
||||
| `GPIO::HIGH_Z` | `0x04` | High-impedance (tri-state) |
|
||||
| `GPIO::PULL_UP` | `0x08` | Enable pull-up resistor |
|
||||
| `GPIO::PULL_DOWN` | `0x10` | Enable pull-down resistor |
|
||||
| `GPIO::OPEN_DRAIN` | `0x20` | Enable open-drain output |
|
||||
|
||||
### GPIO.new
|
||||
|
||||
```ruby
|
||||
gpio = GPIO.new(pin, flags)
|
||||
```
|
||||
|
||||
- `pin` - GPIO pin number (Integer)
|
||||
- `flags` - direction and mode flags (combined with `|`)
|
||||
- Exactly one of `IN`, `OUT`, or `HIGH_Z` must be specified
|
||||
- `PULL_UP` and `PULL_DOWN` are mutually exclusive
|
||||
- Raises `ArgumentError` on invalid flag combinations
|
||||
|
||||
```ruby
|
||||
# Input with pull-up
|
||||
button = GPIO.new(2, GPIO::IN | GPIO::PULL_UP)
|
||||
|
||||
# Output
|
||||
led = GPIO.new(25, GPIO::OUT)
|
||||
```
|
||||
|
||||
### Instance Methods
|
||||
|
||||
#### GPIO#read
|
||||
|
||||
Read the current pin value.
|
||||
|
||||
```ruby
|
||||
val = gpio.read # => 0 or 1
|
||||
```
|
||||
|
||||
#### GPIO#write
|
||||
|
||||
Set the pin output value.
|
||||
|
||||
```ruby
|
||||
gpio.write(1) # set high
|
||||
gpio.write(0) # set low
|
||||
```
|
||||
|
||||
- Raises `ArgumentError` if value is not 0 or 1
|
||||
|
||||
#### GPIO#high? / GPIO#low?
|
||||
|
||||
```ruby
|
||||
gpio.high? # => true if read != 0
|
||||
gpio.low? # => true if read == 0
|
||||
```
|
||||
|
||||
#### GPIO#pin
|
||||
|
||||
```ruby
|
||||
gpio.pin # => pin number passed to new
|
||||
```
|
||||
|
||||
#### GPIO#setmode
|
||||
|
||||
Reconfigure pin direction and mode flags after initialization.
|
||||
|
||||
```ruby
|
||||
gpio.setmode(GPIO::OUT)
|
||||
```
|
||||
|
||||
### Class Methods
|
||||
|
||||
These operate directly on pin numbers without creating an instance.
|
||||
|
||||
```ruby
|
||||
GPIO.read_at(pin) # => 0 or 1
|
||||
GPIO.write_at(pin, val) # set pin output (0 or 1)
|
||||
GPIO.set_dir_at(pin, flags) # set direction (IN/OUT/HIGH_Z)
|
||||
GPIO.pull_up_at(pin) # enable pull-up
|
||||
GPIO.pull_down_at(pin) # enable pull-down
|
||||
GPIO.open_drain_at(pin) # enable open-drain
|
||||
```
|
||||
|
||||
## HAL Interface
|
||||
|
||||
To add support for a new platform, create a `ports/<name>/`
|
||||
directory and implement the following C functions declared in
|
||||
`<mruby/gpio.h>`:
|
||||
|
||||
```c
|
||||
void mrb_gpio_init(uint8_t pin);
|
||||
void mrb_gpio_set_dir(uint8_t pin, uint8_t flags);
|
||||
void mrb_gpio_pull_up(uint8_t pin);
|
||||
void mrb_gpio_pull_down(uint8_t pin);
|
||||
void mrb_gpio_open_drain(uint8_t pin);
|
||||
int mrb_gpio_read(uint8_t pin);
|
||||
void mrb_gpio_write(uint8_t pin, uint8_t val);
|
||||
```
|
||||
|
||||
The port sources are compiled automatically when the build
|
||||
configuration includes a matching `conf.ports` tag.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef MRUBY_GPIO_H
|
||||
#define MRUBY_GPIO_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* direction/mode flags (bitmask) */
|
||||
#define MRB_GPIO_IN 0x01
|
||||
#define MRB_GPIO_OUT 0x02
|
||||
#define MRB_GPIO_HIGH_Z 0x04
|
||||
#define MRB_GPIO_PULL_UP 0x08
|
||||
#define MRB_GPIO_PULL_DOWN 0x10
|
||||
#define MRB_GPIO_OPEN_DRAIN 0x20
|
||||
|
||||
/* HAL functions - implemented by hw-<platform>-gpio gems */
|
||||
void mrb_gpio_init(uint8_t pin);
|
||||
void mrb_gpio_set_dir(uint8_t pin, uint8_t flags);
|
||||
void mrb_gpio_pull_up(uint8_t pin);
|
||||
void mrb_gpio_pull_down(uint8_t pin);
|
||||
void mrb_gpio_open_drain(uint8_t pin);
|
||||
int mrb_gpio_read(uint8_t pin);
|
||||
void mrb_gpio_write(uint8_t pin, uint8_t val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MRUBY_GPIO_H */
|
||||
@@ -1,5 +0,0 @@
|
||||
MRuby::Gem::Specification.new('hw-gpio') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = ['HASUMI Hitoshi', 'mruby developers']
|
||||
spec.summary = 'GPIO peripheral interface'
|
||||
end
|
||||
@@ -1,44 +0,0 @@
|
||||
class GPIO
|
||||
IN = 0x01
|
||||
OUT = 0x02
|
||||
HIGH_Z = 0x04
|
||||
PULL_UP = 0x08
|
||||
PULL_DOWN = 0x10
|
||||
OPEN_DRAIN = 0x20
|
||||
|
||||
attr_reader :pin
|
||||
|
||||
def initialize(pin, flags)
|
||||
@pin = pin
|
||||
__init(pin)
|
||||
setmode(flags)
|
||||
end
|
||||
|
||||
def setmode(flags)
|
||||
dir = flags & (IN | OUT | HIGH_Z)
|
||||
n = (flags & IN != 0 ? 1 : 0) + (flags & OUT != 0 ? 1 : 0) + (flags & HIGH_Z != 0 ? 1 : 0)
|
||||
if n == 0
|
||||
raise ArgumentError, "specify one of IN, OUT, or HIGH_Z"
|
||||
elsif n > 1
|
||||
raise ArgumentError, "IN, OUT, and HIGH_Z are exclusive"
|
||||
end
|
||||
GPIO.set_dir_at(@pin, dir)
|
||||
|
||||
pull = flags & (PULL_UP | PULL_DOWN)
|
||||
if pull == (PULL_UP | PULL_DOWN)
|
||||
raise ArgumentError, "PULL_UP and PULL_DOWN are exclusive"
|
||||
end
|
||||
GPIO.pull_up_at(@pin) if pull == PULL_UP
|
||||
GPIO.pull_down_at(@pin) if pull == PULL_DOWN
|
||||
GPIO.open_drain_at(@pin) if flags & OPEN_DRAIN != 0
|
||||
nil
|
||||
end
|
||||
|
||||
def high?
|
||||
read != 0
|
||||
end
|
||||
|
||||
def low?
|
||||
read == 0
|
||||
end
|
||||
end
|
||||
@@ -1,50 +0,0 @@
|
||||
#include "driver/gpio.h"
|
||||
#include <mruby/gpio.h>
|
||||
|
||||
void
|
||||
mrb_gpio_init(uint8_t pin)
|
||||
{
|
||||
gpio_reset_pin(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_set_dir(uint8_t pin, uint8_t flags)
|
||||
{
|
||||
if (flags & MRB_GPIO_IN) {
|
||||
gpio_set_direction(pin, GPIO_MODE_INPUT);
|
||||
}
|
||||
else if (flags & MRB_GPIO_OUT) {
|
||||
gpio_set_direction(pin, GPIO_MODE_OUTPUT);
|
||||
}
|
||||
/* HIGH_Z: not yet implemented */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_pull_up(uint8_t pin)
|
||||
{
|
||||
gpio_pullup_en(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_pull_down(uint8_t pin)
|
||||
{
|
||||
gpio_pulldown_en(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_open_drain(uint8_t pin)
|
||||
{
|
||||
/* not yet implemented */
|
||||
}
|
||||
|
||||
int
|
||||
mrb_gpio_read(uint8_t pin)
|
||||
{
|
||||
return gpio_get_level(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_write(uint8_t pin, uint8_t val)
|
||||
{
|
||||
gpio_set_level(pin, val);
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#include <stdbool.h>
|
||||
#include "hardware/gpio.h"
|
||||
#include <mruby/gpio.h>
|
||||
|
||||
void
|
||||
mrb_gpio_init(uint8_t pin)
|
||||
{
|
||||
gpio_init(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_set_dir(uint8_t pin, uint8_t flags)
|
||||
{
|
||||
if (flags & MRB_GPIO_IN) {
|
||||
gpio_set_dir(pin, false);
|
||||
}
|
||||
else if (flags & MRB_GPIO_OUT) {
|
||||
gpio_set_dir(pin, true);
|
||||
}
|
||||
/* HIGH_Z: not yet implemented */
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_pull_up(uint8_t pin)
|
||||
{
|
||||
gpio_pull_up(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_pull_down(uint8_t pin)
|
||||
{
|
||||
gpio_pull_down(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_open_drain(uint8_t pin)
|
||||
{
|
||||
/* not yet implemented */
|
||||
}
|
||||
|
||||
int
|
||||
mrb_gpio_read(uint8_t pin)
|
||||
{
|
||||
return gpio_get(pin);
|
||||
}
|
||||
|
||||
void
|
||||
mrb_gpio_write(uint8_t pin, uint8_t val)
|
||||
{
|
||||
gpio_put(pin, val == 1);
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/presym.h>
|
||||
#include <mruby/variable.h>
|
||||
#include <mruby/gpio.h>
|
||||
|
||||
static mrb_value
|
||||
mrb_gpio_m_init(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
mrb_gpio_init((uint8_t)pin);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO.set_dir_at(pin, flags) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_set_dir_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin, flags;
|
||||
mrb_get_args(mrb, "ii", &pin, &flags);
|
||||
mrb_gpio_set_dir((uint8_t)pin, (uint8_t)flags);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO.pull_up_at(pin) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_pull_up_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
mrb_gpio_pull_up((uint8_t)pin);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO.pull_down_at(pin) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_pull_down_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
mrb_gpio_pull_down((uint8_t)pin);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO.open_drain_at(pin) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_open_drain_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
mrb_gpio_open_drain((uint8_t)pin);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO.read_at(pin) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_read_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin;
|
||||
mrb_get_args(mrb, "i", &pin);
|
||||
return mrb_fixnum_value(mrb_gpio_read((uint8_t)pin));
|
||||
}
|
||||
|
||||
/* GPIO.write_at(pin, val) */
|
||||
static mrb_value
|
||||
mrb_gpio_s_write_at(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_int pin, val;
|
||||
mrb_get_args(mrb, "ii", &pin, &val);
|
||||
if (val != 0 && val != 1) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "value must be 0 or 1");
|
||||
}
|
||||
mrb_gpio_write((uint8_t)pin, (uint8_t)val);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
/* GPIO#read */
|
||||
static mrb_value
|
||||
mrb_gpio_m_read(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int pin = mrb_integer(mrb_iv_get(mrb, self, MRB_IVSYM(pin)));
|
||||
return mrb_fixnum_value(mrb_gpio_read((uint8_t)pin));
|
||||
}
|
||||
|
||||
/* GPIO#write(val) */
|
||||
static mrb_value
|
||||
mrb_gpio_m_write(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int val;
|
||||
mrb_get_args(mrb, "i", &val);
|
||||
if (val != 0 && val != 1) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "value must be 0 or 1");
|
||||
}
|
||||
mrb_int pin = mrb_integer(mrb_iv_get(mrb, self, MRB_IVSYM(pin)));
|
||||
mrb_gpio_write((uint8_t)pin, (uint8_t)val);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hw_gpio_gem_init(mrb_state *mrb)
|
||||
{
|
||||
struct RClass *cls = mrb_define_class_id(mrb, MRB_SYM(GPIO), mrb->object_class);
|
||||
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(__init), mrb_gpio_m_init, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(read), mrb_gpio_m_read, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, cls, MRB_SYM(write), mrb_gpio_m_write, MRB_ARGS_REQ(1));
|
||||
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(set_dir_at), mrb_gpio_s_set_dir_at, MRB_ARGS_REQ(2));
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(pull_up_at), mrb_gpio_s_pull_up_at, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(pull_down_at), mrb_gpio_s_pull_down_at, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(open_drain_at), mrb_gpio_s_open_drain_at, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(read_at), mrb_gpio_s_read_at, MRB_ARGS_REQ(1));
|
||||
mrb_define_class_method_id(mrb, cls, MRB_SYM(write_at), mrb_gpio_s_write_at, MRB_ARGS_REQ(2));
|
||||
}
|
||||
|
||||
void
|
||||
mrb_hw_gpio_gem_final(mrb_state *mrb)
|
||||
{
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
# hw-i2c - I2C peripheral interface for mruby
|
||||
|
||||
This gem provides the `I2C` class for communicating with I2C devices from mruby. It is designed for embedded platforms such as ESP32 and RP2040.
|
||||
|
||||
## Architecture
|
||||
|
||||
Platform-specific HAL implementations are in `ports/` directories:
|
||||
|
||||
- `ports/esp32/` - ESP32 using ESP-IDF I2C master driver
|
||||
- `ports/rp2040/` - RP2040 using Pico SDK
|
||||
|
||||
The build system automatically compiles matching port sources based
|
||||
on `conf.ports` setting.
|
||||
|
||||
## Build Configuration
|
||||
|
||||
```ruby
|
||||
# For ESP32
|
||||
MRuby::CrossBuild.new('esp32') do |conf|
|
||||
conf.ports :esp32
|
||||
conf.gem core: 'hw-i2c'
|
||||
end
|
||||
|
||||
# For RP2040
|
||||
MRuby::CrossBuild.new('rp2040') do |conf|
|
||||
conf.ports :rp2040
|
||||
conf.gem core: 'hw-i2c'
|
||||
end
|
||||
```
|
||||
|
||||
## Ruby API
|
||||
|
||||
### I2C.new
|
||||
|
||||
```ruby
|
||||
i2c = I2C.new(
|
||||
unit: :ESP32_I2C0, # I2C unit name (platform-specific, required)
|
||||
frequency: 100_000, # bus frequency in Hz (default: 100kHz)
|
||||
sda_pin: 21, # SDA GPIO pin number (default: -1 for platform default)
|
||||
scl_pin: 22, # SCL GPIO pin number (default: -1 for platform default)
|
||||
timeout: 500 # default timeout in ms (default: 500)
|
||||
)
|
||||
```
|
||||
|
||||
#### Unit Names
|
||||
|
||||
| Platform | Available Units |
|
||||
| -------- | ------------------------------ |
|
||||
| ESP32 | `:ESP32_I2C0`, `:ESP32_I2C1` |
|
||||
| RP2040 | `:RP2040_I2C0`, `:RP2040_I2C1` |
|
||||
|
||||
On RP2040, if `sda_pin` or `scl_pin` is -1, the Pico SDK default pins are used.
|
||||
|
||||
### I2C#write
|
||||
|
||||
Write data to an I2C device.
|
||||
|
||||
```ruby
|
||||
i2c.write(addr, *data, timeout: 500)
|
||||
```
|
||||
|
||||
- `addr` - 7-bit I2C device address (Integer)
|
||||
- `data` - one or more data arguments, each can be:
|
||||
- **Integer** - a single byte (0-255)
|
||||
- **Array of Integer** - multiple bytes
|
||||
- **String** - raw bytes
|
||||
- `timeout:` - optional timeout in ms (overrides instance default)
|
||||
- Returns the number of bytes written (Integer)
|
||||
- Raises `IOError` on failure
|
||||
|
||||
```ruby
|
||||
# Write a single byte
|
||||
i2c.write(0x3C, 0x00)
|
||||
|
||||
# Write multiple bytes
|
||||
i2c.write(0x3C, 0x00, [0xAE, 0xD5, 0x80])
|
||||
|
||||
# Write a string
|
||||
i2c.write(0x3C, "hello")
|
||||
|
||||
# Mix data types
|
||||
i2c.write(0x3C, 0x40, [0x01, 0x02], "data")
|
||||
```
|
||||
|
||||
### I2C#read
|
||||
|
||||
Read data from an I2C device. Optionally write data before reading (repeated START).
|
||||
|
||||
```ruby
|
||||
i2c.read(addr, length, *write_data, timeout: 500)
|
||||
```
|
||||
|
||||
- `addr` - 7-bit I2C device address (Integer)
|
||||
- `length` - number of bytes to read (Integer, must be positive)
|
||||
- `write_data` - optional data to write before reading (same format as `write`). When provided, the gem performs a write-then-read transaction using I2C repeated START condition. This is the standard way to read from a specific register.
|
||||
- `timeout:` - optional timeout in ms (overrides instance default)
|
||||
- Returns the data read (String)
|
||||
- Raises `IOError` on failure, `ArgumentError` if length <= 0
|
||||
|
||||
```ruby
|
||||
# Simple read (2 bytes from device)
|
||||
data = i2c.read(0x50, 2)
|
||||
|
||||
# Register read: write register address 0x00, then read 2 bytes
|
||||
data = i2c.read(0x50, 2, 0x00)
|
||||
|
||||
# Multi-byte register address
|
||||
data = i2c.read(0x50, 4, [0x00, 0x10])
|
||||
```
|
||||
|
||||
### I2C#scan
|
||||
|
||||
Scan the I2C bus for responsive devices.
|
||||
|
||||
```ruby
|
||||
i2c.scan(timeout: 500)
|
||||
```
|
||||
|
||||
- `timeout:` - optional timeout per probe in ms
|
||||
- Returns an Array of 7-bit addresses (Integer) that responded
|
||||
|
||||
```ruby
|
||||
found = i2c.scan
|
||||
# => [0x3C, 0x50, 0x68]
|
||||
```
|
||||
|
||||
## HAL Interface
|
||||
|
||||
To add support for a new platform, create a `ports/<name>/`
|
||||
directory and implement the following C functions declared in
|
||||
`<mruby/i2c.h>`:
|
||||
|
||||
```c
|
||||
int mrb_i2c_unit_name_to_num(const char *name);
|
||||
mrb_i2c_status mrb_i2c_init(int unit, uint32_t freq, int8_t sda, int8_t scl);
|
||||
int mrb_i2c_read(int unit, uint8_t addr, uint8_t *dst, size_t len,
|
||||
uint32_t timeout_us);
|
||||
int mrb_i2c_write(int unit, uint8_t addr, const uint8_t *src, size_t len,
|
||||
uint32_t timeout_us);
|
||||
int mrb_i2c_write_read(int unit, uint8_t addr,
|
||||
const uint8_t *src, size_t wlen,
|
||||
uint8_t *dst, size_t rlen,
|
||||
uint32_t timeout_us);
|
||||
```
|
||||
|
||||
The port sources are compiled automatically when the build
|
||||
configuration includes a matching `conf.ports` tag.
|
||||
|
||||
### Error Codes
|
||||
|
||||
```c
|
||||
typedef enum {
|
||||
MRB_I2C_OK = 0,
|
||||
MRB_I2C_ERROR_UNIT = -1, /* invalid or uninitialized unit */
|
||||
MRB_I2C_ERROR_TIMEOUT = -2, /* communication timeout */
|
||||
MRB_I2C_ERROR_NACK = -3, /* device did not acknowledge */
|
||||
} mrb_i2c_status;
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef MRUBY_I2C_H
|
||||
#define MRUBY_I2C_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
MRB_I2C_OK = 0,
|
||||
MRB_I2C_ERROR_UNIT = -1,
|
||||
MRB_I2C_ERROR_TIMEOUT = -2,
|
||||
MRB_I2C_ERROR_NACK = -3,
|
||||
} mrb_i2c_status;
|
||||
|
||||
/* HAL functions - implemented by hw-<platform>-i2c gems */
|
||||
mrb_i2c_status mrb_i2c_init(int unit, uint32_t freq, int8_t sda, int8_t scl);
|
||||
int mrb_i2c_read(int unit, uint8_t addr, uint8_t *dst, size_t len, uint32_t timeout_us);
|
||||
int mrb_i2c_write(int unit, uint8_t addr, const uint8_t *src, size_t len, uint32_t timeout_us);
|
||||
int mrb_i2c_write_read(int unit, uint8_t addr, const uint8_t *src, size_t wlen,
|
||||
uint8_t *dst, size_t rlen, uint32_t timeout_us);
|
||||
int mrb_i2c_unit_name_to_num(const char *name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MRUBY_I2C_H */
|
||||
@@ -1,5 +0,0 @@
|
||||
MRuby::Gem::Specification.new('hw-i2c') do |spec|
|
||||
spec.license = 'MIT'
|
||||
spec.authors = ['HASUMI Hitoshi', 'mruby developers']
|
||||
spec.summary = 'I2C peripheral interface'
|
||||
end
|
||||
@@ -1,21 +0,0 @@
|
||||
class I2C
|
||||
DEFAULT_FREQUENCY = 100_000 # Hz
|
||||
DEFAULT_TIMEOUT = 500 # ms
|
||||
|
||||
def initialize(unit:, frequency: DEFAULT_FREQUENCY, sda_pin: -1, scl_pin: -1, timeout: DEFAULT_TIMEOUT)
|
||||
@timeout = timeout
|
||||
@unit_num = __init(unit.to_s, frequency, sda_pin, scl_pin)
|
||||
end
|
||||
|
||||
def scan(timeout: @timeout)
|
||||
found = []
|
||||
(0x08..0x77).each do |addr|
|
||||
begin
|
||||
read(addr, 1, timeout: timeout)
|
||||
found << addr
|
||||
rescue IOError
|
||||
end
|
||||
end
|
||||
found
|
||||
end
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user