Skip to content

Forward String::length in RuntimeDecorator and WithRuntimeDecorator - #2205

Closed
mrousavy wants to merge 1 commit into
facebook:static_hfrom
mrousavy:decorator-string-length
Closed

mrousavy wants to merge 1 commit into
facebook:static_hfrom
mrousavy:decorator-string-length

Conversation

@mrousavy

Copy link
Copy Markdown
Contributor

Summary

IRuntime::length(const String&) came in with "Add String::length API" (590396b on static_h, D96030262), and that commit didn't touch decorator.h. Neither RuntimeDecorator nor WithRuntimeDecorator overrides it, so on a decorated runtime length() falls back to the default utf16(str).size() and never reaches the wrapped runtime.

It looks like an oversight. The same stack added push, tryGetMutableBuffer, detached and the TypedArray methods, and each of those commits added decorator overrides, including one for this method's overload length(const TypedArray&). The createError* commit (#2203) and this one didn't.

For Hermes-backed decorators the value is already right, because Hermes' utf16() is exact, but every call copies the whole string instead of reading the length. Runtimes with a native length() and the default utf16() get wrong answers. React Native's JSCRuntime is one: built against the system JavaScriptCore and wrapped in a RuntimeDecorator, 'a\uD800b' has length 1 instead of 3 and 'x\uDC00yz' has 1 instead of 4. With this change both match the undecorated runtime. That setup lives outside this repo, so it isn't a test here.

WithRuntimeDecorator needs the override too. Otherwise it would inherit the plain forward and length() would skip Around, which it currently goes through via utf16().

TracingRuntime no longer records an incidental Utf16Record when length() is called. That record only came from the utf16() fallback. I didn't add a record for length(): strings are immutable, and TracingRuntime already leaves pure queries like size(Array) untraced.

Test Plan

Added JSITest.DecoratorForwardsStringLength. An inner decorator returns a sentinel from length() and counts length() and utf16() calls. The test checks that a RuntimeDecorator and a WithRuntimeDecorator over it both reach that length() without calling utf16(), and that Around runs once. It fails without the change (it gets 5 from the utf16() fallback) and passes with it. The full APITests binary passes (357 tests) in a Debug + ASan build, including the SynthTrace and TraceInterpreter tests.

🤖 Generated with Claude Code

@meta-cla meta-cla Bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Sep 25, 2026
@mrousavy
mrousavy deployed to npm-publish September 26, 2026 00:22 — with GitHub Actions Active
IRuntime::length(const String&) was added in "Add `String::length` API"
(D96030262) without decorator overrides, so calls on a decorated runtime
fall back to the default Runtime::length, which copies the string
through utf16() instead of reaching the wrapped runtime's own length().
Forward it like the other string methods, and wrap it in Around in
WithRuntimeDecorator.
@mrousavy
mrousavy force-pushed the decorator-string-length branch from 93f8987 to f0dab2b Compare September 26, 2026 13:16
@mrousavy
mrousavy deployed to npm-publish September 26, 2026 13:40 — with GitHub Actions Active
@meta-codesync

meta-codesync Bot commented Oct 7, 2026

Copy link
Copy Markdown

@lavenzg has imported this pull request. If you are a Meta employee, you can view this in D123943189.

lavenzg pushed a commit to lavenzg/react-native that referenced this pull request Oct 7, 2026
…eact#58936)

Summary:


`IRuntime::length(const String&)` came in with "Add `String::length` API" (590396bd4 on static_h, D96030262), and that commit didn't touch `decorator.h`. Neither `RuntimeDecorator` nor `WithRuntimeDecorator` overrides it, so on a decorated runtime `length()` falls back to the default `utf16(str).size()` and never reaches the wrapped runtime.

It looks like an oversight. The same stack added `push`, `tryGetMutableBuffer`, `detached` and the TypedArray methods, and each of those commits added decorator overrides, including one for this method's overload `length(const TypedArray&)`. The `createError*` commit (facebook/hermes#2203) and this one didn't.

For Hermes-backed decorators the value is already right, because Hermes' `utf16()` is exact, but every call copies the whole string instead of reading the length. Runtimes with a native `length()` and the default `utf16()` get wrong answers. React Native's `JSCRuntime` is one: built against the system JavaScriptCore and wrapped in a `RuntimeDecorator`, `'a\uD800b'` has length 1 instead of 3 and `'x\uDC00yz'` has 1 instead of 4. With this change both match the undecorated runtime. That setup lives outside this repo, so it isn't a test here.

`WithRuntimeDecorator` needs the override too. Otherwise it would inherit the plain forward and `length()` would skip `Around`, which it currently goes through via `utf16()`.

`TracingRuntime` no longer records an incidental `Utf16Record` when `length()` is called. That record only came from the `utf16()` fallback. I didn't add a record for `length()`: strings are immutable, and `TracingRuntime` already leaves pure queries like `size(Array)` untraced.

X-link: facebook/hermes#2205

Test Plan:
Added `JSITest.DecoratorForwardsStringLength`. An inner decorator returns a sentinel from `length()` and counts `length()` and `utf16()` calls. The test checks that a `RuntimeDecorator` and a `WithRuntimeDecorator` over it both reach that `length()` without calling `utf16()`, and that `Around` runs once. It fails without the change (it gets 5 from the `utf16()` fallback) and passes with it. The full `APITests` binary passes (357 tests) in a Debug + ASan build, including the SynthTrace and TraceInterpreter tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: avp

Differential Revision: D123943189

Pulled By: lavenzg
meta-codesync Bot pushed a commit that referenced this pull request Oct 8, 2026
…2205)

Summary:
X-link: react/react-native#58936

`IRuntime::length(const String&)` came in with "Add `String::length` API" (590396b on static_h, D96030262), and that commit didn't touch `decorator.h`. Neither `RuntimeDecorator` nor `WithRuntimeDecorator` overrides it, so on a decorated runtime `length()` falls back to the default `utf16(str).size()` and never reaches the wrapped runtime.

It looks like an oversight. The same stack added `push`, `tryGetMutableBuffer`, `detached` and the TypedArray methods, and each of those commits added decorator overrides, including one for this method's overload `length(const TypedArray&)`. The `createError*` commit (#2203) and this one didn't.

For Hermes-backed decorators the value is already right, because Hermes' `utf16()` is exact, but every call copies the whole string instead of reading the length. Runtimes with a native `length()` and the default `utf16()` get wrong answers. React Native's `JSCRuntime` is one: built against the system JavaScriptCore and wrapped in a `RuntimeDecorator`, `'a\uD800b'` has length 1 instead of 3 and `'x\uDC00yz'` has 1 instead of 4. With this change both match the undecorated runtime. That setup lives outside this repo, so it isn't a test here.

`WithRuntimeDecorator` needs the override too. Otherwise it would inherit the plain forward and `length()` would skip `Around`, which it currently goes through via `utf16()`.

`TracingRuntime` no longer records an incidental `Utf16Record` when `length()` is called. That record only came from the `utf16()` fallback. I didn't add a record for `length()`: strings are immutable, and `TracingRuntime` already leaves pure queries like `size(Array)` untraced.

Pull Request resolved: #2205

Test Plan:
Added `JSITest.DecoratorForwardsStringLength`. An inner decorator returns a sentinel from `length()` and counts `length()` and `utf16()` calls. The test checks that a `RuntimeDecorator` and a `WithRuntimeDecorator` over it both reach that `length()` without calling `utf16()`, and that `Around` runs once. It fails without the change (it gets 5 from the `utf16()` fallback) and passes with it. The full `APITests` binary passes (357 tests) in a Debug + ASan build, including the SynthTrace and TraceInterpreter tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: avp

Differential Revision: D123943189

Pulled By: lavenzg

fbshipit-source-id: 519fdde9f2ad46ce906567bfd1d94d787015915c
meta-codesync Bot pushed a commit that referenced this pull request Oct 8, 2026
…2205)

Summary:
X-link: react/react-native#58936

`IRuntime::length(const String&)` came in with "Add `String::length` API" (590396b on static_h, D96030262), and that commit didn't touch `decorator.h`. Neither `RuntimeDecorator` nor `WithRuntimeDecorator` overrides it, so on a decorated runtime `length()` falls back to the default `utf16(str).size()` and never reaches the wrapped runtime.

It looks like an oversight. The same stack added `push`, `tryGetMutableBuffer`, `detached` and the TypedArray methods, and each of those commits added decorator overrides, including one for this method's overload `length(const TypedArray&)`. The `createError*` commit (#2203) and this one didn't.

For Hermes-backed decorators the value is already right, because Hermes' `utf16()` is exact, but every call copies the whole string instead of reading the length. Runtimes with a native `length()` and the default `utf16()` get wrong answers. React Native's `JSCRuntime` is one: built against the system JavaScriptCore and wrapped in a `RuntimeDecorator`, `'a\uD800b'` has length 1 instead of 3 and `'x\uDC00yz'` has 1 instead of 4. With this change both match the undecorated runtime. That setup lives outside this repo, so it isn't a test here.

`WithRuntimeDecorator` needs the override too. Otherwise it would inherit the plain forward and `length()` would skip `Around`, which it currently goes through via `utf16()`.

`TracingRuntime` no longer records an incidental `Utf16Record` when `length()` is called. That record only came from the `utf16()` fallback. I didn't add a record for `length()`: strings are immutable, and `TracingRuntime` already leaves pure queries like `size(Array)` untraced.

Pull Request resolved: #2205

Test Plan:
Added `JSITest.DecoratorForwardsStringLength`. An inner decorator returns a sentinel from `length()` and counts `length()` and `utf16()` calls. The test checks that a `RuntimeDecorator` and a `WithRuntimeDecorator` over it both reach that `length()` without calling `utf16()`, and that `Around` runs once. It fails without the change (it gets 5 from the `utf16()` fallback) and passes with it. The full `APITests` binary passes (357 tests) in a Debug + ASan build, including the SynthTrace and TraceInterpreter tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: avp

Differential Revision: D123943189

Pulled By: lavenzg

fbshipit-source-id: 519fdde9f2ad46ce906567bfd1d94d787015915c
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Oct 8, 2026
…58936)

Summary:
Pull Request resolved: #58936

`IRuntime::length(const String&)` came in with "Add `String::length` API" (590396bd4 on static_h, D96030262), and that commit didn't touch `decorator.h`. Neither `RuntimeDecorator` nor `WithRuntimeDecorator` overrides it, so on a decorated runtime `length()` falls back to the default `utf16(str).size()` and never reaches the wrapped runtime.

It looks like an oversight. The same stack added `push`, `tryGetMutableBuffer`, `detached` and the TypedArray methods, and each of those commits added decorator overrides, including one for this method's overload `length(const TypedArray&)`. The `createError*` commit (facebook/hermes#2203) and this one didn't.

For Hermes-backed decorators the value is already right, because Hermes' `utf16()` is exact, but every call copies the whole string instead of reading the length. Runtimes with a native `length()` and the default `utf16()` get wrong answers. React Native's `JSCRuntime` is one: built against the system JavaScriptCore and wrapped in a `RuntimeDecorator`, `'a\uD800b'` has length 1 instead of 3 and `'x\uDC00yz'` has 1 instead of 4. With this change both match the undecorated runtime. That setup lives outside this repo, so it isn't a test here.

`WithRuntimeDecorator` needs the override too. Otherwise it would inherit the plain forward and `length()` would skip `Around`, which it currently goes through via `utf16()`.

`TracingRuntime` no longer records an incidental `Utf16Record` when `length()` is called. That record only came from the `utf16()` fallback. I didn't add a record for `length()`: strings are immutable, and `TracingRuntime` already leaves pure queries like `size(Array)` untraced.

X-link: facebook/hermes#2205

Test Plan:
Added `JSITest.DecoratorForwardsStringLength`. An inner decorator returns a sentinel from `length()` and counts `length()` and `utf16()` calls. The test checks that a `RuntimeDecorator` and a `WithRuntimeDecorator` over it both reach that `length()` without calling `utf16()`, and that `Around` runs once. It fails without the change (it gets 5 from the `utf16()` fallback) and passes with it. The full `APITests` binary passes (357 tests) in a Debug + ASan build, including the SynthTrace and TraceInterpreter tests.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: avp

Differential Revision: D123943189

Pulled By: lavenzg

fbshipit-source-id: 519fdde9f2ad46ce906567bfd1d94d787015915c
@meta-codesync meta-codesync Bot closed this in 4f8e5e2 Oct 8, 2026
@meta-codesync meta-codesync Bot added the Merged label Oct 8, 2026
@meta-codesync

meta-codesync Bot commented Oct 8, 2026

Copy link
Copy Markdown

@lavenzg merged this pull request in 4f8e5e2.

This branch was successfully deployed

1 active deployment
npm-publish — f0dab2b8 Deployed Sep 26, 2026 by mrousavy via publish #1522
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Do not delete this pull request or issue due to inactivity. Merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant