Summary:
Changelog: [Internal]
This diff introduce a helper `performMicrotaskCheckpoint` to
repetitively invoke `jsi::Runtime::drainMicrotasks` to exhaust
the microtasks queue provided by JS VMs. Please refer to `jsi.h`
for more details about the behavior of the API.
Conceptually, the checkpoint needs to be performed whenever the
JS stack is considered empty. In practice, we can just make a
call whenever RN is returned from C++->JS calls.
In the current RN, this happened in JSIExecutor:
- `::callFunction` => `callFunctionReturnFlushedQueue_-> call`
- `::invokeCallback` => `invokeCallbackAndReturnFlushedQueue_-> call`
- `::flush` => `flushedQueue_->call`
Each of them invoke a bound method on the JS bridge object. Note
that `setImmediate` callbacks are executed before they returned.
This means immmediates are invoked before engine microtasks. This
is okay because the priority between `setImmediate` and engine
"microtask" are not defined. (`setImmediate` is non-standard and RN
already treat `setImmediate` in a similar priority as microtask
for the existing Promise polyfill.)
Reviewed By: RSNara
Differential Revision: D27729702
fbshipit-source-id: b64b3705d2ff5100075d860c89f03a847369b7ac
Summary:
When we call JSIExecutor::nativeCallSyncHook, we assume that the third argument is an object and call Value::asObject on it, before checking if the Object is an Array. Calling Value::asObject throws an error if the Value isn't an Object.
This diff includes an isObject check on the third argument.
Changelog: [Internal]
Reviewed By: fkgozali
Differential Revision: D26735262
fbshipit-source-id: 96eb43d6c8bc1d78f3b5e0dc24ed6d419a446ecf
Summary:
We're seeing that GCs caused by memory warnings on Android are barely collecting
any memory and are operating on much smaller heaps than natural GCs.
This is likely due to some of the TRIM_MEMORY_* events firing too often.
Log which event name it was, instead of the generic "memory warning", to narrow
down the cases where the memory warning was helpful. Unhelpful warnings will
later be moved to not force a GC.
Note that this diff changes Venice, but we don't see any Venice heaps in production,
so it won't matter much other than making the code match up.
Also note that iOS has a similar memory warning in `RCTCxxBridge.mm`, but it hasn't
been called in production. Perhaps iOS is less trigger-happy for memory warnings than
Android.
Changelog: [Internal]
Reviewed By: neildhar
Differential Revision: D24093394
fbshipit-source-id: 03304f0f79083133c4d9b730559aef291319b6eb
Summary:
Continuing the adding of a "cause" field for logging to GCs.
This allows embedders of Hermes (such as React Native) to specify
the cause of a call to `collectGarbage`.
Notably, this allows Hermes to know when a GC is triggered by a memory warning.
Changelog: [Internal]
Reviewed By: sammy-SC
Differential Revision: D23742099
fbshipit-source-id: 99453e632328c00045b92a72f789d41c898dc518
Summary:
There are a few places where we cast JSI values to objects without much validation and without proper error logging, and in some places the crashes aren't symbolicated well. To make debugging easier in the short-term, I'm adding some additional logs.
Changelog: [Internal]
Reviewed By: mdvacca, RSNara
Differential Revision: D23033222
fbshipit-source-id: 9343d693a441f0af728e560a0c245bcc4eb97869
Summary:
## Motivation
We got this crash T67304907, which shows a `EXC_BAD_ACCESS / KERN_INVALID_ADDRESS` when calling this line:
```
NativeModulePerfLogger::getInstance().asyncMethodCallBatchPreprocessStart();
```
There are no arguments in that call, so I figured the only error could be when we try to invoke `getInstance()` or `asyncMethodCallBatchPreprocessStart()`.
This diff:
1. Removes the `NativeModulePerfLogger::getInstance()` bit. Now NativeModulePerfLogger is used via regular static C functions. So, there's no way that simply invoking one of the logging functions crashes the application: there's no vtable lookup.
2. Inside each logging function, when perf-logging is disabled, the global perflogger should be `nullptr`. This diff makes it so that in that case, we won't execute any code in the control group of the perf-logging experiment.
## Changes
**How do we enable NativeModule perf-logging?**
- Previously:
- `NativeModulePerfLogger::setInstance(std::make_shared<FBReactNativeModulePerfLogger>(...))`
- `TurboModulePerfLogger::setInstance(std::make_shared<FBReactNativeModulePerfLogger>(...))`.
- Now:
- `BridgeNativeModulePerfLogger::enableLogging(std::make_unique<FBReactNativeModulePerfLogger>(...))`
- `TurboModulePerfLogger::enableLogging(std::make_unique<FBReactNativeModulePerfLogger>(...))`
**How do we do NativeModule perf-logging now?**
- Previously:
- `NativeModulePerfLogger::getInstance().command(...args)`
- `TurboModulePerfLogger::getInstance().command(...args)`.
- Now:
- `BridgeNativeModulePerfLogger::command(...args)`
- `TurboModulePerfLogger::command(...args)`.
The benefit of this approach is that each method in `BridgeNativeModulePerfLogger` is guarded with an if check. Example:
```
void moduleCreateConstructStart(const char *moduleName, int32_t id) {
NativeModulePerfLogger *logger = g_perfLogger.get();
if (logger != nullptr) {
logger->moduleCreateConstructStart(moduleName, id);
}
}
```
Therefore, we don't actually execute any code when perf-logging is disabled.
Changelog:
[Internal]
Reviewed By: fkgozali
Differential Revision: D21669888
fbshipit-source-id: 80c73754c430ce787404b563878bad146295e01f
Summary:
## Motivation
This rename will fix the following CircleCI build failures:
- [test_ios_unit_frameworks](https://circleci.com/gh/facebook/react-native/150473?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link)
- [test_ios_detox_frameworks](https://circleci.com/gh/facebook/react-native/150474?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link)
## Investigation
We have 4 podspec targets that map to the same header namespace (i.e: `header_dir`) `ReactCommon`:
- **New:** `React-perflogger`: Directory is `ReactCommon/preflogger`, and contains `NativeModulePerfLogger.{h,cpp}`.
- `React-runtimeexecutor`: Directory is `ReactCommon/runtimeexecutor`, and contains only `RuntimeExecutor.h`
- `React-callinvoker`: Directory is `ReactCommon/callinvoker`, and contains only `CallInvoker.h`
- `ReactCommon/turbomodule/core`: Directory is `ReactCommon/turbomodule`, and contains C++ files, as well has header files.
**The problem:**
We couldn't import headers from `React-perflogger` in `ReactCommon/turbomodule/core` files.
**The cause:**
I'm not entirely sure why, but I was able to discern the following two rules by playing around with the podspecs:
1. If your podspec target has a cpp file, it'll generate a framework when `USE_FRAMEWORKS=1`.
2. Two different frameworks cannot map to the same `module_name` or `header_dir`. (Why? No clue. But something breaks silently when this is the case).
So, this is what happened when I landed `React-perflogger` (D21443610):
1. The TurboModules code generates the `ReactCommon` framework that uses the `ReactCommon` header namespace.
2. `React-runtimeexecutor` and `React-callinvoker` also used the `ReactCommon` header namespace. However, neither generate a framework because of Rule 1.
3. When I comitted `React-perflogger`, I introduced a second framework that competed with the `ReactCommon` framework (i.e: TurboModules code) for the `ReactCommon` header namespace. Rule 2 violation.
## Thoughts on renaming
- `<perflogger/NativeModulePerfLogger.h>` is too generic, and the `perflogger` namepsace is used internally within FB.
- `<react/perflogger/NativeModulePerfLogger.h>` matches our fabric header format, but I'm pretty sure that slashes aren't allowed in `header_dir`: I tested this and it didn't work. IIRC, only alphanumeric and underscore are valid characters for `header_dir` or `module_name`. So, I opted to just use `reactperflogger`.
Changelog: [Internal]
Reviewed By: fkgozali
Differential Revision: D21598852
fbshipit-source-id: 60da5d0f7758eaf13907a080b7d8756688f40723
Summary:
## Motivation
This rename will fix the following CircleCI build failures:
- [test_ios_unit_frameworks](https://circleci.com/gh/facebook/react-native/150473?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link)
- [test_ios_detox_frameworks](https://circleci.com/gh/facebook/react-native/150474?utm_campaign=vcs-integration-link&utm_medium=referral&utm_source=github-build-link)
## Investigation
We have 4 podspec targets that map to the same header namespace (i.e: `header_dir`) `ReactCommon`:
- **New:** `React-perflogger`: Directory is `ReactCommon/preflogger`, and contains `NativeModulePerfLogger.{h,cpp}`.
- `React-runtimeexecutor`: Directory is `ReactCommon/runtimeexecutor`, and contains only `RuntimeExecutor.h`
- `React-callinvoker`: Directory is `ReactCommon/callinvoker`, and contains only `CallInvoker.h`
- `ReactCommon/turbomodule/core`: Directory is `ReactCommon/turbomodule`, and contains C++ files, as well has header files.
**The problem:**
We couldn't import headers from `React-perflogger` in `ReactCommon/turbomodule/core` files.
**The cause:**
I'm not entirely sure why, but I was able to discern the following two rules by playing around with the podspecs:
1. If your podspec target has a cpp file, it'll generate a framework when `USE_FRAMEWORKS=1`.
2. Two different frameworks cannot map to the same `module_name` or `header_dir`. (Why? No clue. But something breaks silently when this is the case).
So, this is what happened when I landed `React-perflogger` (D21443610):
1. The TurboModules code generates the `ReactCommon` framework that uses the `ReactCommon` header namespace.
2. `React-runtimeexecutor` and `React-callinvoker` also used the `ReactCommon` header namespace. However, neither generate a framework because of Rule 1.
3. When I comitted `React-perflogger`, I introduced a second framework that competed with the `ReactCommon` framework (i.e: TurboModules code) for the `ReactCommon` header namespace. Rule 2 violation.
## Thoughts on renaming
- `<perflogger/NativeModulePerfLogger.h>` is too generic, and the `perflogger` namepsace is used internally within FB.
- `<react/perflogger/NativeModulePerfLogger.h>` matches our fabric header format, but I'm pretty sure that slashes aren't allowed in `header_dir`: I tested this and it didn't work. IIRC, only alphanumeric and underscore are valid characters for `header_dir` or `module_name`. So, I opted to just use `reactperflogger`.
Changelog: [Internal]
Reviewed By: fkgozali
Differential Revision: D21585006
fbshipit-source-id: e3339273af5dfd65a1454d87213d1221de6a4651
Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/28893
`JSIExecutor::callSerializableNativeHook` converts the arguments from `JSI::Value` to `folly::dynamic`. Then, `RCTNativeModule` converts the arguments from `folly::dynamic` to ObjC data structures in its `static invokeInner` function.
Therefore, I decided to start the sync markers inside `JSIExecutor::callSerializableNativeHook`, which required me to expose these two methode `ModuleRegistry::getModuleName` and `ModuleRegistry::getModuleSyncMethodName`. This shouldn't modify performance because we eagerly generate a NativeModule's methods when it's first required. So, at worst, this is doing a cache lookup.
Changelog: [Internal]
Reviewed By: PeteTheHeat
Differential Revision: D21443610
fbshipit-source-id: 67cf563b0b06153e56e63ba7e186eea31eafc853
Summary:
NativeModule async method calls are queued up on the JS side, and flushed to C++ on every Native -> JS call. Before we execute the batch of async NativeModule method calls, we convert it (a JS object) from a `jsi::Value` to a `folly::dynamic` object in `JSIExecutor::callNativeModules`. Then, in `JsToNativeBridge::callNativeModules`, we convert this `folly::dynamic` object into an `std::vector<MethodCall>`, before finally looping over these `MethodCall`s and invoking each NativeModule async method call.
The markers I'm adding in this diff measure this `jsi::Value -> folly::dynamic -> std::vector<MethodCall>` pre-processing.
Changelog: [Internal]
Reviewed By: PeteTheHeat
Differential Revision: D21435455
fbshipit-source-id: 4c5a9e2b73c1a2a49d7a8f224a0d30afe3a0c79c
Summary:
This is the first of three PRs related to enabling multi-bundle support in React Native. More details, motivation and reasoning behind it can be found in RFC [here](https://github.com/react-native-community/discussions-and-proposals/issues/152).
Logic responsible for installing globals was pulled out from `loadApplicationScript` to `initializeRuntime` since it should be ran only once, what was left was renamed to `loadBundle`.
It's based on dratwas work from [here](https://github.com/callstack/react-native/tree/feat/multibundle/split-load-application), but applied to current `master` to avoid rebasing 3-months old branch and issues that come with that.
## Changelog
[Internal] [Changed] - split `loadApplicationScript` into `initializeRuntime` and `loadBundle` to enable multi-bundle support in the future
Pull Request resolved: https://github.com/facebook/react-native/pull/27844
Test Plan: Initialized new RN app with CLI, set RN to build from source and verified the still app builds and runs OK using code from this branch.
Reviewed By: rickhanlonii
Differential Revision: D19888605
Pulled By: ejanzer
fbshipit-source-id: 24ace48ffe8978796591fe7c6cf53a61b127cce6
Summary:
Someone pointed out in this Github issue: https://github.com/facebook/react-native/issues/27532
that the memory pressure warning from Android was being ignored, when it can easily
be used to start a garbage collection on the JS runtime.
Changelog: [Internal] Add a memory pressure handler for jsi::Runtime
Reviewed By: mhorowitz
Differential Revision: D20072943
fbshipit-source-id: 869a14068aa02bd378e8b26d8c18b76a5d0f7bc0
Summary:
Implements a new host function on the global object in debug builds, called `globalEvalWithSourceUrl`. This performs a global `eval()` and attaches a URL/filename to the evaluated script (in stack traces, debuggers, etc).
It serves a similar purpose to the `//# sourceURL=` directive (which most JS engines support, but JSC doesn't) and to the old `nativeInjectHMRUpdate` function which was dropped in the JSC->JSI migration.
Reviewed By: cpojer
Differential Revision: D16491506
fbshipit-source-id: bd9a89311dcbb1d0baece77ead16b9ecfb13bfe3
Summary:
This change lets `registerBundle(bundleId, file)` throw an exception
when the file is empty, improving on the current behavior of an
eventual SIGABRT saying "MAP_FAILED: Invalid argument"
Reviewed By: ridiculousfish
Differential Revision: D16451938
fbshipit-source-id: b8b2d0bfed476319c379122fad59a5bf0a8c813b
Summary: Restores the bridge description in the debug menu on iOS.
Reviewed By: fkgozali
Differential Revision: D15680775
fbshipit-source-id: c17ad44f2287e03bb2039b4aa4b1311e7ec9106b
Summary: This is based on the work done in D8686586. Removed the logger instance from JSIExecutor constructor and installed it into the runtimeInstaller at all call sites.
Reviewed By: mhorowitz
Differential Revision: D14444120
fbshipit-source-id: 0476fda4230c467573ea04102a12101bcdf36c53
Summary:
From the git log, we added `__fbRequireBatchedBridge` in this commit https://github.com/facebook/react-native/commit/6dc3a83e88ed120decbeaed8e4e62dc2bb7107a3, I don't ensure wether I missed something, we actually don't define `__fbRequireBatchedBridge` on `JS` or `Native` side, so `__fbRequireBatchedBridge` getter operation itself would throw exception.
[General] [Fixed] - Remove __fbRequireBatchedBridge call when not get batchedBridge
Pull Request resolved: https://github.com/facebook/react-native/pull/23547
Differential Revision: D14160706
Pulled By: cpojer
fbshipit-source-id: df9180a9a16716a91369249333752316fb6648c5
Summary: It was made dead by the previous revisions
Reviewed By: amnn
Differential Revision: D13313263
fbshipit-source-id: b8c8402b5427dc5d3efbbd2ee871aebf1e14ee0d
Summary:
This is similar in function to the old JSCExecutor, but uses the more abstract JSI API to interact with the JSVM.
@public
Reviewed By: axe-fb
Differential Revision: D9328241
fbshipit-source-id: 3212ff4f43d0589a70d7bebc4d463d4433590f1d