Skip to content

Forward String::length in RuntimeDecorator and WithRuntimeDecorator (#58936) - #58936

Closed
lavenzg wants to merge 1 commit into
react:mainfrom
lavenzg:export-D123943189
Closed

lavenzg wants to merge 1 commit into
react:mainfrom
lavenzg:export-D123943189

Conversation

@lavenzg

@lavenzg lavenzg commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

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

Reviewed By: avp

Differential Revision: D123943189

Pulled By: lavenzg

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 7, 2026
@facebook-github-tools facebook-github-tools Bot added p: Facebook Partner: Facebook Partner labels Oct 7, 2026
@meta-codesync

meta-codesync Bot commented Oct 7, 2026

Copy link
Copy Markdown

@lavenzg has exported this pull request. If you are a Meta employee, you can view the originating Diff in D123943189.

…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 meta-codesync Bot changed the title Forward String::length in RuntimeDecorator and WithRuntimeDecorator Forward String::length in RuntimeDecorator and WithRuntimeDecorator (#58936) Oct 7, 2026
@lavenzg
lavenzg force-pushed the export-D123943189 branch from ff67900 to f610edd Compare October 7, 2026 21:45
meta-codesync Bot pushed a commit to facebook/hermes 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 facebook/hermes 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 meta-codesync Bot closed this in be567d2 Oct 8, 2026
@meta-codesync meta-codesync Bot added the Merged This PR has been merged. label Oct 8, 2026
@meta-codesync

meta-codesync Bot commented Oct 8, 2026

Copy link
Copy Markdown

@lavenzg merged this pull request in be567d2.

meta-codesync Bot pushed a commit to facebook/hermes 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants