Compare commits

...
224 Commits
Author SHA1 Message Date
Moonchild ce61835a81 revert 8a2a9ead92
revert [gtk] Default the file dialog operation to cancelling the operation.

While this could be an annoying default for users expecting fast-track
dialog operations with hitting enter, it avoids potential social
engineering attacks and unintended file operations.
2026-06-30 13:53:18 +00:00
Moonchild 8a2a9ead92 [gtk] Default the file dialog operation to cancelling the operation.
While this could be an annoying default for users expecting fast-track
dialog operations with hitting enter, it avoids potential social
engineering attacks and unintended file operations.
2026-06-28 12:09:07 +02:00
Moonchild efdbd34b0b Revert "Bug 2033848 - Use non-default response ID for GTK file picker accept button. r=stransky"
This reverts commit 789e976ace.
2026-06-28 12:08:59 +02:00
Moonchild d2fa69f593 Merge pull request 'Import missing libpng files for loongarch and plug them into moz.build' (#3135) from Basilisk-Dev/UXP-contrib:png-loongarch-fix into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3135
2026-06-27 07:25:51 +00:00
Basilisk-Dev 18d0a1a525 Issue #3134 - Import missing libpng files for loongarch and plug them into moz.build 2026-06-26 14:48:51 -04:00
Moonchild 9d9802c660 Issue #3129 - Follow-up: Add aarch64 to platforms enabling Neon in libpng. 2026-06-26 16:58:21 +02:00
Moonchild 27c579652a Issue #3122 - Stop using <base> element in json viewer.
Resolves #3122
2026-06-23 21:09:02 +02:00
Moonchild 8ffa6b3c13 Issue #3129 - Add palette_neon_intrinsics.c to moz.build 2026-06-23 10:23:17 +02:00
Moonchild 83f6efc33d Issue #3122 - Put base paths in the json viewer client deps.
The dependency modules are requested early. Seems CSP can block baseURL
on these networking requests, so add the base manually to the resource
paths to prevent network requests before the html base element is
resolved and active.
2026-06-22 17:58:21 +02:00
Moonchild 47f1928610 Merge pull request 'Libpng update 1.6.58' (#3125) from libpng-update-1.6.58 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3125
2026-06-21 12:14:42 +00:00
Moonchild 7b3d961465 Bump NSS version for adopted changes. 2026-06-19 14:19:43 +02:00
Moonchild 22b2e18d91 [DOM] Clean up WebGL transform feedback validation. 2026-06-19 13:30:35 +02:00
John Schanck f6c9c0c59f Bug 2030564 - add defensive input validation to sftk_compute_ANSI_X9_63_kdf. 2026-06-19 12:56:26 +02:00
John Schanck d8c9d24a9c Bug 2030366 - avoid race with module unloading in NSSTrustDomain_FindTokensByURI. 2026-06-19 12:04:23 +02:00
John Schanck a466b73267 Bug 2029403 - avoid PORT_Strdup in ssl_DecodeResumptionToken. 2026-06-19 10:51:37 +02:00
Julian Descottes 1ce14fb014 [devtools] Consistently show filepicker on first save action from StyleEditor.
Bug 2038133
2026-06-19 10:45:33 +02:00
Moonchild 8bbf60fb38 Issue #3127 - Add trademark notice to the tree.
Resolves #3127
2026-06-19 08:37:27 +02:00
Moonchild f2d7c02290 Apply (hopefully for the last time before 2.0.x) APNG support code.
This commit also removes MOZCHANGES (old and irrelevant information)
This commit also adds a new readme.
2026-06-18 22:57:29 +02:00
Moonchild 65ddfc21b6 Fresh import of libpng 1.6.58 2026-06-18 21:50:35 +02:00
Moonchild 163619de60 [network] Make HttpBaseChannel::mLoadFlags atomic. 2026-06-18 20:32:03 +02:00
Moonchild 29c4d554a0 [gfx] Check more offsets during CFF subsetting.
Also fixes a bunch of whitespace (TAB -> spaces)
2026-06-18 19:35:49 +02:00
Moonchild 3e59569d0b [DOM] Avoid over-optimizing some getter/function calls. 2026-06-18 13:45:20 +02:00
Moonchild fb8483407b [parser] Better align with spec definition of adding nodes. 2026-06-18 13:32:16 +02:00
Moonchild ec8b7f86d0 No issue - Use ImmGCPtr for module meta data visits.
This should make module GCs less touchy.
2026-06-17 23:46:18 +02:00
Moonchild 9899d59010 [DOM media] Zero-initialize ThreadSharedFloatArrayBufferList. 2026-06-17 18:13:15 +02:00
Kui-Feng Lee 789e976ace Bug 2033848 - Use non-default response ID for GTK file picker accept button. r=stransky
Replace GTK_RESPONSE_ACCEPT (-3) with a non-negative application-defined
response ID (kFilePickerAccept = 0) for the accept button in the GTK file
chooser dialog, and remove the gtk_dialog_set_default_response() call.

GTK treats buttons with negative built-in response IDs as candidates for
the dialog's default widget, which activates on Enter key press. By using
a non-negative ID and not calling set_default_response(), the accept button
is no longer pre-selected, preventing a page from tricking the user into
confirming a file upload by holding Enter before the dialog appears.

GTK's file chooser internally emits GTK_RESPONSE_ACCEPT via file_activated_cb
when the user double-clicks a file, so we keep that case in DoneNonPortal()
alongside kFilePickerAccept.
2026-06-17 12:47:03 +02:00
John Schanck d5bf2555a3 Bug 2023478 - improve handling of escape sequences in pk11uri_ParseAttributes. 2026-06-17 12:17:06 +02:00
Moonchild be672813f6 [DOM] Reject too large mLength in MutableBlobStorage::WriteRunnable. 2026-06-16 20:06:25 +02:00
John Schanck 746a7be08c Bug 2030570 - use correct data for ID comparison in transfer_uri_certs_to_collection. 2026-06-16 19:54:44 +02:00
Moonchild c222ee80fa [network] Make keep-alive pref Atomic. 2026-06-16 19:50:55 +02:00
John Schanck 4950bd038d Bug 2029765 - avoid refcount over-release in nssTokenObjectCache error path [@ nssToken_Destroy]. 2026-06-16 18:52:25 +02:00
Nicolas B. Pierron 058336a071 Bug 2029066 - Remove Sinking of Live instructions.
Instruction sinking was made possible by the introduction of recover
instructions, which are moving instructions to be executed on bailout, but this
is only possible for instructions which are not used.

This feature, which is now removed, was made to sink instructions which are
live, but only in a small set of branches, by moving the computation of these
instructions to bailout paths, and to the concerned if branches.

The current implementation never delivered and remained as dead-code for
multiple years, without having a firm benefit on performance oriented
benchmarks.

Thus, this change removes the part of the Sink optimization which deals with
live instructions but keeps the part of the Sink optimization which deals with
instructions which are only used on bailout paths.
2026-06-16 13:37:21 +02:00
John Schanck 6823388a85 Bug 2029803 - add defensive info->len check in PK11_HPKE_SetupS and PK11_HPKE_SetupR. 2026-06-16 09:27:28 +02:00
Moonchild b68d097eb6 Issue #3122 - Exclude local resources from <base> CSP checks.
This avoids local-resource <base> URLs being restricted/nullified by
remote CSP. This aligns the CSP handling with direct requests.

Resolves #3122
2026-06-14 10:08:17 +02:00
Moonchild c97a22776d Merge pull request 'Re-introduce pref for WeakRef API spec.' (#3117) from weakref-finreg-pref into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3117
2026-06-12 15:46:16 +00:00
Moonchild c484dbcca5 Issue #888 - Follow-up: Update about:license with AV1 codec licensing.
LibAOM was actually omitted before (oops); added both.
2026-06-11 20:07:10 +02:00
Moonchild 54f15d7afe Issue #3111 - Clean up logic in SweepFinalizationRegistries.
Resolves #3111
2026-06-09 18:06:00 +02:00
Moonchild 05441188be Issue #2306 - Enable full weakref by default in platform. 2026-06-07 23:54:52 +02:00
Moonchild 25a2d31be7 Issue #2306 - Re-introduce pref for WeakRef API spec.
Effectively avoids doing any GC work if preffed off, and adopts the same
for FinalizationRegistry which internally does similar work as WeakRefs.
2026-06-07 21:36:39 +02:00
Moonchild 58a4e0d545 [DOM] Provide more silent audio processing frames. 2026-06-05 12:29:30 +02:00
Moonchild ad06b4ce5e Revert "Bug 2027433 Treat null input channels as zero in InterleaveAndConvertBuffer()"
This reverts commit e76fc5637a.
2026-06-05 11:28:55 +02:00
Moonchild be3827b088 Revert "Bug 2027433 Treat null input channels as zero in AudioChannelsDownMix()"
This reverts commit ddd016a6f8.
2026-06-05 11:28:42 +02:00
Moonchild a136aaf502 Revert "Bug 2027433 use nullptr for silent up-mix channels"
This reverts commit 5309640d6c.
2026-06-05 11:28:35 +02:00
Moonchild 40d91a8eae Merge pull request 'Always Uppercase Eszett' (#3114) from RealityRipple/UXP:capital-eszett into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3114
2026-06-04 08:15:36 +00:00
Moonchild 5b81a81ac4 Merge pull request 'Fix LoongArch64 debug build assertions' (#3115) from Basilisk-Dev/UXP-contrib:loongarch-asserts into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3115
2026-06-04 04:08:45 +00:00
Basilisk-Dev 328ddb2927 Issue #3095 followup - Fix LoongArch64 debug build assertions 2026-06-03 18:13:31 -04:00
Andy 06b9622302 Issue #2964 - Part 3: JS Override for ToUpperCase 2026-06-02 15:25:47 -07:00
Andy 1218649202 Issue #2964 - Part 2b: Improve ToUpperCaseLength
Adds a method to force 16-bit characters, regardless of the type of the `chars` argument.
2026-06-02 15:21:44 -07:00
Andy cbea8f5a53 Issue #2964 - Part 2a: Correctly Detect End of Buffer in ToUpperCaseImpl
This code made two assumptions:
- That the `SrcChar` type should determine the output type, as used in `CanUpperCaseSpecialCasing`.
- That `AppendUpperCaseSpecialCasing` would always return a value larger than the previous value.

The new code uses `DestChar`'s type for `CanUpperCaseSpecialCasing` and for a more accurate End of Buffer check.
2026-06-02 15:21:26 -07:00
Andy f42e644486 Issue #2964 - Part 1: CSS Override for uppercase and capitalize 2026-06-02 15:20:45 -07:00
Moonchild a40490b946 Merge pull request 'Fix a build failure for WebRTC on Python 3.14 on MacOS' (#3113) from Basilisk-Dev/UXP-contrib:webrtc-fix-mac into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3113
2026-06-01 09:09:29 +00:00
Basilisk-Dev ad98693f3d Issue #3105 followup - Fix a build failure for WebRTC on Python 3.14 2026-05-31 09:54:46 -04:00
Moonchild 7b4aaca975 Merge pull request 'Clamp border-radius value to Int32.MaxValue' (#3112) from border-radius-clamp into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3112
2026-05-30 08:42:57 +00:00
Moonchild 400e59a96d Issue #3109 - Use CSS' internal length clamp value instead. 2026-05-29 23:53:22 +02:00
Moonchild 09276b72a6 Issue #3109 - Clamp border-radius value to Int32.MaxValue
This avoids artifacts from out-of-bounds values.
Resolves #3109
2026-05-29 22:53:43 +02:00
Moonchild ec18304362 Merge pull request 'Cleanup references to IA64/HP-UX' (#3106) from Basilisk-Dev/UXP-contrib:ia64-cleanup into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3106
2026-05-27 10:46:31 +00:00
Moonchild 4cf411f393 Merge pull request 'Remove gonk/Android/iOS/NACL code in WebRTC' (#3105) from Basilisk-Dev/UXP-contrib:webrtc-cleanup-mobile into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3105
2026-05-27 10:45:37 +00:00
Moonchild a0f135b94f NSS version update 2026-05-26 14:16:25 +02:00
Moonchild 3be679effc [DOM] Stop speech synthesis if the originating document is closed. 2026-05-25 20:32:10 +02:00
Moonchild 2d91c80555 [media] ffvpx patch: Fix leak in flac decoder in case of alloc failure. 2026-05-25 19:10:46 +02:00
Moonchild e5326c1d74 [DOM] Hold a strong ref to VoiceData in nsSynthVoiceRegistry::RemoveVoice. 2026-05-25 18:56:57 +02:00
Jens Stutte 5ddccdc7f6 Bug 1784128 - Assert count passed to PR_Read/PR_Write in nsFileStreamBase fits INT32_MAX. 2026-05-25 15:44:51 +02:00
Moonchild 8dc41b293a [gfx/layout] Simplify textruns
Cache overflow textruns in a better place and stop using a lazy class.
This avoids doing caching in the rendering back-end, and does so where
necessary in TextOverflow (for ellipses)
2026-05-25 14:59:51 +02:00
Moonchild f02956a324 No issue - Remove ISO-2022-JP from menu, overridability and detector.
Removed autodetection of this charset due to unreliability.
There are known security issues around charset auto-detection for ISO-2022-JP.
Given the usage is around 0.000002% of page loads, and Safari does not
support auto-detection of ISO-2022-JP, Chrome also planned to remove
support for it to eliminate the security issues.

See also https://www.sonarsource.com/blog/encoding-differentials-why-charset-matters/

Removal from the menu to avoid social engineering hazards and it being
literally unused on the web.
2026-05-25 13:08:29 +02:00
Moonchild e3646af419 [libvorbis] Allocate memory with _ogg_malloc
See https://gitlab.xiph.org/xiph/vorbis/-/commit/28965ede851bb9c1ce5cc0ed733fdf4ebd3d4241 and related commits.
2026-05-25 11:44:16 +02:00
Moonchild ee1f2e31a1 [layout] Hide accessible carets when needed. 2026-05-25 11:23:05 +02:00
Moonchild dcb90d6f92 [DOM] Check values in audio resampling. 2026-05-25 10:57:18 +02:00
John Schanck f9cdc54e09 Bug 2029818 - avoid refcount over-release in CERT_CertChainFromCert error path. 2026-05-25 10:22:44 +02:00
Moonchild 28be7ae6e0 [NSS] Fix use of uninitialized length after failed PK11_SignWithMechanism/SymKey. 2026-05-25 07:27:51 +02:00
Moonchild 463e7ec3c6 Force Clobber 2026-05-25 06:44:48 +02:00
John Schanck 531eeaabaa [NSS] Fix maxSize calculation in NSSUTIL_AddNSSFlagToModuleSpec. 2026-05-25 06:43:53 +02:00
Moonchild af92afbd6c Merge pull request 'Revert all Issue #3092 Commits' (#3107) from Basilisk-Dev/UXP-contrib:revert-3092 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3107
2026-05-25 04:05:41 +00:00
John Schanck 5005a47921 Bug 2027381 - improve error handling in SECITEM_DupArray with non-null arena. 2026-05-24 22:30:38 +02:00
Basilisk-Dev 72d4ca2b35 Clean up Issue #3092 revert whitespace 2026-05-24 16:19:36 -04:00
Basilisk-Dev b8951dbc2a Revert "Issue #3092 - Fix unsafe GC multithreading changes"
This reverts commit 2ca5d21147.

The mechanical inverse patch would restore earlier Issue #3092 parallel GC code that has already been removed by the preceding revert commits, so this records the revert without changing the tree.
2026-05-24 16:18:45 -04:00
Basilisk-Dev 20c92e63c5 Revert "Issue #3092 - Safely parallelize GC background finalization"
This reverts commit 3cf7c94995.
2026-05-24 16:13:21 -04:00
Moonchild ea785c3bb0 [netwerk] Make socket transport hold a reference to TLSServerConnectionInfo. 2026-05-24 21:48:55 +02:00
Randell Jesup 7abc11b3d1 Bug 2036905: Fix UDPSocketParent::ConnectInternal data race on mSocket. 2026-05-24 21:22:57 +02:00
Moonchild 2a4c4687c6 [netwerk] Make nsSocketTransport2::mConnectionFlags atomic. 2026-05-24 21:10:00 +02:00
Basilisk-Dev de3970d9b4 Revert "Issue #3092 - Refactor WASM compilation handling"
This reverts commit 1c09cd7816.
2026-05-24 14:58:21 -04:00
Basilisk-Dev 4da8c1fe4c Revert "Issue #3092 - Add new GC sweep tasks."
This reverts commit 8b6414ea7c.
2026-05-24 14:57:38 -04:00
Basilisk-Dev 8230f9b359 Revert "Issue #3092 - Implement BackgroundFinalizeTask for parallel garbage collection finalization"
This reverts commit 8ca5438db9.
2026-05-24 14:57:38 -04:00
Basilisk-Dev 310fec9ad5 Revert "Issue #3092 - Implement parallel sweeping and compaction tasks"
This reverts commit f33ccb5ce3.
2026-05-24 14:55:47 -04:00
Basilisk-Dev 5f2040153b Revert "Issue #3092 - Initial idle GC implementation"
This reverts commit fba218cff4.
2026-05-24 14:54:58 -04:00
Basilisk-Dev 30a774eb08 Revert "Issue #3092 - Perform a minor GC on tab close"
This reverts commit 266cc371f7.
2026-05-24 14:53:56 -04:00
Moonchild e8ee09b41f Merge pull request 'Implement CSSStyleSheet constructor' (#3103) from Basilisk-Dev/UXP-contrib:cssstylesheet-updates into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3103
2026-05-24 18:36:53 +00:00
Moonchild 5fc626f0fc [netwerk] nsRequestObserverProxy ref cleanup. 2026-05-24 19:40:23 +02:00
John Schanck c87c0e440b Bug 2029782 - fix 8-byte over-read of AES-192 key buffer in x86 builds without USE_HW_AES. 2026-05-24 15:10:06 +02:00
John Schanck 39b34ed8c5 Bug 2029771 - Heap use-after-free in [@ token_destructor] reading tok->pk11slot after nssToken_Destroy frees the token arena. 2026-05-24 15:07:24 +02:00
John Schanck e6b4a84e7e [NSS] Avoid integer overflow when converting AVA value to hex string. 2026-05-24 15:03:12 +02:00
John Schanck f7dfc278c4 [NSS] Enforce minimum buffer length in sftk_CheckCBCPadding. 2026-05-24 14:58:53 +02:00
Dana Keeler 13349f484c [NSS] VerifyCodeSigningCertificateChain: require at least one certificate. 2026-05-24 14:40:56 +02:00
Moonchild bd2670e006 [NSS] Initialize src in SEC_PKCS5GetIV 2026-05-24 14:37:06 +02:00
Dana Keeler e5bebae2c7 [NSS] NSS_CMSContentInfo_SetContent: only modify cinfo if everything succeeds. 2026-05-24 12:03:33 +02:00
Dennis Jackson d93df7216d [NSS] Align PKCS7 digest array with digestAlgorithms. 2026-05-24 11:50:38 +02:00
Moonchild 3d0a6899ce [libjar] Check Jar entry names for nulls. 2026-05-24 10:51:21 +02:00
John Schanck fdde68855b [NSS] Handle SEC_ASN1_NULL in sec_asn1e_contents_length. 2026-05-24 10:16:24 +02:00
Moonchild 2d038e6c1a [NSS] Fix instances of softoken attributes freed after owning object. 2026-05-24 10:09:28 +02:00
Moonchild c10f8a567b Merge branch 'master' of https://repo.palemoon.org/MoonchildProductions/UXP 2026-05-24 09:10:39 +02:00
Moonchild dcfa35e1ff Merge pull request 'Restore libAOM to the tree and making it a build-time configuration.' (#3104) from 888-32-bit-work2 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3104
2026-05-24 07:09:19 +00:00
Iain Ireland de1a7f5fe1 [js] Use size_t when inflating UTF8 2026-05-24 09:08:03 +02:00
Basilisk-Dev 2b0935adf4 Issue #3007 - Remove HP-UX LDAP compatibility code 2026-05-23 17:08:16 -04:00
Basilisk-Dev cbdc5fa85f Issue #3007 - Remove HP-UX launcher setup 2026-05-23 17:06:16 -04:00
Basilisk-Dev 2a06c40a09 Issue #3007 - Remove IA64 runtime support paths 2026-05-23 17:04:19 -04:00
Basilisk-Dev f499e3dd36 Issue #3007 - Remove IA64 from build configuration 2026-05-23 17:04:18 -04:00
Basilisk-Dev 34d88ac937 Issue #3053 - Implement CSSStyleSheet constructor 2026-05-23 16:45:54 -04:00
Basilisk-Dev 48d21fa2bf Issue #3008 - Prefer Windows memory barrier in WebRTC FIFO 2026-05-23 16:31:36 -04:00
Basilisk-Dev c91c69272b Issue #3008 - Remove stale B2G WebRTC camera comment 2026-05-23 16:25:35 -04:00
Basilisk-Dev 91f4fa744e Issue #3008 - Remove mobile leftovers from DOM WebRTC 2026-05-23 16:25:35 -04:00
Basilisk-Dev c2abd4aaa6 Issue #3008 - Remove stale Android WebView GYP guards 2026-05-23 16:25:34 -04:00
Basilisk-Dev 617ad84f96 Issue #3008 - Keep WebRTC audio FIFO after OpenSL removal 2026-05-23 16:25:33 -04:00
Basilisk-Dev 33b6bfa1b9 Issue #3008 - Fix GYP defaults after mobile cleanup 2026-05-23 16:25:33 -04:00
Basilisk-Dev 4e03afd191 Issue #3008 - Remove remaining mobile WebRTC build references 2026-05-23 16:25:32 -04:00
Basilisk-Dev 3512b73bc3 Issue #3008 - Remove stale iOS comments from WebRTC 2026-05-23 16:25:31 -04:00
Basilisk-Dev d0ac45cb08 Issue #3008 - Remove iOS support from bundled GYP generators 2026-05-23 16:25:31 -04:00
Basilisk-Dev ab3d950bd3 Issue #3008 - Remove mobile and NaCl defaults from WebRTC common gyp 2026-05-23 16:25:30 -04:00
Basilisk-Dev 44ddd79356 Issue #3008 - Remove stale iOS labels from WebRTC assembly 2026-05-23 16:25:29 -04:00
Basilisk-Dev 054ddf661f Issue #3008 - Remove stale mobile notes from WebRTC metadata 2026-05-23 16:25:29 -04:00
Basilisk-Dev da466a3bdd Issue #3008 - Remove stale mobile references from WebRTC headers 2026-05-23 16:25:28 -04:00
Basilisk-Dev 42f0c2d78f Issue #3008 - Remove mobile support from bundled WebRTC tools 2026-05-23 16:25:27 -04:00
Basilisk-Dev 5853784a31 Issue #3008 - Remove stale WebRTC mobile build metadata 2026-05-23 16:25:27 -04:00
Basilisk-Dev 5b20295620 Issue #3008 - Remove mobile guards from WebRTC voice tests 2026-05-23 16:25:26 -04:00
Basilisk-Dev 68e151c2a3 Issue #3008 - Remove mobile guards from WebRTC audio device tests 2026-05-23 16:25:25 -04:00
Basilisk-Dev dd764a70a2 Issue #3008 - Remove mobile guards from WebRTC module tests 2026-05-23 16:25:24 -04:00
Basilisk-Dev 12defe0d12 Issue #3008 - Remove mobile guards from WebRTC audio tests 2026-05-23 16:25:24 -04:00
Basilisk-Dev 8868dd5785 Issue #3008 - Remove mobile guards from WebRTC tests 2026-05-23 16:25:23 -04:00
Basilisk-Dev e787d585a4 Issue #3008 - Remove stale WebRTC mobile metadata 2026-05-23 16:25:22 -04:00
Basilisk-Dev 5eb7518ce2 Issue #3008 - Remove mobile WebRTC runtime conditionals 2026-05-23 16:25:21 -04:00
Basilisk-Dev 5be93da111 Issue #3008 - Remove obsolete mobile WebRTC source trees 2026-05-23 16:25:21 -04:00
Moonchild 39a89b708e Issue #888 - Fix makefile configure syntax for x86 check.
Not sure what language I was thinking but it was the wrong one. :P
2026-05-23 14:02:04 +02:00
Moonchild 69ad4f1674 Fix line endings in WebmDemuxer.cpp
No code changes.
2026-05-23 13:42:03 +02:00
Moonchild 59ae55a0e2 Issue #888 - Back out changes to the Dav1d lib. 2026-05-23 12:46:23 +02:00
Moonchild 6eb551332e Issue #888 - Hook libAOM back up, and make it configurable at build time.
Since the Dav1d changes will be reverted in the next commit, this also
includes a test for 32-bit x86 targets which makes libAOM mandatory.
2026-05-23 12:44:12 +02:00
Moonchild 96be1bb7a0 Revert "Issue #888 - Remove bundled libaom"
This reverts commit eb487c2ca1.
2026-05-23 10:26:43 +02:00
Moonchild 4dc3b6db93 Merge pull request 'Follow up on Dav1d implementation for 32-bit targets' (#3100) from 888-32bit into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3100
2026-05-23 07:37:32 +00:00
Moonchild a1da555b51 Issue #888 - Follow-up: Put smooth_weights_{1|2}d_16bpc back in ipred16 sources.
This reverts commit 16212905de and places
the SMOOTH_WEIGHTS in the SSE source instead, since that is always included.
2026-05-22 12:15:20 +02:00
Moonchild c1abc2eb3e Merge pull request 'ffvpx: Configuration for NetBSD/powerpc' (#3101) from nia/UXP:ffvpx-ppc into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3101
2026-05-22 08:14:01 +00:00
nia f0acda0bf4 ffvpx: Configuration for NetBSD/powerpc
Signed-off-by: Nia Alarie <nia@NetBSD.org>
2026-05-21 17:10:41 +02:00
Moonchild 16212905de Issue #888 - Follow-up: Lift smooth_weights_{1|2}d_16bpc out of AVX source.
This lifts the 2 functions out of the AVX-specific source (since it's
also used in the SSE one as external) and places it in the common x86
include.

This is an upstream code placement error; should be reported upstream.
2026-05-21 13:38:47 +02:00
Moonchild 2eb5e91b62 Issue #888 - Follow-up: don't assemble AVX into Dav1d on 32-bit x86 2026-05-21 13:34:47 +02:00
Moonchild fa6b67c8ac Re-land: Fix devtools on 32-bit big endian platforms
Tag PR #3098
2026-05-21 09:42:07 +02:00
Moonchild 6a117bd9d1 Revert "Fix dev tools on 32-bit big endian platforms"
This reverts commit f363ec1838.
2026-05-20 16:18:09 +02:00
Moonchild 714c709ad0 Merge pull request 'Add NetBSD to list of platforms where mapfile gets generated' (#3099) from nia/UXP:mapfile into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3099
2026-05-20 10:47:37 +00:00
Moonchild eafc230ff2 Merge pull request 'A collection of random fixes I've been accumulating.' (#3097) from dbsoft/UXP:miscfixes4 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3097
2026-05-20 10:46:57 +00:00
Moonchild 523a9aa2de Merge pull request 'Split loongarch jit so it no longer uses any mips files' (#3096) from Basilisk-Dev/UXP-contrib:loongarch-fix-jit into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3096
2026-05-20 10:46:19 +00:00
Moonchild ec92c29029 Merge pull request 'Fix dev tools on 32-bit big endian platforms' (#3098) from nia/UXP:devtools-lp32 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3098
2026-05-20 10:45:41 +00:00
nia 4a9d702bc1 Add NetBSD to list of platforms where mapfile gets generated
Signed-off-by: Nia Alarie <nia@NetBSD.org>
2026-05-20 10:26:38 +02:00
nia f363ec1838 Fix dev tools on 32-bit big endian platforms
This resolves a crash when pressing F12.

The __LP64__ macro is relied upon elsewhere in UXP so I think
this change should be safe.

Signed-off-by: Nia Alarie <nia@NetBSD.org>
2026-05-20 10:05:48 +02:00
Basilisk-Dev ffb3a95eb9 Issue #3095 - split loongarch jit so it no longer uses any mips files 2026-05-19 15:43:21 -04:00
Moonchild 63094adef4 Merge pull request 'Fix build on NetBSD/aarch64' (#3094) from nia/UXP:netbsd-aarch64 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3094
2026-05-19 15:50:04 +00:00
nia 1f8dcf74c8 Fix build on NetBSD/aarch64
Signed-off-by: Nia Alarie <nia@NetBSD.org>
2026-05-19 09:28:23 +02:00
Moonchild f20c549f66 Issue #888 - Follow-up: Spot-fix; set PREFIX in Dav1d config on Apple. 2026-05-19 09:02:10 +02:00
Brian Smith b62cccda62 Issue #1829 - Follow-up: Fix package name check for 32-bit Intel. 2026-05-18 08:51:11 -05:00
Brian Smith 43f3b3c7ee Issue #1829 - Follow-up: Fix version check for CoreLocation on 10.5 and earlier. 2026-05-18 08:51:11 -05:00
Brian Smith a328464912 Issue #1829 - Follow-up: Remove obsolete font code from Cairo.
This code only gets built on 32-bit MacOS, and it isn't used.
This allows Intel 32-bit MacOS builds to succeed.
2026-05-18 08:51:11 -05:00
Brian Smith 977ddd9e81 No Issue - Fix font crash on MacOS 10.7-10.11 using fonts with variations.
Switch to MacOS version guard's instead of PowerPC guards, for Intel support.
Remove inactive debug code.
2026-05-18 08:51:11 -05:00
Brian Smith 67717762f9 Issue #2051 - Follow-up: Fix CSS image masks on PowerPC Mac.
When I brought back CoreGraphics backend I brought back a fix for this.
However the fix was designed for Intel which uses Skia as a backend.
Our Skia does not support big endian, so change it to use Cairo backend.
2026-05-18 08:51:11 -05:00
Brian Smith a33f6857fd Issue #2354 - Follow-up: Fix building WebRTC on 32-bit ARM without hardware float. 2026-05-18 08:51:11 -05:00
Brian Smith 5c7c192df1 No Issue - Fix cubeb compilation targeting MacOS 10.5 from newer versions.
Remove obsolete iOS checks.
2026-05-18 08:51:11 -05:00
Basilisk-Dev 0186e78221 Fix WeakRef constructor realm prototype 2026-05-18 13:05:28 +02:00
Basilisk-Dev e9e858348b Fix FinalizationRegistry constructor realm prototype 2026-05-18 13:05:21 +02:00
Basilisk-Dev 631bb15b05 Implement FinalizationRegistry 2026-05-18 13:05:15 +02:00
Basilisk-Dev e7d6301c75 Make WeakRef support always enabled 2026-05-18 12:52:09 +02:00
Moonchild 22001fbca3 Fix incorrect variadic for size_t in fprintf statement in hyphen.c. 2026-05-18 12:41:20 +02:00
Basilisk-Dev 22e3028d56 Fix ArrayBuffer storage and error types 2026-05-18 12:31:46 +02:00
Basilisk-Dev 9498ce3f1e Fix ArrayBuffer slice after resizable source shrink 2026-05-18 12:31:40 +02:00
Basilisk-Dev 172c7b6f25 Validate typed array set and constructors on resizable buffers 2026-05-18 12:31:35 +02:00
Basilisk-Dev 750ef67831 Validate typed array methods on resizable buffers 2026-05-18 12:31:29 +02:00
Basilisk-Dev c19a39c4a5 Fix resizable DataView out-of-bounds semantics 2026-05-18 12:31:24 +02:00
Basilisk-Dev d6bfeeaf1a Support BigInt Atomics waiters 2026-05-18 12:31:17 +02:00
Basilisk-Dev e7ea20c073 Support DataView on shared array buffers 2026-05-18 12:31:11 +02:00
Basilisk-Dev a7e01b3f77 Guard typed array JIT paths for resizable buffers 2026-05-18 12:31:06 +02:00
Basilisk-Dev c3a541c55a Implement resizable buffer view semantics 2026-05-18 12:30:59 +02:00
Basilisk-Dev 41efdfd488 Implement Atomics.waitAsync 2026-05-18 12:30:52 +02:00
Basilisk-Dev 7d41d2a47c Implement growable SharedArrayBuffer 2026-05-18 12:30:46 +02:00
Basilisk-Dev ec951c592a Allow symbols as weak collection keys 2026-05-18 12:30:39 +02:00
Basilisk-Dev 829fd431e2 Implement ES2024 ArrayBuffer transfer APIs 2026-05-18 12:30:33 +02:00
Basilisk-Dev 9b7d25d1fd Implement ES2024 grouping and resolver builtins 2026-05-18 12:30:28 +02:00
Basilisk-Dev 1ab3e82a4d Fix JS shell module hook build 2026-05-18 12:30:22 +02:00
Moonchild b07102b821 Merge pull request 'Paralellize GC and implement GC-on-Idle' (#3093) from 3092 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3093
2026-05-18 10:28:10 +00:00
Moonchild 3adf3917ee Merge pull request 'Port various code changes from eUXP that should have been upstreamed' (#3091) from eUXP_ports2 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3091
2026-05-18 10:27:54 +00:00
Moonchild bbaf41e032 Merge pull request 'Truncate fractional border calculations to integers with special handling' (#3090) from 3088 into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3090
2026-05-18 10:26:16 +00:00
Moonchild 618c017249 Merge pull request 'Replace libAOM reference AV1 implementation with Dav1d' (#3087) from dav1d-work into master
Reviewed-on: https://repo.palemoon.org/MoonchildProductions/UXP/pulls/3087
2026-05-18 10:25:52 +00:00
Basilisk-Dev 3cf7c94995 Issue #3092 - Safely parallelize GC background finalization
Parallelize background finalization across zones within each finalize
phase while preserving phase ordering and falling back to serial work
when no helper thread is idle.

Make compacting GC pointer updates schedule background work per zone and
only when enough background-safe arenas exist.
2026-05-18 12:18:05 +02:00
Basilisk-Dev 2ca5d21147 Issue #3092 - Fix unsafe GC multithreading changes 2026-05-18 12:17:18 +02:00
ownedbywuigi 266cc371f7 Issue #3092 - Perform a minor GC on tab close 2026-05-18 12:16:56 +02:00
ownedbywuigi fba218cff4 Issue #3092 - Initial idle GC implementation 2026-05-18 12:15:55 +02:00
ownedbywuigi f33ccb5ce3 Issue #3092 - Implement parallel sweeping and compaction tasks
for improved garbage collection performance
2026-05-18 12:15:34 +02:00
ownedbywuigi 8ca5438db9 Issue #3092 - Implement BackgroundFinalizeTask for parallel garbage collection finalization 2026-05-18 12:15:09 +02:00
ownedbywuigi 8b6414ea7c Issue #3092 - Add new GC sweep tasks.
For saved stacks, self-hosting scripts, and native iterators.
2026-05-18 12:14:30 +02:00
ownedbywuigi 1c09cd7816 Issue #3092 - Refactor WASM compilation handling 2026-05-18 12:13:18 +02:00
wuggy 07b47c8472 Whitelist virtual GPUs (VirtualBox, VMware, VirtIO (QEMU and forks like UTM), Parallels) 2026-05-18 09:48:35 +02:00
Basilisk-Dev 950a608e01 Support CSS shadow parts 2026-05-17 09:57:14 +02:00
Basilisk-Dev c7f08c7e53 Issue #2506 - Support range media query syntax
Resolves #2506
2026-05-17 09:55:27 +02:00
Basilisk-Dev 4f3857c1ea Issue #1826 - Parse calc() weights in color-mix 2026-05-17 09:53:56 +02:00
Basilisk-Dev 60b4b1ad47 Issue #3089 - Support logical border radius properties
Resolves #3089
2026-05-17 09:53:05 +02:00
Basilisk-Dev 8262184873 Revert "Cloudflare Image Resizing fix take 2"
This reverts commit ef19ad3ffd.

No longer necessary with aspect-ratio in place.
2026-05-17 09:46:52 +02:00
Basilisk-Dev e9abd8b022 Support CSS sizing math functions
Prereq for parts of #2404
2026-05-17 09:46:07 +02:00
Basilisk-Dev fe29e0430c Issue #2404 - Enable CSS aspect-ratio sizing 2026-05-17 09:44:59 +02:00
Moonchild 589967f3df Merge branch '3088' into euxp-ports2 2026-05-17 09:44:13 +02:00
Basilisk-Dev 9db275d300 Remove stale imagebitmap support file entry 2026-05-17 09:42:03 +02:00
Basilisk-Dev b6d0a261d2 Load mochitest modules without imp 2026-05-17 09:41:56 +02:00
Basilisk-Dev dad0daf389 Issue #2982 - Follow-up: allow color-mix to work with oklab and oklch
Tag #2489 and #3003
2026-05-17 09:41:44 +02:00
Basilisk-Dev b58e2b9312 Issue #1826 - Serialize special calc() number values 2026-05-17 09:39:23 +02:00
Basilisk-Dev b8f458a819 Issue #1826 - Add typed calc() arithmetic for media queries 2026-05-17 09:39:00 +02:00
Basilisk-Dev 39321f4796 Issue #1826 - Canonicalize nested calc() serialization 2026-05-17 09:38:31 +02:00
Basilisk-Dev d8de738239 Issue #1826 - Support calc() in media queries 2026-05-17 09:37:49 +02:00
Basilisk-Dev 40407bb784 Issue #1826 - Implement broader CSS calc() parsing 2026-05-17 09:37:11 +02:00
Basilisk-Dev a5b2671f1e Fix app-unit rounding for border width edges 2026-05-17 09:34:28 +02:00
Basilisk-Dev 4249686af4 Flush layout for computed border-width shorthand 2026-05-17 09:34:20 +02:00
Basilisk-Dev 69ba22d624 Fix CSS border rounding and currentcolor clipping 2026-05-17 09:34:13 +02:00
Basilisk-Dev 4359582e67 Test fractional border width rounding 2026-05-17 09:33:59 +02:00
Basilisk-Dev fa06d2de31 Floor fractional border widths 2026-05-17 09:33:49 +02:00
ownedbywuigi b7b1918a36 Issue #888 - Add dav1d_flush 2026-05-17 09:06:09 +02:00
ownedbywuigi aa69d5ec99 Issue #888 - Make symbols direct to dav1d, not AOM. 2026-05-17 09:05:44 +02:00
ownedbywuigi 6e4bb257a4 Issue #888 - (potentially) fix MSVC builderr 2026-05-17 09:05:24 +02:00
wuggy a30f439a9c Issue #888 - Fix alphabetical order issue 2026-05-17 09:04:52 +02:00
Basilisk-Dev 0ccaab55ca Issue #888 - Update AV1 configure comment for dav1d 2026-05-17 09:04:31 +02:00
Basilisk-Dev e61621692c Issue #888 - Enable AV1 playback by default 2026-05-17 09:04:05 +02:00
Basilisk-Dev 9a8cb2e22e Issue #888 - Enable dav1d SIMD on more architectures 2026-05-17 09:03:41 +02:00
Basilisk-Dev eb487c2ca1 Issue #888 - Remove bundled libaom 2026-05-17 09:03:21 +02:00
Basilisk-Dev 5c0a35a358 Issue #888 - Enable dav1d LoongArch SIMD 2026-05-17 09:02:50 +02:00
Basilisk-Dev a468f81a5e Issue #888 - Use in-tree dav1d for AV1 decoding 2026-05-17 09:00:34 +02:00
Basilisk-Dev d1b46d7347 Issue #888 - Vendor dav1d 1.5.3 2026-05-17 09:00:07 +02:00
1345 changed files with 348261 additions and 55730 deletions

No files matched your search

+1 -1
View File
@@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Clobber for Python 3 migration
Clobber for Idle GC backout
+8
View File
@@ -0,0 +1,8 @@
TRADEMARK NOTICE
================
The name "Goanna" and visual representations (logo) have not been
registered by the Copyright owners as a trademark in any jurisdiction.
However, because Goanna has been distributed and maintained world-wide,
continually since 2015, the Copyright owners claim "common-law trademark
protection" in any jurisdiction where common-law trademark is recognized.
-2
View File
@@ -43,8 +43,6 @@ gyp_vars.update({
'arm_neon': 0,
'arm_neon_optional': 1,
'moz_webrtc_omx': 0,
'moz_webrtc_mediacodec': 0,
# Turn off multi monitor screen share
'multi_monitor_screenshare%' : 0,
+1 -1
View File
@@ -344,7 +344,7 @@ def split_triplet(triplet):
if cpu.endswith('86') or (cpu.startswith('i') and '86' in cpu):
canonical_cpu = 'x86'
endianness = 'little'
elif cpu in ('x86_64', 'ia64'):
elif cpu == 'x86_64':
canonical_cpu = cpu
endianness = 'little'
elif cpu in ('s390', 's390x'):
+1
View File
@@ -152,6 +152,7 @@ def old_configure_options(*options):
'--enable-jitspew',
'--enable-js-lto',
'--enable-leak-sanitizer',
'--enable-libaom',
'--enable-libjpeg-turbo',
'--enable-libproxy',
'--enable-llvm-hacks',
+38
View File
@@ -61,6 +61,44 @@ set_config('HAVE_YASM', have_yasm)
# Until the YASM variable is not necessary in old-configure.
add_old_configure_assignment('YASM', have_yasm)
# nasm detection
# ==============================================================
nasm = check_prog('NASM', ['nasm'], allow_missing=True)
@depends_if(nasm)
@checking('nasm version')
def nasm_version(nasm):
version = check_cmd_output(
nasm, '-v',
onerror=lambda: die('Failed to get nasm version.')
).splitlines()[0].split()[2]
return Version(version)
@depends(nasm, nasm_version)
def have_nasm(nasm, version):
if nasm and version >= Version('2.14'):
return True
set_config('HAVE_NASM', have_nasm)
@depends(have_nasm, target)
def nasm_asflags(have_nasm, target):
if have_nasm:
asflags = {
('OSX', 'x86'): '-f macho32',
('OSX', 'x86_64'): '-f macho64',
('WINNT', 'x86'): '-f win32',
('WINNT', 'x86_64'): '-f win64',
}.get((target.os, target.cpu), None)
if asflags is None:
if target.cpu == 'x86':
asflags = '-f elf32'
elif target.cpu == 'x86_64':
asflags = '-f elf64'
return asflags
set_config('NASM_ASFLAGS', nasm_asflags)
# MacOS deployment target version
# ==============================================================
# This needs to happen before any compilation test is done.
+1 -7
View File
@@ -290,11 +290,6 @@ fi
if [ -n "$LD_LIBRARY_PATH_64" ]; then
LD_LIBRARY_PATH_64=${MOZ_DIST_BIN}:${MOZ_DIST_BIN}/plugins:${MRE_HOME}${LD_LIBRARY_PATH_64:+":$LD_LIBRARY_PATH_64"}
fi
#
#
## Set SHLIB_PATH for HPUX
SHLIB_PATH=${MOZ_DIST_BIN}:${MRE_HOME}${SHLIB_PATH:+":$SHLIB_PATH"}
#
## Set LIBPATH for AIX
LIBPATH=${MOZ_DIST_BIN}:${MRE_HOME}${LIBPATH:+":$LIBPATH"}
#
@@ -339,7 +334,6 @@ then
fi
echo "DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH"
echo " LIBRARY_PATH=$LIBRARY_PATH"
echo " SHLIB_PATH=$SHLIB_PATH"
echo " LIBPATH=$LIBPATH"
echo " ADDON_PATH=$ADDON_PATH"
echo " MOZ_PROGRAM=$MOZ_PROGRAM"
@@ -350,7 +344,7 @@ then
fi
#
export MOZILLA_FIVE_HOME LD_LIBRARY_PATH
export SHLIB_PATH LIBPATH LIBRARY_PATH ADDON_PATH DYLD_LIBRARY_PATH
export LIBPATH LIBRARY_PATH ADDON_PATH DYLD_LIBRARY_PATH
if [ $moz_debug -eq 1 ]
then
+4 -1
View File
@@ -29,7 +29,10 @@ if CONFIG['MOZ_WEBM_ENCODER']:
external_dirs += ['media/libvpx']
if CONFIG['MOZ_AV1']:
external_dirs += ['media/libaom']
if CONFIG['AV1_USE_AOM']:
external_dirs += ['media/libaom']
else:
external_dirs += ['media/libdav1d']
external_dirs += ['media/libpng']
-1
View File
@@ -448,7 +448,6 @@ gtk/gtkx.h
gtk/gtkunixprint.h
HIToolbox/HIToolbox.h
hlink.h
ia64/sys/inline.h
Icons.h
iconv.h
ieeefp.h
+7 -6
View File
@@ -204,21 +204,22 @@ function initialHTML(doc) {
os = "linux";
}
let base = doc.createElement("base");
base.href = "resource://devtools/client/jsonview/";
// The appRoot URI is prepended to all URIs instead of using a <base> element
// because the latter can cause spurious network requests (UXP Issue #3122)
let appRoot = "resource://devtools/client/jsonview/";
let style = doc.createElement("link");
style.rel = "stylesheet";
style.type = "text/css";
style.href = "css/main.css";
style.href = appRoot +"css/main.css";
let script = doc.createElement("script");
script.src = "lib/require.js";
script.dataset.main = "viewer-config";
script.src = appRoot + "lib/require.js";
script.dataset.main = appRoot + "viewer-config.js";
script.defer = true;
let head = doc.createElement("head");
head.append(base, style, script);
head.append(style, script);
return "<!DOCTYPE html>\n" +
startTag("html", {
@@ -4,6 +4,8 @@ subsuite = devtools
support-files =
array_json.json
array_json.json^headers^
csp_json.json
csp_json.json^headers^
doc_frame_script.js
head.js
invalid_json.json
@@ -22,6 +24,7 @@ subsuite = clipboard
subsuite = clipboard
[browser_jsonview_copy_rawdata.js]
subsuite = clipboard
[browser_jsonview_csp_json.js]
[browser_jsonview_filter.js]
[browser_jsonview_invalid_json.js]
[browser_jsonview_valid_json.js]
@@ -0,0 +1,17 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const TEST_JSON_URL = URL_ROOT + "csp_json.json";
add_task(function* () {
info("Test CSP JSON started");
yield addJsonViewTab(TEST_JSON_URL);
let count = yield getElementCount(".jsonPanelBox .treeTable .treeRow");
is(count, 1, "There must be one row");
});
@@ -0,0 +1 @@
{"csp": true}
@@ -0,0 +1,2 @@
Content-Type: application/json
Content-Security-Policy: default-src 'none'; base-uri 'none';
+1 -1
View File
@@ -23,7 +23,7 @@
* of the code base, so it's consistent and modules can be easily reused.
*/
require.config({
baseUrl: ".",
baseUrl: "resource://devtools/client/jsonview/",
paths: {
"devtools/client/shared": "resource://devtools/client/shared",
"devtools/shared": "resource://devtools/shared",
@@ -103,12 +103,6 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker, highlighter) {
}
};
this._styleSheetFilePath = null;
if (styleSheet.href &&
Services.io.extractScheme(this.styleSheet.href) == "file") {
this._styleSheetFilePath = this.styleSheet.href;
}
this._onPropertyChange = this._onPropertyChange.bind(this);
this._onError = this._onError.bind(this);
this._onMediaRuleMatchesChange = this._onMediaRuleMatchesChange.bind(this);
@@ -664,8 +658,7 @@ StyleSheetEditor.prototype = {
if (this._friendlyName) {
defaultName = OS.Path.basename(this._friendlyName);
}
showFilePicker(file || this._styleSheetFilePath, true, this._window,
onFile, defaultName);
showFilePicker(file, true, this._window, onFile, defaultName);
},
/**
@@ -1,98 +1,112 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that 'Save' function works.
const TESTCASE_URI_HTML = TEST_BASE_HTTP + "simple.html";
const TESTCASE_URI_CSS = TEST_BASE_HTTP + "simple.css";
var tempScope = {};
Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope);
Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope);
var FileUtils = tempScope.FileUtils;
var NetUtil = tempScope.NetUtil;
add_task(function* () {
let htmlFile = yield copy(TESTCASE_URI_HTML, "simple.html");
yield copy(TESTCASE_URI_CSS, "simple.css");
let uri = Services.io.newFileURI(htmlFile);
let filePath = uri.resolve("");
let { ui } = yield openStyleEditorForURL(filePath);
let editor = ui.editors[0];
yield editor.getSourceEditor();
info("Editing the style sheet.");
let dirty = editor.sourceEditor.once("dirty-change");
let beginCursor = {line: 0, ch: 0};
editor.sourceEditor.replaceText("DIRTY TEXT", beginCursor, beginCursor);
yield dirty;
is(editor.sourceEditor.isClean(), false, "Editor is dirty.");
ok(editor.summary.classList.contains("unsaved"),
"Star icon is present in the corresponding summary.");
info("Saving the changes.");
dirty = editor.sourceEditor.once("dirty-change");
editor.saveToFile(null, function (file) {
ok(file, "file should get saved directly when using a file:// URI");
});
yield dirty;
is(editor.sourceEditor.isClean(), true, "Editor is clean.");
ok(!editor.summary.classList.contains("unsaved"),
"Star icon is not present in the corresponding summary.");
});
function copy(srcChromeURL, destFileName) {
let deferred = defer();
let destFile = FileUtils.getFile("ProfD", [destFileName]);
write(read(srcChromeURL), destFile, deferred.resolve);
return deferred.promise;
}
function read(srcChromeURL) {
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
.getService(Ci.nsIScriptableInputStream);
let channel = NetUtil.newChannel({
uri: srcChromeURL,
loadUsingSystemPrincipal: true
});
let input = channel.open2();
scriptableStream.init(input);
let data = "";
while (input.available()) {
data = data.concat(scriptableStream.read(input.available()));
}
scriptableStream.close();
input.close();
return data;
}
function write(data, file, callback) {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(data);
let ostream = FileUtils.openSafeFileOutputStream(file);
NetUtil.asyncCopy(istream, ostream, function (status) {
if (!Components.isSuccessCode(status)) {
info("Couldn't write to " + file.path);
return;
}
callback(file);
});
}
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that 'Save' function works.
const TESTCASE_URI_HTML = TEST_BASE_HTTP + "simple.html";
const TESTCASE_URI_CSS = TEST_BASE_HTTP + "simple.css";
var tempScope = {};
Components.utils.import("resource://gre/modules/FileUtils.jsm", tempScope);
Components.utils.import("resource://gre/modules/NetUtil.jsm", tempScope);
var FileUtils = tempScope.FileUtils;
var NetUtil = tempScope.NetUtil;
add_task(function* () {
let htmlFile = yield copy(TESTCASE_URI_HTML, "simple.html");
const cssFile = await copy(TESTCASE_URI_CSS, "simple.css");
let uri = Services.io.newFileURI(htmlFile);
let filePath = uri.resolve("");
let { ui } = yield openStyleEditorForURL(filePath);
let editor = ui.editors[0];
yield editor.getSourceEditor();
is(
editor.savedFile,
null,
"savedFile should not be pre-populated from the source file"
);
info("Editing the style sheet.");
let dirty = editor.sourceEditor.once("dirty-change");
let beginCursor = {line: 0, ch: 0};
editor.sourceEditor.replaceText("DIRTY TEXT", beginCursor, beginCursor);
yield dirty;
is(editor.sourceEditor.isClean(), false, "Editor is dirty.");
ok(editor.summary.classList.contains("unsaved"),
"Star icon is present in the corresponding summary.");
info(
"Saving the changes with an explicit file (simulating a user-chosen save location)."
);
dirty = editor.sourceEditor.once("dirty-change");
editor.saveToFile(cssFile, function (file) {
ok(file, "file should get saved when explicitly passing a file");
});
yield dirty;
is(editor.sourceEditor.isClean(), true, "Editor is clean.");
ok(!editor.summary.classList.contains("unsaved"),
"Star icon is not present in the corresponding summary.");
is(
editor.savedFile?.path,
cssFile.path,
"savedFile should now be set on the editor"
);
});
function copy(srcChromeURL, destFileName) {
let deferred = defer();
let destFile = FileUtils.getFile("ProfD", [destFileName]);
write(read(srcChromeURL), destFile, deferred.resolve);
return deferred.promise;
}
function read(srcChromeURL) {
let scriptableStream = Cc["@mozilla.org/scriptableinputstream;1"]
.getService(Ci.nsIScriptableInputStream);
let channel = NetUtil.newChannel({
uri: srcChromeURL,
loadUsingSystemPrincipal: true
});
let input = channel.open2();
scriptableStream.init(input);
let data = "";
while (input.available()) {
data = data.concat(scriptableStream.read(input.available()));
}
scriptableStream.close();
input.close();
return data;
}
function write(data, file, callback) {
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
.createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let istream = converter.convertToInputStream(data);
let ostream = FileUtils.openSafeFileOutputStream(file);
NetUtil.asyncCopy(istream, ostream, function (status) {
if (!Components.isSuccessCode(status)) {
info("Couldn't write to " + file.path);
return;
}
callback(file);
});
}
@@ -28,7 +28,10 @@ add_task(function* () {
let HTMLFile = yield copy(TESTCASE_URI_HTML, ["sourcemaps.html"]);
let CSSFile = yield copy(TESTCASE_URI_CSS,
["sourcemap-css", "sourcemaps.css"]);
yield copy(TESTCASE_URI_SCSS, ["sourcemap-sass", "sourcemaps.scss"]);
const SCSSFile = await copy(TESTCASE_URI_SCSS, [
"sourcemap-sass",
"sourcemaps.scss",
]);
yield copy(TESTCASE_URI_MAP, ["sourcemap-css", "sourcemaps.css.map"]);
yield copy(TESTCASE_URI_REG_CSS, ["simple.css"]);
@@ -59,7 +62,7 @@ add_task(function* () {
// Edit and save Sass in the editor. This will start off a file-watching
// process waiting for the CSS file to change.
yield editSCSS(editor);
yield editSCSS(SCSSFile, editor);
// We can't run Sass or another compiler, so we fake it by just
// directly changing the CSS file.
@@ -73,12 +76,12 @@ add_task(function* () {
is(color, "rgb(0, 0, 255)", "div is blue after saving file");
});
function editSCSS(editor) {
function editSCSS(SCSSFile, editor) {
let deferred = defer();
editor.sourceEditor.setText(CSS_TEXT);
editor.saveToFile(null, function (file) {
editor.saveToFile(SCSSFile, function (file) {
ok(file, "Scss file should be saved");
deferred.resolve();
});
+1 -1
View File
@@ -196,7 +196,7 @@ public:
{
MOZ_ASSERT(!NS_IsMainThread());
int32_t written = PR_Write(mFD, mData, mLength);
int32_t written = mLength < INT32_MAX ? PR_Write(mFD, mData, mLength) : -1;
if (NS_WARN_IF(written < 0 || uint32_t(written) != mLength)) {
return NS_DispatchToMainThread(
new ErrorPropagationRunnable(mBlobStorage, NS_ERROR_FAILURE));
+1
View File
@@ -1004,6 +1004,7 @@ GK_ATOM(parameter, "parameter")
GK_ATOM(parent, "parent")
GK_ATOM(parentfocused, "parentfocused")
GK_ATOM(parsetype, "parsetype")
GK_ATOM(part, "part")
GK_ATOM(password, "password")
GK_ATOM(pattern, "pattern")
GK_ATOM(patternSeparator, "pattern-separator")
+46 -30
View File
@@ -39,6 +39,44 @@ WebGLTransformFeedback::Delete()
////////////////////////////////////////
// Validation helper for beginning/resuming the TF and computing the
// vertex capacity.
bool
WebGLTransformFeedback::PrepareTransformFeedback() {
const auto& prog = mContext->mCurrentProgram;
if (!prog ||
!prog->IsLinked() ||
!prog->LinkInfo()->componentsPerTFVert.size()) {
mContext->ErrorInvalidOperation("Current program not valid for transform feedback.");
return false;
}
const auto& linkInfo = prog->LinkInfo();
const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
mActive_VertCapacity = 0;
size_t minVertCapacity = SIZE_MAX;
for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
const auto& indexedBinding = mIndexedBindings[i];
const auto& componentsPerVert = componentsPerTFVert[i];
const auto& buffer = indexedBinding.mBufferBinding;
if (!buffer) {
mContext->ErrorInvalidOperation("No buffer attached to required transform feedback index %u.",
(uint32_t)i);
return false;
}
const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
minVertCapacity = std::min(minVertCapacity, vertCapacity);
}
mActive_VertCapacity = minVertCapacity;
return true;
}
void
WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
{
@@ -59,37 +97,10 @@ WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
return;
}
const auto& prog = mContext->mCurrentProgram;
if (!prog ||
!prog->IsLinked() ||
!prog->LinkInfo()->componentsPerTFVert.size())
{
mContext->ErrorInvalidOperation("%s: Current program not valid for transform"
" feedback.",
funcName);
if (!PrepareTransformFeedback()) {
return;
}
const auto& linkInfo = prog->LinkInfo();
const auto& componentsPerTFVert = linkInfo->componentsPerTFVert;
size_t minVertCapacity = SIZE_MAX;
for (size_t i = 0; i < componentsPerTFVert.size(); i++) {
const auto& indexedBinding = mIndexedBindings[i];
const auto& componentsPerVert = componentsPerTFVert[i];
const auto& buffer = indexedBinding.mBufferBinding;
if (!buffer) {
mContext->ErrorInvalidOperation("%s: No buffer attached to required transform"
" feedback index %u.",
funcName, (uint32_t)i);
return;
}
const size_t vertCapacity = buffer->ByteLength() / 4 / componentsPerVert;
minVertCapacity = std::min(minVertCapacity, vertCapacity);
}
////
const auto& gl = mContext->gl;
@@ -101,10 +112,9 @@ WebGLTransformFeedback::BeginTransformFeedback(GLenum primMode)
mIsActive = true;
MOZ_ASSERT(!mIsPaused);
mActive_Program = prog;
mActive_Program = mContext->mCurrentProgram;
mActive_PrimMode = primMode;
mActive_VertPosition = 0;
mActive_VertCapacity = minVertCapacity;
////
@@ -173,6 +183,12 @@ WebGLTransformFeedback::ResumeTransformFeedback()
return;
}
// Re-run prepare in case some of the buffers have been modified
// while the TF was paused.
if (!PrepareTransformFeedback()) {
return;
}
////
const auto& gl = mContext->gl;
+1
View File
@@ -44,6 +44,7 @@ public:
WebGLTransformFeedback(WebGLContext* webgl, GLuint tf);
private:
~WebGLTransformFeedback();
bool PrepareTransformFeedback();
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
-1
View File
@@ -26,7 +26,6 @@ support-files =
image_yellow75.png
imagebitmap_bug1239300.js
imagebitmap_bug1239752.js
imagebitmap_extensions.html
imagebitmap_on_worker.js
imagebitmap_structuredclone.js
imagebitmap_structuredclone_iframe.html
+1
View File
@@ -63,6 +63,7 @@ EncodingUtils::IsAsciiCompatible(const nsACString& aPreferredName)
aPreferredName.LowerCaseEqualsLiteral("utf-16be") ||
aPreferredName.LowerCaseEqualsLiteral("utf-16le") ||
aPreferredName.LowerCaseEqualsLiteral("replacement") ||
aPreferredName.LowerCaseEqualsLiteral("iso-2022-jp") ||
aPreferredName.LowerCaseEqualsLiteral("hz-gb-2312") ||
aPreferredName.LowerCaseEqualsLiteral("utf-7") ||
aPreferredName.LowerCaseEqualsLiteral("x-imap4-modified-utf7"));
+1 -1
View File
@@ -652,7 +652,7 @@ nsresult nsGeolocationService::Init()
#endif
#ifdef MOZ_WIDGET_COCOA
#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6)
if (Preferences::GetBool("geo.provider.use_corelocation", true)) {
mProvider = new CoreLocationLocationProvider();
}
+5 -1
View File
@@ -18,6 +18,8 @@
#include "nsContentUtils.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsIProtocolHandler.h"
NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
@@ -186,6 +188,8 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
newBaseURI = nullptr;
}
if (csp && newBaseURI) {
bool isLocalResource = false;
rv = NS_URIChainHasFlags(newBaseURI, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &isLocalResource);
// base-uri is only enforced if explicitly defined in the
// policy - do *not* consult default-src, see:
// http://www.w3.org/TR/CSP2/#directive-default-src
@@ -193,7 +197,7 @@ SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
rv = csp->Permits(newBaseURI, nsIContentSecurityPolicy::BASE_URI_DIRECTIVE,
true /* aSpecific */, true /* aSendViolationReports */,
&cspPermitsBaseURI);
if (NS_FAILED(rv) || !cspPermitsBaseURI) {
if ((NS_FAILED(rv) || !cspPermitsBaseURI) && !isLocalResource) {
newBaseURI = nullptr;
}
}
+5 -17
View File
@@ -105,8 +105,6 @@ gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] =
* Given an array of input channels, downmix to aOutputChannelCount, and copy
* the results to the channel buffers in aOutputChannels. Don't call this with
* input count <= output count.
* Each of aOutputChannels must be non-null.
* aChannelArray elements may be null.
*/
template<typename T>
void AudioChannelsDownMix(const nsTArray<const T*>& aChannelArray,
@@ -121,11 +119,7 @@ void AudioChannelsDownMix(const nsTArray<const T*>& aChannelArray,
if (inputChannelCount > 6) {
// Just drop the unknown channels.
for (uint32_t o = 0; o < aOutputChannelCount; ++o) {
if (inputChannels[o]) {
PodCopy(aOutputChannels[o], inputChannels[o], aDuration);
} else {
std::fill_n(aOutputChannels[o], aDuration, static_cast<T>(0));
}
PodCopy(aOutputChannels[o], inputChannels[o], aDuration);
}
return;
}
@@ -144,19 +138,13 @@ void AudioChannelsDownMix(const nsTArray<const T*>& aChannelArray,
// want an input channel to contribute to nothing
T outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1] = {0};
for (uint32_t c = 0; c < inputChannelCount; ++c) {
if (inputChannels[c]) {
outputChannels[m.mInputDestination[c]] +=
m.mInputCoefficient[c] *
(static_cast<const T*>(inputChannels[c]))[s];
}
outputChannels[m.mInputDestination[c]] +=
m.mInputCoefficient[c]*(static_cast<const T*>(inputChannels[c]))[s];
}
// Utilize the fact that in every layout, C is the third channel.
if (m.mCExtraDestination != IGNORE) {
if (inputChannels[SURROUND_C]) {
outputChannels[m.mCExtraDestination] +=
m.mInputCoefficient[SURROUND_C] *
(static_cast<const T*>(inputChannels[SURROUND_C]))[s];
}
outputChannels[m.mCExtraDestination] +=
m.mInputCoefficient[SURROUND_C]*(static_cast<const T*>(inputChannels[SURROUND_C]))[s];
}
for (uint32_t c = 0; c < aOutputChannelCount; ++c) {
+26 -8
View File
@@ -7,6 +7,7 @@
#include <speex/speex_resampler.h>
#include <string.h>
#include <cmath>
#include "mozilla/CheckedInt.h"
/*
* Parts derived from MythTV AudioConvert Class
@@ -262,8 +263,15 @@ AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
if (!mResampler) {
return 0;
}
uint32_t outframes = ResampleRecipientFrames(aFrames);
uint32_t inframes = aFrames;
uint32_t outframes;
if (!ResampleRecipientFrames(aFrames, &outframes)) {
return 0;
}
CheckedUint32 inframesChecked(aFrames);
if (!inframesChecked.isValid()) {
return 0;
}
uint32_t inframes = inframesChecked.value();
int error;
if (mOut.Format() == AudioConfig::FORMAT_FLT) {
@@ -288,7 +296,7 @@ AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
mResampler = nullptr;
return 0;
}
MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
MOZ_ASSERT(static_cast<size_t>(inframes) == aFrames, "Some frames will be dropped");
return outframes;
}
@@ -373,17 +381,27 @@ AudioConverter::UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const
return aFrames;
}
size_t
AudioConverter::ResampleRecipientFrames(size_t aFrames) const
{
bool AudioConverter::ResampleRecipientFrames(size_t aFrames,
uint32_t* aOutFrames) const {
if (!aFrames && mIn.Rate() != mOut.Rate()) {
if (!mResampler) {
return 0;
*aOutFrames = 0;
return true;
}
// We drain by pushing in get_input_latency() samples of 0
aFrames = speex_resampler_get_input_latency(mResampler);
}
return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
CheckedInt<uint64_t> numerator = CheckedInt<uint64_t>(aFrames) * mOut.Rate();
if (!numerator.isValid()) {
return false;
}
CheckedUint32 outFrames(numerator.value() / mIn.Rate());
outFrames += 1u;
if (!outFrames.isValid()) {
return false;
}
*aOutFrames = outFrames.value();
return true;
}
size_t
+9 -2
View File
@@ -7,6 +7,7 @@
#define AudioConverter_h
#include "MediaInfo.h"
#include "mozilla/CheckedInt.h"
// Forward declaration
typedef struct SpeexResamplerState_ SpeexResamplerState;
@@ -163,9 +164,15 @@ public:
AlignedBuffer<Value>* outputBuffer = &temp1;
AlignedBuffer<Value> temp2;
if (!frames || mOut.Rate() > mIn.Rate()) {
uint32_t resampledFrames;
// We are upsampling or about to drain, we can't work in place.
// Allocate another temporary buffer where the upsampling will occur.
if (!temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)))) {
if (!ResampleRecipientFrames(frames, &resampledFrames)) {
return AudioDataBuffer<Format, Value>(std::move(temp2));
}
CheckedInt<size_t> outputSamples =
CheckedInt<size_t>(resampledFrames) * mOut.Channels();
if (!outputSamples.isValid() || !temp2.SetLength(outputSamples.value())) {
return AudioDataBuffer<Format, Value>(Move(temp2));
}
outputBuffer = &temp2;
@@ -229,7 +236,7 @@ private:
// Resampler context.
SpeexResamplerState* mResampler;
size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
size_t ResampleRecipientFrames(size_t aFrames) const;
bool ResampleRecipientFrames(size_t aFrames, uint32_t* aOutFrames) const;
void RecreateResampler();
size_t DrainResampler(void* aOut);
};
+3 -9
View File
@@ -121,19 +121,13 @@ AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
}
if (channelData.Length() < aOutputChannels) {
// Up-mix.
AudioChannelsUpMix(&channelData, aOutputChannels, static_cast<const AudioDataValue*>(nullptr));
AudioChannelsUpMix(&channelData, aOutputChannels, SilentChannel::ZeroChannel<AudioDataValue>());
for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
AudioDataValue* ptr =
PointerForOffsetInChannel(buf.Elements(), outBufferLength,
aOutputChannels, channel, offsetSamples);
if (channelData[channel]) {
PodCopy(
ptr,
reinterpret_cast<const AudioDataValue*>(channelData[channel]),
frames);
} else {
PodZero(ptr, frames);
}
PodCopy(ptr, reinterpret_cast<const AudioDataValue*>(channelData[channel]),
frames);
}
MOZ_ASSERT(channelData.Length() == aOutputChannels);
} else if (channelData.Length() > aOutputChannels) {
+9 -16
View File
@@ -61,22 +61,15 @@ template <typename SrcT, typename DestT>
static void
InterleaveAndConvertBuffer(const SrcT* const* aSourceChannels,
uint32_t aLength, float aVolume,
uint32_t aChannelCount,
uint32_t aChannels,
DestT* aOutput)
{
for (size_t channel = 0; channel < aChannelCount; ++channel) {
DestT* output = aOutput;
if (aSourceChannels[channel]) {
for (size_t i = 0; i < aLength; ++i) {
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
*output = FloatToAudioSample<DestT>(v);
output += aChannelCount;
}
} else {
for (size_t i = 0; i < aLength; ++i) {
*output = static_cast<DestT>(0);
output += aChannelCount;
}
DestT* output = aOutput;
for (size_t i = 0; i < aLength; ++i) {
for (size_t channel = 0; channel < aChannels; ++channel) {
float v = AudioSampleToFloat(aSourceChannels[channel][i])*aVolume;
*output = FloatToAudioSample<DestT>(v);
++output;
}
}
}
@@ -100,7 +93,7 @@ DeinterleaveAndConvertBuffer(const SrcT* aSourceBuffer,
class SilentChannel
{
public:
static const int AUDIO_PROCESSING_FRAMES = 640; /* > 10ms of 48KHz audio */
static const int AUDIO_PROCESSING_FRAMES = 4096; /* > 10ms of 48KHz audio */
static const uint8_t gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*AUDIO_PROCESSING_FRAMES];
// We take advantage of the fact that zero in float and zero in int have the
// same all-zeros bit layout.
@@ -415,7 +408,7 @@ void WriteChunk(AudioChunk& aChunk,
if (channelData.Length() < aOutputChannels) {
// Up-mix. Note that this might actually make channelData have more
// than aOutputChannels temporarily.
AudioChannelsUpMix(&channelData, aOutputChannels, static_cast<const SrcT*>(nullptr));
AudioChannelsUpMix(&channelData, aOutputChannels, SilentChannel::ZeroChannel<SrcT>());
}
if (channelData.Length() > aOutputChannels) {
// Down-mix.
+1 -1
View File
@@ -111,7 +111,7 @@ private:
DECL_MEDIA_PREF("media.ffvpx.enabled", PDMFFVPXEnabled, bool, true);
#endif
#ifdef MOZ_AV1
DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, false);
DECL_MEDIA_PREF("media.av1.enabled", AV1Enabled, bool, true);
#endif
#ifdef XP_WIN
DECL_MEDIA_PREF("media.wmf.enabled", PDMWMFEnabled, bool, true);
@@ -13,7 +13,11 @@
#include "TheoraDecoder.h"
#ifdef MOZ_AV1
#ifdef AV1_USE_AOM
#include "AOMDecoder.h"
#else
#include "Dav1dDecoder.h"
#endif
#endif
namespace mozilla {
@@ -30,7 +34,11 @@ AgnosticDecoderModule::SupportsMimeType(const nsACString& aMimeType,
TheoraDecoder::IsTheora(aMimeType);
#ifdef MOZ_AV1
if (MediaPrefs::AV1Enabled()) {
#ifdef AV1_USE_AOM
supports |= AOMDecoder::IsAV1(aMimeType);
#else
supports |= Dav1dDecoder::IsAV1(aMimeType);
#endif
}
#endif
MOZ_LOG(sPDMLog, LogLevel::Debug, ("Agnostic decoder %s requested type",
@@ -47,10 +55,17 @@ AgnosticDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
m = new VPXDecoder(aParams);
}
#ifdef MOZ_AV1
#ifdef AV1_USE_AOM
else if (AOMDecoder::IsAV1(aParams.mConfig.mMimeType) &&
MediaPrefs::AV1Enabled()) {
m = new AOMDecoder(aParams);
}
#else
else if (Dav1dDecoder::IsAV1(aParams.mConfig.mMimeType) &&
MediaPrefs::AV1Enabled()) {
m = new Dav1dDecoder(aParams);
}
#endif
#endif
else if (TheoraDecoder::IsTheora(aParams.mConfig.mMimeType)) {
m = new TheoraDecoder(aParams);
@@ -0,0 +1,376 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Dav1dDecoder.h"
#include "MediaResult.h"
#include "TimeUnits.h"
#include "dav1d/dav1d.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/PodOperations.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "nsError.h"
#include "prsystem.h"
#include <algorithm>
#include <errno.h>
#include <string.h>
#undef LOG
#define LOG(arg, ...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, ("Dav1dDecoder(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
namespace mozilla {
using namespace gfx;
using namespace layers;
Dav1dDecoder::Dav1dDecoder(const CreateDecoderParams& aParams)
: mImageContainer(aParams.mImageContainer)
, mTaskQueue(aParams.mTaskQueue)
, mCallback(aParams.mCallback)
, mIsFlushing(false)
, mDecoder(nullptr)
, mInfo(aParams.VideoConfig())
{
}
Dav1dDecoder::~Dav1dDecoder()
{
}
void
Dav1dDecoder::Shutdown()
{
if (mDecoder) {
dav1d_close(&mDecoder);
}
}
RefPtr<MediaDataDecoder::InitPromise>
Dav1dDecoder::Init()
{
int decodeThreads = 2;
if (mInfo.mDisplay.width >= 2048) {
decodeThreads = 8;
} else if (mInfo.mDisplay.width >= 1024) {
decodeThreads = 4;
}
decodeThreads = std::min(decodeThreads, PR_GetNumberOfProcessors());
Dav1dSettings settings;
dav1d_default_settings(&settings);
settings.n_threads = decodeThreads;
settings.logger.callback = nullptr;
if (dav1d_open(&mDecoder, &settings) < 0) {
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__);
}
return InitPromise::CreateAndResolve(TrackInfo::kVideoTrack, __func__);
}
void
Dav1dDecoder::Flush()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
mIsFlushing = true;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([this] () {
if (mDecoder) {
dav1d_flush(mDecoder);
}
});
SyncRunnable::DispatchToThread(mTaskQueue, r);
mIsFlushing = false;
}
static bool
GetPlaneSize(int aWidth, int aHeight, size_t* aSize)
{
CheckedInt<size_t> size = aWidth;
size *= aHeight;
if (!size.isValid()) {
return false;
}
*aSize = size.value();
return true;
}
static void
DownshiftPlane(uint8_t* aDst, int aDstStride, const uint8_t* aSrc,
ptrdiff_t aSrcStride, int aWidth, int aHeight, int aShift)
{
for (int y = 0; y < aHeight; y++) {
const uint16_t* src =
reinterpret_cast<const uint16_t*>(aSrc + y * aSrcStride);
uint8_t* dst = aDst + y * aDstStride;
for (int x = 0; x < aWidth; x++) {
dst[x] = (src[x] >> aShift) & 0xff;
}
}
}
MediaResult
Dav1dDecoder::OutputPicture(const Dav1dPicture& aPicture)
{
const int width = aPicture.p.w;
const int height = aPicture.p.h;
if (width <= 0 || height <= 0) {
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("dav1d returned invalid AV1 picture size"));
}
int chromaWidth = width;
int chromaHeight = height;
switch (aPicture.p.layout) {
case DAV1D_PIXEL_LAYOUT_I420:
chromaWidth = (width + 1) >> 1;
chromaHeight = (height + 1) >> 1;
break;
case DAV1D_PIXEL_LAYOUT_I422:
chromaWidth = (width + 1) >> 1;
chromaHeight = height;
break;
case DAV1D_PIXEL_LAYOUT_I444:
break;
default:
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("dav1d returned unsupported AV1 pixel layout: %d",
int(aPicture.p.layout)));
}
const int planeWidths[3] = { width, chromaWidth, chromaWidth };
const int planeHeights[3] = { height, chromaHeight, chromaHeight };
const ptrdiff_t srcStrides[3] = {
aPicture.stride[0],
aPicture.stride[1],
aPicture.stride[1]
};
uint8_t* planeData[3] = {
static_cast<uint8_t*>(aPicture.data[0]),
static_cast<uint8_t*>(aPicture.data[1]),
static_cast<uint8_t*>(aPicture.data[2])
};
uint32_t planeStrides[3] = { 0, 0, 0 };
UniquePtr<uint8_t[]> downshifted[3];
if (aPicture.p.bpc > 8) {
const int shift = aPicture.p.bpc - 8;
for (int plane = 0; plane < 3; plane++) {
size_t planeSize;
if (!GetPlaneSize(planeWidths[plane], planeHeights[plane], &planeSize)) {
return MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("AV1 downshift plane size overflow"));
}
downshifted[plane] = MakeUniqueFallible<uint8_t[]>(planeSize);
if (!downshifted[plane]) {
return MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("Couldn't allocate AV1 conversion buffer"));
}
DownshiftPlane(downshifted[plane].get(), planeWidths[plane],
planeData[plane], srcStrides[plane],
planeWidths[plane], planeHeights[plane], shift);
planeData[plane] = downshifted[plane].get();
planeStrides[plane] = planeWidths[plane];
}
} else {
for (int plane = 0; plane < 3; plane++) {
CheckedInt<uint32_t> stride(srcStrides[plane]);
if (srcStrides[plane] < 0 || !stride.isValid()) {
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("dav1d returned invalid AV1 stride"));
}
planeStrides[plane] = stride.value();
}
}
VideoData::YCbCrBuffer b;
for (int plane = 0; plane < 3; plane++) {
b.mPlanes[plane].mData = planeData[plane];
b.mPlanes[plane].mStride = planeStrides[plane];
b.mPlanes[plane].mHeight = planeHeights[plane];
b.mPlanes[plane].mWidth = planeWidths[plane];
b.mPlanes[plane].mOffset = 0;
b.mPlanes[plane].mSkip = 0;
}
if (aPicture.seq_hdr) {
switch (aPicture.seq_hdr->mtrx) {
case DAV1D_MC_BT601:
case DAV1D_MC_BT470BG:
b.mYUVColorSpace = YUVColorSpace::BT601;
break;
case DAV1D_MC_BT709:
b.mYUVColorSpace = YUVColorSpace::BT709;
break;
case DAV1D_MC_IDENTITY:
b.mYUVColorSpace = YUVColorSpace::IDENTITY;
break;
default:
LOG("Unhandled colorspace %d", aPicture.seq_hdr->mtrx);
break;
}
b.mColorRange = aPicture.seq_hdr->color_range ? ColorRange::FULL
: ColorRange::LIMITED;
}
const int64_t time =
aPicture.m.timestamp == INT64_MIN ? 0 : aPicture.m.timestamp;
const int64_t duration = aPicture.m.duration;
const int64_t offset = aPicture.m.offset;
const bool keyframe =
aPicture.frame_hdr &&
aPicture.frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY;
RefPtr<VideoData> v =
VideoData::CreateAndCopyData(mInfo,
mImageContainer,
offset,
time,
duration,
b,
keyframe,
time,
mInfo.ScaledImageRect(width, height));
if (!v) {
LOG("Image allocation error source %dx%d display %ux%u picture %ux%u",
width, height, mInfo.mDisplay.width, mInfo.mDisplay.height,
mInfo.mImage.width, mInfo.mImage.height);
return MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__);
}
mCallback->Output(v);
return NS_OK;
}
MediaResult
Dav1dDecoder::DrainOutput()
{
while (true) {
Dav1dPicture picture;
PodZero(&picture);
const int res = dav1d_get_picture(mDecoder, &picture);
if (res == DAV1D_ERR(EAGAIN)) {
return NS_OK;
}
if (res < 0) {
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("dav1d error getting AV1 picture: %d",
res));
}
MediaResult rv = OutputPicture(picture);
dav1d_picture_unref(&picture);
if (NS_FAILED(rv)) {
return rv;
}
}
}
MediaResult
Dav1dDecoder::DoDecode(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
Dav1dData data;
PodZero(&data);
uint8_t* dst = dav1d_data_create(&data, aSample->Size());
if (!dst) {
return MediaResult(NS_ERROR_OUT_OF_MEMORY,
RESULT_DETAIL("Couldn't allocate dav1d AV1 input buffer"));
}
memcpy(dst, aSample->Data(), aSample->Size());
data.m.timestamp = aSample->mTime;
data.m.duration = aSample->mDuration;
data.m.offset = aSample->mOffset;
data.m.size = aSample->Size();
while (data.sz) {
const int res = dav1d_send_data(mDecoder, &data);
if (res == DAV1D_ERR(EAGAIN)) {
MediaResult rv = DrainOutput();
if (NS_FAILED(rv)) {
dav1d_data_unref(&data);
return rv;
}
continue;
}
if (res < 0) {
dav1d_data_unref(&data);
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("dav1d error decoding AV1 sample: %d",
res));
}
}
dav1d_data_unref(&data);
return DrainOutput();
}
void
Dav1dDecoder::ProcessDecode(MediaRawData* aSample)
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
if (mIsFlushing) {
return;
}
MediaResult rv = DoDecode(aSample);
if (NS_FAILED(rv)) {
mCallback->Error(rv);
} else {
mCallback->InputExhausted();
}
}
void
Dav1dDecoder::Input(MediaRawData* aSample)
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
mTaskQueue->Dispatch(NewRunnableMethod<RefPtr<MediaRawData>>(
this, &Dav1dDecoder::ProcessDecode, aSample));
}
void
Dav1dDecoder::ProcessDrain()
{
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
MediaResult rv = DrainOutput();
if (NS_FAILED(rv)) {
mCallback->Error(rv);
} else {
mCallback->DrainComplete();
}
}
void
Dav1dDecoder::Drain()
{
MOZ_ASSERT(mCallback->OnReaderTaskQueue());
mTaskQueue->Dispatch(NewRunnableMethod(this, &Dav1dDecoder::ProcessDrain));
}
/* static */
bool
Dav1dDecoder::IsAV1(const nsACString& aMimeType)
{
return aMimeType.EqualsLiteral("video/webm; codecs=av1") ||
aMimeType.EqualsLiteral("video/av1");
}
/* static */
nsIntSize
Dav1dDecoder::GetFrameSize(Span<const uint8_t> aBuffer)
{
Dav1dSequenceHeader seqHdr;
PodZero(&seqHdr);
if (dav1d_parse_sequence_header(&seqHdr,
aBuffer.Elements(),
aBuffer.Length()) < 0) {
return nsIntSize(0, 0);
}
return nsIntSize(seqHdr.max_width, seqHdr.max_height);
}
} // namespace mozilla
#undef LOG
@@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if !defined(Dav1dDecoder_h_)
#define Dav1dDecoder_h_
#include "PlatformDecoderModule.h"
#include "mozilla/Span.h"
#include <stdint.h>
typedef struct Dav1dContext Dav1dContext;
typedef struct Dav1dPicture Dav1dPicture;
namespace mozilla {
class Dav1dDecoder : public MediaDataDecoder
{
public:
explicit Dav1dDecoder(const CreateDecoderParams& aParams);
RefPtr<InitPromise> Init() override;
void Input(MediaRawData* aSample) override;
void Flush() override;
void Drain() override;
void Shutdown() override;
const char* GetDescriptionName() const override
{
return "dav1d (AV1) video decoder";
}
// Return true if aMimeType is a one of the strings used
// by our demuxers to identify AV1 streams.
static bool IsAV1(const nsACString& aMimeType);
// Return the frame dimensions from a sequence header, when one is present.
static nsIntSize GetFrameSize(Span<const uint8_t> aBuffer);
private:
~Dav1dDecoder();
void ProcessDecode(MediaRawData* aSample);
MediaResult DoDecode(MediaRawData* aSample);
MediaResult DrainOutput();
MediaResult OutputPicture(const Dav1dPicture& aPicture);
void ProcessDrain();
const RefPtr<layers::ImageContainer> mImageContainer;
const RefPtr<TaskQueue> mTaskQueue;
MediaDataDecoderCallback* mCallback;
Atomic<bool> mIsFlushing;
Dav1dContext* mDecoder;
const VideoInfo& mInfo;
};
} // namespace mozilla
#endif // Dav1dDecoder_h_
+14 -6
View File
@@ -55,12 +55,20 @@ if CONFIG['MOZ_FFMPEG']:
]
if CONFIG['MOZ_AV1']:
EXPORTS += [
'agnostic/AOMDecoder.h',
]
UNIFIED_SOURCES += [
'agnostic/AOMDecoder.cpp',
]
if CONFIG['AV1_USE_AOM']:
EXPORTS += [
'agnostic/AOMDecoder.h',
]
UNIFIED_SOURCES += [
'agnostic/AOMDecoder.cpp',
]
else:
EXPORTS += [
'agnostic/Dav1dDecoder.h',
]
UNIFIED_SOURCES += [
'agnostic/Dav1dDecoder.cpp',
]
if CONFIG['MOZ_APPLEMEDIA']:
EXPORTS += [
+1 -1
View File
@@ -26,7 +26,7 @@ ThreadSharedFloatArrayBufferList::Create(uint32_t aChannelCount,
new ThreadSharedFloatArrayBufferList(aChannelCount);
for (uint32_t i = 0; i < aChannelCount; ++i) {
float* channelData = js_pod_malloc<float>(aLength);
float* channelData = js_pod_calloc<float>(aLength);
if (!channelData) {
return nullptr;
}
+2 -2
View File
@@ -40,8 +40,8 @@ public:
}
/**
* Create with buffers suitable for transfer to
* JS_NewArrayBufferWithContents(). The buffer contents are uninitialized
* and so should be set using GetDataForWrite().
* JS_NewArrayBufferWithContents(). The buffer contents are
* zero-initialized; callers should set them using GetDataForWrite().
*/
static already_AddRefed<ThreadSharedFloatArrayBufferList>
Create(uint32_t aChannelCount, size_t aLength, const mozilla::fallible_t&);
+1 -2
View File
@@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/Preferences.h"
#ifdef MOZ_AV1
#if defined(MOZ_AV1) && defined(AV1_USE_AOM)
#include "AOMDecoder.h"
#endif
#include "MediaPrefs.h"
@@ -136,4 +136,3 @@ WebMDecoder::GetMozDebugReaderData(nsAString& aString)
}
} // namespace mozilla
File diff suppressed because it is too large. Load diff
+5
View File
@@ -24,6 +24,11 @@ if CONFIG['MOZ_WEBM_ENCODER']:
'WebMWriter.cpp',
]
if CONFIG['MOZ_AV1']:
LOCAL_INCLUDES += [
'/dom/media/platforms/agnostic',
]
CXXFLAGS += CONFIG['MOZ_LIBVPX_CFLAGS']
FINAL_LIBRARY = 'xul'
+1 -3
View File
@@ -29,8 +29,7 @@ enum {
* Abstract interface for managing audio and video devices. Each platform
* must implement a concrete class that will map these classes and methods
* to the appropriate backend. For example, on Desktop platforms, these will
* correspond to equivalent webrtc (GIPS) calls, and on B2G they will map to
* a Gonk interface.
* correspond to equivalent webrtc (GIPS) calls.
*/
class MediaEngineVideoSource;
class MediaEngineAudioSource;
@@ -302,7 +301,6 @@ public:
/* If implementation of MediaEngineSource supports TakePhoto(), the picture
* should be return via aCallback object. Otherwise, it returns NS_ERROR_NOT_IMPLEMENTED.
* Currently, only Gonk MediaEngineSource implementation supports it.
*/
virtual nsresult TakePhoto(MediaEnginePhotoCallback* aCallback) = 0;
@@ -36,8 +36,8 @@ bool MediaEngineCameraVideoSource::AppendToTrack(SourceMediaStream* aSource,
return aSource->AppendToTrack(aID, &(segment));
}
// Sub-classes (B2G or desktop) should overload one of both of these two methods
// to provide capabilities
// Subclasses should overload one or both of these methods to provide
// capabilities.
size_t
MediaEngineCameraVideoSource::NumCapabilities() const
{
@@ -324,21 +324,6 @@ MediaEngineCameraVideoSource::SetName(nsString aName)
bool hasFacingMode = false;
VideoFacingModeEnum facingMode = VideoFacingModeEnum::User;
// Set facing mode based on device name.
#if defined(ANDROID)
// Names are generated. Example: "Camera 0, Facing back, Orientation 90"
//
// See media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/
// webrtc/videoengine/VideoCaptureDeviceInfoAndroid.java
if (aName.Find(NS_LITERAL_STRING("Facing back")) != kNotFound) {
hasFacingMode = true;
facingMode = VideoFacingModeEnum::Environment;
} else if (aName.Find(NS_LITERAL_STRING("Facing front")) != kNotFound) {
hasFacingMode = true;
facingMode = VideoFacingModeEnum::User;
}
#endif // ANDROID
#ifdef XP_MACOSX
// Kludge to test user-facing cameras on OSX.
if (aName.Find(NS_LITERAL_STRING("Face")) != -1) {
@@ -108,7 +108,7 @@ protected:
nsTArray<PrincipalHandle> mPrincipalHandles; // Directly mapped to mSources.
RefPtr<layers::Image> mImage;
RefPtr<layers::ImageContainer> mImageContainer;
int mWidth, mHeight; // protected with mMonitor on Gonk due to different threading
int mWidth, mHeight; // protected with mMonitor
// end of data protected by mMonitor
+1 -1
View File
@@ -15,7 +15,7 @@
#ifdef FF
#undef FF
#endif
#include "webrtc/modules/audio_device/opensl/single_rw_fifo.h"
#include "SingleRwFifo.h"
#define CHANNELS 1
#define ENCODING "L16"
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "SingleRwFifo.h"
#include <assert.h>
#if defined(_MSC_VER)
#include <windows.h>
#endif
static int
UpdatePos(int pos, int capacity)
{
return (pos + 1) % capacity;
}
namespace webrtc {
namespace subtle {
#if defined(_MSC_VER)
inline void
MemoryBarrier()
{
::MemoryBarrier();
}
#elif defined(__GNUC__) || defined(__clang__)
inline void
MemoryBarrier()
{
__sync_synchronize();
}
#else
#error Add an implementation of MemoryBarrier() for this platform!
#endif
} // namespace subtle
SingleRwFifo::SingleRwFifo(int capacity)
: capacity_(capacity)
, size_(0)
, read_pos_(0)
, write_pos_(0)
{
queue_.reset(new int8_t*[capacity_]);
}
SingleRwFifo::~SingleRwFifo()
{
}
void
SingleRwFifo::Push(int8_t* mem)
{
assert(mem);
// Ensure that there is space for the new data in the FIFO. There is only one
// writer, so the other thread is guaranteed only to decrease the size.
const int free_slots = capacity() - size();
if (free_slots <= 0) {
// Size can be queried outside of Push. The caller is expected to ensure
// that Push will be successful before calling it.
assert(false);
return;
}
queue_[write_pos_] = mem;
// Ensure that |size_| is updated after the stored pointer is visible.
subtle::MemoryBarrier();
++size_;
write_pos_ = UpdatePos(write_pos_, capacity());
}
int8_t*
SingleRwFifo::Pop()
{
int8_t* ret_val = nullptr;
if (size() <= 0) {
// Size can be queried outside of Pop. The caller is expected to ensure
// that Pop will be successful before calling it.
assert(false);
return ret_val;
}
ret_val = queue_[read_pos_];
// Ensure that |size_| is updated after the stored pointer is read.
subtle::MemoryBarrier();
--size_;
read_pos_ = UpdatePos(read_pos_, capacity());
return ret_val;
}
} // namespace webrtc
@@ -8,8 +8,8 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_SINGLE_RW_FIFO_H_
#define WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_SINGLE_RW_FIFO_H_
#ifndef DOM_MEDIA_WEBRTC_SINGLE_RW_FIFO_H_
#define DOM_MEDIA_WEBRTC_SINGLE_RW_FIFO_H_
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/atomic32.h"
@@ -17,10 +17,9 @@
namespace webrtc {
// Implements a lock-free FIFO losely based on
// Implements a lock-free FIFO loosely based on
// http://src.chromium.org/viewvc/chrome/trunk/src/media/base/audio_fifo.cc
// Note that this class assumes there is one producer (writer) and one
// consumer (reader) thread.
// This class assumes there is one producer and one consumer thread.
class SingleRwFifo {
public:
explicit SingleRwFifo(int capacity);
@@ -29,8 +28,6 @@ class SingleRwFifo {
void Push(int8_t* mem);
int8_t* Pop();
void Clear();
int size() { return size_.Value(); }
int capacity() const { return capacity_; }
@@ -46,4 +43,4 @@ class SingleRwFifo {
} // namespace webrtc
#endif // WEBRTC_MODULES_AUDIO_DEVICE_ANDROID_SINGLE_RW_FIFO_H_
#endif // DOM_MEDIA_WEBRTC_SINGLE_RW_FIFO_H_
+2 -2
View File
@@ -38,6 +38,7 @@ if CONFIG['MOZ_WEBRTC']:
# MediaEngineWebRTC.cpp needs to be built separately.
SOURCES += [
'MediaEngineWebRTC.cpp',
'SingleRwFifo.cpp',
]
LOCAL_INCLUDES += [
'/dom/base',
@@ -68,8 +69,7 @@ include('/ipc/chromium/chromium-config.mozbuild')
# Suppress some GCC/clang warnings being treated as errors:
# - about attributes on forward declarations for types that are already
# defined, which complains about important MOZ_EXPORT attributes for
# android API types
# defined, which complains about important MOZ_EXPORT attributes.
if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']:
CXXFLAGS += [
'-Wno-error=attributes',
@@ -293,6 +293,12 @@ SpeechSynthesis::ForceEnd()
}
}
void SpeechSynthesis::DisconnectFromOwner() {
Pause();
Cancel();
DOMEventTargetHelper::DisconnectFromOwner();
}
NS_IMETHODIMP
SpeechSynthesis::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
@@ -58,6 +58,8 @@ public:
void GetVoices(nsTArray< RefPtr<SpeechSynthesisVoice> >& aResult);
void ForceEnd();
void DisconnectFromOwner() override;
IMPL_EVENT_HANDLER(voiceschanged)
@@ -325,12 +325,12 @@ nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
(XRE_IsContentProcess()) ? "child" : "parent"));
bool found = false;
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
RefPtr<VoiceData> retval = mUriVoiceMap.GetWeak(aUri, &found);
if(NS_WARN_IF(!(found))) {
if(NS_WARN_IF(!found)) {
return NS_ERROR_NOT_AVAILABLE;
}
if(NS_WARN_IF(!(aService == retval->mService))) {
if(NS_WARN_IF(aService != retval->mService)) {
return NS_ERROR_INVALID_ARG;
}
+6 -4
View File
@@ -294,7 +294,7 @@ UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
const UDPAddressInfo& aAddressInfo)
{
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, aAddressInfo.addr().get(), aAddressInfo.port()));
if (NS_FAILED(ConnectInternal(aAddressInfo.addr(), aAddressInfo.port()))) {
if (NS_FAILED(ConnectInternal(aSocket, aAddressInfo.addr(), aAddressInfo.port()))) {
SendInternalError(aReturnThread, __LINE__);
return;
}
@@ -320,13 +320,15 @@ UDPSocketParent::DoConnect(nsCOMPtr<nsIUDPSocket>& aSocket,
}
nsresult
UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
UDPSocketParent::ConnectInternal(const nsCOMPtr<nsIUDPSocket>& aSocket,
const nsCString& aHost,
const uint16_t& aPort)
{
nsresult rv;
UDPSOCKET_LOG(("%s: %s:%u", __FUNCTION__, nsCString(aHost).get(), aPort));
if (!mSocket) {
if (!aSocket) {
return NS_ERROR_NOT_AVAILABLE;
}
@@ -340,7 +342,7 @@ UDPSocketParent::ConnectInternal(const nsCString& aHost, const uint16_t& aPort)
mozilla::net::NetAddr addr;
PRNetAddrToNetAddr(&prAddr, &addr);
rv = mSocket->Connect(&addr);
rv = aSocket->Connect(&addr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
+3 -1
View File
@@ -62,7 +62,9 @@ private:
const bool& aAddressReuse, const bool& aLoopback,
const uint32_t& recvBufferSize,
const uint32_t& sendBufferSize);
nsresult ConnectInternal(const nsCString& aHost, const uint16_t& aPort);
nsresult ConnectInternal(const nsCOMPtr<nsIUDPSocket>& aSocket,
const nsCString& aHost,
const uint16_t& aPort);
void FireInternalError(uint32_t aLineNo);
void SendInternalError(nsIEventTarget *aThread,
uint32_t aLineNo);
+1 -3
View File
@@ -194,7 +194,7 @@ static void FreeStringArray(uint32_t variants, char ** array)
static bool CanLoadPlugin(char16ptr_t aBinaryPath)
{
#if defined(_M_IX86) || defined(_M_X64) || defined(_M_IA64)
#if defined(_M_IX86) || defined(_M_X64)
bool canLoad = false;
HANDLE file = CreateFileW(aBinaryPath, GENERIC_READ,
@@ -214,8 +214,6 @@ static bool CanLoadPlugin(char16ptr_t aBinaryPath)
canLoad = (arch == IMAGE_FILE_MACHINE_I386);
#elif defined(_M_X64)
canLoad = (arch == IMAGE_FILE_MACHINE_AMD64);
#elif defined(_M_IA64)
canLoad = (arch == IMAGE_FILE_MACHINE_IA64);
#endif
}
}
+1
View File
@@ -13,6 +13,7 @@ enum CSSStyleSheetParsingMode {
"agent"
};
[Constructor]
interface CSSStyleSheet : StyleSheet {
[Pure]
readonly attribute CSSRule? ownerRule;
+1 -2
View File
@@ -34,7 +34,6 @@ interface Element : Node {
[SameObject]
readonly attribute NamedNodeMap attributes;
[Pure]
sequence<DOMString> getAttributeNames();
[Pure]
DOMString? getAttribute(DOMString name);
@@ -159,7 +158,7 @@ interface Element : Node {
* this property returns an object with computed values for grid
* tracks and lines.
*/
[ChromeOnly, Pure]
[ChromeOnly]
sequence<Grid> getGridFragments();
};
+1 -1
View File
@@ -23,7 +23,7 @@ interface HTMLElement : Element {
[CEReactions, SetterThrows, Pure]
attribute DOMString dir;
[CEReactions, GetterThrows, Pure]
[CEReactions, GetterThrows]
attribute [TreatNullAs=EmptyString] DOMString innerText;
// user interaction
+1 -1
View File
@@ -51,7 +51,7 @@ interface HTMLInputElement : HTMLElement {
attribute boolean formNoValidate;
[CEReactions, Pure, SetterThrows]
attribute DOMString formTarget;
[CEReactions, Pure, SetterThrows]
[CEReactions, SetterThrows]
attribute unsigned long height;
[Pure]
attribute boolean indeterminate;
+28 -7
View File
@@ -823,16 +823,37 @@ nsBindingManager::WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc,
}
}
// The approach in WalkAllShadowRootHostRules seems reasonable on the surface and reminds me of what is done with mScopedRoot elsewhere. But something important is missing, either here or in the code that would normally use it.
void
nsBindingManager::WalkAllShadowRootHostRules(nsIStyleRuleProcessor::EnumFunc aFunc,
ElementDependentRuleProcessorData* aData)
{
aData->mTreeMatchContext.mOnlyMatchHostPseudo = true;
WalkAllRules(aFunc, aData, true);
aData->mTreeMatchContext.mOnlyMatchHostPseudo = false;
}
{
if (!mBoundContentSet) {
return;
}
bool oldOnlyMatchHostPseudo = aData->mTreeMatchContext.mOnlyMatchHostPseudo;
nsIContent* oldScopedRoot = aData->mTreeMatchContext.mScopedRoot;
aData->mTreeMatchContext.mOnlyMatchHostPseudo = true;
for (auto iter = mBoundContentSet->Iter(); !iter.Done(); iter.Next()) {
nsIContent* boundContent = iter.Get()->GetKey();
ShadowRoot* shadowRoot = boundContent->GetShadowRoot();
if (!shadowRoot) {
continue;
}
nsXBLBinding* binding = shadowRoot->GetAssociatedBinding();
if (!binding) {
continue;
}
aData->mTreeMatchContext.mScopedRoot = boundContent;
binding->WalkRules(aFunc, aData);
}
aData->mTreeMatchContext.mScopedRoot = oldScopedRoot;
aData->mTreeMatchContext.mOnlyMatchHostPseudo = oldOnlyMatchHostPseudo;
}
nsresult
nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
@@ -7,8 +7,6 @@ UNIFIED_SOURCES += [
'CharDistribution.cpp',
'JpCntx.cpp',
'nsCharSetProber.cpp',
'nsEscCharsetProber.cpp',
'nsEscSM.cpp',
'nsEUCJPProber.cpp',
'nsLatin1Prober.cpp',
'nsMBCSGroupProber.cpp',
@@ -1,46 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsEscCharsetProber.h"
#include "nsUniversalDetector.h"
nsEscCharSetProber::nsEscCharSetProber()
{
mCodingSM = new nsCodingStateMachine(&ISO2022JPSMModel);
mState = eDetecting;
mDetectedCharset = nullptr;
}
nsEscCharSetProber::~nsEscCharSetProber(void)
{
}
void nsEscCharSetProber::Reset(void)
{
mState = eDetecting;
mCodingSM->Reset();
mDetectedCharset = nullptr;
}
nsProbingState nsEscCharSetProber::HandleData(const char* aBuf, uint32_t aLen)
{
nsSMState codingState;
uint32_t i;
for ( i = 0; i < aLen && mState == eDetecting; i++)
{
codingState = mCodingSM->NextState(aBuf[i]);
if (codingState == eItsMe)
{
mState = eFoundIt;
mDetectedCharset = mCodingSM->GetCodingStateMachine();
return mState;
}
}
return mState;
}
@@ -1,32 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsEscCharSetProber_h__
#define nsEscCharSetProber_h__
#include "nsCharSetProber.h"
#include "nsCodingStateMachine.h"
#include "nsAutoPtr.h"
class nsEscCharSetProber: public nsCharSetProber {
public:
nsEscCharSetProber();
virtual ~nsEscCharSetProber(void);
nsProbingState HandleData(const char* aBuf, uint32_t aLen);
const char* GetCharSetName() {return mDetectedCharset;}
nsProbingState GetState(void) {return mState;}
void Reset(void);
float GetConfidence(void){return (float)0.99;}
protected:
void GetDistribution(uint32_t aCharLen, const char* aStr);
nsAutoPtr<nsCodingStateMachine> mCodingSM;
nsProbingState mState;
const char * mDetectedCharset;
};
#endif /* nsEscCharSetProber_h__ */
@@ -1,63 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCodingStateMachine.h"
static const uint32_t ISO2022JP_cls [ 256 / 8 ] = {
PCK4BITS(2,0,0,0,0,0,0,0), // 00 - 07
PCK4BITS(0,0,0,0,0,0,2,2), // 08 - 0f
PCK4BITS(0,0,0,0,0,0,0,0), // 10 - 17
PCK4BITS(0,0,0,1,0,0,0,0), // 18 - 1f
PCK4BITS(0,0,0,0,7,0,0,0), // 20 - 27
PCK4BITS(3,0,0,0,0,0,0,0), // 28 - 2f
PCK4BITS(0,0,0,0,0,0,0,0), // 30 - 37
PCK4BITS(0,0,0,0,0,0,0,0), // 38 - 3f
PCK4BITS(6,0,4,0,8,0,0,0), // 40 - 47
PCK4BITS(0,9,5,0,0,0,0,0), // 48 - 4f
PCK4BITS(0,0,0,0,0,0,0,0), // 50 - 57
PCK4BITS(0,0,0,0,0,0,0,0), // 58 - 5f
PCK4BITS(0,0,0,0,0,0,0,0), // 60 - 67
PCK4BITS(0,0,0,0,0,0,0,0), // 68 - 6f
PCK4BITS(0,0,0,0,0,0,0,0), // 70 - 77
PCK4BITS(0,0,0,0,0,0,0,0), // 78 - 7f
PCK4BITS(2,2,2,2,2,2,2,2), // 80 - 87
PCK4BITS(2,2,2,2,2,2,2,2), // 88 - 8f
PCK4BITS(2,2,2,2,2,2,2,2), // 90 - 97
PCK4BITS(2,2,2,2,2,2,2,2), // 98 - 9f
PCK4BITS(2,2,2,2,2,2,2,2), // a0 - a7
PCK4BITS(2,2,2,2,2,2,2,2), // a8 - af
PCK4BITS(2,2,2,2,2,2,2,2), // b0 - b7
PCK4BITS(2,2,2,2,2,2,2,2), // b8 - bf
PCK4BITS(2,2,2,2,2,2,2,2), // c0 - c7
PCK4BITS(2,2,2,2,2,2,2,2), // c8 - cf
PCK4BITS(2,2,2,2,2,2,2,2), // d0 - d7
PCK4BITS(2,2,2,2,2,2,2,2), // d8 - df
PCK4BITS(2,2,2,2,2,2,2,2), // e0 - e7
PCK4BITS(2,2,2,2,2,2,2,2), // e8 - ef
PCK4BITS(2,2,2,2,2,2,2,2), // f0 - f7
PCK4BITS(2,2,2,2,2,2,2,2) // f8 - ff
};
static const uint32_t ISO2022JP_st [ 9] = {
PCK4BITS(eStart, 3,eError,eStart,eStart,eStart,eStart,eStart),//00-07
PCK4BITS(eStart,eStart,eError,eError,eError,eError,eError,eError),//08-0f
PCK4BITS(eError,eError,eError,eError,eItsMe,eItsMe,eItsMe,eItsMe),//10-17
PCK4BITS(eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eItsMe,eError,eError),//18-1f
PCK4BITS(eError, 5,eError,eError,eError, 4,eError,eError),//20-27
PCK4BITS(eError,eError,eError, 6,eItsMe,eError,eItsMe,eError),//28-2f
PCK4BITS(eError,eError,eError,eError,eError,eError,eItsMe,eItsMe),//30-37
PCK4BITS(eError,eError,eError,eItsMe,eError,eError,eError,eError),//38-3f
PCK4BITS(eError,eError,eError,eError,eItsMe,eError,eStart,eStart) //40-47
};
static const uint32_t ISO2022JPCharLenTable[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
const SMModel ISO2022JPSMModel = {
{eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_cls },
10,
{eIdxSft4bits, eSftMsk4bits, eBitSft4bits, eUnitMsk4bits, ISO2022JP_st },
CHAR_LEN_TABLE(ISO2022JPCharLenTable),
"ISO-2022-JP",
};
@@ -8,7 +8,6 @@
#include "nsUniversalDetector.h"
#include "nsMBCSGroupProber.h"
#include "nsEscCharsetProber.h"
#include "nsLatin1Prober.h"
nsUniversalDetector::nsUniversalDetector()
@@ -16,7 +15,6 @@ nsUniversalDetector::nsUniversalDetector()
mDone = false;
mBestGuess = -1; //illegal value as signal
mInTag = false;
mEscCharSetProber = nullptr;
mStart = true;
mDetectedCharset = nullptr;
@@ -33,8 +31,6 @@ nsUniversalDetector::~nsUniversalDetector()
{
for (int32_t i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
delete mCharSetProbers[i];
delete mEscCharSetProber;
}
void
@@ -50,9 +46,6 @@ nsUniversalDetector::Reset()
mInputState = ePureAscii;
mLastChar = '\0';
if (mEscCharSetProber)
mEscCharSetProber->Reset();
uint32_t i;
for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
if (mCharSetProbers[i])
@@ -117,12 +110,6 @@ nsresult nsUniversalDetector::HandleData(const char* aBuf, uint32_t aLen)
//adjust state
mInputState = eHighbyte;
//kill mEscCharSetProber if it is active
if (mEscCharSetProber) {
delete mEscCharSetProber;
mEscCharSetProber = nullptr;
}
//start multibyte and singlebyte charset prober
if (nullptr == mCharSetProbers[0])
{
@@ -140,12 +127,6 @@ nsresult nsUniversalDetector::HandleData(const char* aBuf, uint32_t aLen)
}
else
{
//ok, just pure ascii so far
if ((ePureAscii == mInputState) && (aBuf[i] == '\033'))
{
//found escape character
mInputState = eEscAscii;
}
mLastChar = aBuf[i];
}
}
@@ -153,19 +134,6 @@ nsresult nsUniversalDetector::HandleData(const char* aBuf, uint32_t aLen)
nsProbingState st;
switch (mInputState)
{
case eEscAscii:
if (nullptr == mEscCharSetProber) {
mEscCharSetProber = new nsEscCharSetProber();
if (nullptr == mEscCharSetProber)
return NS_ERROR_OUT_OF_MEMORY;
}
st = mEscCharSetProber->HandleData(aBuf, aLen);
if (st == eFoundIt)
{
mDone = true;
mDetectedCharset = mEscCharSetProber->GetCharSetName();
}
break;
case eHighbyte:
for (i = 0; i < NUM_OF_CHARSET_PROBERS; i++)
{
@@ -231,8 +199,6 @@ void nsUniversalDetector::DataEnd()
Report(mCharSetProbers[maxProber]->GetCharSetName());
}
break;
case eEscAscii:
break;
default:
;
}
@@ -12,8 +12,7 @@ class nsCharSetProber;
typedef enum {
ePureAscii = 0,
eEscAscii = 1,
eHighbyte = 2
eHighbyte = 1
} nsInputState;
class nsUniversalDetector {
@@ -37,7 +36,6 @@ protected:
uint32_t mLanguageFilter;
nsCharSetProber *mCharSetProbers[NUM_OF_CHARSET_PROBERS];
nsCharSetProber *mEscCharSetProber;
};
#endif
+120 -105
View File
@@ -805,6 +805,10 @@ cairo_cff_font_read_cid_fontdict (cairo_cff_font_t *font, unsigned char *ptr)
}
operand = decode_integer (operand, &size);
decode_integer (operand, &offset);
if (unlikely (offset < 0 || (unsigned long)offset > font->data_length)) {
status = CAIRO_INT_STATUS_UNSUPPORTED;
goto fail;
}
status = cff_dict_init (&font->fd_private_dict[i]);
if (unlikely (status))
goto fail;
@@ -866,6 +870,8 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
operand = cff_dict_get_operands (font->top_dict, CHARSTRINGS_OP, &size);
decode_integer (operand, &offset);
p = font->data + offset;
if (unlikely (p < font->data || p > font->data_end))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = cff_index_read (&font->charstrings_index, &p, font->data_end);
if (unlikely (status))
goto fail;
@@ -874,49 +880,58 @@ cairo_cff_font_read_top_dict (cairo_cff_font_t *font)
if (font->is_cid) {
operand = cff_dict_get_operands (font->top_dict, FDSELECT_OP, &size);
decode_integer (operand, &offset);
status = cairo_cff_font_read_fdselect (font, font->data + offset);
if (unlikely (status))
goto fail;
p = font->data + offset;
if (unlikely (p < font->data || p > font->data_end))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = cairo_cff_font_read_fdselect (font, p);
if (unlikely (status))
goto fail;
operand = cff_dict_get_operands (font->top_dict, FDARRAY_OP, &size);
decode_integer (operand, &offset);
status = cairo_cff_font_read_cid_fontdict (font, font->data + offset);
if (unlikely (status))
goto fail;
p = font->data + offset;
if (unlikely (p < font->data || p > font->data_end))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = cairo_cff_font_read_cid_fontdict (font, p);
if (unlikely (status))
goto fail;
} else {
operand = cff_dict_get_operands (font->top_dict, PRIVATE_OP, &size);
operand = decode_integer (operand, &size);
decode_integer (operand, &offset);
p = font->data + offset;
if (unlikely (p < font->data || p > font->data_end))
return CAIRO_INT_STATUS_UNSUPPORTED;
status = cairo_cff_font_read_private_dict (font,
font->private_dict,
&font->local_sub_index,
font->data + offset,
size);
if (unlikely (status))
goto fail;
&font->local_sub_index,
p,
size);
if (unlikely (status))
goto fail;
}
/* Use maximum sized encoding to reserve space for later modification. */
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (font->top_dict,
CHARSTRINGS_OP, buf, end_buf - buf);
CHARSTRINGS_OP, buf, end_buf - buf);
if (unlikely (status))
goto fail;
goto fail;
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
FDSELECT_OP, buf, end_buf - buf);
if (unlikely (status))
goto fail;
goto fail;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
FDARRAY_OP, buf, end_buf - buf);
if (unlikely (status))
goto fail;
goto fail;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
CHARSET_OP, buf, end_buf - buf);
if (unlikely (status))
goto fail;
goto fail;
cff_dict_remove (font->top_dict, ENCODING_OP);
cff_dict_remove (font->top_dict, PRIVATE_OP);
@@ -985,26 +1000,26 @@ cairo_cff_font_set_ros_strings (cairo_cff_font_t *font)
(unsigned char *)registry,
strlen(registry));
if (unlikely (status))
return status;
return status;
sid2 = NUM_STD_STRINGS + _cairo_array_num_elements (&font->strings_subset_index);
status = cff_index_append_copy (&font->strings_subset_index,
(unsigned char *)ordering,
strlen(ordering));
strlen(ordering));
if (unlikely (status))
return status;
return status;
p = encode_integer (buf, sid1);
p = encode_integer (p, sid2);
p = encode_integer (p, 0);
status = cff_dict_set_operands (font->top_dict, ROS_OP, buf, p - buf);
if (unlikely (status))
return status;
return status;
p = encode_integer (buf, font->scaled_font_subset->num_glyphs);
status = cff_dict_set_operands (font->top_dict, CIDCOUNT_OP, buf, p - buf);
if (unlikely (status))
return status;
return status;
return CAIRO_STATUS_SUCCESS;
}
@@ -1038,7 +1053,7 @@ cairo_cff_font_subset_dict_string(cairo_cff_font_t *font,
p = encode_integer (buf, sid);
status = cff_dict_set_operands (dict, operator, buf, p - buf);
if (unlikely (status))
return status;
return status;
return CAIRO_STATUS_SUCCESS;
}
@@ -1101,19 +1116,19 @@ cairo_cff_font_subset_fontdict (cairo_cff_font_t *font)
font->fdselect_subset = calloc (font->scaled_font_subset->num_glyphs,
sizeof (int));
if (unlikely (font->fdselect_subset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map = calloc (font->num_fontdicts, sizeof (int));
if (unlikely (font->fd_subset_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = calloc (font->num_fontdicts, sizeof (int));
if (unlikely (font->private_dict_offset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
reverse_map = calloc (font->num_fontdicts, sizeof (int));
if (unlikely (reverse_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
for (i = 0; i < font->num_fontdicts; i++)
reverse_map[i] = -1;
@@ -1143,22 +1158,22 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
font->num_fontdicts = 1;
font->fd_dict = malloc (sizeof (cairo_hash_table_t *));
if (unlikely (font->fd_dict == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
if (cff_dict_init (&font->fd_dict[0])) {
free (font->fd_dict);
font->fd_dict = NULL;
font->num_fontdicts = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
free (font->fd_dict);
font->fd_dict = NULL;
font->num_fontdicts = 0;
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
}
font->fd_subset_map = malloc (sizeof (int));
if (unlikely (font->fd_subset_map == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->private_dict_offset = malloc (sizeof (int));
if (unlikely (font->private_dict_offset == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->fd_subset_map[0] = 0;
font->num_subset_fontdicts = 1;
@@ -1169,7 +1184,7 @@ cairo_cff_font_create_cid_fontdict (cairo_cff_font_t *font)
end_buf = encode_integer_max (end_buf, 0);
status = cff_dict_set_operands (font->fd_dict[0], PRIVATE_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
return CAIRO_STATUS_SUCCESS;
}
@@ -1208,7 +1223,7 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
status = cairo_cff_font_set_ros_strings (font);
if (unlikely (status))
return status;
return status;
status = cairo_cff_font_subset_charstrings (font);
if (unlikely (status))
@@ -1219,7 +1234,7 @@ cairo_cff_font_subset_font (cairo_cff_font_t *font)
else
status = cairo_cff_font_create_cid_fontdict (font);
if (unlikely (status))
return status;
return status;
status = cairo_cff_font_subset_strings (font);
if (unlikely (status))
@@ -1271,7 +1286,7 @@ cairo_cff_font_write_name (cairo_cff_font_t *font)
(unsigned char *) font->subset_font_name,
strlen(font->subset_font_name));
if (unlikely (status))
goto FAIL;
goto FAIL;
status = cff_index_write (&index, &font->output);
if (unlikely (status))
@@ -1464,9 +1479,9 @@ cairo_cff_font_write_cid_fontdict (cairo_cff_font_t *font)
if (unlikely (status))
return status;
offset_array_ptr = (uint32_t *) _cairo_array_index (&font->output, offset_array);
offset_array_ptr = (uint32_t *) _cairo_array_index (&font->output, offset_array);
*offset_array_ptr = cpu_to_be32(_cairo_array_num_elements (&font->output) - offset_base);
offset_array += sizeof(uint32_t);
offset_array += sizeof(uint32_t);
}
return CAIRO_STATUS_SUCCESS;
@@ -1566,15 +1581,15 @@ cairo_cff_font_write_cid_private_dict_and_local_sub (cairo_cff_font_t *font)
0,
font->fd_dict[0],
font->private_dict);
if (unlikely (status))
return status;
if (unlikely (status))
return status;
status = cairo_cff_font_write_local_sub (font,
0,
font->private_dict,
&font->local_sub_index);
if (unlikely (status))
return status;
if (unlikely (status))
return status;
}
return CAIRO_STATUS_SUCCESS;
@@ -1698,7 +1713,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
backend = scaled_font_subset->scaled_font->backend;
if (!backend->load_truetype_table)
return CAIRO_INT_STATUS_UNSUPPORTED;
return CAIRO_INT_STATUS_UNSUPPORTED;
data_length = 0;
status = backend->load_truetype_table( scaled_font_subset->scaled_font,
@@ -1736,12 +1751,12 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
if (unlikely (status))
goto fail2;
goto fail2;
font->subset_font_name = strdup (subset_name);
if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
goto fail2;
}
font->x_min = (int16_t) be16_to_cpu (head.x_min);
font->y_min = (int16_t) be16_to_cpu (head.y_min);
@@ -1755,18 +1770,18 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
font->font_name = NULL;
status = _cairo_truetype_read_font_name (scaled_font_subset->scaled_font,
&font->ps_name,
&font->font_name);
&font->ps_name,
&font->font_name);
if (_cairo_status_is_error (status))
goto fail3;
goto fail3;
/* If the PS name is not found, create a CairoFont-x-y name. */
if (font->ps_name == NULL) {
font->ps_name = malloc (30);
if (unlikely (font->ps_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
}
snprintf(font->ps_name, 30, "CairoFont-%u-%u",
scaled_font_subset->font_id,
@@ -1781,7 +1796,7 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
status = cairo_cff_font_create_set_widths (font);
if (unlikely (status))
goto fail5;
goto fail5;
font->data_length = data_length;
font->data = malloc (data_length);
@@ -1799,11 +1814,11 @@ _cairo_cff_font_create (cairo_scaled_font_subset_t *scaled_font_subset,
status = cff_dict_init (&font->top_dict);
if (unlikely (status))
goto fail6;
goto fail6;
status = cff_dict_init (&font->private_dict);
if (unlikely (status))
goto fail7;
goto fail7;
cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index);
@@ -1831,7 +1846,7 @@ fail5:
free (font->widths);
fail4:
if (font->font_name)
free (font->font_name);
free (font->font_name);
fail3:
free (font->subset_font_name);
fail2:
@@ -1848,7 +1863,7 @@ cairo_cff_font_destroy (cairo_cff_font_t *font)
free (font->widths);
if (font->font_name)
free (font->font_name);
free (font->font_name);
free (font->ps_name);
free (font->subset_font_name);
_cairo_array_fini (&font->output);
@@ -1902,7 +1917,7 @@ cairo_cff_font_destroy (cairo_cff_font_t *font)
cairo_status_t
_cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
const char *subset_name,
const char *subset_name,
cairo_scaled_font_subset_t *font_subset)
{
cairo_cff_font_t *font = NULL; /* squelch bogus compiler warning */
@@ -1913,32 +1928,32 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
status = _cairo_cff_font_create (font_subset, &font, subset_name);
if (unlikely (status))
return status;
return status;
status = cairo_cff_font_generate (font, &data, &length);
if (unlikely (status))
goto fail1;
goto fail1;
cff_subset->ps_name = strdup (font->ps_name);
if (unlikely (cff_subset->ps_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
}
if (font->font_name) {
cff_subset->font_name = strdup (font->font_name);
if (cff_subset->font_name == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
cff_subset->font_name = strdup (font->font_name);
if (cff_subset->font_name == NULL) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
} else {
cff_subset->font_name = NULL;
cff_subset->font_name = NULL;
}
cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs);
if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
cff_subset->widths[i] = (double)font->widths[i]/font->units_per_em;
@@ -1952,8 +1967,8 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
cff_subset->data = malloc (length);
if (unlikely (cff_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
memcpy (cff_subset->data, data, length);
@@ -1967,7 +1982,7 @@ _cairo_cff_subset_init (cairo_cff_subset_t *cff_subset,
free (cff_subset->widths);
fail3:
if (cff_subset->font_name)
free (cff_subset->font_name);
free (cff_subset->font_name);
fail2:
free (cff_subset->ps_name);
fail1:
@@ -1981,7 +1996,7 @@ _cairo_cff_subset_fini (cairo_cff_subset_t *subset)
{
free (subset->ps_name);
if (subset->font_name)
free (subset->font_name);
free (subset->font_name);
free (subset->widths);
free (subset->data);
}
@@ -1996,7 +2011,7 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
font = calloc (1, sizeof (cairo_cff_font_t));
if (unlikely (font == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
font->backend = NULL;
font->scaled_font_subset = scaled_font_subset;
@@ -2004,18 +2019,18 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
_cairo_array_init (&font->output, sizeof (char));
status = _cairo_array_grow_by (&font->output, 4096);
if (unlikely (status))
goto fail1;
goto fail1;
font->subset_font_name = strdup (subset_name);
if (unlikely (font->subset_font_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail1;
goto fail1;
}
font->ps_name = strdup (subset_name);
if (unlikely (font->ps_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
goto fail2;
}
font->font_name = NULL;
@@ -2038,11 +2053,11 @@ _cairo_cff_font_fallback_create (cairo_scaled_font_subset_t *scaled_font_subset
status = cff_dict_init (&font->top_dict);
if (unlikely (status))
goto fail4;
goto fail4;
status = cff_dict_init (&font->private_dict);
if (unlikely (status))
goto fail5;
goto fail5;
cff_index_init (&font->strings_index);
cff_index_init (&font->charstrings_index);
@@ -2068,7 +2083,7 @@ fail4:
free (font->widths);
fail3:
if (font->font_name)
free (font->font_name);
free (font->font_name);
free (font->ps_name);
fail2:
free (font->subset_font_name);
@@ -2105,39 +2120,39 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
end_buf = encode_integer (end_buf, type2_subset->x_max);
end_buf = encode_integer (end_buf, type2_subset->y_max);
status = cff_dict_set_operands (font->top_dict,
FONTBBOX_OP, buf, end_buf - buf);
FONTBBOX_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
end_buf = encode_integer_max (buf, 0);
status = cff_dict_set_operands (font->top_dict,
CHARSTRINGS_OP, buf, end_buf - buf);
CHARSTRINGS_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
status = cff_dict_set_operands (font->top_dict,
FDSELECT_OP, buf, end_buf - buf);
FDSELECT_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
status = cff_dict_set_operands (font->top_dict,
FDARRAY_OP, buf, end_buf - buf);
FDARRAY_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
status = cff_dict_set_operands (font->top_dict,
CHARSET_OP, buf, end_buf - buf);
CHARSET_OP, buf, end_buf - buf);
if (unlikely (status))
return status;
return status;
status = cairo_cff_font_set_ros_strings (font);
if (unlikely (status))
return status;
return status;
/* Create CID FD dictionary */
status = cairo_cff_font_create_cid_fontdict (font);
if (unlikely (status))
return status;
return status;
/* Create charstrings */
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++) {
@@ -2163,7 +2178,7 @@ cairo_cff_font_fallback_generate (cairo_cff_font_t *font,
cairo_status_t
_cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
const char *subset_name,
const char *subset_name,
cairo_scaled_font_subset_t *font_subset)
{
cairo_cff_font_t *font = NULL; /* squelch bogus compiler warning */
@@ -2175,27 +2190,27 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
status = _cairo_cff_font_fallback_create (font_subset, &font, subset_name);
if (unlikely (status))
return status;
return status;
status = _cairo_type2_charstrings_init (&type2_subset, font_subset);
if (unlikely (status))
goto fail1;
goto fail1;
status = cairo_cff_font_fallback_generate (font, &type2_subset, &data, &length);
if (unlikely (status))
goto fail2;
goto fail2;
cff_subset->font_name = NULL;
cff_subset->ps_name = strdup (font->ps_name);
if (unlikely (cff_subset->ps_name == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail2;
}
cff_subset->widths = calloc (sizeof (double), font->scaled_font_subset->num_glyphs);
if (unlikely (cff_subset->widths == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail3;
}
for (i = 0; i < font->scaled_font_subset->num_glyphs; i++)
@@ -2210,8 +2225,8 @@ _cairo_cff_fallback_init (cairo_cff_subset_t *cff_subset,
cff_subset->data = malloc (length);
if (unlikely (cff_subset->data == NULL)) {
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
goto fail4;
}
memcpy (cff_subset->data, data, length);
-4
View File
@@ -5,8 +5,6 @@
#ifndef CAIRO_DEPRECATED_H
#define CAIRO_DEPRECATED_H
#define CAIRO_FONT_TYPE_ATSUI CAIRO_FONT_TYPE_QUARTZ
/* Obsolete functions. These definitions exist to coerce the compiler
* into providing a little bit of guidance with its error
* messages. The idea is to help users port their old code without
@@ -59,8 +57,6 @@
#define cairo_ps_surface_set_dpi cairo_ps_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_pdf_surface_set_dpi cairo_pdf_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_svg_surface_set_dpi cairo_svg_surface_set_dpi_REPLACED_BY_cairo_surface_set_fallback_resolution
#define cairo_atsui_font_face_create_for_atsu_font_id cairo_atsui_font_face_create_for_atsu_font_id_REPLACED_BY_cairo_quartz_font_face_create_for_atsu_font_id
#define cairo_current_path cairo_current_path_DEPRECATED_BY_cairo_copy_path
#define cairo_current_path_flat cairo_current_path_flat_DEPRECATED_BY_cairo_copy_path_flat
#define cairo_get_path cairo_get_path_DEPRECATED_BY_cairo_copy_path
-42
View File
@@ -767,45 +767,3 @@ _cairo_quartz_scaled_font_get_ct_font_ref (cairo_scaled_font_t *abstract_font)
return ffont->ctFont;
}
#if !defined(__LP64__) && !TARGET_OS_IPHONE
/*
* compat with old ATSUI backend
*/
/**
* cairo_quartz_font_face_create_for_atsu_font_id
* @font_id: an ATSUFontID for the font.
*
* Creates a new font for the Quartz font backend based on an
* #ATSUFontID. This font can then be used with
* cairo_set_font_face() or cairo_scaled_font_create().
*
* Return value: a newly created #cairo_font_face_t. Free with
* cairo_font_face_destroy() when you are done using it.
*
* Since: 1.6
**/
cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
ATSFontRef atsFont = FMGetATSFontRefFromFont (font_id);
CGFontRef cgFont = CGFontCreateWithPlatformFont (&atsFont);
cairo_font_face_t *ff;
ff = cairo_quartz_font_face_create_for_cgfont (cgFont);
CGFontRelease (cgFont);
return ff;
}
/* This is the old name for the above function, exported for compat purposes */
cairo_font_face_t *cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id);
cairo_font_face_t *
cairo_atsui_font_face_create_for_atsu_font_id (ATSUFontID font_id)
{
return cairo_quartz_font_face_create_for_atsu_font_id (font_id);
}
#endif
-5
View File
@@ -63,11 +63,6 @@ cairo_quartz_surface_get_image (cairo_surface_t *surface);
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_cgfont (CGFontRef font);
#if !defined(__LP64__) && !TARGET_OS_IPHONE
cairo_public cairo_font_face_t *
cairo_quartz_font_face_create_for_atsu_font_id (ATSUFontID font_id);
#endif
#endif /* CAIRO_HAS_QUARTZ_FONT */
CAIRO_END_DECLS
-2
View File
@@ -213,8 +213,6 @@
#define cairo_qpainter_surface_create_with_qpixmap _moz_cairo_qpainter_surface_create_with_qpixmap
#define cairo_qpainter_surface_get_image _moz_cairo_qpainter_surface_get_image
#define cairo_qpainter_surface_get_qimage _moz_cairo_qpainter_surface_get_qimage
#define cairo_qpainter_surface_get_qpainter _moz_cairo_qpainter_surface_get_qpainter
#define cairo_quartz_font_face_create_for_atsu_font_id _moz_cairo_quartz_font_face_create_for_atsu_font_id
#define cairo_quartz_font_face_create_for_cgfont _moz_cairo_quartz_font_face_create_for_cgfont
#define cairo_quartz_image_surface_create _moz_cairo_quartz_image_surface_create
#define cairo_quartz_image_surface_get_image _moz_cairo_quartz_image_surface_get_image
+5 -1
View File
@@ -50,6 +50,10 @@
#include "gfxWindowsPlatform.h"
#endif
#ifdef XP_MACOSX
#include <AvailabilityMacros.h>
#endif
#include "harfbuzz/hb.h"
#include "harfbuzz/hb-ot.h"
#include "graphite2/Font.h"
@@ -884,7 +888,7 @@ gfxFont::GetGlyphHAdvance(DrawTarget* aDrawTarget, uint16_t aGID)
if (!SetupCairoFont(aDrawTarget)) {
return 0;
}
#if !defined(XP_MACOSX) || (defined(XP_MACOSX) && !(defined(__ppc__) || defined(__ppc64__)))
#if !defined(XP_MACOSX) || (defined(XP_MACOSX) && (defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6))
if (ProvidesGlyphWidths()) {
return GetGlyphWidth(*aDrawTarget, aGID) / 65536.0;
}
+5 -1
View File
@@ -19,6 +19,10 @@
#include "unicode/unorm.h"
#include "unicode/utext.h"
#ifdef XP_MACOSX
#include <AvailabilityMacros.h>
#endif
static const UNormalizer2 * sNormalizer = nullptr;
#include <algorithm>
@@ -327,7 +331,7 @@ gfxHarfBuzzShaper::GetGlyphHAdvance(hb_codepoint_t glyph) const
glyph = mNumLongHMetrics - 1;
}
#if defined(XP_MACOSX) && (defined(__ppc__) || defined(__ppc64__))
#if defined(XP_MACOSX) && !(defined(MAC_OS_X_VERSION_10_6) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6))
if (MOZ_UNLIKELY(mFont->mSpacingKludge && glyph == mFont->GetSpaceGlyph())) {
// This is one of the fonts where the spacing went awry,
// invariably on an nbsp character that escaped into the run.
+6 -15
View File
@@ -23,6 +23,8 @@
#include "cairo-quartz.h"
#include "nsCocoaFeatures.h"
using namespace mozilla;
using namespace mozilla::gfx;
@@ -474,25 +476,11 @@ gfxMacFont::InitMetrics()
// If we are dealing with a weird font (Apple is notorious), we could have
// the situation where we wind up with space == maxAdvance due to a 10.4 bug.
// In that case, kludge a reasonable upper limit (TenFourFox issue 355).
//fprintf(stderr, "glyph: %i sB=%s width=%f avg=%f max=%f cgf=%f mAS=%f\n", glyphID, (IsSyntheticBold() ? "Y" : "n"), mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.maxAdvance, cgConvFactor, mAdjustedSize);
if (MOZ_UNLIKELY(!hasX && mMetrics.spaceWidth >= mMetrics.maxAdvance)) {
mMetrics.spaceWidth = std::min((float)mMetrics.emDescent * 1.4f,
(float)mMetrics.maxAdvance * 0.4f);
mSpacingKludge = true;
}
//fprintf(stderr, "glyph: %i sB=%s ......%f avg=%f max=%f cgf=%f mAS=%f\n", glyphID, (IsSyntheticBold() ? "Y" : "n"), mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.maxAdvance, cgConvFactor, mAdjustedSize);
#if 0
fprintf (stderr, "Font: %p (%s) size: %f\n", this,
NS_ConvertUTF16toUTF8(GetName()).get(), mStyle.size);
// fprintf (stderr, " fbounds.origin.x %f y %f size.width %f height %f\n", fbounds.origin.x, fbounds.origin.y, fbounds.size.width, fbounds.size.height);
fprintf (stderr, " emHeight: %f emAscent: %f emDescent: %f\n", mMetrics.emHeight, mMetrics.emAscent, mMetrics.emDescent);
fprintf (stderr, " maxAscent: %f maxDescent: %f maxAdvance: %f\n", mMetrics.maxAscent, mMetrics.maxDescent, mMetrics.maxAdvance);
fprintf (stderr, " internalLeading: %f externalLeading: %f\n", mMetrics.internalLeading, mMetrics.externalLeading);
fprintf (stderr, " spaceWidth: %f aveCharWidth: %f xHeight: %f capHeight: %f\n", mMetrics.spaceWidth, mMetrics.aveCharWidth, mMetrics.xHeight, mMetrics.capHeight);
fprintf (stderr, " uOff: %f uSize: %f stOff: %f stSize: %f\n", mMetrics.underlineOffset, mMetrics.underlineSize, mMetrics.strikeoutOffset, mMetrics.strikeoutSize);
#endif
}
gfxFloat
@@ -527,7 +515,10 @@ gfxMacFont::CreateCTFontFromCGFontWithVariations(CGFontRef aCGFont,
CGFloat aSize,
CTFontDescriptorRef aFontDesc)
{
CFDictionaryRef variations = ::CGFontCopyVariations(aCGFont);
// Avoid calling potentially buggy variation APIs on pre-Sierra macOS
// versions (see bug 1331683)
CFDictionaryRef variations = nsCocoaFeatures::OnSierraOrLater() ?
::CGFontCopyVariations(aCGFont) : 0;
CTFontRef ctFont;
if (variations) {
CFDictionaryRef varAttr =
+4 -1
View File
@@ -42,7 +42,10 @@ public:
// with embedded color bitmaps (Apple Color Emoji), as Core Text renders
// the glyphs with non-linear scaling at small pixel sizes.
virtual bool ProvidesGlyphWidths() const override {
return mVariationFont ||
return
#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
mVariationFont ||
#endif
mFontEntry->HasFontTable(TRUETYPE_TAG('s','b','i','x'));
}
+12 -40
View File
@@ -147,7 +147,6 @@ gfxTextRun::gfxTextRun(const gfxTextRunFactory::Parameters *aParams,
: gfxShapedText(aLength, aFlags, aParams->mAppUnitsPerDevUnit)
, mUserData(aParams->mUserData)
, mFontGroup(aFontGroup)
, mReleasedFontGroup(false)
, mShapingState(eShapingState_Normal)
{
NS_ASSERTION(mAppUnitsPerDevUnit > 0, "Invalid app unit scale");
@@ -184,30 +183,18 @@ gfxTextRun::~gfxTextRun()
mFlags = 0xFFFFFFFF;
#endif
// The cached ellipsis textrun (if any) in a fontgroup will have already
// been told to release its reference to the group, so we mustn't do that
// again here.
if (!mReleasedFontGroup) {
#ifdef DEBUG
gfxTextPerfMetrics *tp = mFontGroup->GetTextPerfMetrics();
if (tp) {
tp->current.textrunDestr++;
}
#endif
NS_RELEASE(mFontGroup);
gfxTextPerfMetrics* tp = mFontGroup->GetTextPerfMetrics();
if (tp) {
tp->current.textrunDestr++;
}
#endif
NS_RELEASE(mFontGroup);
MOZ_COUNT_DTOR(gfxTextRun);
}
void
gfxTextRun::ReleaseFontGroup()
{
NS_ASSERTION(!mReleasedFontGroup, "doubly released!");
NS_RELEASE(mFontGroup);
mReleasedFontGroup = true;
}
bool
gfxTextRun::SetPotentialLineBreaks(Range aRange, const uint8_t* aBreakBefore)
{
@@ -2541,17 +2528,11 @@ gfxFontGroup::InitScriptRun(DrawTarget* aDrawTarget,
}
}
gfxTextRun *
gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, uint32_t aFlags,
LazyReferenceDrawTargetGetter& aRefDrawTargetGetter)
{
already_AddRefed<gfxTextRun>
gfxFontGroup::MakeEllipsisTextRun(int32_t aAppUnitsPerDevPixel, uint32_t aFlags,
DrawTarget* aRefDrawTarget) {
MOZ_ASSERT(!(aFlags & ~TEXT_ORIENT_MASK),
"flags here should only be used to specify orientation");
if (mCachedEllipsisTextRun &&
(mCachedEllipsisTextRun->GetFlags() & TEXT_ORIENT_MASK) == aFlags &&
mCachedEllipsisTextRun->GetAppUnitsPerDevUnit() == aAppUnitsPerDevPixel) {
return mCachedEllipsisTextRun.get();
}
// Use a Unicode ellipsis if the font supports it,
// otherwise use three ASCII periods as fallback.
@@ -2562,20 +2543,11 @@ gfxFontGroup::GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, uint32_t aFlags,
: nsDependentString(kASCIIPeriodsChar,
ArrayLength(kASCIIPeriodsChar) - 1);
RefPtr<DrawTarget> refDT = aRefDrawTargetGetter.GetRefDrawTarget();
Parameters params = {
refDT, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel
aRefDrawTarget, nullptr, nullptr, nullptr, 0, aAppUnitsPerDevPixel
};
mCachedEllipsisTextRun =
MakeTextRun(ellipsis.get(), ellipsis.Length(), &params,
aFlags | TEXT_IS_PERSISTENT, nullptr);
if (!mCachedEllipsisTextRun) {
return nullptr;
}
// don't let the presence of a cached ellipsis textrun prolong the
// fontgroup's life
mCachedEllipsisTextRun->ReleaseFontGroup();
return mCachedEllipsisTextRun.get();
return MakeTextRun(ellipsis.get(), ellipsis.Length(), &params,
aFlags | TEXT_IS_PERSISTENT, nullptr);
}
already_AddRefed<gfxFont>
+5 -18
View File
@@ -755,8 +755,6 @@ private:
bool mSkipDrawing; // true if the font group we used had a user font
// download that's in progress, so we should hide text
// until the download completes (or timeout fires)
bool mReleasedFontGroup; // we already called NS_RELEASE on
// mFontGroup, so don't do it again
// shaping state for handling variant fallback features
// such as subscript/superscript variant glyphs
@@ -897,7 +895,6 @@ public:
mUnderlineOffset = UNDERLINE_OFFSET_NOT_SET;
mSkipDrawing = false;
mHyphenWidth = -1;
mCachedEllipsisTextRun = nullptr;
}
// If there is a user font set, check to see whether the font list or any
@@ -911,17 +908,11 @@ public:
return mSkipDrawing;
}
class LazyReferenceDrawTargetGetter {
public:
virtual already_AddRefed<DrawTarget> GetRefDrawTarget() = 0;
};
// The gfxFontGroup keeps ownership of this textrun.
// It is only guaranteed to exist until the next call to GetEllipsisTextRun
// (which might use a different appUnitsPerDev value or flags) for the font
// group, or until UpdateUserFonts is called, or the fontgroup is destroyed.
// Get it/use it/forget it :) - don't keep a reference that might go stale.
gfxTextRun* GetEllipsisTextRun(int32_t aAppUnitsPerDevPixel, uint32_t aFlags,
LazyReferenceDrawTargetGetter& aRefDrawTargetGetter);
// Make a textrun for the ellipsis character (with fallback to "..." if
// ellipsis is not supported by the font).
already_AddRefed<gfxTextRun> MakeEllipsisTextRun(int32_t aAppUnitsPerDevPixel,
uint32_t aFlags,
DrawTarget* aRefDrawTarget);
protected:
// search through pref fonts for a character, return nullptr if no matching pref font
@@ -1093,10 +1084,6 @@ protected:
gfxTextPerfMetrics *mTextPerf;
// Cache a textrun representing an ellipsis (useful for CSS text-overflow)
// at a specific appUnitsPerDevPixel size and orientation
RefPtr<gfxTextRun> mCachedEllipsisTextRun;
// cache the most recent pref font to avoid general pref font lookup
RefPtr<gfxFontFamily> mLastPrefFamily;
RefPtr<gfxFont> mLastPrefFont;
+1 -1
View File
@@ -446,7 +446,7 @@ for (k = 0; k < 2; k++) {
while ((c = fgetc(f)) != '\n' && c != EOF);
/* issue warning if not a comment */
if (buf[0] != '%') {
fprintf(stderr, "Warning: skipping too long pattern (more than %lu chars)\n", sizeof(buf));
fprintf(stderr, "Warning: skipping too long pattern (more than %zu chars)\n", sizeof(buf));
}
continue;
}
+459 -40
View File
@@ -47,10 +47,12 @@
#include "builtin/AtomicsObject.h"
#include "mozilla/Atomics.h"
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/Unused.h"
#include "builtin/Promise.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "jsnum.h"
@@ -58,7 +60,9 @@
#include "jit/AtomicOperations.h"
#include "jit/InlinableNatives.h"
#include "js/Class.h"
#include "vm/BigIntType.h"
#include "vm/GlobalObject.h"
#include "vm/HelperThreads.h"
#include "vm/Time.h"
#include "vm/TypedArrayObject.h"
#include "wasm/WasmInstance.h"
@@ -121,6 +125,68 @@ GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle<TypedArrayObject*> view,
return true;
}
static bool
IsWaitableTypedArray(Scalar::Type viewType)
{
return viewType == Scalar::Int32 || viewType == Scalar::BigInt64;
}
static uint32_t
GetWaiterByteOffset(Handle<TypedArrayObject*> view, uint32_t offset)
{
return view->byteOffset() + offset * TypedArrayElemSize(view->type());
}
static uint64_t
BigIntToRawBits(Scalar::Type viewType, BigInt* value)
{
if (viewType == Scalar::BigInt64)
return uint64_t(BigInt::toInt64(value));
MOZ_ASSERT(viewType == Scalar::BigUint64);
return BigInt::toUint64(value);
}
static bool
BigIntToRawBits(JSContext* cx, Scalar::Type viewType, HandleValue value, uint64_t* bits)
{
MOZ_ASSERT(Scalar::isBigIntType(viewType));
RootedBigInt bigint(cx, ToBigInt(cx, value));
if (!bigint)
return false;
*bits = BigIntToRawBits(viewType, bigint);
return true;
}
static bool
SetBigIntResult(JSContext* cx, Scalar::Type viewType, uint64_t bits, MutableHandleValue result)
{
MOZ_ASSERT(Scalar::isBigIntType(viewType));
BigInt* bigint = viewType == Scalar::BigInt64
? BigInt::createFromInt64(cx, mozilla::BitwiseCast<int64_t>(bits))
: BigInt::createFromUint64(cx, bits);
if (!bigint)
return false;
result.setBigInt(bigint);
return true;
}
static bool
WaitValueMatches(Handle<TypedArrayObject*> view, uint32_t offset, uint64_t expected)
{
SharedMem<void*> viewData = view->viewDataShared();
if (view->type() == Scalar::BigInt64) {
return jit::AtomicOperations::loadSafeWhenRacy(viewData.cast<uint64_t*>() + offset) ==
expected;
}
return uint32_t(jit::AtomicOperations::loadSafeWhenRacy(viewData.cast<int32_t*>() + offset)) ==
uint32_t(expected);
}
static int32_t
CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate,
SharedMem<void*> viewData, uint32_t offset, bool* badArrayType = nullptr)
@@ -191,6 +257,20 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp)
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
if (Scalar::isBigIntType(view->type())) {
uint64_t oldCandidate;
if (!BigIntToRawBits(cx, view->type(), oldv, &oldCandidate))
return false;
uint64_t newCandidate;
if (!BigIntToRawBits(cx, view->type(), newv, &newCandidate))
return false;
uint64_t result = jit::AtomicOperations::compareExchangeSeqCst(
view->viewDataShared().cast<uint64_t*>() + offset, oldCandidate, newCandidate);
return SetBigIntResult(cx, view->type(), result, r);
}
int32_t oldCandidate;
if (!ToInt32(cx, oldv, &oldCandidate))
return false;
@@ -259,6 +339,22 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp)
r.setNumber(v);
return true;
}
case Scalar::BigInt64: {
int64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<int64_t*>() + offset);
BigInt* bigint = BigInt::createFromInt64(cx, v);
if (!bigint)
return false;
r.setBigInt(bigint);
return true;
}
case Scalar::BigUint64: {
uint64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast<uint64_t*>() + offset);
BigInt* bigint = BigInt::createFromUint64(cx, v);
if (!bigint)
return false;
r.setBigInt(bigint);
return true;
}
default:
return ReportBadArrayType(cx);
}
@@ -337,6 +433,25 @@ ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp)
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
if (Scalar::isBigIntType(view->type())) {
RootedBigInt bigint(cx, ToBigInt(cx, valv));
if (!bigint)
return false;
uint64_t value = BigIntToRawBits(view->type(), bigint);
if (op == DoStore) {
jit::AtomicOperations::storeSeqCst(view->viewDataShared().cast<uint64_t*>() + offset,
value);
r.setBigInt(bigint);
return true;
}
uint64_t result = jit::AtomicOperations::exchangeSeqCst(
view->viewDataShared().cast<uint64_t*>() + offset, value);
return SetBigIntResult(cx, view->type(), result, r);
}
double integerValue;
if (!ToInteger(cx, valv, &integerValue))
return false;
@@ -380,6 +495,24 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
if (Scalar::isBigIntType(view->type())) {
uint64_t value;
if (!BigIntToRawBits(cx, view->type(), valv, &value))
return false;
SharedMem<uint64_t*> addr = view->viewDataShared().cast<uint64_t*>() + offset;
uint64_t old = jit::AtomicOperations::loadSeqCst(addr);
for (;;) {
uint64_t replacement = T::operate64(old, value);
uint64_t observed = jit::AtomicOperations::compareExchangeSeqCst(addr, old,
replacement);
if (observed == old)
return SetBigIntResult(cx, view->type(), old, r);
old = observed;
}
}
int32_t numberValue;
if (!ToInt32(cx, valv, &numberValue))
return false;
@@ -434,6 +567,7 @@ class PerformAdd
public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x + y; }
static uint64_t operate64(uint64_t x, uint64_t y) { return x + y; }
};
bool
@@ -448,6 +582,7 @@ class PerformSub
public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x - y; }
static uint64_t operate64(uint64_t x, uint64_t y) { return x - y; }
};
bool
@@ -462,6 +597,7 @@ class PerformAnd
public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x & y; }
static uint64_t operate64(uint64_t x, uint64_t y) { return x & y; }
};
bool
@@ -476,6 +612,7 @@ class PerformOr
public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x | y; }
static uint64_t operate64(uint64_t x, uint64_t y) { return x | y; }
};
bool
@@ -490,6 +627,7 @@ class PerformXor
public:
INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst)
static int32_t perform(int32_t x, int32_t y) { return x ^ y; }
static uint64_t operate64(uint64_t x, uint64_t y) { return x ^ y; }
};
bool
@@ -693,11 +831,13 @@ js::atomics_cmpxchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t of
namespace js {
class AtomicsWaitAsyncTask;
// Represents one waiting worker.
//
// The type is declared opaque in SharedArrayObject.h. Instances of
// js::FutexWaiter are stack-allocated and linked onto a list across a
// call to FutexRuntime::wait().
// js::FutexWaiter are linked onto a list across a call to FutexRuntime::wait()
// or an async wait task.
//
// The 'waiters' field of the SharedArrayRawBuffer points to the highest
// priority waiter in the list, and lower priority nodes are linked through
@@ -711,14 +851,34 @@ class FutexWaiter
public:
FutexWaiter(uint32_t offset, JSRuntime* rt)
: offset(offset),
kind(Sync),
rt(rt),
asyncTask(nullptr),
lower_pri(nullptr),
back(nullptr)
{
}
uint32_t offset; // int32 element index within the SharedArrayBuffer
FutexWaiter(uint32_t offset, AtomicsWaitAsyncTask* asyncTask)
: offset(offset),
kind(Async),
rt(nullptr),
asyncTask(asyncTask),
lower_pri(nullptr),
back(nullptr)
{
}
bool isWaiting() const;
void notify();
uint32_t offset; // byte offset within the SharedArrayBuffer
enum WaiterKind {
Sync,
Async
} kind;
JSRuntime* rt; // The runtime of the waiter
AtomicsWaitAsyncTask* asyncTask; // The async waiter task, if any
FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters
FutexWaiter* back; // Other direction
};
@@ -742,8 +902,195 @@ class AutoLockFutexAPI
js::UniqueLock<js::Mutex>& unique() { return *unique_; }
};
static void
AddWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter)
{
if (FutexWaiter* waiters = sarb->waiters()) {
waiter->lower_pri = waiters;
waiter->back = waiters->back;
waiters->back->lower_pri = waiter;
waiters->back = waiter;
} else {
waiter->lower_pri = waiter->back = waiter;
sarb->setWaiters(waiter);
}
}
static void
RemoveWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter)
{
if (waiter->lower_pri == waiter) {
sarb->setWaiters(nullptr);
} else {
waiter->lower_pri->back = waiter->back;
waiter->back->lower_pri = waiter->lower_pri;
if (sarb->waiters() == waiter)
sarb->setWaiters(waiter->lower_pri);
}
waiter->lower_pri = nullptr;
waiter->back = nullptr;
}
class AtomicsWaitAsyncTask : public PromiseTask
{
enum class State {
Waiting,
Notified,
TimedOut
};
SharedArrayRawBuffer* sarb_;
FutexWaiter waiter_;
mozilla::Maybe<mozilla::TimeDuration> timeout_;
ConditionVariable cond_;
State state_;
bool isInWaiterList_;
public:
AtomicsWaitAsyncTask(JSContext* cx, Handle<PromiseObject*> promise,
SharedArrayRawBuffer* sarb, uint32_t offset,
mozilla::Maybe<mozilla::TimeDuration>& timeout)
: PromiseTask(cx, promise),
sarb_(sarb),
waiter_(offset, this),
timeout_(timeout),
state_(State::Waiting),
isInWaiterList_(false)
{
}
~AtomicsWaitAsyncTask() {
if (isInWaiterList_) {
AutoLockFutexAPI lock;
if (isInWaiterList_)
removeFromWaiterList();
}
sarb_->dropReference();
}
FutexWaiter* waiter() {
return &waiter_;
}
void setInWaiterList() {
isInWaiterList_ = true;
}
bool isWaiting() const {
return state_ == State::Waiting;
}
void notify() {
MOZ_ASSERT(isWaiting());
state_ = State::Notified;
cond_.notify_all();
}
void execute() override {
AutoLockFutexAPI lock;
const bool isTimed = timeout_.isSome();
auto finalEnd = timeout_.map([](mozilla::TimeDuration& timeout) {
return mozilla::TimeStamp::Now() + timeout;
});
auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0);
while (state_ == State::Waiting) {
if (isTimed) {
auto sliceEnd = finalEnd.map([&](mozilla::TimeStamp& finalEnd) {
auto sliceEnd = mozilla::TimeStamp::Now() + maxSlice;
if (finalEnd < sliceEnd)
sliceEnd = finalEnd;
return sliceEnd;
});
mozilla::Unused << cond_.wait_until(lock.unique(), *sliceEnd);
if (state_ == State::Waiting && mozilla::TimeStamp::Now() >= *finalEnd) {
state_ = State::TimedOut;
break;
}
} else {
cond_.wait(lock.unique());
}
}
if (isInWaiterList_)
removeFromWaiterList();
}
private:
void removeFromWaiterList() {
MOZ_ASSERT(isInWaiterList_);
RemoveWaiter(sarb_, &waiter_);
isInWaiterList_ = false;
}
bool finishPromise(JSContext* cx, Handle<PromiseObject*> promise) override {
RootedValue result(cx);
if (state_ == State::TimedOut)
result.setString(cx->names().futexTimedOut);
else
result.setString(cx->names().futexOK);
return PromiseObject::resolve(cx, promise, result);
}
};
bool
FutexWaiter::isWaiting() const
{
if (kind == Sync)
return rt->fx.isWaiting();
return asyncTask->isWaiting();
}
void
FutexWaiter::notify()
{
if (kind == Sync) {
rt->fx.notify(FutexRuntime::NotifyExplicit);
return;
}
asyncTask->notify();
}
} // namespace js
static bool
GetWaitTimeout(JSContext* cx, HandleValue timeoutv,
mozilla::Maybe<mozilla::TimeDuration>* timeout)
{
timeout->reset();
if (!timeoutv.isUndefined()) {
double timeout_ms;
if (!ToNumber(cx, timeoutv, &timeout_ms))
return false;
if (!mozilla::IsNaN(timeout_ms)) {
if (timeout_ms < 0)
*timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0));
else if (!mozilla::IsInfinite(timeout_ms))
*timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms));
}
}
return true;
}
static bool
CreateWaitAsyncResult(JSContext* cx, bool isAsync, HandleValue value, MutableHandleValue rval)
{
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!obj)
return false;
RootedValue asyncValue(cx, BooleanValue(isAsync));
if (!NativeDefineDataProperty(cx, obj, cx->names().async, asyncValue, JSPROP_ENUMERATE))
return false;
if (!NativeDefineDataProperty(cx, obj, cx->names().value, value, JSPROP_ENUMERATE))
return false;
rval.setObject(*obj);
return true;
}
bool
js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
{
@@ -759,26 +1106,24 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
Rooted<TypedArrayObject*> view(cx, nullptr);
if (!GetSharedTypedArray(cx, objv, &view))
return false;
if (view->type() != Scalar::Int32)
if (!IsWaitableTypedArray(view->type()))
return ReportBadArrayType(cx);
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
int32_t value;
if (!ToInt32(cx, valv, &value))
return false;
mozilla::Maybe<mozilla::TimeDuration> timeout;
if (!timeoutv.isUndefined()) {
double timeout_ms;
if (!ToNumber(cx, timeoutv, &timeout_ms))
uint64_t value = 0;
if (view->type() == Scalar::BigInt64) {
if (!BigIntToRawBits(cx, view->type(), valv, &value))
return false;
if (!mozilla::IsNaN(timeout_ms)) {
if (timeout_ms < 0)
timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0));
else if (!mozilla::IsInfinite(timeout_ms))
timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms));
}
} else {
int32_t int32Value;
if (!ToInt32(cx, valv, &int32Value))
return false;
value = uint32_t(int32Value);
}
mozilla::Maybe<mozilla::TimeDuration> timeout;
if (!GetWaitTimeout(cx, timeoutv, &timeout))
return false;
if (!rt->fx.canWait())
return ReportCannotWait(cx);
@@ -787,8 +1132,7 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
// and it provides the necessary memory fence.
AutoLockFutexAPI lock;
SharedMem<int32_t*> addr = view->viewDataShared().cast<int32_t*>() + offset;
if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) {
if (!WaitValueMatches(view, offset, value)) {
r.setString(cx->names().futexNotEqual);
return true;
}
@@ -796,16 +1140,8 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
FutexWaiter w(offset, rt);
if (FutexWaiter* waiters = sarb->waiters()) {
w.lower_pri = waiters;
w.back = waiters->back;
waiters->back->lower_pri = &w;
waiters->back = &w;
} else {
w.lower_pri = w.back = &w;
sarb->setWaiters(&w);
}
FutexWaiter w(GetWaiterByteOffset(view, offset), rt);
AddWaiter(sarb, &w);
FutexRuntime::WaitResult result = FutexRuntime::FutexOK;
bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result);
@@ -820,17 +1156,98 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp)
}
}
if (w.lower_pri == &w) {
sarb->setWaiters(nullptr);
} else {
w.lower_pri->back = w.back;
w.back->lower_pri = w.lower_pri;
if (sarb->waiters() == &w)
sarb->setWaiters(w.lower_pri);
}
RemoveWaiter(sarb, &w);
return retval;
}
bool
js::atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
HandleValue objv = args.get(0);
HandleValue idxv = args.get(1);
HandleValue valv = args.get(2);
HandleValue timeoutv = args.get(3);
MutableHandleValue r = args.rval();
Rooted<TypedArrayObject*> view(cx, nullptr);
if (!GetSharedTypedArray(cx, objv, &view))
return false;
if (!IsWaitableTypedArray(view->type()))
return ReportBadArrayType(cx);
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
uint64_t value = 0;
if (view->type() == Scalar::BigInt64) {
if (!BigIntToRawBits(cx, view->type(), valv, &value))
return false;
} else {
int32_t int32Value;
if (!ToInt32(cx, valv, &int32Value))
return false;
value = uint32_t(int32Value);
}
mozilla::Maybe<mozilla::TimeDuration> timeout;
if (!GetWaitTimeout(cx, timeoutv, &timeout))
return false;
Rooted<PromiseObject*> promise(cx, PromiseObject::createSkippingExecutor(cx));
if (!promise)
return false;
RootedValue promiseValue(cx, ObjectValue(*promise));
RootedValue result(cx);
if (!CreateWaitAsyncResult(cx, true, promiseValue, &result))
return false;
Rooted<SharedArrayBufferObject*> sab(cx, view->bufferShared());
SharedArrayRawBuffer* sarb = sab->rawBufferObject();
if (!sarb->addReference()) {
JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer");
return false;
}
auto task = cx->make_unique<AtomicsWaitAsyncTask>(cx, promise, sarb, offset, timeout);
if (!task) {
sarb->dropReference();
return false;
}
bool isAsync = false;
RootedValue immediateResult(cx);
{
AutoLockFutexAPI lock;
if (!WaitValueMatches(view, offset, value)) {
immediateResult.setString(cx->names().futexNotEqual);
} else if (timeout.isSome() && timeout->ToMilliseconds() == 0.0) {
immediateResult.setString(cx->names().futexTimedOut);
} else {
if (!cx->startAsyncTaskCallback || !cx->finishAsyncTaskCallback ||
!CanUseExtraThreads())
{
JS_ReportErrorASCII(cx, "Atomics.waitAsync not supported in this runtime.");
return false;
}
task->waiter()->offset = GetWaiterByteOffset(view, offset);
AddWaiter(sarb, task->waiter());
task->setInWaiterList();
isAsync = true;
}
}
if (!isAsync)
return CreateWaitAsyncResult(cx, false, immediateResult, r);
if (!StartPromiseTask(cx, Move(task)))
return false;
r.set(result);
return true;
}
bool
js::atomics_notify(JSContext* cx, unsigned argc, Value* vp)
{
@@ -843,11 +1260,12 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp)
Rooted<TypedArrayObject*> view(cx, nullptr);
if (!GetSharedTypedArray(cx, objv, &view))
return false;
if (view->type() != Scalar::Int32)
if (!IsWaitableTypedArray(view->type()))
return ReportBadArrayType(cx);
uint32_t offset;
if (!GetTypedArrayIndex(cx, idxv, view, &offset))
return false;
offset = GetWaiterByteOffset(view, offset);
double count;
if (countv.isUndefined()) {
count = mozilla::PositiveInfinity<double>();
@@ -870,9 +1288,9 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp)
do {
FutexWaiter* c = iter;
iter = iter->lower_pri;
if (c->offset != offset || !c->rt->fx.isWaiting())
if (c->offset != offset || !c->isWaiting())
continue;
c->rt->fx.notify(FutexRuntime::NotifyExplicit);
c->notify();
++woken;
--count;
} while (count > 0 && iter != waiters);
@@ -1106,6 +1524,7 @@ const JSFunctionSpec AtomicsMethods[] = {
JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor),
JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree),
JS_FN("wait", atomics_wait, 4,0),
JS_FN("waitAsync", atomics_waitAsync, 4,0),
JS_FN("notify", atomics_notify, 3,0),
JS_FN("wake", atomics_notify, 3,0), //Legacy name
JS_FS_END
+1
View File
@@ -35,6 +35,7 @@ class AtomicsObject : public JSObject
[[nodiscard]] bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] bool atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] bool atomics_notify(JSContext* cx, unsigned argc, Value* vp);
/* asm.js callouts */
@@ -0,0 +1,636 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "builtin/FinalizationRegistryObject.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "builtin/WeakRefObject.h"
#include "gc/Nursery.h"
#include "gc/Tracer.h"
#include "vm/EqualityOperations.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/Symbol.h"
#include "jswrapper.h"
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
#include "vm/NativeObject-inl.h"
using namespace js;
enum class WeakCellKind {
Empty,
Object,
Symbol
};
static JSObject*
NormalizeWeakObject(JSObject* obj)
{
if (JSObject* unwrapped = CheckedUnwrap(obj, /* stopAtWindowProxy = */ false))
return unwrapped;
return obj;
}
static bool
GetPrototypeFromFinalizationRegistryConstructor(JSContext* cx, HandleObject newTarget,
MutableHandleObject proto)
{
if (!GetPrototypeFromConstructor(cx, newTarget, proto))
return false;
if (proto)
return true;
RootedObject realmObject(cx, CheckedUnwrap(newTarget, /* stopAtWindowProxy = */ false));
if (!realmObject)
return false;
{
JSAutoCompartment ac(cx, realmObject);
Rooted<GlobalObject*> global(cx, &realmObject->global());
if (!GlobalObject::ensureConstructor(cx, global, JSProto_FinalizationRegistry))
return false;
proto.set(&global->getPrototype(JSProto_FinalizationRegistry).toObject());
}
return cx->compartment()->wrap(cx, proto);
}
struct WeakCell {
WeakCellKind kind;
WeakRef<JSObject*> object;
WeakRef<JS::Symbol*> symbol;
bool enabled;
WeakCell()
: kind(WeakCellKind::Empty)
, object(nullptr)
, symbol(nullptr)
, enabled(true)
{}
explicit WeakCell(JSObject* obj, bool enabled)
: kind(WeakCellKind::Object)
, object(obj)
, symbol(nullptr)
, enabled(enabled)
{}
explicit WeakCell(JS::Symbol* sym, bool enabled)
: kind(WeakCellKind::Symbol)
, object(nullptr)
, symbol(sym)
, enabled(enabled)
{}
void clear() {
kind = WeakCellKind::Empty;
object = nullptr;
symbol = nullptr;
}
bool isEmpty() const { return kind == WeakCellKind::Empty; }
bool isDead() const {
if (kind == WeakCellKind::Object)
return !object.unbarrieredGet();
if (kind == WeakCellKind::Symbol)
return !symbol.unbarrieredGet();
return false;
}
bool sameValue(HandleValue value) const {
if (kind == WeakCellKind::Object)
return value.isObject() && object.get() == NormalizeWeakObject(&value.toObject());
if (kind == WeakCellKind::Symbol)
return value.isSymbol() && symbol.get() == value.toSymbol();
return false;
}
void trace(JSTracer* trc, const char* name) {
if (kind == WeakCellKind::Object) {
JSObject* target = object.unbarrieredGet();
if (!target)
return;
if (!enabled) {
// Do nothing
} else if (IsInsideNursery(target)) {
TraceManuallyBarrieredEdge(trc, object.unsafeGet(), name);
} else {
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
return;
TraceWeakEdge(trc, &object, name);
}
} else if (kind == WeakCellKind::Symbol) {
JS::Symbol* target = symbol.unbarrieredGet();
if (enabled && target) {
if (trc->isMarkingTracer() && !target->asTenured().zone()->isCollecting())
return;
TraceWeakEdge(trc, &symbol, name);
}
}
}
void traceIfZoneIsCollecting(JSTracer* trc, const char* name) {
if (kind == WeakCellKind::Object) {
JSObject* target = object.unbarrieredGet();
if (!target)
return;
if (!enabled) {
// Do nothing
} else if (IsInsideNursery(target)) {
TraceManuallyBarrieredEdge(trc, object.unsafeGet(), name);
} else if (target->asTenured().zone()->isCollecting()) {
TraceWeakEdge(trc, &object, name);
}
} else if (kind == WeakCellKind::Symbol) {
JS::Symbol* target = symbol.unbarrieredGet();
if (enabled && target && target->asTenured().zone()->isCollecting())
TraceWeakEdge(trc, &symbol, name);
}
}
};
struct FinalizationRecord {
WeakCell target;
JS::Heap<Value> heldValue;
WeakCell unregisterToken;
bool active;
bool queued;
bool enabled;
FinalizationRecord(HandleValue targetValue, HandleValue heldValue,
HandleValue unregisterTokenValue, bool enabled)
: heldValue(heldValue),
active(true),
queued(false),
enabled(enabled)
{
if (targetValue.isObject())
target = WeakCell(NormalizeWeakObject(&targetValue.toObject()), enabled);
else
target = WeakCell(targetValue.toSymbol(), enabled);
if (unregisterTokenValue.isObject())
unregisterToken = WeakCell(NormalizeWeakObject(&unregisterTokenValue.toObject()), enabled);
else if (unregisterTokenValue.isSymbol())
unregisterToken = WeakCell(unregisterTokenValue.toSymbol(), enabled);
}
void trace(JSTracer* trc) {
if (active || queued)
JS::TraceEdge(trc, &heldValue, "FinalizationRegistry held value");
if (active) {
target.trace(trc, "FinalizationRegistry target");
if (!unregisterToken.isEmpty())
unregisterToken.trace(trc, "FinalizationRegistry unregister token");
}
}
void traceWeakEdgesForCollectedZones(JSTracer* trc) {
if (!active)
return;
target.traceIfZoneIsCollecting(trc, "FinalizationRegistry target");
if (!unregisterToken.isEmpty())
unregisterToken.traceIfZoneIsCollecting(trc,
"FinalizationRegistry unregister token");
}
bool targetIsDead() const {
return active && target.isDead();
}
bool matchesToken(HandleValue token) const {
return active && !queued && !unregisterToken.isEmpty() &&
unregisterToken.sameValue(token);
}
void queueForCleanup() {
MOZ_ASSERT(active);
MOZ_ASSERT(!queued);
active = false;
queued = true;
target.clear();
unregisterToken.clear();
}
void clear() {
active = false;
queued = false;
target.clear();
unregisterToken.clear();
heldValue.setUndefined();
}
};
using FinalizationRecordVector = Vector<FinalizationRecord*, 0, SystemAllocPolicy>;
struct FinalizationRegistryObject::Data {
JS::Heap<JSObject*> cleanupCallback;
JS::Heap<JSObject*> cleanupJob;
FinalizationRecordVector records;
FinalizationRecordVector cleanupQueue;
bool queuedForCleanup;
bool enabled;
explicit Data(JSObject* cleanupCallback, bool enabled)
: cleanupCallback(cleanupCallback),
cleanupJob(nullptr),
records(SystemAllocPolicy()),
cleanupQueue(SystemAllocPolicy()),
queuedForCleanup(false),
enabled(enabled)
{}
~Data() {
for (size_t i = 0; i < records.length(); i++)
js_delete(records[i]);
}
void trace(JSTracer* trc) {
if (enabled) {
JS::TraceEdge(trc, &cleanupCallback, "FinalizationRegistry cleanup callback");
if (cleanupJob.unbarrieredGet())
JS::TraceEdge(trc, &cleanupJob, "FinalizationRegistry cleanup job");
for (size_t i = 0; i < records.length(); i++)
records[i]->trace(trc);
}
}
bool appendRecord(FinalizationRecord* record) {
return records.append(record);
}
bool appendCleanupRecord(FinalizationRecord* record) {
return cleanupQueue.append(record);
}
void compactRecords() {
for (size_t i = 0; i < records.length();) {
FinalizationRecord* record = records[i];
if (!record->active && !record->queued) {
js_delete(record);
records.erase(records.begin() + i);
continue;
}
i++;
}
}
void unregister(HandleValue token, bool* removed) {
*removed = false;
for (size_t i = 0; i < records.length(); i++) {
FinalizationRecord* record = records[i];
if (record->matchesToken(token)) {
record->clear();
*removed = true;
}
}
compactRecords();
}
};
static FinalizationRegistryObject::Data*
GetData(JSObject* obj)
{
return obj->as<FinalizationRegistryObject>().getData();
}
static MOZ_ALWAYS_INLINE bool
IsFinalizationRegistry(HandleValue v)
{
return v.isObject() && v.toObject().is<FinalizationRegistryObject>();
}
static bool
FinalizationRegistry_register_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsFinalizationRegistry(args.thisv()));
if (!CanBeHeldWeakly(args.get(0))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BAD_FINALIZATION_REGISTRY_TARGET);
return false;
}
RootedValue target(cx, args[0]);
RootedValue heldValue(cx, args.get(1));
bool same;
if (!SameValue(cx, target, heldValue, &same))
return false;
if (same) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BAD_FINALIZATION_REGISTRY_HELD_VALUE);
return false;
}
RootedValue unregisterToken(cx, args.get(2));
if (!CanBeHeldWeakly(unregisterToken)) {
if (!unregisterToken.isUndefined()) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BAD_FINALIZATION_REGISTRY_TOKEN);
return false;
}
unregisterToken.setUndefined();
}
FinalizationRecord* record = cx->new_<FinalizationRecord>(target, heldValue, unregisterToken, cx->options().weakRefs());
if (!record)
return false;
auto* data = GetData(&args.thisv().toObject());
if (!data->appendRecord(record)) {
js_delete(record);
ReportOutOfMemory(cx);
return false;
}
args.rval().setUndefined();
return true;
}
static bool
FinalizationRegistry_unregister_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsFinalizationRegistry(args.thisv()));
RootedValue unregisterToken(cx, args.get(0));
if (!CanBeHeldWeakly(unregisterToken)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BAD_FINALIZATION_REGISTRY_TOKEN);
return false;
}
bool removed = false;
auto* data = GetData(&args.thisv().toObject());
data->unregister(unregisterToken, &removed);
args.rval().setBoolean(removed);
return true;
}
const JSPropertySpec FinalizationRegistryObject::properties[] = {
JS_PS_END
};
const JSFunctionSpec FinalizationRegistryObject::methods[] = {
JS_FN("register", FinalizationRegistryObject::register_, 2, 0),
JS_FN("unregister", FinalizationRegistryObject::unregister, 1, 0),
JS_FS_END
};
static JSObject*
InitFinalizationRegistryClass(JSContext* cx, HandleObject obj, bool defineMembers)
{
Handle<GlobalObject*> global = obj.as<GlobalObject>();
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!proto)
return nullptr;
RootedFunction ctor(cx, GlobalObject::createConstructor(cx, FinalizationRegistryObject::construct,
ClassName(JSProto_FinalizationRegistry, cx), 1));
if (!ctor)
return nullptr;
if (!LinkConstructorAndPrototype(cx, ctor, proto))
return nullptr;
if (defineMembers) {
if (!DefinePropertiesAndFunctions(cx, proto, FinalizationRegistryObject::properties,
FinalizationRegistryObject::methods)) {
return nullptr;
}
if (!DefineToStringTag(cx, proto, cx->names().FinalizationRegistry))
return nullptr;
}
if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_FinalizationRegistry, ctor, proto))
return nullptr;
return proto;
}
/* static */ FinalizationRegistryObject*
FinalizationRegistryObject::create(JSContext* cx, HandleObject cleanupCallback,
HandleObject proto /* = nullptr */)
{
Rooted<FinalizationRegistryObject*> obj(cx,
NewObjectWithClassProto<FinalizationRegistryObject>(cx, proto));
if (!obj)
return nullptr;
Data* data = cx->new_<Data>(cleanupCallback, cx->options().weakRefs());
if (!data)
return nullptr;
obj->setPrivate(data);
RootedAtom funName(cx, cx->names().empty);
RootedFunction cleanupJob(cx, NewNativeFunction(cx, FinalizationRegistryObject::cleanupJob, 0,
funName, gc::AllocKind::FUNCTION_EXTENDED,
GenericObject));
if (!cleanupJob)
return nullptr;
cleanupJob->setExtendedSlot(0, ObjectValue(*obj));
data->cleanupJob = cleanupJob;
if (!cx->zone()->finalizationRegistries.append(WeakRef<JSObject*>(obj))) {
ReportOutOfMemory(cx);
return nullptr;
}
return obj;
}
/* static */ bool
FinalizationRegistryObject::construct(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (!ThrowIfNotConstructing(cx, args, "FinalizationRegistry"))
return false;
RootedValue cleanupCallbackValue(cx, args.get(0));
RootedObject cleanupCallback(cx, ValueToCallable(cx, cleanupCallbackValue, 0, NO_CONSTRUCT));
if (!cleanupCallback)
return false;
RootedObject proto(cx);
RootedObject newTarget(cx, &args.newTarget().toObject());
if (!GetPrototypeFromFinalizationRegistryConstructor(cx, newTarget, &proto))
return false;
Rooted<FinalizationRegistryObject*> obj(cx,
FinalizationRegistryObject::create(cx, cleanupCallback, proto));
if (!obj)
return false;
args.rval().setObject(*obj);
return true;
}
/* static */ bool
FinalizationRegistryObject::register_(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsFinalizationRegistry, FinalizationRegistry_register_impl>(cx, args);
}
/* static */ bool
FinalizationRegistryObject::unregister(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsFinalizationRegistry, FinalizationRegistry_unregister_impl>(cx, args);
}
/* static */ bool
FinalizationRegistryObject::cleanupJob(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
RootedFunction job(cx, &args.callee().as<JSFunction>());
Rooted<FinalizationRegistryObject*> registry(cx,
&job->getExtendedSlot(0).toObject().as<FinalizationRegistryObject>());
Data* data = registry->getData();
if (!data) {
args.rval().setUndefined();
return true;
}
data->queuedForCleanup = false;
RootedValue callback(cx, ObjectValue(*data->cleanupCallback.get()));
RootedValue heldValue(cx);
RootedValue ignored(cx);
RootedValue undefined(cx, UndefinedValue());
while (data->cleanupQueue.length() > 0) {
FinalizationRecord* record = data->cleanupQueue[0];
data->cleanupQueue.erase(data->cleanupQueue.begin());
if (!record->queued) {
data->compactRecords();
continue;
}
heldValue.set(record->heldValue.get());
record->clear();
data->compactRecords();
if (!Call(cx, callback, undefined, heldValue, &ignored))
return false;
}
args.rval().setUndefined();
return true;
}
/* static */ void
FinalizationRegistryObject::trace(JSTracer* trc, JSObject* obj)
{
if (Data* data = GetData(obj))
data->trace(trc);
}
/* static */ void
FinalizationRegistryObject::finalize(FreeOp* fop, JSObject* obj)
{
if (Data* data = GetData(obj))
fop->delete_(data);
}
void
FinalizationRegistryObject::traceWeakEdgesForCollectedZones(JSTracer* trc)
{
Data* data = getData();
if (!data)
return;
for (size_t i = 0; i < data->records.length(); i++)
data->records[i]->traceWeakEdgesForCollectedZones(trc);
}
void
FinalizationRegistryObject::sweepAfterGC(JSRuntime* rt)
{
Data* data = getData();
if (!data)
return;
bool needsCleanupJob = false;
for (size_t i = 0; i < data->records.length(); i++) {
FinalizationRecord* record = data->records[i];
if (!record->targetIsDead())
continue;
record->queueForCleanup();
if (!data->appendCleanupRecord(record)) {
AutoEnterOOMUnsafeRegion oomUnsafe;
oomUnsafe.crash("queueing FinalizationRegistry cleanup record");
}
needsCleanupJob = true;
}
if (needsCleanupJob && !data->queuedForCleanup) {
JSContext* cx = rt->contextFromMainThread();
RootedObject cleanupJob(cx, data->cleanupJob.unbarrieredGet());
if (!rt->enqueueFinalizationRegistryCleanupJob(cx, cleanupJob)) {
AutoEnterOOMUnsafeRegion oomUnsafe;
oomUnsafe.crash("queueing FinalizationRegistry cleanup job");
}
data->queuedForCleanup = true;
}
data->compactRecords();
}
static const ClassOps FinalizationRegistryObjectClassOps = {
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
FinalizationRegistryObject::finalize,
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
FinalizationRegistryObject::trace
};
const Class FinalizationRegistryObject::class_ = {
"FinalizationRegistry",
JSCLASS_HAS_PRIVATE |
JSCLASS_HAS_CACHED_PROTO(JSProto_FinalizationRegistry) |
JSCLASS_FOREGROUND_FINALIZE,
&FinalizationRegistryObjectClassOps
};
/* static */ JSObject*
FinalizationRegistryObject::initClass(JSContext* cx, HandleObject obj)
{
return ::InitFinalizationRegistryClass(cx, obj, true);
}
JSObject*
js::InitFinalizationRegistryClass(JSContext* cx, HandleObject obj)
{
return FinalizationRegistryObject::initClass(cx, obj);
}
JSObject*
js::InitBareFinalizationRegistryCtor(JSContext* cx, HandleObject obj)
{
return ::InitFinalizationRegistryClass(cx, obj, false);
}
@@ -0,0 +1,51 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef builtin_FinalizationRegistryObject_h
#define builtin_FinalizationRegistryObject_h
#include "gc/Barrier.h"
#include "vm/NativeObject.h"
namespace js {
class FinalizationRegistryObject : public NativeObject
{
public:
struct Data;
static const Class class_;
static JSObject* initClass(JSContext* cx, HandleObject obj);
static FinalizationRegistryObject* create(JSContext* cx, HandleObject cleanupCallback,
HandleObject proto = nullptr);
static void trace(JSTracer* trc, JSObject* obj);
static void finalize(FreeOp* fop, JSObject* obj);
void traceWeakEdgesForCollectedZones(JSTracer* trc);
[[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool register_(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool unregister(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool cleanupJob(JSContext* cx, unsigned argc, Value* vp);
void sweepAfterGC(JSRuntime* rt);
Data* getData() const {
return static_cast<Data*>(getPrivate());
}
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
};
extern JSObject*
InitFinalizationRegistryClass(JSContext* cx, HandleObject obj);
extern JSObject*
InitBareFinalizationRegistryCtor(JSContext* cx, HandleObject obj);
} // namespace js
#endif /* builtin_FinalizationRegistryObject_h */
+43
View File
@@ -55,6 +55,49 @@ function MapForEach(callbackfn, thisArg = undefined) {
}
}
// ES2024
// Map.groupBy ( items, callbackfn )
function MapGroupBy(items, callbackfn) {
// Step 1.
RequireObjectCoercible(items);
// Step 2.
if (!IsCallable(callbackfn))
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn));
// Step 3.
var groups = std_Map_create();
// Step 4.
var k = 0;
// Steps 5-8.
for (var value of allowContentIter(items)) {
// Step 6.a.
if (k >= MAX_NUMERIC_INDEX)
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
// Step 6.b.
var key = callContentFunction(callbackfn, undefined, value, k);
// Steps 6.c-d.
var elements;
if (callFunction(std_Map_has, groups, key)) {
elements = callFunction(std_Map_get, groups, key);
callFunction(std_Array_push, elements, value);
} else {
elements = [value];
callFunction(std_Map_set, groups, key, elements);
}
// Step 6.e.
k++;
}
// Step 9.
return groups;
}
var iteratorTemp = { mapIterationResultPair : null };
function MapIteratorNext() {
+15 -4
View File
@@ -332,9 +332,15 @@ const JSPropertySpec MapObject::staticProperties[] = {
JS_PS_END
};
const JSFunctionSpec MapObject::staticMethods[] = {
JS_SELF_HOSTED_FN("groupBy", "MapGroupBy", 2, 0),
JS_FS_END
};
static JSObject*
InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSProtoKey key, Native construct,
const JSPropertySpec* properties, const JSFunctionSpec* methods,
const JSFunctionSpec* staticMethods,
const JSPropertySpec* staticProperties)
{
RootedPlainObject proto(cx, NewBuiltinClassInstance<PlainObject>(cx));
@@ -343,8 +349,13 @@ InitClass(JSContext* cx, Handle<GlobalObject*> global, const Class* clasp, JSPro
Rooted<JSFunction*> ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0));
if (!ctor ||
!JS_DefineProperties(cx, ctor, staticProperties) ||
!LinkConstructorAndPrototype(cx, ctor, proto) ||
!JS_DefineProperties(cx, ctor, staticProperties))
{
return nullptr;
}
if (staticMethods && !JS_DefineFunctions(cx, ctor, staticMethods))
return nullptr;
if (!LinkConstructorAndPrototype(cx, ctor, proto) ||
!DefinePropertiesAndFunctions(cx, proto, properties, methods) ||
!GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto))
{
@@ -359,7 +370,7 @@ MapObject::initClass(JSContext* cx, JSObject* obj)
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
RootedObject proto(cx,
InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods,
staticProperties));
staticMethods, staticProperties));
if (proto) {
// Define the "entries" method.
JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0);
@@ -1084,7 +1095,7 @@ SetObject::initClass(JSContext* cx, JSObject* obj)
Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
RootedObject proto(cx,
InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods,
staticProperties));
nullptr, staticProperties));
if (proto) {
// Define the "values" method.
JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0);
+3 -2
View File
@@ -110,7 +110,9 @@ class MapObject : public NativeObject {
[[nodiscard]] static bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj,
JS::MutableHandle<GCVector<JS::Value>> entries);
[[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
static MapObject* create(JSContext* cx, HandleObject proto = nullptr);
// Publicly exposed Map calls for JSAPI access (webidl maplike/setlike
@@ -137,6 +139,7 @@ class MapObject : public NativeObject {
static const JSPropertySpec properties[];
static const JSFunctionSpec methods[];
static const JSFunctionSpec staticMethods[];
static const JSPropertySpec staticProperties[];
ValueMap* getData() { return static_cast<ValueMap*>(getPrivate()); }
static ValueMap& extract(HandleObject o);
@@ -153,10 +156,8 @@ class MapObject : public NativeObject {
[[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args);
[[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp);
[[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args);
+7 -3
View File
@@ -240,12 +240,16 @@ function ObjectGroupBy(items, callbackfn) {
// Steps 5-8.
for (var value of allowContentIter(items)) {
// Step 6.a.
var key = callContentFunction(callbackfn, undefined, value, k);
if (k >= MAX_NUMERIC_INDEX)
ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
// Step 6.b.
var key = callContentFunction(callbackfn, undefined, value, k);
// Step 6.c.
key = ToPropertyKey(key);
// Steps 6.c-d.
// Steps 6.d-e.
var elements = groups[key];
if (elements === undefined) {
_DefineDataProperty(groups, key, [value]);
@@ -253,7 +257,7 @@ function ObjectGroupBy(items, callbackfn) {
callFunction(std_Array_push, elements, value);
}
// Step 6.e.
// Step 6.f.
k++;
}
+43
View File
@@ -3722,6 +3722,48 @@ Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp)
return true;
}
// ES2024
// Promise.withResolvers ( )
static bool
Promise_static_withResolvers(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Step 1.
if (!args.thisv().isObject()) {
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, args.thisv(), nullptr);
return false;
}
RootedObject C(cx, &args.thisv().toObject());
// Step 2.
Rooted<PromiseCapability> capability(cx);
if (!NewPromiseCapability(cx, C, &capability, false))
return false;
// Step 3.
RootedPlainObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
if (!obj)
return false;
// Steps 4-7.
RootedValue promise(cx, ObjectValue(*capability.promise()));
if (!::JS_DefineProperty(cx, obj, "promise", promise, JSPROP_ENUMERATE))
return false;
RootedValue resolve(cx, ObjectValue(*capability.resolve()));
if (!::JS_DefineProperty(cx, obj, "resolve", resolve, JSPROP_ENUMERATE))
return false;
RootedValue reject(cx, ObjectValue(*capability.reject()));
if (!::JS_DefineProperty(cx, obj, "reject", reject, JSPROP_ENUMERATE))
return false;
// Step 8.
args.rval().setObject(*obj);
return true;
}
/**
* Unforgeable version of ES2016, 25.4.4.5, Promise.resolve.
*/
@@ -5251,6 +5293,7 @@ static const JSFunctionSpec promise_static_methods[] = {
JS_FN("race", Promise_static_race, 1, 0),
JS_FN("reject", Promise_reject, 1, 0),
JS_FN("resolve", Promise_static_resolve, 1, 0),
JS_FN("withResolvers", Promise_static_withResolvers, 0, 0),
JS_FS_END
};
+76
View File
@@ -654,6 +654,82 @@ function String_repeat(count) {
return T;
}
// ES2024
// String.prototype.isWellFormed ( )
function String_isWellFormed() {
// Steps 1-2.
RequireObjectCoercible(this);
var S = ToString(this);
// Step 3.
var length = S.length;
for (var k = 0; k < length; k++) {
var c = callFunction(std_String_charCodeAt, S, k);
if (c >= 0xD800 && c <= 0xDBFF) {
if (k + 1 >= length)
return false;
var d = callFunction(std_String_charCodeAt, S, k + 1);
if (d < 0xDC00 || d > 0xDFFF)
return false;
k++;
} else if (c >= 0xDC00 && c <= 0xDFFF) {
return false;
}
}
// Step 4.
return true;
}
// ES2024
// String.prototype.toWellFormed ( )
function String_toWellFormed() {
// Steps 1-2.
RequireObjectCoercible(this);
var S = ToString(this);
// Step 3.
var length = S.length;
var result = "";
var copied = 0;
for (var k = 0; k < length; k++) {
var c = callFunction(std_String_charCodeAt, S, k);
var isUnpairedSurrogate = false;
if (c >= 0xD800 && c <= 0xDBFF) {
if (k + 1 < length) {
var d = callFunction(std_String_charCodeAt, S, k + 1);
if (d >= 0xDC00 && d <= 0xDFFF) {
k++;
continue;
}
}
isUnpairedSurrogate = true;
} else if (c >= 0xDC00 && c <= 0xDFFF) {
isUnpairedSurrogate = true;
}
if (isUnpairedSurrogate) {
if (copied < k)
result += callFunction(String_substring, S, copied, k);
result += "\uFFFD";
copied = k + 1;
}
}
if (copied === 0)
return S;
if (copied < length)
result += callFunction(String_substring, S, copied, length);
// Step 4.
return result;
}
// ES6 draft specification, section 21.1.3.27, version 2013-09-27.
function String_iterator() {
RequireObjectCoercible(this);
+26 -2
View File
@@ -41,10 +41,21 @@ function TypedArrayContentTypeIsBigIntMethod() {
return IsBigInt64TypedArray(this) || IsBigUint64TypedArray(this);
}
function ThrowIfTypedArrayOutOfBounds(tarray) {
if (TypedArrayIsOutOfBounds(tarray))
ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
}
function ThrowIfPossiblyWrappedTypedArrayOutOfBounds(tarray) {
if (PossiblyWrappedTypedArrayIsOutOfBounds(tarray))
ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
}
function GetAttachedArrayBuffer(tarray) {
var buffer = ViewedArrayBufferIfReified(tarray);
if (IsDetachedBuffer(buffer))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
ThrowIfTypedArrayOutOfBounds(tarray);
return buffer;
}
@@ -67,6 +78,7 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
if (IsObject(arg) && IsPossiblyWrappedTypedArray(arg)) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(arg))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(arg);
return false;
}
@@ -89,6 +101,7 @@ function ValidateTypedArray(obj, error) {
if (IsPossiblyWrappedTypedArray(obj)) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(obj);
return false;
}
}
@@ -1130,12 +1143,18 @@ function TypedArraySet(overloaded, offset = 0) {
// Steps 9-10.
var targetBuffer = GetAttachedArrayBuffer(target);
ThrowIfTypedArrayOutOfBounds(target);
// Step 11.
var targetLength = TypedArrayLength(target);
// Steps 12 et seq.
if (IsPossiblyWrappedTypedArray(overloaded))
if (IsPossiblyWrappedTypedArray(overloaded)) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(overloaded))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
ThrowIfPossiblyWrappedTypedArrayOutOfBounds(overloaded);
return SetFromTypedArray(target, overloaded, targetOffset, targetLength);
}
return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer);
}
@@ -1472,6 +1491,8 @@ function TypedArraySubarray(begin, end) {
"TypedArraySubarray");
}
GetAttachedArrayBuffer(obj);
// Steps 4-6.
var buffer = TypedArrayBuffer(obj);
var srcLength = TypedArrayLength(obj);
@@ -1952,7 +1973,10 @@ function ArrayBufferSlice(start, end) {
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
// Steps 19-21.
ArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped);
var currentLen = ArrayBufferByteLength(O);
var copyLen = first >= currentLen ? 0 : std_Math_min(newLen, currentLen - first);
if (copyLen > 0)
ArrayBufferCopyData(new_, 0, O, first | 0, copyLen | 0, isWrapped);
// Step 22.
return new_;
+171 -52
View File
@@ -8,6 +8,7 @@
#include "jsapi.h"
#include "jscntxt.h"
#include "builtin/WeakRefObject.h"
#include "vm/SelfHosting.h"
#include "vm/Interpreter-inl.h"
@@ -21,21 +22,80 @@ IsWeakMap(HandleValue v)
return v.isObject() && v.toObject().is<WeakMapObject>();
}
struct WeakMapObject::Data
{
ObjectValueMap objectMap;
SymbolValueMap symbolMap;
Data(JSContext* cx, JSObject* owner)
: objectMap(cx, owner),
symbolMap(cx, owner)
{}
bool init() {
return objectMap.init() && symbolMap.init();
}
};
ObjectValueMap*
WeakMapObject::getMap()
{
Data* data = getData();
return data ? &data->objectMap : nullptr;
}
SymbolValueMap*
WeakMapObject::getSymbolMap()
{
Data* data = getData();
return data ? &data->symbolMap : nullptr;
}
static bool
EnsureWeakMapData(JSContext* cx, Handle<WeakMapObject*> mapObj)
{
if (mapObj->getData())
return true;
auto data = cx->make_unique<WeakMapObject::Data>(cx, mapObj.get());
if (!data)
return false;
if (!data->init()) {
JS_ReportOutOfMemory(cx);
return false;
}
mapObj->setPrivate(data.release());
return true;
}
MOZ_ALWAYS_INLINE bool
WeakMap_has_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
if (!CanBeHeldWeakly(args.get(0))) {
args.rval().setBoolean(false);
return true;
}
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
JSObject* key = &args[0].toObject();
if (map->has(key)) {
args.rval().setBoolean(true);
return true;
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
if (args.get(0).isObject()) {
if (ObjectValueMap* map = weakMap.getMap()) {
JSObject* key = &args[0].toObject();
if (map->has(key)) {
args.rval().setBoolean(true);
return true;
}
}
} else {
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
JS::Symbol* key = args[0].toSymbol();
if (map->has(key)) {
args.rval().setBoolean(true);
return true;
}
}
}
@@ -55,16 +115,27 @@ WeakMap_get_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
if (!CanBeHeldWeakly(args.get(0))) {
args.rval().setUndefined();
return true;
}
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
JSObject* key = &args[0].toObject();
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
args.rval().set(ptr->value());
return true;
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
if (args.get(0).isObject()) {
if (ObjectValueMap* map = weakMap.getMap()) {
JSObject* key = &args[0].toObject();
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
args.rval().set(ptr->value());
return true;
}
}
} else {
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
JS::Symbol* key = args[0].toSymbol();
if (SymbolValueMap::Ptr ptr = map->lookup(key)) {
args.rval().set(ptr->value());
return true;
}
}
}
@@ -84,17 +155,29 @@ WeakMap_delete_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!args.get(0).isObject()) {
if (!CanBeHeldWeakly(args.get(0))) {
args.rval().setBoolean(false);
return true;
}
if (ObjectValueMap* map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
JSObject* key = &args[0].toObject();
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
map->remove(ptr);
args.rval().setBoolean(true);
return true;
WeakMapObject& weakMap = args.thisv().toObject().as<WeakMapObject>();
if (args.get(0).isObject()) {
if (ObjectValueMap* map = weakMap.getMap()) {
JSObject* key = &args[0].toObject();
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
map->remove(ptr);
args.rval().setBoolean(true);
return true;
}
}
} else {
if (SymbolValueMap* map = weakMap.getSymbolMap()) {
JS::Symbol* key = args[0].toSymbol();
if (SymbolValueMap::Ptr ptr = map->lookup(key)) {
map->remove(ptr);
args.rval().setBoolean(true);
return true;
}
}
}
@@ -126,22 +209,13 @@ TryPreserveReflector(JSContext* cx, HandleObject obj)
return true;
}
static MOZ_ALWAYS_INLINE bool
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
HandleObject key, HandleValue value)
static bool
SetWeakMapObjectEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
HandleObject key, HandleValue value)
{
if (!EnsureWeakMapData(cx, mapObj))
return false;
ObjectValueMap* map = mapObj->getMap();
if (!map) {
auto newMap = cx->make_unique<ObjectValueMap>(cx, mapObj.get());
if (!newMap)
return false;
if (!newMap->init()) {
JS_ReportOutOfMemory(cx);
return false;
}
map = newMap.release();
mapObj->setPrivate(map);
}
// Preserve wrapped native keys to prevent wrapper optimization.
if (!TryPreserveReflector(cx, key))
@@ -162,13 +236,28 @@ SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
return true;
}
MOZ_ALWAYS_INLINE bool
WeakMap_set_impl(JSContext* cx, const CallArgs& args)
static bool
SetWeakMapSymbolEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
Handle<JS::Symbol*> key, HandleValue value)
{
MOZ_ASSERT(IsWeakMap(args.thisv()));
if (!EnsureWeakMapData(cx, mapObj))
return false;
SymbolValueMap* map = mapObj->getSymbolMap();
if (!args.get(0).isObject()) {
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment());
if (!map->put(key, value)) {
JS_ReportOutOfMemory(cx);
return false;
}
return true;
}
static MOZ_ALWAYS_INLINE bool
SetWeakMapEntryInternal(JSContext* cx, Handle<WeakMapObject*> mapObj,
HandleValue key, HandleValue value)
{
if (!CanBeHeldWeakly(key)) {
UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, key, nullptr);
if (!bytes)
return false;
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
@@ -176,11 +265,24 @@ WeakMap_set_impl(JSContext* cx, const CallArgs& args)
return false;
}
RootedObject key(cx, &args[0].toObject());
if (key.isObject()) {
RootedObject objectKey(cx, &key.toObject());
return SetWeakMapObjectEntryInternal(cx, mapObj, objectKey, value);
}
Rooted<JS::Symbol*> symbolKey(cx, key.toSymbol());
return SetWeakMapSymbolEntryInternal(cx, mapObj, symbolKey, value);
}
MOZ_ALWAYS_INLINE bool
WeakMap_set_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsWeakMap(args.thisv()));
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
if (!SetWeakMapEntryInternal(cx, map, key, args.get(1)))
if (!SetWeakMapEntryInternal(cx, map, args.get(0), args.get(1)))
return false;
args.rval().set(args.thisv());
return true;
@@ -193,6 +295,13 @@ js::WeakMap_set(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<IsWeakMap, WeakMap_set_impl>(cx, args);
}
bool
js::SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val)
{
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
return SetWeakMapEntryInternal(cx, rootedMap, key, val);
}
JS_FRIEND_API(bool)
JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret)
{
@@ -205,11 +314,11 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
RootedObject arr(cx, NewDenseEmptyArray(cx));
if (!arr)
return false;
ObjectValueMap* map = obj->as<WeakMapObject>().getMap();
if (map) {
WeakMapObject::Data* data = obj->as<WeakMapObject>().getData();
if (data) {
// Prevent GC from mutating the weakmap while iterating.
AutoSuppressGC suppress(cx);
for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) {
for (ObjectValueMap::Base::Range r = data->objectMap.all(); !r.empty(); r.popFront()) {
JS::ExposeObjectToActiveJS(r.front().key());
RootedObject key(cx, r.front().key());
if (!cx->compartment()->wrap(cx, &key))
@@ -217,6 +326,14 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
if (!NewbornArrayPush(cx, arr, ObjectValue(*key)))
return false;
}
for (SymbolValueMap::Base::Range r = data->symbolMap.all(); !r.empty(); r.popFront()) {
gc::ExposeGCThingToActiveJS(JS::GCCellPtr(r.front().key().get()));
RootedValue key(cx, SymbolValue(r.front().key()));
if (!cx->compartment()->wrap(cx, &key))
return false;
if (!NewbornArrayPush(cx, arr, key))
return false;
}
}
ret.set(arr);
return true;
@@ -225,21 +342,23 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan
static void
WeakMap_mark(JSTracer* trc, JSObject* obj)
{
if (ObjectValueMap* map = obj->as<WeakMapObject>().getMap())
map->trace(trc);
if (WeakMapObject::Data* data = obj->as<WeakMapObject>().getData()) {
data->objectMap.trace(trc);
data->symbolMap.trace(trc);
}
}
static void
WeakMap_finalize(FreeOp* fop, JSObject* obj)
{
MOZ_ASSERT(fop->maybeOffMainThread());
if (ObjectValueMap* map = obj->as<WeakMapObject>().getMap()) {
if (WeakMapObject::Data* data = obj->as<WeakMapObject>().getData()) {
#ifdef DEBUG
map->~ObjectValueMap();
memset(static_cast<void*>(map), 0xdc, sizeof(*map));
fop->free_(map);
data->~Data();
memset(static_cast<void*>(data), 0xdc, sizeof(*data));
fop->free_(data);
#else
fop->delete_(map);
fop->delete_(data);
#endif
}
}
@@ -282,7 +401,8 @@ JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj, HandleObject key,
CHECK_REQUEST(cx);
assertSameCompartment(cx, key, val);
Rooted<WeakMapObject*> rootedMap(cx, &mapObj->as<WeakMapObject>());
return SetWeakMapEntryInternal(cx, rootedMap, key, val);
RootedValue keyValue(cx, ObjectValue(*key));
return SetWeakMapEntryInternal(cx, rootedMap, keyValue, val);
}
static bool
@@ -386,4 +506,3 @@ js::InitBareWeakMapCtor(JSContext* cx, HandleObject obj)
{
return InitWeakMapClass(cx, obj, false);
}
+5 -1
View File
@@ -16,7 +16,11 @@ class WeakMapObject : public NativeObject
public:
static const Class class_;
ObjectValueMap* getMap() { return static_cast<ObjectValueMap*>(getPrivate()); }
struct Data;
Data* getData() { return static_cast<Data*>(getPrivate()); }
ObjectValueMap* getMap();
SymbolValueMap* getSymbolMap();
};
} // namespace js
+96 -28
View File
@@ -11,7 +11,9 @@
#include "gc/Nursery.h"
#include "gc/Tracer.h"
#include "vm/GlobalObject.h"
#include "vm/Symbol.h"
#include "jswrapper.h"
#include "jsobjinlines.h"
#include "vm/Interpreter-inl.h"
@@ -31,17 +33,64 @@ IsWeakRef(HandleValue v)
return v.isObject() && v.toObject().is<WeakRefObject>();
}
static bool
GetPrototypeFromWeakRefConstructor(JSContext* cx, HandleObject newTarget,
MutableHandleObject proto)
{
if (!GetPrototypeFromConstructor(cx, newTarget, proto))
return false;
if (proto)
return true;
RootedObject realmObject(cx, CheckedUnwrap(newTarget, /* stopAtWindowProxy = */ false));
if (!realmObject)
return false;
{
JSAutoCompartment ac(cx, realmObject);
Rooted<GlobalObject*> global(cx, &realmObject->global());
if (!GlobalObject::ensureConstructor(cx, global, JSProto_WeakRef))
return false;
proto.set(&global->getPrototype(JSProto_WeakRef).toObject());
}
return cx->compartment()->wrap(cx, proto);
}
static bool
WeakRef_deref_impl(JSContext* cx, const CallArgs& args)
{
MOZ_ASSERT(IsWeakRef(args.thisv()));
WeakRefObject::Referent* data = GetReferent(&args.thisv().toObject());
JSObject* target = data ? data->target.get() : nullptr;
if (target)
args.rval().setObject(*target);
else
if (!data) {
args.rval().setUndefined();
return true;
}
if (data->isObject()) {
JSObject* target = data->objectTarget.get();
if (target) {
RootedValue kept(cx, ObjectValue(*target));
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
return false;
args.rval().set(kept);
} else {
args.rval().setUndefined();
}
} else {
MOZ_ASSERT(data->isSymbol());
JS::Symbol* target = data->symbolTarget.get();
if (target) {
RootedValue kept(cx, SymbolValue(target));
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
return false;
args.rval().set(kept);
} else {
args.rval().setUndefined();
}
}
return true;
}
@@ -83,13 +132,18 @@ InitWeakRefClass(JSContext* cx, HandleObject obj, bool defineMembers)
}
/* static */ WeakRefObject*
WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /* = nullptr */)
WeakRefObject::create(JSContext* cx, HandleValue target, HandleObject proto /* = nullptr */)
{
Rooted<WeakRefObject*> obj(cx, NewObjectWithClassProto<WeakRefObject>(cx, proto));
if (!obj)
return nullptr;
Referent* data = cx->new_<Referent>(target, cx->options().weakRefs());
Referent* data;
if (target.isObject())
data = cx->new_<Referent>(&target.toObject(), cx->options().weakRefs());
else
data = cx->new_<Referent>(target.toSymbol(), cx->options().weakRefs());
if (!data)
return nullptr;
@@ -97,6 +151,18 @@ WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /*
return obj;
}
bool
js::CanBeHeldWeakly(HandleValue target)
{
if (target.isObject())
return true;
if (target.isSymbol())
return target.toSymbol()->code() != JS::SymbolCode::InSymbolRegistry;
return false;
}
/* static */ bool
WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
{
@@ -105,28 +171,25 @@ WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp)
if (!ThrowIfNotConstructing(cx, args, "WeakRef"))
return false;
if (!args.get(0).isObject()) {
UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr);
if (!bytes)
return false;
JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
bytes.get());
if (!CanBeHeldWeakly(args.get(0))) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_WEAKREF_TARGET);
return false;
}
RootedObject target(cx, &args[0].toObject());
RootedValue target(cx, args[0]);
RootedObject proto(cx);
RootedObject newTarget(cx, &args.newTarget().toObject());
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
if (!GetPrototypeFromWeakRefConstructor(cx, newTarget, &proto))
return false;
Rooted<WeakRefObject*> obj(cx, WeakRefObject::create(cx, target, proto));
if (!obj)
return false;
if (!cx->runtime()->addWeakRefKeptObject(cx, target))
return false;
args.rval().setObject(*obj);
return true;
}
@@ -142,19 +205,25 @@ WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp)
WeakRefObject::trace(JSTracer* trc, JSObject* obj)
{
if (Referent* data = GetReferent(obj)) {
JSObject* target = data->target.unbarrieredGet();
if (!target)
return;
if (data->isObject()) {
JSObject* target = data->objectTarget.unbarrieredGet();
if (!target)
return;
// When pref-disabled, keep referent alive via strong trace so deref()
// stays usable as a stub without touching GC internals.
if (!data->enabled) {
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef stub referent");
} else if (IsInsideNursery(target)) {
// Weak edges must be tenured; trace strongly while referent is in the nursery.
TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef nursery referent");
if (!data->enabled) {
// Pref disabled, don't do anything.
} else if (IsInsideNursery(target)) {
// Weak edges must be tenured; trace strongly while referent is in the nursery.
TraceManuallyBarrieredEdge(trc, data->objectTarget.unsafeGet(),
"WeakRef nursery referent");
} else {
TraceWeakEdge(trc, &data->objectTarget, "WeakRef referent");
}
} else {
TraceWeakEdge(trc, &data->target, "WeakRef referent");
MOZ_ASSERT(data->isSymbol());
JS::Symbol* target = data->symbolTarget.unbarrieredGet();
if (data->enabled && target)
TraceWeakEdge(trc, &data->symbolTarget, "WeakRef symbol referent");
}
}
}
@@ -162,7 +231,6 @@ WeakRefObject::trace(JSTracer* trc, JSObject* obj)
/* static */ void
WeakRefObject::finalize(FreeOp* fop, JSObject* obj)
{
MOZ_ASSERT(!fop->maybeOffMainThread());
if (Referent* data = GetReferent(obj))
fop->delete_(data);
}
+29 -4
View File
@@ -11,20 +11,44 @@
namespace js {
bool CanBeHeldWeakly(HandleValue target);
class WeakRefObject : public NativeObject
{
public:
struct Referent {
enum class Kind {
Object,
Symbol
};
explicit Referent(JSObject* obj, bool enabled)
: target(obj), enabled(enabled) {}
WeakRef<JSObject*> target;
: kind(Kind::Object)
, objectTarget(obj)
, symbolTarget(nullptr)
, enabled(enabled)
{}
explicit Referent(JS::Symbol* sym, bool enabled)
: kind(Kind::Symbol)
, objectTarget(nullptr)
, symbolTarget(sym)
, enabled(enabled)
{}
bool isObject() const { return kind == Kind::Object; }
bool isSymbol() const { return kind == Kind::Symbol; }
Kind kind;
WeakRef<JSObject*> objectTarget;
WeakRef<JS::Symbol*> symbolTarget;
bool enabled;
};
static const Class class_;
static JSObject* initClass(JSContext* cx, HandleObject obj);
static WeakRefObject* create(JSContext* cx, HandleObject target, HandleObject proto = nullptr);
static WeakRefObject* create(JSContext* cx, HandleValue target, HandleObject proto = nullptr);
static void trace(JSTracer* trc, JSObject* obj);
static void finalize(FreeOp* fop, JSObject* obj);
@@ -37,7 +61,8 @@ class WeakRefObject : public NativeObject
WeakRef<JSObject*>& target() {
MOZ_ASSERT(getData());
return getData()->target;
MOZ_ASSERT(getData()->isObject());
return getData()->objectTarget;
}
static const JSPropertySpec properties[];
+3 -3
View File
@@ -32,7 +32,7 @@ function WeakSet_add(value) {
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "add", typeof S);
// Step 5.
if (!IsObject(value))
if (!CanBeHeldWeakly(value))
ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value));
// Steps 7-8.
@@ -55,7 +55,7 @@ function WeakSet_delete(value) {
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "delete", typeof S);
// Step 5.
if (!IsObject(value))
if (!CanBeHeldWeakly(value))
return false;
// Steps 7-8.
@@ -75,7 +75,7 @@ function WeakSet_has(value) {
ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "has", typeof S);
// Step 6.
if (!IsObject(value))
if (!CanBeHeldWeakly(value))
return false;
// Steps 7-8.
+3 -4
View File
@@ -12,6 +12,7 @@
#include "builtin/MapObject.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/WeakMapObject.h"
#include "builtin/WeakRefObject.h"
#include "vm/GlobalObject.h"
#include "vm/SelfHosting.h"
@@ -108,7 +109,6 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
if (optimized) {
RootedValue keyVal(cx);
RootedObject keyObject(cx);
RootedValue placeholder(cx, BooleanValue(true));
RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject());
RootedArrayObject array(cx, &iterable.toObject().as<ArrayObject>());
@@ -116,7 +116,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
keyVal.set(array->getDenseElement(index));
MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE));
if (keyVal.isPrimitive()) {
if (!CanBeHeldWeakly(keyVal)) {
UniqueChars bytes =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr);
if (!bytes)
@@ -126,8 +126,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp)
return false;
}
keyObject = &keyVal.toObject();
if (!SetWeakMapEntry(cx, map, keyObject, placeholder))
if (!SetWeakMapEntryValue(cx, map, keyVal, placeholder))
return false;
}
} else {
+4 -1
View File
@@ -939,6 +939,8 @@ class GCRuntime
IncrementalProgress drainMarkStack(SliceBudget& sliceBudget, gcstats::Phase phase);
template <class CompartmentIterT> void markWeakReferences(gcstats::Phase phase);
void markWeakReferencesInCurrentGroup(gcstats::Phase phase);
template <class ZoneIterT> void traceFinalizationRegistryWeakRefs();
void traceFinalizationRegistryWeakRefsInCurrentGroup();
template <class ZoneIterT, class CompartmentIterT> void markGrayReferences(gcstats::Phase phase);
void markBufferedGrayRoots(JS::Zone* zone);
void markGrayReferencesInCurrentGroup(gcstats::Phase phase);
@@ -951,6 +953,7 @@ class GCRuntime
void getNextZoneGroup();
void endMarkingZoneGroup();
void beginSweepingZoneGroup(AutoLockForExclusiveAccess& lock);
void sweepFinalizationRegistries();
bool shouldReleaseObservedTypes();
void endSweepingZoneGroup();
IncrementalProgress performSweepActions(SliceBudget& sliceBudget, AutoLockForExclusiveAccess& lock);
@@ -977,7 +980,7 @@ class GCRuntime
void sweepTypesAfterCompacting(Zone* zone);
void sweepZoneAfterCompacting(Zone* zone);
[[nodiscard]] bool relocateArenas(Zone* zone, JS::gcreason::Reason reason,
Arena*& relocatedListOut, SliceBudget& sliceBudget);
Arena*& relocatedListOut, SliceBudget& sliceBudget);
void updateTypeDescrObjects(MovingTracer* trc, Zone* zone);
void updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, size_t bgTaskCount);
void updateAllCellPointers(MovingTracer* trc, Zone* zone);
+10 -10
View File
@@ -416,13 +416,13 @@ MapMemoryAt(void* desired, size_t length, int prot = PROT_READ | PROT_WRITE,
int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0)
// Solaris manages 64-bit address space in a different manner from every other
// AMD64 operating system, but fortunately the fix is the same one
// required for every operating system on 64-bit SPARC, Itanium, and ARM.
// AMD64 operating system, but fortunately the fix is the same one
// required for every operating system on 64-bit SPARC and ARM.
// Most people's intuition failed them here and they thought this couldn't
// possibly be correct on AMD64, but for Solaris/illumos it is.
{
#if defined(__ia64__) || defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) || (defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
#if defined(__aarch64__) || (defined(__sun) && defined(__x86_64__)) || (defined(__sparc__) && defined(__arch64__) && (defined(__NetBSD__) || defined(__linux__)))
MOZ_ASSERT((0xffff800000000000ULL & (uintptr_t(desired) + length - 1)) == 0);
#endif
void* region = mmap(desired, length, prot, flags, fd, offset);
@@ -445,14 +445,14 @@ static inline void*
MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE,
int flags = MAP_PRIVATE | MAP_ANON, int fd = -1, off_t offset = 0)
{
#if defined(__ia64__) || (defined(__sparc__) && defined(__arch64__) && defined(__NetBSD__))
#if defined(__sparc__) && defined(__arch64__) && defined(__NetBSD__)
/*
* The JS engine assumes that all allocated pointers have their high 17 bits clear,
* which ia64's mmap doesn't support directly. However, we can emulate it by passing
* mmap an "addr" parameter with those bits clear. The mmap will return that address,
* or the nearest available memory above that address, providing a near-guarantee
* that those bits are clear. If they are not, we return nullptr below to indicate
* out-of-memory.
* which mmap on this platform doesn't support directly. However, we can emulate it
* by passing mmap an "addr" parameter with those bits clear. The mmap will return
* that address, or the nearest available memory above that address, providing a
* near-guarantee that those bits are clear. If they are not, we return nullptr below
* to indicate out-of-memory.
*
* The addr is chosen as 0x0000070000000000, which still allows about 120TB of virtual
* address space.
@@ -479,7 +479,7 @@ MapMemory(size_t length, int prot = PROT_READ | PROT_WRITE,
* different due to the different mmap behavior.
*
* TODO: Merge with the above code block if this implementation works for
* ia64 and sparc64.
* sparc64.
*/
const uintptr_t start = UINT64_C(0x0000070000000000);
const uintptr_t end = UINT64_C(0x0000800000000000);
+5
View File
@@ -12,6 +12,7 @@
#include "jscntxt.h"
#include "ds/SplayTree.h"
#include "gc/Barrier.h"
#include "gc/FindSCCs.h"
#include "gc/GCRuntime.h"
#include "js/GCHashTable.h"
@@ -325,6 +326,10 @@ struct Zone : public JS::shadow::Zone,
using WeakEdges = js::Vector<js::gc::TenuredCell**, 0, js::SystemAllocPolicy>;
WeakEdges gcWeakRefs;
// FinalizationRegistry objects with weakly-held target cells in this zone.
using FinalizationRegistryVector = js::Vector<js::WeakRef<JSObject*>, 0, js::SystemAllocPolicy>;
FinalizationRegistryVector finalizationRegistries;
// List of non-ephemeron weak containers to sweep during beginSweepingZoneGroup.
mozilla::LinkedList<WeakCache<void*>> weakCaches_;
void registerWeakCache(WeakCache<void*>* cachep) {
@@ -1,4 +1,3 @@
// |jit-test| --ion-sink=on
// Sink Algorithm should not move instruction into merge blocks
// which have no corresponding pc.
+13
View File
@@ -1470,6 +1470,12 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
res.isNumber() &&
!TypedArrayGetElemStubExists(stub, obj))
{
if (obj->is<TypedArrayObject>() &&
obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
{
return true;
}
if (!cx->runtime()->jitSupportsFloatingPoint &&
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
{
@@ -2160,6 +2166,8 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg);
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
if (layout_ == Layout_TypedArray)
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
// Ensure the index is an integer.
if (cx->runtime()->jitSupportsFloatingPoint) {
@@ -2631,6 +2639,9 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
bool expectOutOfBounds;
double idx = index.toNumber();
if (obj->is<TypedArrayObject>()) {
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
return true;
expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
} else {
// Typed objects throw on out of bounds accesses. Don't attach
@@ -3221,6 +3232,8 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
if (layout_ == Layout_TypedArray)
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
// Ensure the index is an integer.
if (cx->runtime()->jitSupportsFloatingPoint) {
+10 -2
View File
@@ -2439,7 +2439,7 @@ static const VMFunction GetOrCreateModuleMetaObjectInfo =
void
CodeGenerator::visitModuleMetadata(LModuleMetadata* lir)
{
pushArg(ImmPtr(lir->mir()->module()));
pushArg(ImmGCPtr(lir->mir()->module()));
callVM(GetOrCreateModuleMetaObjectInfo, lir);
}
@@ -8889,9 +8889,17 @@ CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
Address(obj, NativeObject::offsetOfElements()),
ImmPtr(js::emptyObjectElements),
&emptyObj);
masm.branchPtr(Assembler::NotEqual,
masm.branchPtr(Assembler::Equal,
Address(obj, NativeObject::offsetOfElements()),
ImmPtr(js::emptyObjectElementsShared),
&emptyObj);
masm.branchPtr(Assembler::Equal,
Address(obj, NativeObject::offsetOfElements()),
ImmPtr(js::emptyObjectElementsResizableOrGrowable),
&emptyObj);
masm.branchPtr(Assembler::NotEqual,
Address(obj, NativeObject::offsetOfElements()),
ImmPtr(js::emptyObjectElementsSharedResizableOrGrowable),
target);
masm.bind(&emptyObj);
}
Loaded 100 of 1345 files, more files were not shown because too many files have changed in this diff. Show more