Skip to content

chore: Release v0.8.3#1072

Merged
msluszniak merged 4 commits intorelease/0.8from
patch/v0.8.3
Apr 10, 2026
Merged

chore: Release v0.8.3#1072
msluszniak merged 4 commits intorelease/0.8from
patch/v0.8.3

Conversation

@msluszniak
Copy link
Copy Markdown
Member

Summary

Patch release v0.8.3 — cherry-picks the following bug fixes from main into release/0.8:

Checklist

  • Commits cherry-picked from main in chronological order
  • Version bumped to 0.8.3 in packages/react-native-executorch/package.json

🤖 Generated with Claude Code

radko93 and others added 4 commits April 10, 2026 11:39
…rate() and unload() (#1056)

## Description

Add thread-safety to `VoiceActivityDetection` using the same mutex
pattern already established by `VisionModel`.

Without this, `BaseModel::unload()` can destroy `module_` on the JS
thread while `generate()` is still calling `forward()` on a worker
thread, causing `SIGILL` / `SIGSEGV` crashes.

### Introduces a breaking change?

- [x] No

### Type of change

- [x] Bug fix (change which fixes an issue)

### Tested on

- [x] Android

### Testing instructions

Use `useVAD({ model: FSMN_VAD })` with continuous audio input and
trigger rapid mount/unmount cycles. Confirm no crashes or deadlocks.

### Related issues

Fixes #1055

---------

Co-authored-by: Bartosz Hanc <bartosz.hanc02@gmail.com>
## Description

Fix crashes when loading LLMs by using mmap and avoiding reporting model
file size as external memory pressure. This PR changes how LLM models
are loaded to prevent crashes with large models. Previously, reporting
the full model file size via setExternalMemoryPressure() would cause
Hermes to crash because it breaks the GC's heap accounting when external
memory exceeds or approaches the 3GB max heap size.

We also set the LoadMode to Mmap instead of File, causing the ET runtime
to lazy-load weights to RAM on-demand instead of storing the entire file
content in memory, preventing the OS from killing the app.

### Introduces a breaking change?

- [ ] Yes
- [x] No

### Type of change

- [x] Bug fix (change which fixes an issue)
- [ ] New feature (change which adds functionality)
- [ ] Documentation update (improves or adds clarity to existing
documentation)
- [ ] Other (chores, tests, code style improvements etc.)

### Tested on

- [x] iOS
- [x] Android

### Testing instructions

- [ ] Take a large model, verify it crashes the app on main and note the
memory consumption
- [ ] Try running the same model on this branch, make sure it doesn't
crash and note the memory consumption
- [ ] Verify models that would usually fit in your RAM are not slowed
down significantly.

### Screenshots

<!-- Add screenshots here, if applicable -->

### Related issues

<!-- Link related issues here using #issue-number -->

### Checklist

- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have updated the documentation accordingly
- [ ] My changes generate no new warnings

### Additional notes

<!-- Include any additional information, assumptions, or context that
reviewers might need to understand this PR. -->

---------

Co-authored-by: Mateusz Sluszniak <56299341+msluszniak@users.noreply.github.com>
## Description

Adds thread-safety to Text Embeddings and Text-to-Image models mirroring
what was already done for models inheriting from VisionModel and VAD.

### Introduces a breaking change?

- [ ] Yes
- [x] No

### Type of change

- [x] Bug fix (change which fixes an issue)
- [ ] New feature (change which adds functionality)
- [ ] Documentation update (improves or adds clarity to existing
documentation)
- [ ] Other (chores, tests, code style improvements etc.)

### Tested on

- [x] iOS
- [x] Android

### Testing instructions

Use the following app screen and try to trigger the race condition
before fix and verify that it doesn't occur after applying the fix. You
can use `adb logcat | grep -E "FATAL|SIGSEGV|backtrace"` to observe the
error on Android.

```ts
import React, { useState } from 'react';
import { Button, ScrollView, Text, View } from 'react-native';
import {
  BK_SDM_TINY_VPRED_512,
  TextToImageModule,
} from 'react-native-executorch';
import {
  CLIP_VIT_BASE_PATCH32_TEXT,
  TextEmbeddingsModule,
} from 'react-native-executorch';
import { FSMN_VAD, VADModule } from 'react-native-executorch';

const DELAY_MS = 50; // tune this so that forward() is running when delete() is called

const MODEL_VAD = {
  name: 'VAD',
  load: (onProgress: (p: number) => void) =>
    VADModule.fromModelName(FSMN_VAD, onProgress),
  input: () => new Float32Array(16000 * 300),
};
const MODEL_TEXT_EMBEDDINGS = {
  name: 'TextEmbeddings',
  load: (onProgress: (p: number) => void) =>
    TextEmbeddingsModule.fromModelName(CLIP_VIT_BASE_PATCH32_TEXT, onProgress),
  input: () => 'hello world',
};
const MODEL_TEXT_TO_IMAGE = {
  name: 'TextToImage',
  load: (onProgress: (p: number) => void) =>
    TextToImageModule.fromModelName(BK_SDM_TINY_VPRED_512, onProgress),
  input: () => 'a red apple',
};
const MODEL = MODEL_TEXT_EMBEDDINGS;

export default function RaceTest() {
  const [lines, setLines] = useState<string[]>([]);
  const [downloadProgress, setDownloadProgress] = useState<number | null>(null);
  const log = (line: string) => setLines((prev) => [line, ...prev]);
  const run = async () => {
    setLines([]);
    setDownloadProgress(null);
    log(`model: ${MODEL.name}`);

    log('loading');
    const model = await MODEL.load((p) => setDownloadProgress(p));
    setDownloadProgress(null);

    log('running forward()');
    const result = model.forward(MODEL.input());

    log(`waiting ${DELAY_MS} ms`);
    await new Promise((r) => setTimeout(r, DELAY_MS));

    log('calling delete()');
    model.delete();

    try {
      await result;
      log('forward() completed successfully');
    } catch (e: any) {
      log('error: ' + (e?.message ?? String(e)));
    }
  };

  return (
    <View>
      <Button title="Run Race Test" onPress={run} />
      {downloadProgress !== null && (
        <Text>downloading: {Math.round(downloadProgress * 100)}%</Text>
      )}
      <ScrollView>
        {lines.map((l, i) => (
          <Text key={i}>{l}</Text>
        ))}
      </ScrollView>
    </View>
  );
}

```

### Screenshots

<!-- Add screenshots here, if applicable -->

### Related issues

#1055 

### Checklist

- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have updated the documentation accordingly
- [x] My changes generate no new warnings

### Additional notes

<!-- Include any additional information, assumptions, or context that
reviewers might need to understand this PR. -->
@msluszniak msluszniak self-assigned this Apr 10, 2026
@msluszniak msluszniak added the chore PRs that are chores label Apr 10, 2026
@msluszniak msluszniak requested a review from mkopcins April 10, 2026 09:40
@msluszniak msluszniak merged commit c168535 into release/0.8 Apr 10, 2026
2 checks passed
@msluszniak msluszniak deleted the patch/v0.8.3 branch April 10, 2026 10:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore PRs that are chores

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants