Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize UnicodeICU localeCompare #1186

Closed
wants to merge 1 commit into from

Conversation

sujankh
Copy link
Contributor

@sujankh sujankh commented Nov 10, 2023

Summary

This change eliminates repeated calls to ucol_open and ucol_close in hermes::platform_unicode::localeCompare for HERMES_PLATFORM_UNICODE_ICU. On a sample sort.js(that sorted 30k strings using localeCompare), the runtime goes down from ~500 ms to ~120ms.

Before:
I observed in my trace that ucol_open and ucol_close was called in every localeCompare invocation and each ucol_open took around 500-900 ns. ucol_close is tiny ~100ish ns in each call.
Note that the first call to ucol_open, it takes around 100us even after applying this diff.
image

Here is localeCompare call stack before the patch:
image

After
After making UCollator construction static, we avoid repeated ucol_open and ucol_close(except during static initialization) thus making the sort.js sorting fast.
Here is the localeCompare stack after the patch:
image

Looking at the code, i found out that HERMES_PLATFORM_UNICODE_ICU is not used in Android/iOS but can make desktop usage faster (it it useful??).

Here is the sort.js script which i got from one of the issues/posts in hermes.

print("gen...");
  const randInt = (end, start = 0) =>
    Math.floor(Math.random() * (end - start) + start);
  const alphabet = 'abcdefghijklmnopqrstuvwxyz';
  const names = Array.from({length: 30000}, () =>
     Array.from({length: 8}, () => alphabet[randInt(alphabet.length)]).join(''),
   );

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }
  print('sorting...');
  const s = Date.now();
  names.sort(localeCompare);
  print(`...done, took ${Date.now() - s}ms`);

  function localeCompare(a, b) {
    const s = Date.now();
    const result = a.localeCompare(b);
    const e = Date.now();
    if (e - s > 1) {
      print(`slow localeCompare: ${e - s}ms for '${a}' vs '${b}'`);
    }
    return result;
  }

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }

Test Plan

Execute sort.js before applying this patch

hermes (main)$ ../build_release/bin/hermesc -emit-binary -out sort.hbc samples/sort.js
hermes (main)$ ../build_release/bin/hvm ./sort.hbc 
gen...
sorting...
...done, took 466ms
hermes (main)$ ../build_release/bin/hvm ./sort.hbc 
gen...
sorting...
...done, took 486ms

Execute sort.js after applying this patch

$ ../build_release/bin/hermesc -emit-binary -out sort.hbc samples/sort.js
hermes (icu_localecompare_optimize)$ ../build_release/bin/hvm ./sort.hbc 
gen...
sorting...
...done, took 119ms
hermes (icu_localecompare_optimize)$ ../build_release/bin/hvm ./sort.hbc 
gen...
sorting...
...done, took 127ms

Run check-hermes:

hermes (icu_localecompare_optimize)$ cmake --build ../build_release/ --target check-hermes
[0/1] Running the Hermes regression tests
Testing Time: 15.91s
  Expected Passes    : 1773
  Unsupported Tests  : 66
hermes (icu_localecompare_optimize)$ echo $?
0

@facebook-github-bot
Copy link
Contributor

Hi @sujankh!

Thank you for your pull request and welcome to our community.

Action Required

In order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you.

Process

In order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA.

Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with CLA signed. The tagging process may take up to 1 hour after signing. Please give it that time before contacting us about it.

If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks!

@sujankh sujankh force-pushed the icu_localecompare_optimize branch 2 times, most recently from a2fdad8 to d9adb66 Compare November 10, 2023 09:04
@facebook-github-bot
Copy link
Contributor

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks!

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Nov 10, 2023
Copy link
Contributor

@neildhar neildhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this, I just have some minor comments.

namespace {
struct UCollatorDeleter {
void operator()(UCollator *coll) {
if (coll) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't believe the deleter is invoked if the pointer is null.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Thanks, re-read cppreference to make sure.

lib/Platform/Unicode/PlatformUnicodeICU.cpp Show resolved Hide resolved
@sujankh sujankh force-pushed the icu_localecompare_optimize branch 4 times, most recently from cacc3c7 to d57f6f1 Compare November 14, 2023 07:29
Copy link
Contributor

@neildhar neildhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for working on this!

@facebook-github-bot
Copy link
Contributor

@neildhar has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@facebook-github-bot
Copy link
Contributor

@neildhar merged this pull request in 16a6e2c.

facebook-github-bot pushed a commit that referenced this pull request Jan 18, 2024
Summary:
Original Author: sujan.khadka@live.com
Original Git: 16a6e2c
Original Reviewed By: avp
Original Revision: D51429400

This change eliminates repeated calls to `ucol_open` and `ucol_close` in `hermes::platform_unicode::localeCompare` for HERMES_PLATFORM_UNICODE_ICU. On a sample sort.js(that sorted 30k strings using localeCompare), the runtime goes down from ~500 ms to ~120ms.

**Before:**
I observed in my trace that ucol_open and ucol_close was called in every localeCompare invocation and each ucol_open took around 500-900 ns. ucol_close is tiny ~100ish ns in each call.
Note that the first call to ucol_open, it takes around 100us even after applying this diff.
![image](https://github.com/facebook/hermes/assets/6753926/739edffb-6c7b-4e93-babd-f51f9add4231)

Here is localeCompare call stack before the patch:
![image](https://github.com/facebook/hermes/assets/6753926/9b9fbf31-aa5f-4cc6-a594-26c544c6ebcb)

**After**
After making UCollator construction static, we avoid repeated ucol_open and ucol_close(except during static initialization)  thus making the sort.js sorting fast.
Here is the localeCompare stack after the patch:
![image](https://github.com/facebook/hermes/assets/6753926/7deeba56-ec64-480d-9cf2-4ddcec10fc8b)

Looking at the code, i found out that HERMES_PLATFORM_UNICODE_ICU is not used in Android/iOS but can make desktop usage faster (it it useful??).

Here is the sort.js script which i got from one of the issues/posts in hermes.
```
print("gen...");
  const randInt = (end, start = 0) =>
    Math.floor(Math.random() * (end - start) + start);
  const alphabet = 'abcdefghijklmnopqrstuvwxyz';
  const names = Array.from({length: 30000}, () =>
     Array.from({length: 8}, () => alphabet[randInt(alphabet.length)]).join(''),
   );

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }
  print('sorting...');
  const s = Date.now();
  names.sort(localeCompare);
  print(`...done, took ${Date.now() - s}ms`);

  function localeCompare(a, b) {
    const s = Date.now();
    const result = a.localeCompare(b);
    const e = Date.now();
    if (e - s > 1) {
      print(`slow localeCompare: ${e - s}ms for '${a}' vs '${b}'`);
    }
    return result;
  }

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }
```

Pull Request resolved: #1186

Pulled By: neildhar

Reviewed By: tmikov

Differential Revision: D52854458

fbshipit-source-id: bebecb56c919811884263e55fe7da4b7ce10cf55
vmoroz pushed a commit to microsoft/hermes-windows that referenced this pull request Aug 13, 2024
* Add JSI method for setting external memory size

Summary:
X-link: https://github.com/facebook/react-native/pull/41436

Add a JSI API for associating some native memory with a JS object. This
is intended to provide a mechanism to trigger more frequent garbage
collection when JS retains large external memory allocations, in order
to avoid memory buildup.

This diff just adds the JSI method, without any implementations.

Changelog:
[General][Added] - Added JSI method for reporting native memory to the GC.

Reviewed By: tmikov

Differential Revision: D50524912

fbshipit-source-id: c8df0e18b0415d9523e0a00f6d0ed2faa648ac68

* Deploy 0.223.0 to fbsource (#41725)

Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/41725

Reviewed By: SamChou19815

Differential Revision: D51713020

fbshipit-source-id: 84dc8c882f7603d642cb4ccb735fad0fb7e25d4d

* Pass additional parameters to NativeState finalizer

Summary:
Pass the GC and `NativeState*` to the finalizer to make it more
flexible. This will allow it to be used to manage external memory in
the next diff.

Reviewed By: tmikov

Differential Revision: D50531361

fbshipit-source-id: f5483f0e25d92156bc4f593ffa0f19c6de88a1c0

* Remove asserts in objectFromPropertyDescriptor

Summary:
It turned out that these assertions hit with test262 tests. These test
cases are, for example, passing property descriptor with incomplete
attributes. For some tests, this doesn't matter and they are just
testing the behavior of trap functions. Few test cases are testing with
incorrect attribute set up and checking that the runtime is handling as
spec says. Essentially, `objectFromPropertyDescriptor` should create the
descriptor object as specified by the code, and Proxy should pass it to
the `defineProperty` trap function as is. Each of the case handling is
already well  implemented in the Proxy code.

Reviewed By: tmikov

Differential Revision: D51692787

fbshipit-source-id: 340b49007ca7a35eacab07be1c1e40a6e5b7ec7d

* Implement setExternalMemoryPressure in Hermes

Summary:
Add an implementation of `adjustExternalMemoryPressure` in Hermes. It
uses an internal property pointing to a `NativeState` to maintain the
external memory size. The finalizer of the `NativeState` informs the GC
that the memory has been freed.

Reviewed By: tmikov

Differential Revision: D51241265

fbshipit-source-id: d9be03ee71d34a75fc6a2544e34ca98d08dfa70d

* Optimize UnicodeICU localeCompare (#1186)

Summary:
This change eliminates repeated calls to `ucol_open` and `ucol_close` in `hermes::platform_unicode::localeCompare` for HERMES_PLATFORM_UNICODE_ICU. On a sample sort.js(that sorted 30k strings using localeCompare), the runtime goes down from ~500 ms to ~120ms.

**Before:**
I observed in my trace that ucol_open and ucol_close was called in every localeCompare invocation and each ucol_open took around 500-900 ns. ucol_close is tiny ~100ish ns in each call.
Note that the first call to ucol_open, it takes around 100us even after applying this diff.
![image](https://github.com/facebook/hermes/assets/6753926/739edffb-6c7b-4e93-babd-f51f9add4231)

Here is localeCompare call stack before the patch:
![image](https://github.com/facebook/hermes/assets/6753926/9b9fbf31-aa5f-4cc6-a594-26c544c6ebcb)

**After**
After making UCollator construction static, we avoid repeated ucol_open and ucol_close(except during static initialization)  thus making the sort.js sorting fast.
Here is the localeCompare stack after the patch:
![image](https://github.com/facebook/hermes/assets/6753926/7deeba56-ec64-480d-9cf2-4ddcec10fc8b)

Looking at the code, i found out that HERMES_PLATFORM_UNICODE_ICU is not used in Android/iOS but can make desktop usage faster (it it useful??).

Here is the sort.js script which i got from one of the issues/posts in hermes.
```
print("gen...");
  const randInt = (end, start = 0) =>
    Math.floor(Math.random() * (end - start) + start);
  const alphabet = 'abcdefghijklmnopqrstuvwxyz';
  const names = Array.from({length: 30000}, () =>
     Array.from({length: 8}, () => alphabet[randInt(alphabet.length)]).join(''),
   );

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }
  print('sorting...');
  const s = Date.now();
  names.sort(localeCompare);
  print(`...done, took ${Date.now() - s}ms`);

  function localeCompare(a, b) {
    const s = Date.now();
    const result = a.localeCompare(b);
    const e = Date.now();
    if (e - s > 1) {
      print(`slow localeCompare: ${e - s}ms for '${a}' vs '${b}'`);
    }
    return result;
  }

  for(var i = 0; i < 5; ++i){
    print(names[i])
  }
```

Pull Request resolved: https://github.com/facebook/hermes/pull/1186

Test Plan:
**Execute sort.js before applying this patch**
```
hermes (main)$ ../build_release/bin/hermesc -emit-binary -out sort.hbc samples/sort.js
hermes (main)$ ../build_release/bin/hvm ./sort.hbc
gen...
sorting...
...done, took 466ms
hermes (main)$ ../build_release/bin/hvm ./sort.hbc
gen...
sorting...
...done, took 486ms
```

**Execute sort.js after applying this patch**
```
$ ../build_release/bin/hermesc -emit-binary -out sort.hbc samples/sort.js
hermes (icu_localecompare_optimize)$ ../build_release/bin/hvm ./sort.hbc
gen...
sorting...
...done, took 119ms
hermes (icu_localecompare_optimize)$ ../build_release/bin/hvm ./sort.hbc
gen...
sorting...
...done, took 127ms
```

**Run check-hermes:**
```
hermes (icu_localecompare_optimize)$ cmake --build ../build_release/ --target check-hermes
[0/1] Running the Hermes regression tests
Testing Time: 15.91s
  Expected Passes    : 1773
  Unsupported Tests  : 66
hermes (icu_localecompare_optimize)$ echo $?
0
```

Reviewed By: avp

Differential Revision: D51429400

Pulled By: neildhar

fbshipit-source-id: f5a2f56952ec9bcbaad441df8f2e9c49c8a0b09a

* InstSimplify: fix handling of undefined in relational comparisons (#1202)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1202

Relational comparisons (<= and >=) are simplified to a true/false when
it is known that the operands are the same value with a primitive type.
If the value is "undefined", it is converted to NaN, which never equals
itself.
The optimization was not correctly handling the case where the operand
could be "undefined" or another type - it was only checking for
"undefined".

Example:

    try {} catch {
      var v0 = "m";
    }
    return v0 <= v0;

The try/catch is necessary to make the optimizer believe `v0` is not a
constant.

Reported in https://github.com/facebook/hermes/issues/1200.

Reviewed By: neildhar

Differential Revision: D51555324

fbshipit-source-id: 87a4285166a9e11e96014feae45497d1a30d8307

* Deploy 0.223.2 to xplat

Summary: Changelog: [Internal]

Reviewed By: pieterv

Differential Revision: D51768863

fbshipit-source-id: 716add02d82cdfa56f2d3fc4d4560fcb26e8f426

* Do not apply the plugin for TS files

Summary:
Hermes parser currently cannot handle TS files as good as Flow ones. However, the plugin will unconditionally override the parser for all files. This will break if we introduce the plugin in a config that must work for both TS and JS.

This diff skips the parser override if the filename ends in .ts or .tsx. According to babel's implementation, we need to return undefined to ignore the parserOverride:

https://github.com/babel/babel/blob/85e649203b61b7c908eb04c05511a0d35f893e8e/packages/babel-core/src/parser/index.ts#L9-L25

Reviewed By: pieterv

Differential Revision: D51771100

fbshipit-source-id: 7564856952c02d5707536c68a835603aaee77de2

* Fix binop side effects with BigInt

Summary:
`getBinarySideEffect()` wasn't considering that arithmetic operations
between BigInt and non-BigInt (except string addition) throw a
TypeError.

Refactor the code to be explicit about all operators. Add new tests.

Curiously, this change revealed a bug in an existing test:

        t5: string|number|bigint = t1:any + t2:any
        t6: string|number|bigint = t3:any + t4:any
        t7: string|number|bigint = t5 + t6
        t7 is unused

We were incorrectly removing the calculation of t7, because both
operands are primitive types. However it might happen, for example, that
t5 is biging and t6 is a number, which would throw an exception.

Reported in https://github.com/facebook/hermes/issues/1199.

This diff was ported from Static Hermes (since this is a bug). Had to
fix BigInt dumping to make the Optimizer test pass.

Reviewed By: avp

Differential Revision: D51555323

fbshipit-source-id: 927f5e6041899f0800c5a641c62d32e18c3d9f18

* Always write result last in the interpreter (#1203)

Summary:
If an instruction is the last user of one of its operands, the register
allocator may reuse one of its operands as the result register. This is
typically fine since most operands are only input parameters, and they
are always read before the output is written.

However, when the operand is both an input and an output, this requires
care to ensure that the operand register (whose live range ends with
the given instruction) is written before the result. This ensures that
even if the register allocator assigns them the same register, the
value held in that register after the instruction is the result.

Closes #1203

Reviewed By: avp

Differential Revision: D51597086

fbshipit-source-id: 14a4f27887d11cbe21bae5b27712b498b48c3f20

* Skip low-signal assert while fuzzing

Summary:
In debug mode, this assertion is used to catch potential unbounded
handle allocations. It offers however very poor signal when fuzzing.
Skipping it to unblock stress-testing large GCScopes.

Reviewed By: neildhar

Differential Revision: D51587303

fbshipit-source-id: 5d373ecee8535bf38ba8f56055ff9efa03cadec3

* Avoid FMA contraction in makeDate

Summary:
Newer versions of clang will automatically produce FMA instead of
separate multiply and add when the multiplication and addition are in
the same expression. This is undesirable because it results in
non-standard behaviour in makeDate, and breaks an existing test262
test.

We can do this in two ways:
1. We can split them into separate expressions
2. We can use `#pragma STDC FP_CONTRACT OFF`

Unfortunately, neither of these address the issue with GCC, which
uses `-ffp-contract=fast` by default, and cannot be overridden
except by using `volatile`.

To fix this, add `-ffp-contract=on` to our build flags, and split the
expressions.

Reviewed By: tmikov

Differential Revision: D51725454

fbshipit-source-id: 3d4c91bb32c619c05c53fd8b1962adbc862554aa

* Deploy 0.223.3 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/41797

Changelog: [Internal]

Reviewed By: gkz

Differential Revision: D51839509

fbshipit-source-id: 961fc4e8fc0f7a45c3882753301d027f319b9ea6

* Revert D51839509: Deploy 0.223.3 to xplat

Differential Revision:
D51839509

Original commit changeset: 961fc4e8fc0f

Original Phabricator Diff: D51839509

fbshipit-source-id: 71a97ee1971d5c882cb704f4f9ff42a95e6d52f6

* Deploy 0.223.3 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/41809

Changelog: [Internal]

Reviewed By: samwgoldman

Differential Revision: D51855821

fbshipit-source-id: 4fe9c937aff925150fb015be2ea93fa120e7f462

* Added support for ES6 classes (#1176)

Summary:
We are currently experimenting with a Hermes integration as a potential replacement for the QuickJS engine. As part of the migration, we've realized that the lack of support for ES6 classes and block scoped variables within Hermes is a bigger deal than expected for us. We have 3 engine integrations which all support ES2017+, and without support for ES6 classes and block scoped variables we have to either downgrade the ES target to ES5, or integrate Babel in our compilation pipeline which are both invasive and risky changes for us. In order to fix this, I've taken a stab at supporting ES6 classes somewhat natively within Hermes.

I've went with the simplest and the less risky approach that could get the job done. This PR doesn't change the IR, it instead transforms the AST at compile time to convert ES6 classes into plain ES5 classes, very much like what the TypeScript and Babel compiler do. A more advanced implementation would likely add support for classes within the IR. This PR ended up to be fairly straightforward to do, as the JS parser implemented within Hermes already supports most of the ES6 syntax, it's only the IR Gen pass which doesn't support it.

## Supported ES6 class features
- Define a class with a parent class (`class Child extends Parent {}`)
- Method and static method definitions (`method() {}` and `static method() {}`)
- Property and static property definitions (`get prop() {}`, `static get prop() {}`, `set prop(v) {}`, `static set prop(p) {}`
- Super call expression in method and static method definitions (`super.method()`)
- Super member expression in property and static property definitions (`super.property`)
- User defined constructor (`constructor() {}`)
- Properties that are immediately initialized. (`property = someValue`)
- Class expressions (`const MyClass = class {}`)
- Class expressions with private named identifier (`const MyClass = class Self { constructor() { Self.hello = 'world' }})`)

## Unsupported ES6 class features
- static block initializers (`static { // code to eval at class load time }`). The existing parser is not able to parse these blocks yet.
- Private methods and properties (`#privateMethod() {}`)
- Inheritance from built-in types like `Error` or `Map` (`class CustomError extends Error {}`)

## Changes

- Added a `enableES6Classes` compile flag. When enabled, a new post processing step will occur on the AST which will transform ES6 classes into ES5 functions, similar to what Babel or the TypeScript compiler does.
- Added `lib/AST/ES6Class`, an AST visitor which visits the ClassNodeDeclaration and ClassExpressionNode and will turn them into plain ES5 functions. The generated AST relies on a new helper lib that is meant to be available on the global object as `HermesES6Internal`.
- Added the `HermesES6Internal` helper module, which implements `defineClass`, `defineClassProperty`, ` defineStaticClassProperty`, `defineClassMethod` and `defineStaticClassMethod`.
- Added a few tests

Pull Request resolved: https://github.com/facebook/hermes/pull/1176

Test Plan: - All Hermes tests are passing

Reviewed By: tmikov

Differential Revision: D51713522

Pulled By: avp

fbshipit-source-id: 15e5f3cd0762f7ffddb357f1ec9edce9713bbafe

* handle Literal properties in flow-to-flowdif conversion

Summary:
the StringLiteral comparison here doesn't actually work. also NumericLiterals are valid as property keys, so it adds that as well

this change effects object and class properties and methods.

Reviewed By: pieterv

Differential Revision: D51867940

fbshipit-source-id: ad546b7c539d29c80fc83393c2b5b66678d51b43

* Hermes ABI definition skeleton

Summary:
The initial boilerplate for the WIP Hermes stable ABI. This just
creates a directory with the header defining the new interface, which
will be used by both the wrapper and the actual implementation of the
ABI.

Reviewed By: tmikov

Differential Revision: D47563699

fbshipit-source-id: b6da43b3f8fdd168d8bda3adee53277d17275325

* ABI implementation skeleton

Summary:
Create a skeleton for the concrete implementation of our new C-API on
top of the Hermes internal APIs. Set up a build that will build either
a static or dynamic library depending on the setting of
`BUILD_SHARED_LIBS`.

Reviewed By: dannysu

Differential Revision: D50153971

fbshipit-source-id: e8462f914a076efc575d6ad9cec13cc9c4627e09

* Hermes ABI wrapper skeleton

Summary:
Add the boilerplate for the C++ wrapper that implements JSI on top of
the C-API. Currently, each function is just implemented to throw.

Reviewed By: tmikov, avp

Differential Revision: D50153972

fbshipit-source-id: bea12505e75549c13a281fe9153875471ccd6ee5

* Remove unnecessary HostObject trackers in TraceInterpreter

Summary:
It turned out that these maps are holding the HostObjects and
HostFunctions created during replay, and never be released until the
runtime instance is destroyed. This changes the behavior of GC for the
host object during replay compared to tracing time as there objects can
never be collected. These maps are used only for assertions to make sure
the created IDs are unique, but they are created by the real runtime's
function, so such assumptions should be able to be made already. Hence,
simply removing these members and usages.

Reviewed By: neildhar

Differential Revision: D51874351

fbshipit-source-id: 1ca93c35b4abbc78b95e0a24419f820e16946fac

* Add fuzzilli profile for Hermes W2C fuzzer

Summary: Additional Fuzzilli profile for sandbox memory fuzzing.

Differential Revision: D51352212

fbshipit-source-id: 106a4c89704284c0c6c3f99e96f52869f225e3dc

* Trace setExternalMemoryPressure

Summary:
We've added `jsi::Runtime::setExternalMemoryPressure()`.
Let's add tracing and replaying for SynthTrace.

Note that function call to `setExternalMemoryPressure()`
won't affect correctness of the inputs and outputs during
replay, but we want to replay for performance effects
mostly for GC.

Reviewed By: neildhar

Differential Revision: D51835433

fbshipit-source-id: 0701bc2d83fe0f724ed3a215ef53ff016b9f5a58

* Minor fixes in HermesABIRuntimeWrapper

Summary: Capitalise the macro and fix the include guard.

Reviewed By: tmikov, ftanuma

Differential Revision: D51923607

fbshipit-source-id: f7f978fb04ee566af2ffce05d29b04a1c1ef2945

* API for getting the list of loaded scripts

Summary:
CDPHandler needs to know the list of loaded scripts so that when `Debugger.enable` message comes, CDPHandler can emit `Debugger.scriptParsed` notifications. Currently CDPHandler obtains the loaded scripts by requiring that it be instantiated along with HermesRuntime, so that CDPHandler can monitor `PauseReason::ScriptLoaded` and cache the list of scripts.

However, this is not a desirable design because it introduces the unnecessary requirement that CDPHandler must be created along with HermesRuntime even though there is no CDP connection. It introduces the question of "what does the msgCallback do when there is no connection?"

Further examination revealed that there is actually no need for CDPHandler to be doing this caching. This is a sensible API to expose from DebuggerAPI. By exposing this functionality, we also save memory spent on the cache by not duplicating information already exists in the VM.

I also made a change to align CMake with BUCK. The CMake build emits debug info for InternalBytecode whereas the BUCK build doesn't. `hermes_compile` by default builds with `-g0`. When debug info is present, iterating through the RuntimeModules would get InternalBytecode.js included as one of the loaded scripts. That by itself isn't a problem. I just thought it'd be good to be building things the same way.

Reviewed By: mattbfb

Differential Revision: D51684983

fbshipit-source-id: b838f71674320bd641ce47f43d7bff14a1312ff5

* Fix HostObject tracing for setProperty

Summary:
I noticed that we don't have test case nor trace record that exercises
`HostObject`'s `setProperty`` calls. Adding a test case revealed that
thereplay part isn't working, so fixing it here.

Here are short description of bugs
- `FakeHostObject::set()` was not passing
  `PropNameID *nativePropNameToConsumeAsDef` to
  `interpreter.execFunction`, which was actually needed.
- `RecordType::GetPropertyNativeReturn` case was using `getObjForUse`
   when calling `traceValueToJSIValue` even though value can be
   String, BigInt, etc (non Object). `getObjForUse()` internally calls
   `jsi::Value::getObject()` without type check so it asserts in debug
   builds.
- `RecordType::SetPropertyNativeReturn` was doing unnecessary
   operations copied from `RecordType::SetPropertyNative`.

Reviewed By: neildhar

Differential Revision: D51966162

fbshipit-source-id: 5f4cec2b4db4bd125b36e06ae1d5ec40000b05da

* Move hostObjectsCallCount_ to FakeHostObject from TraceInterpreter

Summary:
There is no good reason to have HostObject's call count as
TraceInterpreter's member. We can have it in each FakeHostObject's
instance.

Reviewed By: neildhar

Differential Revision: D51920392

fbshipit-source-id: 50573ae5142efcba90b7c35467cbd268820fa0d4

* Fix build break in SynthTraceTest (#1217)

Summary:
Previous Diff broke the builds on CircleCI.
It was missing include for variant.

Pull Request resolved: https://github.com/facebook/hermes/pull/1217

Reviewed By: neildhar

Differential Revision: D52045636

fbshipit-source-id: 930f1b3af05b3a80281f6050d36489390a939391

* Move hostObjectsPropertyNamesCallCount_ to FakeHostObject from TraceInterpreter

Summary:
There is no good reason to have HostObject's getPropertyNames() call
count as TraceInterpreter's member. We can have it in each
FakeHostObject's instance.

Reviewed By: neildhar

Differential Revision: D51966363

fbshipit-source-id: fd4155c4c15b18ce94d38570f28d1c614d2835d1

* Move hostFunctionsCallCount_ to HostFunction wrapper

Summary:
There is no good reason to have HostFunction's call count as
TraceInterpreter's member. We can have it in each HostFunction wrapper
lambda as a captured variable.

Reviewed By: neildhar

Differential Revision: D51966364

fbshipit-source-id: 93049829651afebe96b8951f36b9be2622c6c913

* Merge HostObjectInfo's propNameToCalls callsToGetPropertyNames

Summary:
We do not need to store set/get calls and getPropertyNames calls for a
HostObject separately. Merge them into a Call vector simplifies the
logic.

Reviewed By: neildhar

Differential Revision: D51997003

fbshipit-source-id: f0d1297e7a6de54b198066459d8a26f3e1a084e3

* Simplify TraceInterpreter getCalls()

Summary:
With the previous change, we can simplify the logic inside getCalls()
that is using stack. The stack used to contain ObjectId or FunctionId
to get Calls vector for each case, but we just need to stack the
reference to the Call vector itself. Only for the case of
GetNativePropertyNamesRecord, we need ObjectID.

Reviewed By: neildhar

Differential Revision: D51998012

fbshipit-source-id: b9c43b5e3ec2e0d8e1f79f36cfc4e5cf41239bab

* Release version to 0.18.1

Summary: Release version to 0.18.1

Reviewed By: noahlemen, alexmckenley

Differential Revision: D52164018

fbshipit-source-id: b819f0935e539d4eaa321b05a81a848819c2a895

* Fix local to utc conversion

Summary: Use the same trick as in V8 to fix local to UTC time conversion.

Reviewed By: neildhar

Differential Revision: D51728232

fbshipit-source-id: 537b57bee65511b2eebfa92f0941ee2b3d64f59d

* Replace localtime with localtime_r for thread safety

Summary:
Fix two things:
1. `localtime()` uses an internal static buffer, so not thread safe,
use `localtime_r()` instead.
2. `localtime_r()` internally calls`tzset()`, but only for the first
time. Add a wrapper in the unit tests to always explicitly call
`tzset()` to update time zone.

Reviewed By: neildhar

Differential Revision: D51728257

fbshipit-source-id: f05745e01555f3d06ca888a64d65e57e51c0f16f

* Deploy 0.224.0 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/41949

Changelog: [internal]

Reviewed By: gkz

Differential Revision: D52177280

fbshipit-source-id: 37fe478645ad30b40f4fb4e81d7fc467ac971928

* Create yarn script for prettier plugin development

Summary:
I've added a script to make development of the prettier plugin easier.

This script can be run with the following:
```
yarn build-prettier
```
It will do the following things:
1. Clone the remote fork to your devserver if necessary (inside a .gitignored directory)
1. Determine if there are any upstream commits you need to pull to ensure we dont accidentally lose any changes
1. run `yarn install`
1. copy the `dist` folder from local `hermes-parser` dir into node_modules
1. run `yarn build --no-minify`
1. copy the necessary assets to the proper directory in our source tree

NOTE: Developers will still need to ensure that they commit any prettier changes to the upstream repo and create and merge a pull request.

Reviewed By: SamChou19815

Differential Revision: D52149102

fbshipit-source-id: 5f800835957181fc0837edea8dd5d562ace6101e

* Fix bigint side effects for >>>, /, % (#1214)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1214

BigInt differs from numbers - several bigint operations can throw an
exception, specifically:
- >>> is not allowed at all and throws
- / and % can result in division by zero

Improve the side effect model and add a test.

This diff was ported from SH.

Closes https://github.com/facebook/hermes/issues/1212

Reviewed By: avp

Differential Revision: D52013223

fbshipit-source-id: 746f1180abfbdfff63928a248c05731e782ed0ad

* Retain prop types when lowering component syntax

Summary: Previously with the component syntax transform we would drop prop type annotations and just output a readonly inexact object. This change ensures all prop types are preserved through the transformation.

Reviewed By: alexmckenley

Differential Revision: D52208500

fbshipit-source-id: 30fc7c0664ef1a3a1be19224188ad101d78acb78

* Back out "Replace localtime with localtime_r for thread safety"

Summary:
Backing out the localtime thread safety change since it is broken on
Windows.

Original commit changeset: f05745e01555

Original Phabricator Diff: D51728257

Reviewed By: lavenzg

Differential Revision: D52210979

fbshipit-source-id: 17e0ac1513eb23cc02c091940327d93a69ce06e0

* Build hdb release with static libraries (#1197)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1197

`hdb` links against `libhermes` and `libjsi`, so make sure they are
built as static libraries when we are building `hdb` for distribution.

Reviewed By: dannysu

Differential Revision: D51520865

fbshipit-source-id: e123afcffc46873c4b492590262ef0d756a06693

* Fixes for ES6 class support (#1221)

Summary:
This change provides a few fixes to the ES6 class support which was added in this PR: https://github.com/facebook/hermes/pull/1176

- Added support for class methods and properties being declared using the element expression syntax:
```js
const propKey = Symbol();
class Test {
  [propKey]() {
  }
}
```
This change required that properties are no longer indexed at compile time into a map, as the property keys themselves might be provided from external values.
- Fixed class expressions not being processed in array literal expressions:
```js
const entries = [0, 1, 2, new (class extends Parent {})]
```
- Methods can now be overwritten as regular properties:
```js
class Test {
  constructor(getter) {
    if (getter) {
      this.getMyNumber = getter;
    }
  }

  getMyNumber() {
    return 42;
  }
}
```
- Method names are now preserved at runtime and can be read through `object.method.name()`
- Added more tests

Pull Request resolved: https://github.com/facebook/hermes/pull/1221

Test Plan: All tests run

Reviewed By: tmikov

Differential Revision: D52273463

Pulled By: avp

fbshipit-source-id: 273aedb1922ed3dc4a6a5863ae9ce9c7a7ab8da0

* Release version to 0.18.2

Reviewed By: alexmckenley

Differential Revision: D52223566

fbshipit-source-id: 5406af0d4ea83676a4929394a45989174f0e56fc

* Deploy 0.225.0 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/42004

Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D52305312

fbshipit-source-id: b18045c450dc3204b08452ede17b76d1a43cce50

* Deploy 0.225.1 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/42027

Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D52353283

fbshipit-source-id: 4f6cefdcfe38d34c8629178823df6b39c5aebbfb

* EASY: silence memory leak with GCC ASAN (#1227)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1227

The leak was caused by the allocation of the alt signal stack. To
prevent leak reporting, it is stored into a global symbol. However, that
symbol is unused and can be optimized out. Force it to be considered
"used".

Closes https://github.com/facebook/hermes/issues/1225

Reviewed By: avp

Differential Revision: D52356667

fbshipit-source-id: 1bd7098218f7d3c155f669e975c26ad491fa23bd

* Fix date-local-to-utc.js failure

Summary:
1. Windows has different TZ name, so allow it to fail.
2. On some old Android devices (e.g. Nexus), the system timezone data
is old, so can't handle America/Santiago correctly, use
America/New_York instead.

Reviewed By: neildhar

Differential Revision: D52213926

fbshipit-source-id: 1597e014893274e02d37eb54a2020be29bd73de9

* Revive "Replace localtime with localtime_r for thread safety" (#1231)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1231

Fix two things:
1. localtime() uses an internal static buffer, so is not thread safe,
use localtime_r() instead.
2. localtime_r() internally calls tzset(), but only for the first
time. Add a wrapper in the unit tests to always explicitly call
tzset() to update time zone.

These changes were committed in 5fdb47a and caused crashes on Windows
due to wrong error code check, and were reverted. Now commit again
with fix for that.

Reviewed By: neildhar

Differential Revision: D52358023

fbshipit-source-id: 2529e874ee631887d93edcb807e93c712e0feab5

* Special-casing `int32`-convertible nums in `fromDouble`

Summary:
Adds a special-case to check for numbers which are storable in an `int32`, and adds a short-circuit if so.

It looks like a lot of time is spent in the `abstractEqualityTest_RJS` method, of which the lion's share is in `BigIntPrimitive::fromDouble`

This function allocates a big buffer capable of storing 1024-bit values, since doubles can represent ints (though very few) up to that size. We then spend cycles trimming extra bytes that aren't needed until this buffer is shrunk-to-fit. This is a separate thing, and can be optimized separately and probably get big wins for `fromDouble` in general as a follow-up.

Instead, if our number fits in a 32-bit int, let's just allocate enough bits for the particular number we're setting, set the value specifically to that number, and return (rather than over-allocating and shrinking).

Reviewed By: avp

Differential Revision: D52234978

fbshipit-source-id: a097151a71b88e6221bfc5323d38c3fe26dcf0b1

* Passing num digits to represent a double into its BigInt `fromDouble` parsing

Summary:
Currently, we'll always allocate a buffer of 1024 digits in order to cast a double to a BigInt. This makes sense in the limit, as doubles can represent 1024-bit numbers.

In lots of current paths, though, we have access to the number of digits before we actually allocate this buffer. This is *really* expensive in practice. As such, let's just allocate enough space to actually represent the number we're converting rather than the largest possible representible number.

Reviewed By: mshamis85

Differential Revision: D52262602

fbshipit-source-id: a02d11f85e39496e159ed5c32a61a278a3ebe4e7

* SimplifyCFG: fix strict equality for literals (#1229)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1229

This diff was imported from Static Hermes D52403620.

Strict equality for literals was incorrect - it was performing a "bit
comparison" for numbers (by comparing pointers to the uniqued literals),
while it should be performing a numeric comparison.

This caused incorrect switch case optimization.

Closes https://github.com/facebook/hermes/issues/1215

Reviewed By: neildhar

Differential Revision: D52403687

fbshipit-source-id: a1496a79dd95e333d54ee307086dc9189e09932f

* EASY:API/hermes.cpp: enable ES6-classes if enabled in config

Summary: The ES6Classes flag wasn't passed to BCProviderFromSrc in the JSI API.

Reviewed By: neildhar

Differential Revision: D52458224

fbshipit-source-id: 4e1010414940c1a396e0a72f80078cbb7852d6dd

* JSLexer: don't auto-register magic comment URLs

Summary:
These changes were imported from Static Hermes D51795387.

## The problem with auto-registering magic URLs

Until now, JSLex would always automatically register `sourceURL=` and
`sourceMappingURL=` magic comments in the associated
`SourceErrorManager` as soon as detected.

That is problematic for a few reasons:
- The comment could be encountered at any time or multiple times,
leading to inconsistent state, where it is registered for half of the
file, or different values are registered for different parts.
- Violates separation of concerns: the lexer shouldn't really be
concerned with populating state in unrelated components.
- The registered sourceMappingURL is usually recorded in the debug
information for later use by the debugger. However we might just want to
fetch the source map and use it. This decision shouldn't belong to the
lexer.
- Finally, it is inefficient because SourceErrorManager creates copies
of the URLs. In many scenarios we know that the URLs point to the
existing source buffer, so we don't need to make a copy.

TODO: look into whether SourceErrorManager needs to make copies or it
could just hold references.

## Change

This diff removes the auto-registration in JSLexer and adds a new
function  `JSParser::registerMagicURLs()`, which performs the same
function, but is invoked only at well defined points.

## Complications with pre-parsing

Under certain conditions, which are not important, pre-parsing is
invoked first to parses the entire source and record locations of all
functions. As such, it encounters all magic comments and other things
that we need to keep track of, like "use static builtins".

The existing pre-parser API does not expose a parser/lexer instance, it
just performs it in one go and discards the parser, which prevents us
from querying the magic URLs or calling `registerMagicURLs()`.

To solve this, we change pre-parsing to return an instance of the
parser, after parsing has finished. This allows users of the API to
query the returned parser.

For practical reasons the returned instance has to use
`std::shared_ptr<>`, which necessitated a change from
`std::unique_ptr<>` to the former in one place. It should make no
difference - parsers are not created that often.

## Misc other changes

Simplify the API of JSParserImpl a bit - a few methods are simply
forwarded to the lexer, so they can be implemented directly in JSParser,
if the lexer is exported by JSParserImpl.

Improve the registration of the magic URLs in SourceErrorManager, so
that an empty URL deletes the record instead of storing the empty
string. This makes a difference in `getSourceUrl()`, which is treated
like an override on top of `getBufferFileName()`.

Lastly, I am aware of the difference in case between the old functions
which used `Url`, while new functions use `URL`. The latter is correct,
but I don't want to perform unrelated stylistic changes in this diff.

## Portability to Hermes

The URL registration changes are only enabled in Static Hermes by
relying on -DSTATIC_HERMES.

Reviewed By: avp

Differential Revision: D52190480

fbshipit-source-id: 871c1fd7d889779439d00eda63abce95e77be4fd

* Add a new type of WeakRefSlot

Summary:
Add a new type of WeakRefSlot, which has an additional pinned
value field. This value will be marked if the WeakRef object is
alive (or it's reached from other objects). This new primitive is
intended to be used in new WeakMap implementation.

Reviewed By: neildhar

Differential Revision: D51435175

fbshipit-source-id: bfe8e2dff98f76c8f5de502281dae6ccd55b2086

* Add weakRefReadBarrier function

Summary: Add weakRefReadBarrier for HermesValue

Reviewed By: neildhar

Differential Revision: D52336308

fbshipit-source-id: 9ef84303e71d02dc21ec2a4df4b27be490b41e24

* Add new WeakRef type

Summary: Add a new WeakRef type to manage the new WeakRefSlot.

Reviewed By: neildhar

Differential Revision: D51605891

fbshipit-source-id: 10bf14bdfb2fcb0fad5e85a8d725ffb0e3215e65

* Mark values in WeakMapRefSlot list

Summary: Add a marking function for WeakMapRefSlots in the ManagedChunkedList.

Reviewed By: neildhar

Differential Revision: D51435851

fbshipit-source-id: b13b11e32c6400e329a4e0f5142425304a8ec0d0

* Re-implement JSWeakMap (#1232)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1232

Reimplement JSWeakMap. Each key/value pair is now stored in a
WeakMapRefSlot, which is managed by a WeakMapRef, so we no longer
need a separate ValueStorage. These slots are freed at three places:
1. of JSWeakMap::deleteValue() (if the key exists).
2. In completeWeakMapMarking(), when the slot has no value or the
object is not marked.
3. In the finalizer of JSWeakMap.

Currently, WeakRefLock is still used in setValue(), since WeakRef
marking is not removed yet. We will do that in separate diffs.

Add a lookup key type for this JSWeakMap, and use it for finding
matching key. This eliminates allocating temporary WeakMapRefSlots
for querying.

Reviewed By: neildhar

Differential Revision: D51584024

fbshipit-source-id: 34dd65e4e729753a3d279b32f5ee380d2f979a9d

* Remove TracingRuntime configs (#1233)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1233

Attempt to remove unnecessary configs for TraceRuntime from
RuntimeConfig.

Naively moved up three params to `makeTracingHermesRuntime` and
`HermesExecutorFactory`.

Reviewed By: neildhar

Differential Revision: D51904121

fbshipit-source-id: 9ac8be2dde48fa4d49dbbb2d6b43e66691aff879

* Implement the ABI value representation

Summary:
Define the layout of values that will be passed across the C-API. These
are largely analagous to `jsi::Value` and the subclasses of
`jsi::Pointer`, with the addition of also carrying error information.

Reviewed By: tmikov

Differential Revision: D47563696

fbshipit-source-id: 921122d2f8705318ea35dd67c6ea64c26f6c1445

* Add pointer types and convenience helpers to ABI implementation

Summary:
Implement the infrastructure needed to support the types specified in
the C-API in `hermes_vtable.cpp`. This includes helper functions that
will be needed in upcoming diffs to make it easier to manipulate values.

Reviewed By: tmikov

Differential Revision: D50396059

fbshipit-source-id: bcca6d615ef5479c178286e8fac438962158b10e

* Implement pointer types in wrapper

Summary: Implement conversions to and from the ABI and JSI value types.

Reviewed By: avp

Differential Revision: D50396060

fbshipit-source-id: a2fbf0a6b860e4d773dcfae0259bd03ba2172617

* Implement exception reporting and retrieval

Summary:
Implement exceptions in both the implementation and wrapper, allowing
Hermes VM errors to be converted to C++ JSI exceptions.

Reviewed By: tmikov

Differential Revision: D50212959

fbshipit-source-id: 1538bba118cae179b23e98ed5ebd606f76cecd3a

* Implement cloning values

Summary: Add support for cloning references end-to-end.

Reviewed By: avp

Differential Revision: D50212960

fbshipit-source-id: ea822617309aae7f3a7ec041493e92d91730492c

* Implement evaluateJavaScript in the ABI (#1060)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1060

Add an API to pass buffers and implement `evaluateJavaScript`.

Reviewed By: avp

Differential Revision: D47563700

fbshipit-source-id: 85d4f00cbaa1ee441b582fd9272565f38fdad7f3

* Implement basic object and string creation

Summary: Implement functions to create objects and strings.

Reviewed By: avp

Differential Revision: D50798237

fbshipit-source-id: 1aca53e647b01e2e07400beba21336d45f4ea407

* Implement object property manipulation

Summary: Implement has/get/set for object properties.

Reviewed By: avp

Differential Revision: D50798238

fbshipit-source-id: be5620f2a5ffee209d2bbbc14b4cf7d605c2b76f

* Implement setting external memory pressure

Summary: Implement the new setExternalMemoryPressure API in the C-API.

Reviewed By: avp

Differential Revision: D51970917

fbshipit-source-id: 9582d0cd418eca8cb515b5683cc0ed05a212a26d

* Implement array creation and manipulation

Summary: Implement array creation and get/set operations as they exist in JSI.

Reviewed By: avp

Differential Revision: D51516039

fbshipit-source-id: 9695c514bb016e433a3316ba47f1c9c22fec69a7

* Implement ArrayBuffer manipulation

Summary:
Implement ArrayBuffer creation from external buffers, as well as
functions to obtain the size and underlying data for an ArrayBuffer.

Reviewed By: avp

Differential Revision: D51535577

fbshipit-source-id: 0fa853958afa77d387f6d2b7c6d1266fe3dd2204

* Implement PropNameID creation

Summary:
Implement creation of PropNameIDs from Symbol and String. Skip creation
of PropNameID from ASCII and UTF-8 buffers for now, since they can be
easily implemented on top of other APIs without incurring significant
cost.

Reviewed By: avp

Differential Revision: D51535575

fbshipit-source-id: 175a460815c9466e8c9841b1b2404eeb644a0659

* Implement calls

Summary: Implement calling JS functions from native code through the ABI.

Reviewed By: avp

Differential Revision: D51541197

fbshipit-source-id: fb5df2d3ce6d6c0c19422c511f507d1b29d9c454

* Implement HostFunction

Summary: Implement HostFunction in the ABI and JSI.

Reviewed By: avp

Differential Revision: D51551527

fbshipit-source-id: dd77825de2ae35f53edd1a6c2f53798ac90f118a

* Implement HostObject

Summary:
Implement HostObject in the ABI and JSI. This includes implementing a
new `HermesABIPropNameIDList` to pass the result of
`HostObject::getPropertyNames`.

The ABI method for getting properties from a `HostObject` is named
slightly differently than its JSI counterpart (`get_own_keys` vs
`getPropertyNames`). This is to align it with `Reflect.ownKeys` and the
Proxy `ownKeys` trap, and permit `Symbol`s to be returned from the
function. Our implementation doesn't currently deal with such symbols
properly, but that is a separate concern.

JSI is currently ambiguous on whether this is permissible, but this is
something we should address and align the two on before we stabilise
the ABI.

Reviewed By: avp

Differential Revision: D51551526

fbshipit-source-id: ff6e399794af2084d34d5333b4ce21f04a1ed824

* Implement NativeState

Summary: Implement NativeState in the ABI and wrapper.

Reviewed By: avp

Differential Revision: D51551528

fbshipit-source-id: 9d26743e9e11ea2cb77dc9e67fb05f3270ba2af2

* Implement object type checks

Summary: Implement type checks for objects in the ABI and wrapper.

Reviewed By: avp

Differential Revision: D51551529

fbshipit-source-id: 2454644033eb3ee475131e3af2edc0ec48c400f8

* Implement WeakObject

Reviewed By: avp

Differential Revision: D48052542

fbshipit-source-id: 4f9bb1f982781eaaae7cf42dea0800e9383b787b

* Implement getting UTF-8 strings from references

Reviewed By: avp

Differential Revision: D51535573

fbshipit-source-id: ba7f4631717e648e6491bfba4967dcffa5278eb5

* Implement instance_of and strict equality

Reviewed By: avp

Differential Revision: D50797413

fbshipit-source-id: 1c5cb6847f838cf9c2dc40b39862d42400edcf28

* Implement drainMicrotasks in the ABI

Summary:
Implement drainMicrotasks, in the ABI and the wrapper, with the same
behaviour as in JSI.

Reviewed By: avp

Differential Revision: D50797412

fbshipit-source-id: e232c010e331d62454cdf2954af40d8c64f5b709

* Implement BigInt manipulation in the ABI

Summary:
Implement JSI's BigInt manipulation functionality in the ABI and
wrapper.

Reviewed By: avp

Differential Revision: D50797414

fbshipit-source-id: c34feffe8ac1d3c103b5d4b3af249fc0db60a081

* Run tests against HermesABIRuntime (#1061)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1061

Set up the new `HermesABIRuntimeWrapper` to run against our JSI tests,
and API tests that use the APITestFactory. We should extend this to
cover more of our APITests, since most of them should run correctly
against the ABI runtime.

Reviewed By: avp

Differential Revision: D47563698

fbshipit-source-id: 5a994c708627c19c30000597e4b6068a52de71b1

* Implement native stack checking for Emscripten

Reviewed By: avp

Differential Revision: D49900200

fbshipit-source-id: cd1785e13a161027aed52808272d576e9b348d71

* Update the Github issue template

Summary:
The issue template was misleading by implying that we might be able to
support non-current versions of Hermes, which is definitely not the
case. React Native occasionally backports fixes, but that is only after
the fix has been applied to the current version.

The stable ABI will improve this, but we are not there yet.

I also attempted to address a couple of things that bugged me:
- Asking for a Hermes version is nonsensical and has been for a long
time.
- It made it seem like reporting the OS is optional.

Frankly, I am still not very happy with the template, but I hope that at
least these are changes in the right direction.

Reviewed By: neildhar

Differential Revision: D52580926

fbshipit-source-id: dfcd266fbe5a30216018781350026fb62cb887ab

* Parse typeof with type arguments

Summary:
This diff implements the parsing support for typeof with type arguments.

Changelog: [Internal]

Reviewed By: avp

Differential Revision: D52527139

fbshipit-source-id: ca2e4255620fe3d28d1cd5eda3bd89e541140108

* Parse typeof with type arguments JS changes

Summary:
This is the companion change of the previous diff.
Most of the stuff are generated, the only notable change is
that I make the babel adapter strip away the type arguments.

Reviewed By: alexmckenley

Differential Revision: D52527138

fbshipit-source-id: 26affce6151ca40a4aca95e4ea1b9ca3282acb22

* format_code_in_doc_comments=true

Summary: D52632085

Reviewed By: zertosh, dtolnay

Differential Revision: D52635896

fbshipit-source-id: a0faaa9a24dbc7216c05581e9af4028866bd454c

* Fix _snapshotAddEdgesImpl for WeakRef edge

Summary: Before adding edges, we should check if WeakRef is freed or empty.

Reviewed By: neildhar

Differential Revision: D52613241

fbshipit-source-id: 91988b80e12e11eb642bac4b6f3cfaf5f9fb4f8b

* Fix NumberFormat SetNumberFormatDigitOptions logic (#1246)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1246

The old Android logic was the 2020 version of the [spec](https://402.ecma-international.org/7.0/index.html#sec-setnfdigitoptions).

The old logic passes `mnfdDefault` as the fallback to
`DefaultNumberOption()` at step 12b. This causes the `mnfd` passed to
step 12d to be whatever the default for 'currency' style is. And since
`maximumFractionDigits` is set to 0 and 0 is less than `mnfd = 2`, a
RangeError was thrown.

This problem was already fixed by the 2021 version of the spec.

`PlatformIntlApple.mm` already implements the newer spec, so that's why
it's an Android-only issue.

Since the future plan is to move Intl to use ICU4C on Android, that
means much of the Java code becomes obsolete. Still, it's relatively
easy to just update the logic to match Apple platform [spec](https://402.ecma-international.org/8.0/index.html#sec-setnfdigitoptions), so I did.

In the process, I added tests to catch this bug. The tests are probably
the more valuable part as we implement on top of ICU4C.

Reviewed By: neildhar

Differential Revision: D52641902

fbshipit-source-id: d85a415c3440b2fe81c899d8ad0fd3c6eefc8031

* Deploy 0.226.0 to xplat

Summary:
X-link: https://github.com/facebook/react-native/pull/42252

Changelog: [Internal]

Reviewed By: SamChou19815

Differential Revision: D52708681

fbshipit-source-id: a864d2f5654ce011a4658564ec140aca03fb9ac8

* Doing single-digit fast-path for abstract equality testing

Summary:
Lots of common Hermes use-cases perform equality checks using `abstractEqualityTest_RJS`. This method compares a `number` against a `BigInt`, which makes total sense.

The current implementation creates a `BigInt` from the `double`, which also makes sense (since the BigInt might need to store a value bigger than the max double size).

However, lots of use-cases need to compare *specifically* against small numbers. Since we store numbers in our BigInts one digit at a time, we can pretty cheaply compare doubles directly against BigInts in the case that they both represent single digits.

This diff adds a fast-path to do that check before performing a BigInt creation from our double.

This fast-path *does* incur an extra couple checks on comparisons where the BigInt actually *is* too big to store in an `int64`, but the cost looks negligible next to the BigInt construction cost (plus real-world workloads seem overwhelmingly likely to have more sub-2^64 comparisons).

NOTE: The Hermes codebase refers to each `int64` as a "digit" instead of a "word". This is not a big deal, but just wanted to call out that a `digit` can store values up to 2^63 today.

Reviewed By: jpporto

Differential Revision: D52551370

fbshipit-source-id: 29dd6752dc702c8257daaca5494f51268a93740b

* Add wording on security bugs in GitHub issue template

Summary:
Add a message to the GitHub issue template, reminding users that if they
believe they have discovered a security vulnerability in Hermes, they
should submit it through the Meta Bug Bounty program rather than filing
a public issue. This is important to avoid publicly disclosing security
vulnerabilities before a fix.

Reviewed By: tmikov

Differential Revision: D52626730

fbshipit-source-id: 18e323051daff9a6def50a05444be6c930157b14

* Use builtin yarn version in yarn build-prettier script

Summary:
I've updated our `yarn build-prettier` build script to use the builtin version of yarn included with prettier to ensure the yarn lockfile is respected.

I've also added logic to run `yarn build` if none of the hermes-parser `dist` assets exist to make the development flow easier from ondemand machines.

NOTE: My changes to .yarnrc.cjs are needed in order to ensure the fwdproxy config is set correctly. See https://github.com/pieterv/prettier/pull/1/files

Reviewed By: SamChou19815

Differential Revision: D52739505

fbshipit-source-id: 4ae67a3ef352b069627b19968fb4ba986f6ad8a1

* Add Hermes wasm2c compilation

Summary:
Add the ability to compile Hermes with the C-API to wasm, and the
resulting wasm to C. Check in the generated artefact for a release and
debug build of Hermes, making it easier to build and develop with.

Reviewed By: avp

Differential Revision: D47065258

fbshipit-source-id: 0de6bc047a6ebc1fdac91a460fefcbf880c4e4b3

* Sandbox runtime skeleton

Summary:
Create a new JSI runtime that will consume the sandbox's exported
interface, and wire up the build.

Reviewed By: avp

Differential Revision: D52531413

fbshipit-source-id: 58a161591f46d0b7ab1ab795cf4633149beb7fcb

* Mirror ABI types and helpers in the sandbox

Summary:
The layout of data structures in the sandbox is different than that on
the host. In order to make it more convenient to consume and create
these data structures, create a full mirror of all the `HermesABI*`
types such that their layout matches what it would have in the
sandbox.

When passing/returning a value from the sandbox, it just needs to be
cast to one of these types to access its fields.

Reviewed By: avp

Differential Revision: D52558676

fbshipit-source-id: 2e88e294c7c827959e304381cc135d354bc0dc51

* Store WeakRefSlot in ManagedChunkList

Summary:
ManagedChunkList can automatically manage free slots, and shrink more
effectively than std::deque. It help reduce the necessary work in GC.

Reviewed By: neildhar

Differential Revision: D51048229

fbshipit-source-id: 10f8c0059fe32dd98eda67db93eeba6f58ea0c6a

* Enforce unique ownership of WeakRefs

Summary:
Each WeakRef uniquely owns a WeakRefSlot, and frees the slot only when
destroying the WeakRef.

Reviewed By: neildhar

Differential Revision: D38065776

fbshipit-source-id: 8283dc22d03e653ccf9d11a9f713cc7ca808b309

* Remove concurrent marking of WeakRefs (#1243)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1243

Remove all WeakRef marking functions and weakRefMutex_.

Reviewed By: neildhar

Differential Revision: D38077265

fbshipit-source-id: 90693c81ce4f5ca168097a3157ccb6ba6da77dd0

* Implement a helper for function type signatures

Summary:
Function pointers in the sandbox are just indices into a function
pointer table. The table also includes a type signature encoded as a
`wasm_rt_func_type_t`, which is used to verify that the function being
retrieved has the expected type (since it would be unsafe to call it if
the types do not match).

So whenever we add a function to the table, or we try to retrieve a
function, it is necessary to construct its corresponding
`wasm_rt_func_type_t` to populate/check the stored type. This results
in a lot of boilerplate, and is error prone since we need to manually
ensure that the constructed `wasm_rt_func_type_t` matches the actual
signature of the function.

This diff defines a template that performs the conversion from a
function signature to a `wasm_rt_func_type_t` automatically, by
decomposing the function type and constructing the right call to
`wasm2c_hermes_get_func_type`.

Reviewed By: avp

Differential Revision: D52558681

fbshipit-source-id: 84f13bdf5a1cbde4a49f89fb70ad4c861892ec87

* Implement utilities for pointers and allocations in sandbox memory

Summary:
Implement some utilities to make it easier to interact with pointers
into the sandbox. Since pointers are just `uint32`s, they convey no
type information and are annoying to dereference.

This diff defines a `Ptr` template, and subclasses, that allow you to
treat the pointer like a reference to the underlying object. Note that
this is safer than directly holding a pointer to the underlying memory,
because the sandbox heap can move when it grows.

The subclasses make it convenient to allocate data on the stack/heap
for the duration of the implementation of JSI functions.

Reviewed By: avp

Differential Revision: D52558679

fbshipit-source-id: 3e189388861a517897288cc90a31f483e25335c6

* Create a sandbox module tied to each runtime

Summary:
Instantiate the w2c_hermes module for each instance of a
`HermesSandboxRuntime`. This is the execution context for the sandbox,
providing things like the heap, stack, and tables. While it is
technically possible to instantiate multiple runtimes in a single
module, for now, just maintain one module per runtime.

This uses a base class instead of a field to make it convenient and
efficient to obtain the module from a `HermesSandboxRuntime *` and
vice versa.

Reviewed By: avp

Differential Revision: D52558675

fbshipit-source-id: c880f7f4700e1963e0ce3de8a3beff09378b6449

* Create and destroy the sandboxed runtime

Summary:
Instantiate a runtime object through the ABI by retrieving the vtable
and calling `make_hermes_runtime`. The object is owned by the JSI
runtime and is released on destruction.

Read out the vtable fields as correctly typed function pointers to
populate the mirrored vtable `vt_`. These will be the primary mechanism
for calling into the sandbox.

Reviewed By: avp

Differential Revision: D52558677

fbshipit-source-id: 770d97291a6985d2b62f747b0c3b804caef5b56c

* Implement GrowableBuffer

Summary:
Implement `GrowableBuffer`, allowing the sandbox to return variable
length data (for now it is just strings). This also requires some
general utilities and patterns that are used to perform allocations and
expose functionality to the runtime.

Reviewed By: avp

Differential Revision: D52558678

fbshipit-source-id: 6e1790eb2a6010e10b65a240960ac64f17eb98ba

* Implement values and exceptions

Summary:
Implement passing values to/from the sandbox and retrieving exceptions.
This mostly mirrors the equivalent implementation in
`HermesABIRuntimeWrapper`.

Reviewed By: avp

Differential Revision: D52558680

fbshipit-source-id: 834c15604d46458708a696ba54479f4e5e10493f

* Expose the time and randomness to the sandbox

Summary: Add implementations for the imported time and randomness functions.

Reviewed By: avp

Differential Revision: D52558753

fbshipit-source-id: fdc8e4c757c24596f18a2e04c6847018e055022b

* Implement evaluateJavaScript in the sandbox

Summary: Implement the buffer API, and use it to implement `evaluateJavaScript`.

Reviewed By: ftanuma

Differential Revision: D48086020

fbshipit-source-id: ee9472b7622f5602c5dd42ce11533c08f7c19489

* Implement most JSI functionality

Summary:
Add basic implementations for most of JSI on top of the sandbox. This
excludes things like HostObject, HostFunction, and NativeState which
require a little more work.

Reviewed By: ftanuma

Differential Revision: D52558754

fbshipit-source-id: b323d5d30f3c72f10d636038ed4cff3770a2d420

* Implement NativeState, HostFunction, and HostObject

Summary:
Add implementations for exposing NativeState, HostFunction, and
HostObject to the sandbox.

This also adds an indirection mechanism for accessing them with an
index, to avoid storing the native pointers in the sandbox heap (which
may get corrupted).

Reviewed By: avp

Differential Revision: D52558752

fbshipit-source-id: fb5be97bccde96374def8594559e78f48dbca84a

* Run API tests against the sandbox runtime (#1248)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1248

X-link: https://github.com/facebook/react-native/pull/42264

Add a buck build for the sandbox, and run our existing API tests
against it.

Reviewed By: avp

Differential Revision: D48086019

fbshipit-source-id: 2ee2eca93e27557d2609eaaec2fce3218d8b873f

* Fix $ReadOnlyMap arity bug, add tests

Summary: `flow-api-translator` currently expects `$ReadOnlyMap` to have only one type argument, but it actually takes two. Here we fix that and also add tests for `$ReadOnlyMap` and `$ReadOnlySet`.

Reviewed By: pieterv

Differential Revision: D52784895

fbshipit-source-id: fa8a3018dfc58e4ca07c797c990c80c275c2407c

* Introduce AsyncDebuggerAPI

Summary:
Adding a new class AsyncDebuggerAPI that wraps the existing
DebuggerAPI. This class extracts some core concepts from the existing
CDPHandler so that we have a class that's not tied to CDP.

The main things that this class enables are:
1) Exposes an interrupt API and guarantees those interrupt callbacks
will be called exactly once.
2) Turns the didPause interaction into an asynchronous one. Consumers
of this class will register DebuggerEventCallback but isn't expected to
decide on a next debugger::Command while handling that callback.
3) Adds an API for unpausing the JavaScript program after a
DebuggerEventCallback has been invoked. Together with #2, this allows
someone to implement a debugging solution like CDP that's asynchronous
in nature.

The reason to introduce this class is so that we can contain most of
the multithread complexity in one place. Rather than having every
function in CDPHandler having to think about multithreading, CDPHandler
can be simplified.

Reviewed By: mattbfb

Differential Revision: D51595285

fbshipit-source-id: f4bfaa9daf13339016e2ee0ac347272eb67e3c54

* Add tests for AsyncDebuggerAPI

Summary: Adding tests for AsyncDebuggerAPI.

Reviewed By: mattbfb

Differential Revision: D51768909

fbshipit-source-id: 17243cca4d4ae0a82337ccb6498b54f4c44628fa

* Fix build when HERMES_ENABLE_DEBUGGER=0 (#1254)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1254

Taking the same strategy as DebuggerAPI by stubbing out all functionality in AsyncDebuggerAPI when `HERMES_ENABLE_DEBUGGER=0`.

Reviewed By: mattbfb

Differential Revision: D52812969

fbshipit-source-id: 7fb05dbe3b92738b715e10f66d2e28d59dc42cf5

* btoa implementation (#1255)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1255

Implement
[btoa](https://html.spec.whatwg.org/multipage/webappapis.html#atob)
utility function for encoding a string to base64. This implementation
doesn't follow the HTML spec 100% in that for error cases, the code
doesn't throw DOMException. Existing alternatives people use with
Hermes simply throw Error, which is what this code throws as well.

Reviewed By: avp

Differential Revision: D51876325

fbshipit-source-id: 085aa069a761d093fd9e504c0478ee18a36e8d34

* atob implementation (#1256)

Summary:
Pull Request resolved: https://github.com/facebook/hermes/pull/1256

Implement
[atob](https://html.spec.whatwg.org/multipage/webappapis.html#atob)
utility function for decoding a base64 string. This implementation
doesn't follow the HTML spec 100% in that for error cases, the code
doesn't throw DOMException. Existing alternatives people use with
Hermes simply throw Error, which is what this code throws as well.

Reviewed By: avp

Differential Revision: D52181353

fbshipit-source-id: c90ec95e1ed3b44a7668a6ae4071df536bb31a71

* Regenerate sandbox code

Summary:
Re-generate the sandbox from the following:

emsdk 3.1.39
wasm2c 1.0.33
git revision: 005897de9ac561b02ace6a61885d75e397491819

Reviewed By: tmikov

Differential Revision: D52807947

fbshipit-source-id: 39b6af111ab2104ece6c60a019c115aa33f644ba

* Check bounds on data pointer in GrowableBufferImpl::getString

Summary:
This was missing the third parameter to the `Ptr` constructor, which
specifies the size of the memory region being accessed.

Adding it ensures that the bounds check applies to the entire region.

Reviewed By: tmikov

Differential Revision: D52807948

fbshipit-source-id: f4629e001e7bba49ee1670f204d30b93faab2d41

* Remove regex breakpoints

Summary:
Remove handling of URL regexes. This functionality is not not used in
our current configurations.

The only reference to regex breakpoints in Chrome DevTools appears
to be for debugging a NodeJS target on Windows, when running
scripts from local filepaths (it's used to work around the case
insensitivity of windows paths).

Our use cases only make use of setting breakpoints by URL or by
script ID.

This change makes the subsequent stack simpler, and removes use of
`std::regex`, which is considered problematic.

Reviewed By: dannysu

Differential Revision: D51674836

fbshipit-source-id: e547738cbe5b0f571f87d8a206002ff2852231f2

* Add end-to-end CI for sandbox (#1252)

Summary:
Add a CI job that recreates the sandbox from source and tests that it
works.

Pull Request resolved: https://github.com/facebook/hermes/pull/1252

Reviewed By: avp

Differential Revision: D52823512

Pulled By: neildhar

fbshipit-source-id: 7c9ef620a78a95db4e7b3608372e513ddb134f3c

* Avoid potential overflow in pointer bounds check

Summary:
This check could overflow on 32 bit platforms if `n` is large. Cast it
to `u64` before checking to ensure that the math is done with 64 bit
numbers to avoid overflow.

Reviewed By: tmikov

Differential Revision: D52807946

fbshipit-source-id: 3adc2f898588b046915966f4d97c8377d1a3d75b

* Fixed symbol conflicts when using identical function and method names in an ES6 class (#1257)

Summary:
This change fixes an issue that could occur when calling a function from a method that has the same name. Consider this example:
```js
function myMethod() {
  console.log('Hello from function');
}

class MyClass {
  myMethod() {
    myMethod();
  }
}
```
In this scenario, `Hello from function` would not be printed when `instance.myMethod()` is called as the method would be called recursively instead of the function that is available in the outer scope.

## Changes
- Added test showcasing the issue
- Always create an anonymous function for methods (maybe there is a way to make the identifier private instead?), so that the method body cannot recursively refers to itself by its name.
- Insert `method.name` at the JS level when the method is about to be registered into the class.

Pull Request resolved: https://github.com/facebook/hermes/pull/1257

Test Plan:
All tests passes.
<!--
  Demonstrate the code is solid.
  Example: The…
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.

3 participants