[L] Change in dart/sdk[main]: [js] Add `js_interop_unsafe` library.

40 views
Skip to first unread message

Joshua Litt (Gerrit)

unread,
Apr 13, 2023, 5:49:23 PM4/13/23
to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org

Attention is currently required from: Joshua Litt, Sigmund Cherem.

Joshua Litt uploaded patch set #6 to this change.

View Change

[js] Add `js_interop_unsafe` library.

Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
---
M pkg/compiler/lib/src/kernel/dart2js_target.dart
M pkg/dart2wasm/lib/js/runtime_generator.dart
M pkg/dart2wasm/lib/target.dart
M pkg/dev_compiler/lib/src/kernel/target.dart
M sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
A sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
M sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
M sdk/lib/_internal/wasm/lib/js_interop_patch.dart
A sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
M sdk/lib/js_interop/js_interop.dart
A sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
A sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni
M sdk/lib/libraries.json
M sdk/lib/libraries.yaml
A tests/lib/js_interop_unsafe/basic_test.dart
15 files changed, 638 insertions(+), 8 deletions(-)

To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
Gerrit-Change-Number: 293743
Gerrit-PatchSet: 6
Gerrit-Owner: Joshua Litt <joshu...@google.com>
Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
Gerrit-Attention: Joshua Litt <joshu...@google.com>
Gerrit-Attention: Sigmund Cherem <sig...@google.com>
Gerrit-MessageType: newpatchset

Joshua Litt (Gerrit)

unread,
Apr 13, 2023, 5:56:07 PM4/13/23
to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Srujan Gaddam, Sigmund Cherem

Attention is currently required from: Sigmund Cherem.

Patch set 7:Commit-Queue +1

View Change

3 comments:

  • Patchset:

  • File sdk/lib/js_interop/js_interop.dart:

    • Patch Set #5, Line 60: // TODO(joshualitt): Add a [JSObject] constructor.

      Ah yeah, this will have to wait until we stop using typdefs. […]

      Done

    • Patch Set #5, Line 135: /// Effectively the inverse of [jsify], [dartify] Takes a JavaScript object, and

      nit:wrap

      Done

To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: sdk
Gerrit-Branch: main
Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
Gerrit-Change-Number: 293743
Gerrit-PatchSet: 7
Gerrit-Owner: Joshua Litt <joshu...@google.com>
Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
Gerrit-Attention: Sigmund Cherem <sig...@google.com>
Gerrit-Comment-Date: Thu, 13 Apr 2023 21:56:03 +0000
Gerrit-HasComments: Yes
Gerrit-Has-Labels: Yes
Comment-In-Reply-To: Srujan Gaddam <sru...@google.com>
Comment-In-Reply-To: Joshua Litt <joshu...@google.com>
Gerrit-MessageType: comment

CBuild (Gerrit)

unread,
Apr 13, 2023, 6:33:10 PM4/13/23
to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

Attention is currently required from: Joshua Litt, Sigmund Cherem.

go/dart-cbuild result: SUCCESS

Details: https://goto.google.com/dart-cbuild/find/bb819aa704316cd5bee70395dfab0f7859fd3b4e

View Change

    To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

    Gerrit-Project: sdk
    Gerrit-Branch: main
    Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
    Gerrit-Change-Number: 293743
    Gerrit-PatchSet: 7
    Gerrit-Owner: Joshua Litt <joshu...@google.com>
    Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
    Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
    Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
    Gerrit-Attention: Joshua Litt <joshu...@google.com>
    Gerrit-Attention: Sigmund Cherem <sig...@google.com>
    Gerrit-Comment-Date: Thu, 13 Apr 2023 22:33:06 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: No
    Gerrit-MessageType: comment

    CBuild (Gerrit)

    unread,
    Apr 13, 2023, 8:07:17 PM4/13/23
    to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

    Attention is currently required from: Joshua Litt, Sigmund Cherem.

    go/dart-cbuild result: SUCCESS

    Details: https://goto.google.com/dart-cbuild/find/52756ee1107aba7528b5592dec04ef1c7baa1651

    View Change

      To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
      Gerrit-Change-Number: 293743
      Gerrit-PatchSet: 10
      Gerrit-Owner: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
      Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
      Gerrit-Attention: Joshua Litt <joshu...@google.com>
      Gerrit-Attention: Sigmund Cherem <sig...@google.com>
      Gerrit-Comment-Date: Fri, 14 Apr 2023 00:07:13 +0000

      Sigmund Cherem (Gerrit)

      unread,
      Apr 18, 2023, 7:51:10 PM4/18/23
      to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

      Attention is currently required from: Joshua Litt.

      View Change

      2 comments:

      • File sdk/lib/_internal/js_shared/lib/js_interop_patch.dart:

        • Patch Set #10, Line 8: import 'dart:js_util' as js_util;

          curious: is the goal to eventually make js_interop self contained and remove the dependency on js_util?

      • File sdk/lib/js_interop/js_interop.dart:

        • Patch Set #10, Line 142: extension NullableObjectUtilExtension on Object? {

          Thoughts on limiting this to a set of types instead?

          I cannot quite pinpoint my concern here, but seeing an extension on all `Object?` stands out to me as potentially risky.

          One concrete concern is that it may give the illusion that this is guaranteed to work on arbitrary code.

          One option is to add the extension separately on various types like List, Map, Null, num, and String. That said, if we don't expect calls to be as common, I'm also OK not making the API fluid (via an extension method) and just keeping it as a top-level instead.

      To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-MessageType: comment
      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
      Gerrit-Change-Number: 293743
      Gerrit-PatchSet: 10
      Gerrit-Owner: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
      Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
      Gerrit-Attention: Joshua Litt <joshu...@google.com>
      Gerrit-Comment-Date: Tue, 18 Apr 2023 23:51:04 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No

      Joshua Litt (Gerrit)

      unread,
      Apr 18, 2023, 8:00:29 PM4/18/23
      to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

      Attention is currently required from: Sigmund Cherem.

      View Change

      2 comments:

      • File sdk/lib/_internal/js_shared/lib/js_interop_patch.dart:

        • curious: is the goal to eventually make js_interop self contained and remove the dependency on js_ut […]

          Yes exactly, but that is down the road.

      • File sdk/lib/js_interop/js_interop.dart:

        • Thoughts on limiting this to a set of types instead? […]

          The reason to make this an extension method is to avoid a name conflict with `js_util`. Also, I really like the API as a getter(see the test, but being able to chain these calls looks and feels good).

          How strong are your feelings here? Three factors which might make it reasonable to leave this as is:
          1) The name of the API is fairly explicity(`jsify`).
          2) The existing API takes an `Object?`.
          3) This is just a regular extension, and thus not sticky. Users will have to explicitly import `dart:js_interop`, which on top of the naming of the extension(`jsify`), seems like it should make this quite safe?

          That said, I'm open to making the type more specific, but I think it will be hard to do that cleanly because of how many types `jsify` applies to.

      To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-MessageType: comment
      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
      Gerrit-Change-Number: 293743
      Gerrit-PatchSet: 10
      Gerrit-Owner: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
      Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
      Gerrit-Attention: Sigmund Cherem <sig...@google.com>
      Gerrit-Comment-Date: Wed, 19 Apr 2023 00:00:19 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Sigmund Cherem <sig...@google.com>

      Sigmund Cherem (Gerrit)

      unread,
      Apr 19, 2023, 12:59:35 PM4/19/23
      to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

      Attention is currently required from: Joshua Litt.

      View Change

      1 comment:

      • File sdk/lib/js_interop/js_interop.dart:

        • I'd be OK with the name conflict to be honest (yay prefixes 😊)

        • How strong are your feelings here?

        • Not sure 😕 - I think not so strong, and given this is all static dispatch, it can potentially all be evolved via `dart fix`es.

          A few more considerations to help us decide:

          • (A) What do we want the default behavior for non serializable Dart classes to be? Do we expect that to be commonly used?
          • (B) Would it be more efficient to have a specialized jsify per type?
          • (C) Are there other parallel APIs we are considering that would live side-by-side?

          Re (A): Today we have logic listing each case we accept and convert ([_noJsifyRequired][1] plus Map and Iterable), but we pass `o` (or a box in wasm) if it isn't any of those. If that's the behavior we plan to have going forward, then it is fine to keep this in `Object?`. If we want to make it an error, I rather put the jsify down where it will not throw.

          In other words. If we had union types in Dart, would the API still take `Object?` or would we have used a union in the type type signature of jsify? Or would we have had two APIs `jsifyAcceptAny` and `jsfiy`, where the latter throws?

          Re (B): One of the hidden features of extension methods is that it gives us a way of providing overloaded methods based on the receiver type. `jsify` in `num` could potentially directly convert numbers and ignore all other cases, making a more efficient implementation. Technically we can still do this if we put it in Object, we just get the most specialized version based on the type. However, removing it from `Object?` would ensure developers don't hit the slow path accidentally.

          Re (C): We also have discussed adding a non-recursive lighter jsify api (this has mainly come up in the context of `objectLiteral` but it could be slightly more general). Do we expect to have both APIs in the same extension or in different places?


          [1]: https://github.com/dart-lang/sdk/blob/a6162d1ff077eff9495ee5adba55440634fa1679/sdk/lib/_internal/js_shared/lib/js_util_patch.dart#L13

      To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-MessageType: comment
      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
      Gerrit-Change-Number: 293743
      Gerrit-PatchSet: 10
      Gerrit-Owner: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
      Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
      Gerrit-Attention: Joshua Litt <joshu...@google.com>
      Gerrit-Comment-Date: Wed, 19 Apr 2023 16:59:31 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Joshua Litt <joshu...@google.com>
      Comment-In-Reply-To: Sigmund Cherem <sig...@google.com>

      Joshua Litt (Gerrit)

      unread,
      Apr 19, 2023, 2:30:30 PM4/19/23
      to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

      Attention is currently required from: Sigmund Cherem.

      View Change

      1 comment:

      • File sdk/lib/js_interop/js_interop.dart:

        • I'd be OK with the name conflict to be honest (yay prefixes 😊) […]

          We spoke offline.

          In the short term, I'm going to make these methods because they are a bit more heavyweight than the other getters.

          In the longer term, we can think about making fast paths for `jsify`. If we need to later on, we can always get rid of the conversion on `Object?` by introducing helpers in user code that perform the recursive conversion.

      To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

      Gerrit-MessageType: comment
      Gerrit-Project: sdk
      Gerrit-Branch: main
      Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
      Gerrit-Change-Number: 293743
      Gerrit-PatchSet: 11
      Gerrit-Owner: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
      Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
      Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
      Gerrit-Attention: Sigmund Cherem <sig...@google.com>
      Gerrit-Comment-Date: Wed, 19 Apr 2023 18:30:26 +0000

      CBuild (Gerrit)

      unread,
      Apr 19, 2023, 3:05:39 PM4/19/23
      to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

      Attention is currently required from: Sigmund Cherem.

      go/dart-cbuild result: SUCCESS

      Details: https://goto.google.com/dart-cbuild/find/387aeaf04944225567f375c449571e26ba0047f4

      View Change

        To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-MessageType: comment
        Gerrit-Project: sdk
        Gerrit-Branch: main
        Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
        Gerrit-Change-Number: 293743
        Gerrit-PatchSet: 11
        Gerrit-Owner: Joshua Litt <joshu...@google.com>
        Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
        Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
        Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
        Gerrit-Attention: Sigmund Cherem <sig...@google.com>
        Gerrit-Comment-Date: Wed, 19 Apr 2023 19:05:34 +0000
        Gerrit-HasComments: No
        Gerrit-Has-Labels: No

        Joshua Litt (Gerrit)

        unread,
        Apr 24, 2023, 1:18:49 PM4/24/23
        to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org

        Attention is currently required from: Joshua Litt, Sigmund Cherem.

        Joshua Litt uploaded patch set #12 to this change.

        View Change

        [js] Add `js_interop_unsafe` library.

        CoreLibraryReviewExempt: Web only library.

        Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
        ---
        M pkg/compiler/lib/src/kernel/dart2js_target.dart
        M pkg/dart2wasm/lib/js/runtime_generator.dart
        M pkg/dart2wasm/lib/target.dart
        M pkg/dev_compiler/lib/src/kernel/target.dart
        M sdk/BUILD.gn

        M sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
        A sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
        M sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
        M sdk/lib/_internal/wasm/lib/js_interop_patch.dart
        A sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
        M sdk/lib/js_interop/js_interop.dart
        A sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
        A sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni
        M sdk/lib/libraries.json
        M sdk/lib/libraries.yaml
        A tests/lib/js_interop_unsafe/basic_test.dart
        M tests/lib/lib.status
        17 files changed, 646 insertions(+), 8 deletions(-)

        To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

        Gerrit-MessageType: newpatchset
        Gerrit-Project: sdk
        Gerrit-Branch: main
        Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
        Gerrit-Change-Number: 293743
        Gerrit-PatchSet: 12
        Gerrit-Owner: Joshua Litt <joshu...@google.com>
        Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
        Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
        Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>

        CBuild (Gerrit)

        unread,
        Apr 24, 2023, 8:22:07 PM4/24/23
        to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

        Attention is currently required from: Joshua Litt, Sigmund Cherem.

        go/dart-cbuild result: SUCCESS

        Details: https://goto.google.com/dart-cbuild/find/bebc1ba4ea5f1d2cb5e4d2826a0815d7cb6f17f4

        View Change

          To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-MessageType: comment
          Gerrit-Project: sdk
          Gerrit-Branch: main
          Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
          Gerrit-Change-Number: 293743
          Gerrit-PatchSet: 13
          Gerrit-Owner: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
          Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
          Gerrit-Attention: Joshua Litt <joshu...@google.com>
          Gerrit-Attention: Sigmund Cherem <sig...@google.com>
          Gerrit-Comment-Date: Tue, 25 Apr 2023 00:22:02 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: No

          Srujan Gaddam (Gerrit)

          unread,
          Apr 25, 2023, 12:03:50 PM4/25/23
          to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Sigmund Cherem

          Attention is currently required from: Joshua Litt, Sigmund Cherem.

          Patch set 13:Code-Review +1

          View Change

          2 comments:

          • File sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart:

            • Patch Set #13, Line 26: == null

              Hmm, it's possible that a call explicitly passes null. We could make this an `isUndefined` check, but that might be too confusing, so this is fine for now.

          • File sdk/lib/js_interop_unsafe/js_interop_unsafe.dart:

          To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-MessageType: comment
          Gerrit-Project: sdk
          Gerrit-Branch: main
          Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
          Gerrit-Change-Number: 293743
          Gerrit-PatchSet: 13
          Gerrit-Owner: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
          Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
          Gerrit-Attention: Joshua Litt <joshu...@google.com>
          Gerrit-Attention: Sigmund Cherem <sig...@google.com>
          Gerrit-Comment-Date: Tue, 25 Apr 2023 16:03:44 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes

          Joshua Litt (Gerrit)

          unread,
          Apr 25, 2023, 4:28:29 PM4/25/23
          to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

          Attention is currently required from: Sigmund Cherem.

          Patch set 14:Commit-Queue +1

          View Change

          1 comment:

          • File sdk/lib/js_interop_unsafe/js_interop_unsafe.dart:

            • We spoke offline, `setProperty` doesn't add anything over `[]=`, so it doesn't make sense to have it. `getProperty` adds a `T` to cast the return value to. TBH, I'd be okay with getting rid of `getProperty` for symmetry, but the tax here is small, so we're just going to leave it in.

          To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

          Gerrit-MessageType: comment
          Gerrit-Project: sdk
          Gerrit-Branch: main
          Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
          Gerrit-Change-Number: 293743
          Gerrit-PatchSet: 14
          Gerrit-Owner: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
          Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
          Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
          Gerrit-Attention: Sigmund Cherem <sig...@google.com>
          Gerrit-Comment-Date: Tue, 25 Apr 2023 20:28:24 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: Yes
          Comment-In-Reply-To: Srujan Gaddam <sru...@google.com>

          CBuild (Gerrit)

          unread,
          Apr 25, 2023, 5:05:11 PM4/25/23
          to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

          Attention is currently required from: Sigmund Cherem.

          go/dart-cbuild result: SUCCESS

          Details: https://goto.google.com/dart-cbuild/find/f0f24367f74c2ae2168bb93aee035b298efe0749

          View Change

            To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-MessageType: comment
            Gerrit-Project: sdk
            Gerrit-Branch: main
            Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
            Gerrit-Change-Number: 293743
            Gerrit-PatchSet: 14
            Gerrit-Owner: Joshua Litt <joshu...@google.com>
            Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
            Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
            Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
            Gerrit-Attention: Sigmund Cherem <sig...@google.com>
            Gerrit-Comment-Date: Tue, 25 Apr 2023 21:05:07 +0000
            Gerrit-HasComments: No
            Gerrit-Has-Labels: No

            Joshua Litt (Gerrit)

            unread,
            Apr 27, 2023, 11:53:01 AM4/27/23
            to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

            Attention is currently required from: Sigmund Cherem.

            Patch set 16:Commit-Queue +1

            View Change

            1 comment:

            • File sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart:

              • Hmm, it's possible that a call explicitly passes null. […]

                Yea, it could happen, eventually we need to callsite specialize these functions. A added a TODO so this doesn't slip between the cracks.

            To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

            Gerrit-MessageType: comment
            Gerrit-Project: sdk
            Gerrit-Branch: main
            Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
            Gerrit-Change-Number: 293743
            Gerrit-PatchSet: 16
            Gerrit-Owner: Joshua Litt <joshu...@google.com>
            Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
            Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
            Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
            Gerrit-Attention: Sigmund Cherem <sig...@google.com>
            Gerrit-Comment-Date: Thu, 27 Apr 2023 15:52:57 +0000

            CBuild (Gerrit)

            unread,
            Apr 27, 2023, 12:18:20 PM4/27/23
            to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Commit Queue, Srujan Gaddam, Sigmund Cherem

            Attention is currently required from: Joshua Litt, Sigmund Cherem.

            go/dart-cbuild result: SUCCESS

            Details: https://goto.google.com/dart-cbuild/find/fb4881842c96543316200ab9f4fab46cbf59624a

            View Change

              To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

              Gerrit-MessageType: comment
              Gerrit-Project: sdk
              Gerrit-Branch: main
              Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
              Gerrit-Change-Number: 293743
              Gerrit-PatchSet: 16
              Gerrit-Owner: Joshua Litt <joshu...@google.com>
              Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
              Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
              Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
              Gerrit-Attention: Joshua Litt <joshu...@google.com>
              Gerrit-Attention: Sigmund Cherem <sig...@google.com>
              Gerrit-Comment-Date: Thu, 27 Apr 2023 16:18:12 +0000
              Gerrit-HasComments: No
              Gerrit-Has-Labels: No

              Joshua Litt (Gerrit)

              unread,
              Apr 27, 2023, 1:45:32 PM4/27/23
              to dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Commit Queue, Srujan Gaddam, Sigmund Cherem

              Attention is currently required from: Joshua Litt, Sigmund Cherem.

              Patch set 17:Commit-Queue +2

              View Change

                To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

                Gerrit-MessageType: comment
                Gerrit-Project: sdk
                Gerrit-Branch: main
                Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
                Gerrit-Change-Number: 293743
                Gerrit-PatchSet: 17
                Gerrit-Owner: Joshua Litt <joshu...@google.com>
                Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
                Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
                Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
                Gerrit-Attention: Joshua Litt <joshu...@google.com>
                Gerrit-Attention: Sigmund Cherem <sig...@google.com>
                Gerrit-Comment-Date: Thu, 27 Apr 2023 17:45:28 +0000
                Gerrit-HasComments: No
                Gerrit-Has-Labels: Yes

                Commit Queue (Gerrit)

                unread,
                Apr 27, 2023, 2:51:57 PM4/27/23
                to Joshua Litt, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, CBuild, Srujan Gaddam, Sigmund Cherem

                Commit Queue submitted this change.

                View Change



                13 is the latest approved patch-set.
                The change was submitted with unreviewed changes in the following files:

                ```
                The name of the file: sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
                Insertions: 4, Deletions: 3.

                The diff is too large to show. Please review the diff.
                ```
                ```
                The name of the file: pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
                Insertions: 1, Deletions: 0.

                The diff is too large to show. Please review the diff.
                ```
                ```
                The name of the file: sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
                Insertions: 2, Deletions: 1.

                The diff is too large to show. Please review the diff.
                ```
                ```
                The name of the file: sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
                Insertions: 8, Deletions: 6.

                The diff is too large to show. Please review the diff.
                ```
                ```
                The name of the file: sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
                Insertions: 7, Deletions: 6.

                The diff is too large to show. Please review the diff.
                ```

                Approvals: Srujan Gaddam: Looks good to me, approved Joshua Litt: Commit
                [js] Add `js_interop_unsafe` library.

                CoreLibraryReviewExempt: Web only library.
                Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
                Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/293743
                Commit-Queue: Joshua Litt <joshu...@google.com>
                Reviewed-by: Srujan Gaddam <sru...@google.com>
                ---
                M pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart

                M pkg/compiler/lib/src/kernel/dart2js_target.dart
                M pkg/dart2wasm/lib/js/runtime_generator.dart
                M pkg/dart2wasm/lib/target.dart
                M pkg/dev_compiler/lib/src/kernel/target.dart
                M sdk/BUILD.gn
                M sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
                A sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
                M sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
                M sdk/lib/_internal/wasm/lib/js_interop_patch.dart
                A sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
                M sdk/lib/js_interop/js_interop.dart
                A sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
                A sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni
                M sdk/lib/libraries.json
                M sdk/lib/libraries.yaml
                A tests/lib/js_interop_unsafe/basic_test.dart
                M tests/lib/lib.status
                18 files changed, 749 insertions(+), 8 deletions(-)

                diff --git a/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
                index 5aa2895..23477ab 100644
                --- a/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
                +++ b/pkg/_js_interop_checks/lib/src/transformations/static_interop_class_eraser.dart
                @@ -126,6 +126,7 @@
                // To avoid this, we use an allowlist that contains libraries that we know use
                // `@staticInterop`.
                late final Set<String> _erasableCoreLibraries = {
                + 'js_interop_unsafe',
                'ui',
                '_engine',
                '_skwasm_impl'
                diff --git a/pkg/compiler/lib/src/kernel/dart2js_target.dart b/pkg/compiler/lib/src/kernel/dart2js_target.dart
                index e04a298..4504444 100644
                --- a/pkg/compiler/lib/src/kernel/dart2js_target.dart
                +++ b/pkg/compiler/lib/src/kernel/dart2js_target.dart
                @@ -290,6 +290,7 @@
                'dart:js',
                'dart:js_interop',
                'dart:js_util',
                + 'dart:js_interop_unsafe',
                'dart:math',
                'dart:svg',
                'dart:typed_data',
                @@ -324,6 +325,7 @@
                'dart:isolate',
                'dart:js',
                'dart:js_interop',
                + 'dart:js_interop_unsafe',
                'dart:js_util',
                'dart:math',
                'dart:typed_data',
                diff --git a/pkg/dart2wasm/lib/js/runtime_generator.dart b/pkg/dart2wasm/lib/js/runtime_generator.dart
                index 7387982..6014ec8 100644
                --- a/pkg/dart2wasm/lib/js/runtime_generator.dart
                +++ b/pkg/dart2wasm/lib/js/runtime_generator.dart
                @@ -29,7 +29,12 @@
                final staticInteropClassEraser = StaticInteropClassEraser(coreTypes, null,
                eraseStaticInteropType: (staticInteropType) =>
                InterfaceType(jsValueClass, staticInteropType.declaredNullability),
                - additionalCoreLibraries: {'_js_helper', '_js_types', 'js_interop'});
                + additionalCoreLibraries: {
                + '_js_helper',
                + '_js_types',
                + 'js_interop',
                + 'js_interop_unsafe'
                + });
                for (Library library in interopDependentLibraries) {
                staticInteropClassEraser.visitLibrary(library);
                }
                diff --git a/pkg/dart2wasm/lib/target.dart b/pkg/dart2wasm/lib/target.dart
                index a8ea4ef..c36f658 100644
                --- a/pkg/dart2wasm/lib/target.dart
                +++ b/pkg/dart2wasm/lib/target.dart
                @@ -73,6 +73,7 @@
                'dart:nativewrappers',
                'dart:io',
                'dart:js_interop',
                + 'dart:js_interop_unsafe',
                'dart:js',
                'dart:js_util',
                'dart:_wasm',
                diff --git a/pkg/dev_compiler/lib/src/kernel/target.dart b/pkg/dev_compiler/lib/src/kernel/target.dart
                index 95cbf83..93f90a5 100644
                --- a/pkg/dev_compiler/lib/src/kernel/target.dart
                +++ b/pkg/dev_compiler/lib/src/kernel/target.dart
                @@ -79,6 +79,7 @@
                'dart:isolate',
                'dart:js',
                'dart:js_interop',
                + 'dart:js_interop_unsafe',
                'dart:js_util',
                'dart:math',
                'dart:typed_data',
                diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
                index 003176e..52897f8 100644
                --- a/sdk/BUILD.gn
                +++ b/sdk/BUILD.gn
                @@ -90,6 +90,7 @@
                # ......isolate/
                # ......js/
                # ......js_interop/
                +# ......js_interop_unsafe/
                # ......js_util/
                # ......math/
                # ......mirrors/
                @@ -160,6 +161,7 @@
                "isolate",
                "js",
                "js_interop",
                + "js_interop_unsafe",
                "js_util",
                "math",
                "mirrors",
                diff --git a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
                index dadf384..850e6bb 100644
                --- a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
                +++ b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart
                @@ -5,17 +5,41 @@
                import 'dart:_foreign_helper' show JS;
                import 'dart:_internal' show patch;
                import 'dart:_js_types';
                -import 'dart:js_util';
                +import 'dart:js_util' as js_util;
                import 'dart:typed_data';

                +@patch
                +JSObject get globalJSObject => js_util.globalThis as JSObject;
                +
                /// Helper for working with the [JSAny?] top type in a backend agnostic way.
                /// TODO(joshualitt): Remove conflation of null and undefined after migration.
                extension NullableUndefineableJSAnyExtension on JSAny? {
                @patch
                - bool get isUndefined => this == null || typeofEquals(this, 'undefined');
                + bool get isUndefined =>
                + this == null || js_util.typeofEquals(this, 'undefined');

                @patch
                bool get isNull => this == null || JS('bool', '# === null', this);
                +
                + @patch
                + JSBoolean typeofEquals(JSString typeString) =>
                + JS('bool', 'typeof # === #', this, typeString);
                +
                + @patch
                + Object? dartify() => js_util.dartify(this);
                +}
                +
                +/// Utility extensions for [Object?].
                +extension NullableObjectUtilExtension on Object? {
                + @patch
                + JSAny? jsify() => js_util.jsify(this) as JSAny?;
                +}
                +
                +/// Utility extensions for [JSObject].
                +extension JSObjectUtilExtension on JSObject {
                + @patch
                + JSBoolean instanceof(JSFunction constructor) =>
                + JS('bool', '# instanceof #', this, constructor);
                }

                /// [JSExportedDartFunction] <-> [Function]
                @@ -27,7 +51,7 @@
                extension FunctionToJSExportedDartFunction on Function {
                @patch
                JSExportedDartFunction get toJS =>
                - allowInterop(this) as JSExportedDartFunction;
                + js_util.allowInterop(this) as JSExportedDartFunction;
                }

                /// [JSExportedDartObject] <-> [Object]
                @@ -44,7 +68,7 @@
                /// [JSPromise] -> [Future<JSAny?>].
                extension JSPromiseToFuture on JSPromise {
                @patch
                - Future<JSAny?> get toDart => promiseToFuture<JSAny?>(this);
                + Future<JSAny?> get toDart => js_util.promiseToFuture<JSAny?>(this);
                }

                /// [JSArrayBuffer] <-> [ByteBuffer]
                diff --git a/sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart b/sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
                new file mode 100644
                index 0000000..26f1535
                --- /dev/null
                +++ b/sdk/lib/_internal/js_shared/lib/js_interop_unsafe_patch.dart
                @@ -0,0 +1,71 @@
                +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
                +// for details. All rights reserved. Use of this source code is governed by a
                +// BSD-style license that can be found in the LICENSE file.
                +
                +import 'dart:_internal' show patch;
                +import 'dart:_foreign_helper' show JS;
                +import 'dart:js_interop' hide JS;
                +import 'dart:js_util' as js_util;
                +
                +extension JSObjectUtilExtension on JSObject {
                + @patch
                + JSBoolean hasProperty(JSAny property) =>
                + JS<bool>('bool', '# in #', property, this).toJS;
                +
                + @patch
                + JSAny? operator [](JSAny property) =>
                + JS<dynamic>('Object|Null', '#[#]', this, property);
                +
                + @patch
                + void operator []=(JSAny property, JSAny? value) =>
                + JS<void>('', '#[#] = #', this, property, value);
                +
                + // TODO(joshualitt): Specialize at callsites.
                + @patch
                + JSAny? _callMethod(JSAny method,
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) {
                + if (arg1 == null) {
                + return JS<dynamic>('Object|Null', '#[#]()', this, method);
                + } else if (arg2 == null) {
                + return JS<dynamic>('Object|Null', '#[#](#)', this, method, arg1);
                + } else if (arg3 == null) {
                + return JS<dynamic>('Object|Null', '#[#](#, #)', this, method, arg1, arg2);
                + } else if (arg4 == null) {
                + return JS<dynamic>(
                + 'Object|Null', '#[#](#, #, #)', this, method, arg1, arg2, arg3);
                + } else {
                + return JS<dynamic>('Object|Null', '#[#](#, #, #, #)', this, method, arg1,
                + arg2, arg3, arg4);
                + }
                + }
                +
                + @patch
                + JSAny? _callMethodVarArgs(JSAny method, [List<JSAny?>? arguments]) =>
                + JS<dynamic>(
                + 'Object|Null', '#[#].apply(#, #)', this, method, this, arguments);
                +
                + @patch
                + JSBoolean delete(JSAny property) =>
                + JS<bool>('bool', 'delete #[#]', this, property).toJS;
                +}
                +
                +extension JSFunctionUtilExtension on JSFunction {
                + // TODO(joshualitt): Specialize `callAsConstructor`.
                + @patch
                + JSObject _callAsConstructor(
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) =>
                + js_util.callConstructor<JSObject>(
                + this,
                + arg1 == null
                + ? null
                + : [
                + arg1,
                + if (arg2 != null) arg2,
                + if (arg3 != null) arg3,
                + if (arg4 != null) arg4,
                + ]);
                +
                + @patch
                + JSObject _callAsConstructorVarArgs([List<JSAny?>? arguments]) =>
                + js_util.callConstructor<JSObject>(this, arguments);
                +}
                diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
                index 9ec8ff0..0af6f11 100644
                --- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
                +++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
                @@ -134,6 +134,12 @@
                documented: false,
                platforms: DART2JS_PLATFORM,
                ),
                + 'js_interop_unsafe': const LibraryInfo(
                + 'js_interop_unsafe/js_interop_unsafe.dart',
                + categories: 'Client',
                + maturity: Maturity.EXPERIMENTAL,
                + platforms: DART2JS_PLATFORM,
                + ),
                'js_util': const LibraryInfo(
                'js_util/js_util.dart',
                categories: 'Client',
                diff --git a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart
                index 843bc6d..3675762 100644
                --- a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart
                +++ b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart
                @@ -6,8 +6,8 @@
                import 'dart:_js_helper';
                import 'dart:_wasm';
                import 'dart:async' show Completer;
                -import 'dart:js_interop';
                -import 'dart:js_util' show NullRejectionException;
                +import 'dart:js_interop' hide JS;
                +import 'dart:js_util' as js_util;
                import 'dart:typed_data';

                /// Some helpers for working with JS types internally. If we implement the JS
                @@ -15,6 +15,11 @@
                /// TODO(joshualitt): Find a way to get rid of the explicit casts.
                T _box<T>(WasmExternRef? ref) => JSValue(ref) as T;

                +// TODO(joshualitt): Eventually delete `dart:js_util` on Dart2Wasm and migrate
                +// any used logic to this file.
                +@patch
                +JSObject get globalJSObject => js_util.globalThis as JSObject;
                +
                /// Helper for working with the [JSAny?] top type in a backend agnostic way.
                extension NullableUndefineableJSAnyExtension on JSAny? {
                // TODO(joshualitt): To support incremental migration of existing users to
                @@ -25,6 +30,27 @@

                @patch
                bool get isNull => this == null || this!.toExternRef.isNull;
                +
                + @patch
                + JSBoolean typeofEquals(JSString type) => _box<JSBoolean>(JS<WasmExternRef?>(
                + '(o, t) => typeof o === t', this?.toExternRef, type.toExternRef));
                +
                + @patch
                + Object? dartify() => js_util.dartify(this);
                +}
                +
                +/// Utility extensions for [Object?].
                +extension NullableObjectUtilExtension on Object? {
                + @patch
                + JSAny? jsify() => js_util.jsify(this) as JSAny?;
                +}
                +
                +/// Utility extensions for [JSObject].
                +extension JSObjectUtilExtension on JSObject {
                + @patch
                + JSBoolean instanceof(JSFunction constructor) =>
                + _box<JSBoolean>(JS<WasmExternRef?>(
                + '(o, c) => o instanceof c', toExternRef, constructor.toExternRef));
                }

                /// [JSExportedDartFunction] <-> [Function]
                @@ -65,7 +91,7 @@
                // TODO(joshualitt): Use helpers to avoid conflating `null` and `JSNull` /
                // `JSUndefined`.
                if (e == null) {
                - return completer.completeError(NullRejectionException(false));
                + return completer.completeError(js_util.NullRejectionException(false));
                }
                return completer.completeError(e);
                }.toJS;
                diff --git a/sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart b/sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
                new file mode 100644
                index 0000000..d1da4e9
                --- /dev/null
                +++ b/sdk/lib/_internal/wasm/lib/js_interop_unsafe_patch.dart
                @@ -0,0 +1,77 @@
                +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
                +// for details. All rights reserved. Use of this source code is governed by a
                +// BSD-style license that can be found in the LICENSE file.
                +
                +library dart.js_interop_unsafe;
                +
                +import 'dart:_internal' show patch;
                +import "dart:_js_helper";
                +import 'dart:_wasm';
                +import 'dart:js_interop' hide JS;
                +
                +/// TODO(joshualitt): When `JSNull` and `JSUndefined` are boxed we can share
                +/// this with `js_interop_patch.dart`.
                +T _box<T>(WasmExternRef? ref) => JSValue.box(ref) as T;
                +
                +extension JSObjectUtilExtension on JSObject {
                + @patch
                + JSBoolean hasProperty(JSAny property) => _box<JSBoolean>(JS<WasmExternRef?>(
                + '(o, p) => p in o', toExternRef, property.toExternRef));
                +
                + @patch
                + JSAny? operator [](JSAny property) => _box<JSAny?>(
                + JS<WasmExternRef?>('(o, p) => o[p]', toExternRef, property.toExternRef));
                +
                + @patch
                + void operator []=(JSAny property, JSAny? value) => JS<void>(
                + '(o, p, v) => o[p] = v',
                + toExternRef,
                + property.toExternRef,
                + value?.toExternRef);
                +
                + // TODO(joshualitt): Consider specializing variadic functions.
                + @patch
                + JSAny? _callMethod(JSAny method,
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) =>
                + _box<JSAny?>(callMethodVarArgsRaw(
                + toExternRef,
                + method.toExternRef,
                + arg1 == null
                + ? null
                + : [
                + arg1,
                + if (arg2 != null) arg2,
                + if (arg3 != null) arg3,
                + if (arg4 != null) arg4,
                + ].toExternRef));
                +
                + @patch
                + JSAny? _callMethodVarArgs(JSAny method, [List<JSAny?>? arguments]) =>
                + _box<JSAny?>(callMethodVarArgsRaw(
                + toExternRef, method.toExternRef, arguments?.toExternRef));
                +
                + @patch
                + JSBoolean delete(JSAny property) => _box<JSBoolean>(JS<WasmExternRef?>(
                + '(o, p) => delete o[p]', toExternRef, property.toExternRef));
                +}
                +
                +extension JSFunctionUtilExtension on JSFunction {
                + @patch
                + JSObject _callAsConstructor(
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) =>
                + _box<JSObject>(callConstructorVarArgsRaw(
                + toExternRef,
                + arg1 == null
                + ? null
                + : [
                + arg1,
                + if (arg2 != null) arg2,
                + if (arg3 != null) arg3,
                + if (arg4 != null) arg4,
                + ].toExternRef));
                +
                + @patch
                + JSObject _callAsConstructorVarArgs([List<JSAny?>? arguments]) =>
                + _box<JSObject>(
                + callConstructorVarArgsRaw(toExternRef, arguments?.toExternRef));
                +}
                diff --git a/sdk/lib/js_interop/js_interop.dart b/sdk/lib/js_interop/js_interop.dart
                index d728b5c..990ebb7 100644
                --- a/sdk/lib/js_interop/js_interop.dart
                +++ b/sdk/lib/js_interop/js_interop.dart
                @@ -71,6 +71,7 @@
                // sealed classes feature.
                // TODO(joshualitt): Do we need to seal any other JS types on JS backends? We
                // probably want to seal all JS types on Wasm backends.
                +// TODO(joshualitt): Add a [JSObject] constructor.
                typedef JSObject = js_types.JSObject;

                /// The type of all JS functions, [JSFunction] <: [JSObject].
                @@ -126,6 +127,9 @@
                /// The type of JS strings, [JSString] <: [JSAny].
                typedef JSString = js_types.JSString;

                +/// A getter to retrieve the Global [JSObject].
                +external JSObject get globalJSObject;
                +
                /// `JSUndefined` and `JSNull` are actual reified types on some backends, but
                /// not others. Instead, users should use nullable types for any type that could
                /// contain `JSUndefined` or `JSNull`. However, instead of trying to determine
                @@ -140,6 +144,24 @@
                external bool get isNull;
                bool get isUndefinedOrNull => isUndefined || isNull;
                bool get isDefinedAndNotNull => !isUndefinedOrNull;
                + external JSBoolean typeofEquals(JSString typeString);
                +
                + /// Effectively the inverse of [jsify], [dartify] Takes a JavaScript object,
                + /// and converts it to a Dart based object. Only JS primitives, arrays, or
                + /// 'map' like JS objects are supported.
                + external Object? dartify();
                +}
                +
                +/// Utility extensions for [Object?].
                +extension NullableObjectUtilExtension on Object? {
                + /// Recursively converts a JSON-like collection, or Dart primitive to a
                + /// JavaScript compatible representation.
                + external JSAny? jsify();
                +}
                +
                +/// Utility extensions for [JSObject].
                +extension JSObjectUtilExtension on JSObject {
                + external JSBoolean instanceof(JSFunction constructor);
                }

                /// The type of `JSUndefined` when returned from functions. Unlike pure JS,
                diff --git a/sdk/lib/js_interop_unsafe/js_interop_unsafe.dart b/sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
                new file mode 100644
                index 0000000..9938311
                --- /dev/null
                +++ b/sdk/lib/js_interop_unsafe/js_interop_unsafe.dart
                @@ -0,0 +1,63 @@
                +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
                +// for details. All rights reserved. Use of this source code is governed by a
                +// BSD-style license that can be found in the LICENSE file.
                +
                +/// Typed utility methods to manipulate JS objects in cases where the name to
                +/// call is not known at runtime.
                +///
                +/// Safe usage of these methods cannot necessarily be verified statically.
                +/// Therefore, they should be used cautiously and only when the same effect
                +/// cannot be achieved with static interop.
                +///
                +/// {@category Web}
                +library dart.js_util_typed;
                +
                +import 'dart:js_interop';
                +
                +extension JSObjectUtilExtension on JSObject {
                + /// Whether or not this [JSObject] has a given property.
                + external JSBoolean hasProperty(JSAny property);
                +
                + /// Equivalent to invoking operator `[]` in JS.
                + external JSAny? operator [](JSAny property);
                +
                + /// Gets a given property from this [JSObject].
                + T getProperty<T extends JSAny?>(JSAny property) => this[property] as T;
                +
                + /// Equivalent to invoking `[]=` in JS.
                + external void operator []=(JSAny property, JSAny? value);
                +
                + /// Calls a method on this [JSObject] with up to four arguments and returns
                + /// the result.
                + external JSAny? _callMethod(JSAny method,
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]);
                + T callMethod<T extends JSAny?>(JSAny method,
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) =>
                + _callMethod(method, arg1, arg2, arg3, arg4) as T;
                +
                + /// Calls a method on this [JSObject] with a variable number of arguments and
                + /// returns the result.
                + external JSAny? _callMethodVarArgs(JSAny method, [List<JSAny?>? arguments]);
                + T callMethodVarArgs<T extends JSAny?>(JSAny method,
                + [List<JSAny?>? arguments]) =>
                + _callMethodVarArgs(method, arguments) as T;
                +
                + /// Deletes the given property from this [JSObject].
                + external JSBoolean delete(JSAny property);
                +}
                +
                +extension JSFunctionUtilExtension on JSFunction {
                + /// Calls this [JSFunction] as a constructor with up to four arguments and
                + /// returns the constructed [JSObject].
                + external JSObject _callAsConstructor(
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]);
                + T callAsConstructor<T>(
                + [JSAny? arg1, JSAny? arg2, JSAny? arg3, JSAny? arg4]) =>
                + _callAsConstructor(arg1, arg2, arg3, arg4) as T;
                +
                + /// Calls this [JSFunction] as a constructor with a variable number of
                + /// arguments and returns the constructed [JSObject].
                + external JSObject _callAsConstructorVarArgs([List<JSAny?>? arguments]);
                + T callAsConstructorVarArgs<T extends JSObject>([List<JSAny?>? arguments]) =>
                + _callAsConstructorVarArgs(arguments) as T;
                +}
                diff --git a/sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni b/sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni
                new file mode 100644
                index 0000000..515fc56
                --- /dev/null
                +++ b/sdk/lib/js_interop_unsafe/js_interop_unsafe_sources.gni
                @@ -0,0 +1,5 @@
                +# Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
                +# for details. All rights reserved. Use of this source code is governed by a
                +# BSD-style license that can be found in the LICENSE file.
                +
                +js_interop_unsafe_sdk_sources = [ "js_interop_unsafe.dart" ]
                diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
                index 004df82..02f2e98 100644
                --- a/sdk/lib/libraries.json
                +++ b/sdk/lib/libraries.json
                @@ -219,6 +219,10 @@
                "uri": "js_interop/js_interop.dart",
                "patches": "_internal/wasm/lib/js_interop_patch.dart"
                },
                + "js_interop_unsafe": {
                + "uri": "js_interop_unsafe/js_interop_unsafe.dart",
                + "patches": "_internal/wasm/lib/js_interop_unsafe_patch.dart"
                + },
                "js_util": {
                "uri": "js_util/js_util.dart",
                "patches": "_internal/wasm/lib/js_util_patch.dart"
                @@ -327,6 +331,10 @@
                "uri": "js_interop/js_interop.dart",
                "patches": "_internal/js_shared/lib/js_interop_patch.dart"
                },
                + "js_interop_unsafe": {
                + "uri": "js_interop_unsafe/js_interop_unsafe.dart",
                + "patches": "_internal/js_shared/lib/js_interop_unsafe_patch.dart"
                + },
                "_js_annotations": {
                "uri": "js/_js_annotations.dart"
                },
                @@ -508,6 +516,10 @@
                "uri": "js_interop/js_interop.dart",
                "patches": "_internal/js_shared/lib/js_interop_patch.dart"
                },
                + "js_interop_unsafe": {
                + "uri": "js_interop_unsafe/js_interop_unsafe.dart",
                + "patches": "_internal/js_shared/lib/js_interop_unsafe_patch.dart"
                + },
                "js_util": {
                "uri": "js_util/js_util.dart",
                "patches": [
                diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
                index fa72e0a..7a805ec 100644
                --- a/sdk/lib/libraries.yaml
                +++ b/sdk/lib/libraries.yaml
                @@ -187,6 +187,9 @@
                js_interop:
                uri: js_interop/js_interop.dart
                patches: _internal/wasm/lib/js_interop_patch.dart
                + js_interop_unsafe:
                + uri: js_interop_unsafe/js_interop_unsafe.dart
                + patches: _internal/wasm/lib/js_interop_unsafe_patch.dart
                js_util:
                uri: js_util/js_util.dart
                patches: _internal/wasm/lib/js_util_patch.dart
                @@ -280,6 +283,10 @@
                uri: "js_interop/js_interop.dart"
                patches: "_internal/js_shared/lib/js_interop_patch.dart"

                + js_interop_unsafe:
                + uri: "js_interop_unsafe/js_interop_unsafe.dart"
                + patches: "_internal/js_shared/lib/js_interop_unsafe_patch.dart"
                +
                _js_annotations:
                uri: "js/_js_annotations.dart"

                @@ -458,6 +465,10 @@
                uri: "js_interop/js_interop.dart"
                patches: "_internal/js_shared/lib/js_interop_patch.dart"

                + js_interop_unsafe:
                + uri: "js_interop_unsafe/js_interop_unsafe.dart"
                + patches: "_internal/js_shared/lib/js_interop_unsafe_patch.dart"
                +
                js_util:
                uri: "js_util/js_util.dart"
                patches:
                diff --git a/tests/lib/js_interop_unsafe/basic_test.dart b/tests/lib/js_interop_unsafe/basic_test.dart
                new file mode 100644
                index 0000000..9f682bc
                --- /dev/null
                +++ b/tests/lib/js_interop_unsafe/basic_test.dart
                @@ -0,0 +1,409 @@
                +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
                +// for details. All rights reserved. Use of this source code is governed by a
                +// BSD-style license that can be found in the LICENSE file.
                +
                +import 'dart:js_interop';
                +import 'dart:js_interop_unsafe';
                +// TODO(joshualitt): Once we reify JS types on JS backends, we can add a
                +// constructor to [JSObject].
                +import 'dart:js_util' show newObject;
                +import 'dart:typed_data';
                +
                +import 'package:expect/expect.dart';
                +import 'package:js/js.dart';
                +
                +@JS()
                +external void eval(String code);
                +
                +void createObjectTest() {
                + JSObject o = newObject<JSObject>();
                + Expect.isFalse(o.hasProperty('foo'.toJS).toDart);
                + o['foo'.toJS] = 'bar'.toJS;
                + Expect.isTrue(o.hasProperty('foo'.toJS).toDart);
                + Expect.equals('bar', (o['foo'.toJS] as JSString).toDart);
                +}
                +
                +void equalTest() {
                + // Different objects aren't equal.
                + {
                + JSObject o1 = newObject<JSObject>();
                + JSObject o2 = newObject<JSObject>();
                + Expect.notEquals(o1, o2);
                + }
                +
                + {
                + eval(r'''
                + function JSClass() {}
                +
                + globalThis.boolData = true;
                + globalThis.boolData2 = true;
                + globalThis.numData = 4;
                + globalThis.numData2 = 4;
                + globalThis.arrData = [1, 2, 3];
                + globalThis.strData = 'foo';
                + globalThis.strData2 = 'foo';
                + globalThis.funcData = function JSClass() {}
                + globalThis.JSClass = new globalThis.funcData();
                + ''');
                + JSObject gt = globalJSObject;
                + void test(String propertyName, bool testCanonicalization) {
                + Expect.equals(gt[propertyName.toJS], gt[propertyName.toJS]);
                + if (testCanonicalization) {
                + Expect.equals(gt[propertyName.toJS], gt[(propertyName + "2").toJS]);
                + }
                + }
                +
                + test("boolData", true);
                + test("numData", true);
                + test("arrData", false);
                + test("strData", true);
                + test("funcData", false);
                + test("JSClass", false);
                + }
                +}
                +
                +void typeofTest() {
                + eval(r'''
                + globalThis.b = true;
                + globalThis.n = 4;
                + globalThis.str = 'foo';
                + globalThis.f = function foo() {}
                + globalThis.o = {};
                + globalThis.u = undefined
                + globalThis.sym = Symbol('sym');
                + ''');
                +
                + final types = {
                + 'boolean',
                + 'number',
                + 'string',
                + 'function',
                + 'object',
                + 'undefined',
                + 'symbol'
                + };
                + void test(String property, String expectedType) {
                + Expect.isTrue(
                + globalJSObject[property.toJS]?.typeofEquals(expectedType.toJS).toDart);
                + for (final type in types) {
                + if (type != expectedType) {
                + Expect.isFalse(
                + globalJSObject[property.toJS]?.typeofEquals(type.toJS).toDart);
                + }
                + }
                + }
                +
                + test('b', 'boolean');
                + test('n', 'number');
                + test('str', 'string');
                + test('f', 'function');
                + test('o', 'object');
                + // TODO(joshualitt): Test for `undefined` when we it can flow into `JSAny?`.
                + // test('u', 'undefined');
                + test('sym', 'symbol');
                +}
                +
                +void instanceOfTest() {
                + eval(r'''
                + globalThis.JSClass1 = function() {}
                + globalThis.JSClass2 = function() {}
                +
                + globalThis.obj = new JSClass1();
                + ''');
                + JSObject gt = globalJSObject;
                + JSObject obj = gt['obj'.toJS] as JSObject;
                + JSFunction jsClass1Constructor = gt['JSClass1'.toJS] as JSFunction;
                + JSFunction jsClass2Constructor = gt['JSClass2'.toJS] as JSFunction;
                + Expect.isTrue(obj.instanceof(jsClass1Constructor).toDart);
                + Expect.isFalse(obj.instanceof(jsClass2Constructor).toDart);
                +}
                +
                +void _expectIterableEquals(Iterable<Object?> l, Iterable<Object?> r) {
                + final lIt = l.iterator;
                + final rIt = r.iterator;
                + while (lIt.moveNext()) {
                + Expect.isTrue(rIt.moveNext());
                + _expectRecEquals(lIt.current, rIt.current);
                + }
                + Expect.isFalse(rIt.moveNext());
                +}
                +
                +void _expectRecEquals(Object? l, Object? r) {
                + if (l is Iterable && r is Iterable) {
                + _expectIterableEquals(l, r);
                + } else if (l is Map && r is Map) {
                + _expectIterableEquals(l.keys, r.keys);
                + for (final key in l.keys) {
                + _expectRecEquals(l[key], r[key]);
                + }
                + } else {
                + Expect.equals(l, r);
                + }
                +}
                +
                +void evalAndConstructTest() {
                + eval(r'''
                + function JSClass(c) {
                + this.c = c;
                + this.sum = (a, b) => {
                + console.log(a + ' ' + b);
                + return a + b + this.c;
                + }
                + }
                + globalThis.JSClass = JSClass;
                + ''');
                + JSObject gt = globalJSObject;
                + JSFunction constructor = gt['JSClass'.toJS] as JSFunction;
                +
                + // Var args
                + JSObject jsObj1 =
                + constructor.callAsConstructorVarArgs<JSObject>(<JSAny?>['world!'.toJS]);
                + Expect.equals(
                + 'hello world!',
                + jsObj1.callMethodVarArgs<JSString>(
                + 'sum'.toJS, <JSAny?>['hello'.toJS, ' '.toJS]).toDart);
                +
                + // Fixed args
                + JSObject jsObj2 = constructor.callAsConstructor<JSObject>('world!'.toJS);
                + Expect.equals('hello world!',
                + jsObj2.callMethod<JSString>('sum'.toJS, 'hello'.toJS, ' '.toJS).toDart);
                +}
                +
                +void deepConversionsTest() {
                + // Dart to JS.
                + Expect.isNull(null.jsify().dartify());
                + Expect.equals(true, true.jsify().dartify());
                + Expect.equals(2.0, 2.0.jsify().dartify());
                + Expect.equals('foo', 'foo'.jsify().dartify());
                + _expectRecEquals(
                + ['a', 'b', 'c'], ['a', 'b', 'c'].jsify().dartify() as List<Object?>);
                + _expectRecEquals(
                + {
                + 'null': 'foo',
                + 'foo': null,
                + 'a': 1,
                + 'b': true,
                + 'c': [1, 2, 3, null],
                + 'd': 'foo',
                + 'e': {
                + 'f': 2,
                + 'g': [2, 4, 6]
                + },
                + },
                + {
                + 'null': 'foo',
                + 'foo': null,
                + 'a': 1,
                + 'b': true,
                + 'c': [1, 2, 3, null],
                + 'd': 'foo',
                + 'e': {
                + 'f': 2,
                + 'g': [2, 4, 6]
                + },
                + }.jsify().dartify());
                + List<Object?> l = Int8List.fromList(<int>[-128, 0, 127]);
                + _expectIterableEquals(l, l.jsify().dartify() as Int8List);
                + l = Uint8List.fromList([-1, 0, 255, 256]);
                + _expectIterableEquals(l, l.jsify().dartify() as Uint8List);
                + l = Uint8ClampedList.fromList([-1, 0, 255, 256]);
                + _expectIterableEquals(l, l.jsify().dartify() as Uint8ClampedList);
                + l = Int16List.fromList([-32769, -32768, 0, 32767, 32768]);
                + _expectIterableEquals(l, l.jsify().dartify() as Int16List);
                + l = Uint16List.fromList([-1, 0, 65535, 65536]);
                + _expectIterableEquals(l, l.jsify().dartify() as Uint16List);
                + l = Int32List.fromList([-2147483648, 0, 2147483647]);
                + _expectIterableEquals(l, l.jsify().dartify() as Int32List);
                + l = Uint32List.fromList([-1, 0, 4294967295, 4294967296]);
                + _expectIterableEquals(l, l.jsify().dartify() as Uint32List);
                + l = Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
                + _expectIterableEquals(l, l.jsify().dartify() as Float32List);
                + l = Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]);
                + _expectIterableEquals(l, l.jsify().dartify() as Float64List);
                + ByteBuffer buffer = Uint8List.fromList([0, 1, 2, 3]).buffer;
                + _expectIterableEquals(buffer.asUint8List(),
                + (buffer.jsify().dartify() as ByteBuffer).asUint8List());
                + ByteData byteData = ByteData.view(buffer);
                + _expectIterableEquals(byteData.buffer.asUint8List(),
                + (byteData.jsify().dartify() as ByteData).buffer.asUint8List());
                +
                + // JS to Dart.
                + eval(r'''
                + globalThis.a = null;
                + globalThis.b = 'foo';
                + globalThis.c = ['a', 'b', 'c'];
                + globalThis.d = 2.5;
                + globalThis.e = true;
                + globalThis.f = function () { return 'hello world'; };
                + globalThis.g = {
                + null: 'foo',
                + 'foo': null,
                + 'a': 1,
                + 'b': true,
                + 'c': [1, 2, 3, null],
                + 'd': 'foo',
                + 'e': {'f': 2, 'g': [2, 4, 6]},
                + };
                + globalThis.invoke = function (f) { return f(); }
                + globalThis.rec = {};
                + globalThis.rec = {'a': rec};
                + globalThis.int8Array = new Int8Array([-128, 0, 127]);
                + globalThis.uint8Array = new Uint8Array([-1, 0, 255, 256]);
                + globalThis.uint8ClampedArray = new Uint8ClampedArray([-1, 0, 255, 256]);
                + globalThis.int16Array = new Int16Array([-32769, -32768, 0, 32767, 32768]);
                + globalThis.uint16Array = new Uint16Array([-1, 0, 65535, 65536]);
                + globalThis.int32Array = new Int32Array([-2147483648, 0, 2147483647]);
                + globalThis.uint32Array = new Uint32Array([-1, 0, 4294967295, 4294967296]);
                + globalThis.float32Array = new Float32Array([-1000.488, -0.00001, 0.0001,
                + 10004.888]);
                + globalThis.float64Array = new Float64Array([-1000.488, -0.00001, 0.0001,
                + 10004.888]);
                + globalThis.arrayBuffer = globalThis.uint8Array.buffer;
                + globalThis.dataView = new DataView(globalThis.arrayBuffer);
                + globalThis.implicitExplicit = [
                + {'foo': 'bar'},
                + [1, 2, 3, {'baz': 'boo'}],
                + ];
                + let keyObject = function () {};
                + globalThis.keyObject1 = keyObject;
                + globalThis.keyObject2 = keyObject;
                + ''');
                + JSObject gt = globalJSObject;
                + Expect.isNull(gt['a'.toJS]);
                + Expect.equals('foo', gt.getProperty<JSString>('b'.toJS).toDart);
                + _expectRecEquals(
                + ['a', 'b', 'c'],
                + gt
                + .getProperty<JSArray>('c'.toJS)
                + .toDart
                + .map((JSAny? o) => (o as JSString).toDart));
                + Expect.equals(2.5, gt.getProperty<JSNumber>('d'.toJS).toDart);
                + Expect.equals(true, gt.getProperty<JSBoolean>('e'.toJS).toDart);
                + _expectRecEquals({
                + 'null': 'foo',
                + 'foo': null,
                + 'a': 1,
                + 'b': true,
                + 'c': [1, 2, 3, null],
                + 'd': 'foo',
                + 'e': {
                + 'f': 2,
                + 'g': [2, 4, 6]
                + },
                + }, gt.getProperty('g'.toJS).dartify());
                + _expectRecEquals({
                + 'a': {},
                + }, gt.getProperty('rec'.toJS).dartify());
                +
                + _expectIterableEquals(Int8List.fromList(<int>[-128, 0, 127]),
                + gt.getProperty<JSInt8Array>('int8Array'.toJS).toDart);
                + _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
                + gt.getProperty<JSUint8Array>('uint8Array'.toJS).toDart);
                + _expectIterableEquals(Uint8ClampedList.fromList([-1, 0, 255, 256]),
                + gt.getProperty<JSUint8ClampedArray>('uint8ClampedArray'.toJS).toDart);
                + _expectIterableEquals(Int16List.fromList([-32769, -32768, 0, 32767, 32768]),
                + gt.getProperty<JSInt16Array>('int16Array'.toJS).toDart);
                + _expectIterableEquals(Uint16List.fromList([-1, 0, 65535, 65536]),
                + gt.getProperty<JSUint16Array>('uint16Array'.toJS).toDart);
                + _expectIterableEquals(Int32List.fromList([-2147483648, 0, 2147483647]),
                + gt.getProperty<JSInt32Array>('int32Array'.toJS).toDart);
                + _expectIterableEquals(Uint32List.fromList([-1, 0, 4294967295, 4294967296]),
                + gt.getProperty<JSUint32Array>('uint32Array'.toJS).toDart);
                + _expectIterableEquals(
                + Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
                + gt.getProperty<JSFloat32Array>('float32Array'.toJS).toDart);
                + _expectIterableEquals(
                + Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]),
                + gt.getProperty<JSFloat64Array>('float64Array'.toJS).toDart);
                + _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
                + gt.getProperty<JSArrayBuffer>('arrayBuffer'.toJS).toDart.asUint8List());
                + _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]),
                + gt.getProperty<JSDataView>('dataView'.toJS).toDart.buffer.asUint8List());
                +
                + // Confirm a function that takes a roundtrip remains a function.
                + JSFunction foo = gt['f'.toJS].dartify() as JSFunction;
                + Expect.equals(
                + 'hello world', gt.callMethod<JSString>('invoke'.toJS, foo).toDart);
                +
                + // Confirm arrays, which need to be converted implicitly, are still
                + // recursively converted by dartify() when desired.
                + _expectIterableEquals([
                + {'foo': 'bar'},
                + [
                + 1,
                + 2,
                + 3,
                + {'baz': 'boo'}
                + ],
                + ], gt['implicitExplicit'.toJS].dartify() as Iterable);
                +
                + // Test that JS objects behave as expected in Map / Set.
                + Set<Object?> set = {};
                + JSAny? key1 = gt['keyObject1'.toJS];
                + JSAny? key2 = gt['keyObject2'.toJS];
                + Expect.isTrue(set.add(key1));
                + Expect.isTrue(set.contains(key1));
                + Expect.isFalse(set.add(key2));
                + Expect.isTrue(set.contains(key2));
                + Expect.equals(1, set.length);
                +
                + Map<Object?, Object?> map = {};
                + map[key1] = 'foo';
                + map[key2] = 'bar';
                + Expect.equals(1, map.length);
                + Expect.equals('bar', map[key1]);
                +}
                +
                +@JS('Symbol')
                +@staticInterop
                +class _JSSymbol {
                + @JS('for')
                + external static JSAny _for(JSString s);
                + external static JSString keyFor(JSAny s);
                +}
                +
                +@JS()
                +external JSAny get symbol;
                +
                +@JS()
                +external JSAny get symbol2;
                +
                +@JS()
                +external JSString methodWithSymbol(JSAny s);
                +
                +void symbolTest() {
                + eval(r'''
                + var s1 = Symbol.for('symbol');
                + globalThis.symbol = s1;
                + globalThis[s1] = 'boo';
                + globalThis.methodWithSymbol = function(s) {
                + return Symbol.keyFor(s);
                + }
                + var symbol2 = Symbol.for('symbolMethod');
                + globalThis[symbol2] = function() {
                + return 'hello world';
                + }
                + globalThis.symbol2 = symbol2;
                + ''');
                + JSObject gt = globalJSObject;
                + Expect.equals(
                + _JSSymbol.keyFor(_JSSymbol._for('symbol'.toJS)).toDart, 'symbol');
                + Expect.equals(
                + gt.getProperty<JSString>(gt.getProperty<JSAny>('symbol'.toJS)).toDart,
                + 'boo');
                + Expect.equals(methodWithSymbol(symbol).toDart, 'symbol');
                + Expect.equals(_JSSymbol.keyFor(symbol).toDart, 'symbol');
                + Expect.equals(
                + _JSSymbol.keyFor(gt.getProperty<JSAny>('symbol'.toJS)).toDart, 'symbol');
                + Expect.equals(gt.callMethod<JSString>(symbol2).toDart, 'hello world');
                +}
                +
                +void main() {
                + createObjectTest();
                + equalTest();
                + typeofTest();
                + instanceOfTest();
                + evalAndConstructTest();
                + deepConversionsTest();
                + symbolTest();
                +}
                diff --git a/tests/lib/lib.status b/tests/lib/lib.status
                index 7f0c0db..1447d0b 100644
                --- a/tests/lib/lib.status
                +++ b/tests/lib/lib.status
                @@ -86,6 +86,9 @@
                [ $simulator ]
                convert/utf85_test: Skip # Pass, Slow Issue 20111.

                +[ $compiler != dart2js && $compiler != dart2wasm && $compiler != ddc ]
                +js_interop_unsafe/*: SkipByDesign # Only supported on web backends.
                +
                [ $compiler != dart2js && $compiler != ddc ]
                web/*: SkipByDesign


                To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

                Gerrit-MessageType: merged
                Gerrit-Project: sdk
                Gerrit-Branch: main
                Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
                Gerrit-Change-Number: 293743
                Gerrit-PatchSet: 18
                Gerrit-Owner: Joshua Litt <joshu...@google.com>

                CBuild (Gerrit)

                unread,
                Apr 27, 2023, 3:30:08 PM4/27/23
                to Joshua Litt, Commit Queue, dart-dc-te...@google.com, dart2js-te...@google.com, dart2wasm-t...@google.com, rev...@dartlang.org, Srujan Gaddam, Sigmund Cherem

                go/dart-cbuild result: SUCCESS

                Details: https://goto.google.com/dart-cbuild/find/47b7c1f31dcae564aac399a5aace158724d10213

                View Change

                  To view, visit change 293743. To unsubscribe, or for help writing mail filters, visit settings.

                  Gerrit-MessageType: comment
                  Gerrit-Project: sdk
                  Gerrit-Branch: main
                  Gerrit-Change-Id: I4d6007e0731ecae81fcc614168baee7d5e662fd8
                  Gerrit-Change-Number: 293743
                  Gerrit-PatchSet: 18
                  Gerrit-Owner: Joshua Litt <joshu...@google.com>
                  Gerrit-Reviewer: Joshua Litt <joshu...@google.com>
                  Gerrit-Reviewer: Sigmund Cherem <sig...@google.com>
                  Gerrit-Reviewer: Srujan Gaddam <sru...@google.com>
                  Gerrit-Comment-Date: Thu, 27 Apr 2023 19:30:04 +0000
                  Gerrit-HasComments: No
                  Gerrit-Has-Labels: No
                  Reply all
                  Reply to author
                  Forward
                  0 new messages