mirror of
https://github.com/Basilisk-Development-Team/UXP-mirror.git
synced 2026-11-04 08:52:01 -05:00
Compare commits
563
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6b18be917d | ||
|
|
037cc5f614 | ||
|
|
4a68bbbd53 | ||
|
|
5762097bc2 | ||
|
|
e86caa48f5 | ||
|
|
612a8991df | ||
|
|
5c991eadc0 | ||
|
|
38e09d2368 | ||
|
|
8fea2ad823 | ||
|
|
c4339b14dc | ||
|
|
bae7a6ec8f | ||
|
|
d42616bb12 | ||
|
|
5f290d1097 | ||
|
|
a0b10f4375 | ||
|
|
1d7ba07673 | ||
|
|
f51bc72a14 | ||
|
|
e8644b494f | ||
|
|
0acf5cb1a1 | ||
|
|
f2d027343a | ||
|
|
eaf2a4ac4b | ||
|
|
aa6a599aa4 | ||
|
|
f385a5e06c | ||
|
|
559e0dbdc5 | ||
|
|
e59e88bfd5 | ||
|
|
7e3d96909f | ||
|
|
d294c31da1 | ||
|
|
d699633e82 | ||
|
|
7079db6476 | ||
|
|
e938cb015b | ||
|
|
15893d9ebc | ||
|
|
0f45bf39af | ||
|
|
23398d176b | ||
|
|
7809ecf653 | ||
|
|
43d19989d4 | ||
|
|
81fce269f5 | ||
|
|
03bdba053e | ||
|
|
5088774087 | ||
|
|
c4d42aaeff | ||
|
|
5b5d7841a6 | ||
|
|
b5e48c5458 | ||
|
|
714c06d255 | ||
|
|
42c59e0781 | ||
|
|
a877a69089 | ||
|
|
98a7463135 | ||
|
|
6cdcc60623 | ||
|
|
c4e2909bdc | ||
|
|
8f1b4387b4 | ||
|
|
a7bc4e7c97 | ||
|
|
62e29a58b0 | ||
|
|
3ede95de79 | ||
|
|
fce465d3a6 | ||
|
|
71edc1fbf5 | ||
|
|
53e4ec00ef | ||
|
|
aa066876a0 | ||
|
|
ae54d6c3d2 | ||
|
|
f69237e99c | ||
|
|
a8fdbd677e | ||
|
|
5316be7d85 | ||
|
|
ea9d3699b0 | ||
|
|
d0c059a3fd | ||
|
|
3a285b8da5 | ||
|
|
d823df1bbb | ||
|
|
a45c04623e | ||
|
|
0f0cbed455 | ||
|
|
a7a133659a | ||
|
|
3a5a5501b9 | ||
|
|
6b6b1828b9 | ||
|
|
c42c56f40e | ||
|
|
bada47c3e0 | ||
|
|
896bdd4e87 | ||
|
|
5faff628ca | ||
|
|
331f1d1716 | ||
|
|
4c19b0c79b | ||
|
|
bb777d838d | ||
|
|
cfd6c45250 | ||
|
|
04cc0dbd19 | ||
|
|
8e1b937e5f | ||
|
|
51e966f1c1 | ||
|
|
f69570b516 | ||
|
|
fb39488301 | ||
|
|
5a3c14e2d3 | ||
|
|
a203222136 | ||
|
|
f77b3dad07 | ||
|
|
7d622afa70 | ||
|
|
c22826727d | ||
|
|
8beee33f4c | ||
|
|
0f0aeca2d5 | ||
|
|
7e68ab76c8 | ||
|
|
3984aba71e | ||
|
|
81b9be16b3 | ||
|
|
cc636f5606 | ||
|
|
67716d3e77 | ||
|
|
47671c9622 | ||
|
|
5f19acf3dc | ||
|
|
271789ceff | ||
|
|
124c914f35 | ||
|
|
8499ba651d | ||
|
|
4a825adf7d | ||
|
|
e6ff828ac7 | ||
|
|
90031251c1 | ||
|
|
059e6407d3 | ||
|
|
46d37a2d26 | ||
|
|
3b5f764740 | ||
|
|
934d61ba05 | ||
|
|
d609be5e04 | ||
|
|
8e2a07c696 | ||
|
|
9aa9d182c7 | ||
|
|
b4bb6051e9 | ||
|
|
53bf5b5a21 | ||
|
|
07b2881965 | ||
|
|
ca1b7c2595 | ||
|
|
a0d8eeb768 | ||
|
|
278ce9a272 | ||
|
|
9367b64f2a | ||
|
|
080247cf2f | ||
|
|
95bf9478c7 | ||
|
|
4ae3149d2e | ||
|
|
9bf01636f1 | ||
|
|
e48fe8e307 | ||
|
|
27c12ad698 | ||
|
|
612ddb64e5 | ||
|
|
c6c8421a2a | ||
|
|
f9859d226c | ||
|
|
7c0e60c4f1 | ||
|
|
e06ef010c4 | ||
|
|
3935cd9ed3 | ||
|
|
f781824676 | ||
|
|
5a231d5bf9 | ||
|
|
02302031dd | ||
|
|
b59b350424 | ||
|
|
99b8669d0a | ||
|
|
919fbff2ec | ||
|
|
4977713834 | ||
|
|
1f8bd8cf45 | ||
|
|
8f6bacf33e | ||
|
|
a79a1b55a1 | ||
|
|
fa4d389b91 | ||
|
|
36b884ff7f | ||
|
|
f3a7e60608 | ||
|
|
a8405c5667 | ||
|
|
829354fb65 | ||
|
|
4be7883908 | ||
|
|
2f77b246b3 | ||
|
|
ddf950f5ed | ||
|
|
ad98fe5130 | ||
|
|
659c690d5b | ||
|
|
f1dc542b0b | ||
|
|
0c5437c80b | ||
|
|
db9881b854 | ||
|
|
c5a37cad2e | ||
|
|
dd97244289 | ||
|
|
5372fed15c | ||
|
|
37a8909357 | ||
|
|
18f4069d8d | ||
|
|
78c01f1b3f | ||
|
|
f946c969a2 | ||
|
|
2dfa2b7c19 | ||
|
|
8b88dd736a | ||
|
|
b9fd964fec | ||
|
|
9c74a819e4 | ||
|
|
f700453cb1 | ||
|
|
4ea0375575 | ||
|
|
7071894a52 | ||
|
|
0f471cfde7 | ||
|
|
a8cc198e79 | ||
|
|
477b1010fe | ||
|
|
8722bc3693 | ||
|
|
e31e3802a0 | ||
|
|
723d95295e | ||
|
|
91b3b6fdc8 | ||
|
|
34a901430d | ||
|
|
83826f1f34 | ||
|
|
3562ba1235 | ||
|
|
1cc002018f | ||
|
|
352863cab4 | ||
|
|
d69570b62b | ||
|
|
26c44d4869 | ||
|
|
f10fc4489c | ||
|
|
3450ed2282 | ||
|
|
967e985c5f | ||
|
|
d6915b9014 | ||
|
|
304e6d045d | ||
|
|
4dea7f04dc | ||
|
|
7cc35f1195 | ||
|
|
afd0648631 | ||
|
|
6524bfee21 | ||
|
|
de8c2d1762 | ||
|
|
5309640d6c | ||
|
|
ddd016a6f8 | ||
|
|
e76fc5637a | ||
|
|
62110dcf7f | ||
|
|
c597f4de77 | ||
|
|
fe4b55154b | ||
|
|
d9f4319bfd | ||
|
|
ec7baced6c | ||
|
|
5ed591c3d7 | ||
|
|
32859868d6 | ||
|
|
4ab80fceb4 | ||
|
|
4e25cc130f | ||
|
|
f1b56f6512 | ||
|
|
b5d6c427ad | ||
|
|
9a900503ea | ||
|
|
f6296891bf | ||
|
|
bbd16ed644 | ||
|
|
8f6cd1cfcd | ||
|
|
70a3532f49 | ||
|
|
c160edb49b | ||
|
|
32f0e6d1e6 | ||
|
|
8c6098ed9e | ||
|
|
5f70302bfc | ||
|
|
f1cc25409a | ||
|
|
1bb67f87d1 | ||
|
|
6f89be191d | ||
|
|
f453aac0eb | ||
|
|
abc2e56e6a | ||
|
|
2f2c86599f | ||
|
|
a52e68f04d | ||
|
|
ee256eda09 | ||
|
|
adbedd87a3 | ||
|
|
4f94981ad9 | ||
|
|
fb15e11ef3 | ||
|
|
b0e1570535 | ||
|
|
b370042040 | ||
|
|
60daf77274 | ||
|
|
4f9ed77789 | ||
|
|
c819a0b3c8 | ||
|
|
104f493044 | ||
|
|
ccfb3fc5db | ||
|
|
9fa543c9f4 | ||
|
|
1d18178eda | ||
|
|
8a6b1f309b | ||
|
|
a60ab0def7 | ||
|
|
6276177e20 | ||
|
|
6c4e8f1466 | ||
|
|
19a4ae248b | ||
|
|
744212dbf3 | ||
|
|
a46fbd6ead | ||
|
|
bb39100caf | ||
|
|
a27a4e4b60 | ||
|
|
490cf03fba | ||
|
|
e93191409e | ||
|
|
5cfdaf4ad4 | ||
|
|
7664a83451 | ||
|
|
f449e1fd7d | ||
|
|
bbd4a99be2 | ||
|
|
4ae471baf9 | ||
|
|
4d41b5df11 | ||
|
|
01188c1465 | ||
|
|
7eac3090a5 | ||
|
|
e9bb602131 | ||
|
|
ddc8b21705 | ||
|
|
6209d33f4e | ||
|
|
cbaace24c0 | ||
|
|
051951ef00 | ||
|
|
a9062b8710 | ||
|
|
18c656ebba | ||
|
|
9220d05de2 | ||
|
|
fdd286d190 | ||
|
|
4fa8a8ce1d | ||
|
|
d5e853a25b | ||
|
|
6ea3635847 | ||
|
|
0ea3d42a38 | ||
|
|
a024df6124 | ||
|
|
11a80021f4 | ||
|
|
301873c751 | ||
|
|
90986caee8 | ||
|
|
778d93ac49 | ||
|
|
f9ba08fa11 | ||
|
|
95911aa2ce | ||
|
|
ccbea05142 | ||
|
|
867c957ceb | ||
|
|
0d2ff3ee65 | ||
|
|
14122475be | ||
|
|
d881e7ed56 | ||
|
|
9b0054c55f | ||
|
|
baeae97784 | ||
|
|
0324bfa219 | ||
|
|
b279fd025b | ||
|
|
f31546817a | ||
|
|
f272382a9c | ||
|
|
aa8af9d7f8 | ||
|
|
e1f03ae019 | ||
|
|
f316bc6535 | ||
|
|
82e4c66520 | ||
|
|
3c923e0467 | ||
|
|
866985ac88 | ||
|
|
ba772b40ad | ||
|
|
7a86f0e1b7 | ||
|
|
7e9286f2d8 | ||
|
|
b0d1e365ec | ||
|
|
dbd5a2cbf4 | ||
|
|
d60fb1d5c0 | ||
|
|
29c91fcdba | ||
|
|
fe65674f3f | ||
|
|
a3a6b5ed7e | ||
|
|
d2de8658a7 | ||
|
|
be785b4783 | ||
|
|
70e34941c4 | ||
|
|
545d52572d | ||
|
|
dfa0736b49 | ||
|
|
c7bb5664d9 | ||
|
|
6bbc6f3417 | ||
|
|
631169a312 | ||
|
|
427b3312a6 | ||
|
|
2287b0b57a | ||
|
|
56aaba09b1 | ||
|
|
332938fef3 | ||
|
|
13710f7a06 | ||
|
|
530693099b | ||
|
|
f68aa7ea88 | ||
|
|
5bdaee5e40 | ||
|
|
1b465bc2e2 | ||
|
|
e455021bea | ||
|
|
4fe1246bcc | ||
|
|
59b4ac4d5f | ||
|
|
de641fedfe | ||
|
|
cb99fabcc0 | ||
|
|
f996ea12c2 | ||
|
|
4e7fb3e0ea | ||
|
|
e7cbbbef0f | ||
|
|
a181078981 | ||
|
|
987a662b51 | ||
|
|
77e3e14e55 | ||
|
|
98ddf30155 | ||
|
|
83da5c58a2 | ||
|
|
7136ae45a7 | ||
|
|
97d3d61749 | ||
|
|
9c8bf1fe5d | ||
|
|
d1cc6ff3cb | ||
|
|
db76d74820 | ||
|
|
8fdd9d52f9 | ||
|
|
d42797f587 | ||
|
|
6b9c1f6ab8 | ||
|
|
4aedc96db2 | ||
|
|
234830da1e | ||
|
|
244b95968f | ||
|
|
810cd553b5 | ||
|
|
e52eaa961c | ||
|
|
b7827091b8 | ||
|
|
2e344377b5 | ||
|
|
15335ce39d | ||
|
|
14b03e1f8c | ||
|
|
0968b94e5c | ||
|
|
ba6b2258aa | ||
|
|
1e1715ff11 | ||
|
|
c93381fa79 | ||
|
|
65b0a59757 | ||
|
|
c785639043 | ||
|
|
512c259822 | ||
|
|
90fea6f0d4 | ||
|
|
d892468fd0 | ||
|
|
81ab98b329 | ||
|
|
3f1cacd3e6 | ||
|
|
6e41e01a29 | ||
|
|
9ce81488d4 | ||
|
|
25bc2630d9 | ||
|
|
e5b69418a0 | ||
|
|
229a69be5f | ||
|
|
7f2561312a | ||
|
|
93d11a07f9 | ||
|
|
8e5e24c4c6 | ||
|
|
517ee6754c | ||
|
|
47690c287c | ||
|
|
364b95170e | ||
|
|
407006d673 | ||
|
|
2d60605cc6 | ||
|
|
2d1129eb7e | ||
|
|
495b4980e7 | ||
|
|
ad480be112 | ||
|
|
a06001c022 | ||
|
|
6cbda74aeb | ||
|
|
576fbdf490 | ||
|
|
52b00c38ea | ||
|
|
8ec56f459b | ||
|
|
5cbe423461 | ||
|
|
369fbba750 | ||
|
|
8e3c35efc6 | ||
|
|
b3b852b877 | ||
|
|
d5c6e20e9e | ||
|
|
89b36775fb | ||
|
|
df16df5693 | ||
|
|
aa1fd576ac | ||
|
|
2512188ca7 | ||
|
|
89e88ca6a0 | ||
|
|
2697dd162f | ||
|
|
53a4179c4a | ||
|
|
a120731ddd | ||
|
|
bda611a41a | ||
|
|
5a02a4a1a4 | ||
|
|
e59f358b45 | ||
|
|
90c9535b39 | ||
|
|
ad778bbfdb | ||
|
|
8868552b24 | ||
|
|
66826eb487 | ||
|
|
39127b5ee9 | ||
|
|
80cff816a8 | ||
|
|
e9dda8dafa | ||
|
|
11fc818dfb | ||
|
|
84ed844e3f | ||
|
|
50af804f1c | ||
|
|
82ce93bce9 | ||
|
|
228abc8259 | ||
|
|
1692fa5291 | ||
|
|
bb58c6ae38 | ||
|
|
4f58dc27f9 | ||
|
|
fc5324b9f7 | ||
|
|
561f65aabf | ||
|
|
9acfe36b95 | ||
|
|
ce495cbd85 | ||
|
|
c44020f188 | ||
|
|
35e7a695af | ||
|
|
7a55055d22 | ||
|
|
061900b87f | ||
|
|
abe32f7309 | ||
|
|
7bfd4c7fe7 | ||
|
|
859d6a3e2c | ||
|
|
c2f05f99af | ||
|
|
55b33fb02b | ||
|
|
c247e40d41 | ||
|
|
05c58f159d | ||
|
|
67d5fefcf2 | ||
|
|
aad017be9e | ||
|
|
4543dbf3ff | ||
|
|
b1cb7e0a8f | ||
|
|
1c6d21c97d | ||
|
|
fc42fb38c9 | ||
|
|
618068c15b | ||
|
|
808516a0a8 | ||
|
|
7d6b806040 | ||
|
|
6b4e2c9d73 | ||
|
|
787883f6a4 | ||
|
|
7f02753c04 | ||
|
|
8fa38b3445 | ||
|
|
541c5f9f45 | ||
|
|
4b6bd4976a | ||
|
|
a0843d52b4 | ||
|
|
977a8cbed8 | ||
|
|
1e85085305 | ||
|
|
188f61505f | ||
|
|
a514d7f6a4 | ||
|
|
47c2c75ceb | ||
|
|
7082ec8a9a | ||
|
|
2907a84362 | ||
|
|
b8d1ee05c3 | ||
|
|
0b625e624a | ||
|
|
a4da712f91 | ||
|
|
185f124e87 | ||
|
|
8633077691 | ||
|
|
39a1899045 | ||
|
|
4dc011a187 | ||
|
|
ccb12e1dda | ||
|
|
63f0d3e295 | ||
|
|
09d598c496 | ||
|
|
7e60482d80 | ||
|
|
10b3237e52 | ||
|
|
99af7cc028 | ||
|
|
76b360b5d1 | ||
|
|
4001b58a3e | ||
|
|
134a8aac87 | ||
|
|
3e2e48872a | ||
|
|
622b43cbc5 | ||
|
|
75b44ef620 | ||
|
|
00084ea49c | ||
|
|
b6fae24296 | ||
|
|
13c6b7422d | ||
|
|
24f2e663cd | ||
|
|
f96b155988 | ||
|
|
d5cc24e916 | ||
|
|
8eba271c5f | ||
|
|
19955c82b3 | ||
|
|
80ae8aec7c | ||
|
|
d8441d7c81 | ||
|
|
c2446f2478 | ||
|
|
6efb7a1904 | ||
|
|
fa0b03a10f | ||
|
|
3ae2972950 | ||
|
|
2d48de9998 | ||
|
|
3b029cdfe4 | ||
|
|
ea9077a8a5 | ||
|
|
b4af6b6265 | ||
|
|
ae1d53ceb1 | ||
|
|
c3f4709d5e | ||
|
|
a7bb3fc175 | ||
|
|
6a0203f25f | ||
|
|
b0dfcb147f | ||
|
|
06fd4c9357 | ||
|
|
b9ea7fd9ee | ||
|
|
58308a5c7a | ||
|
|
88c7d54975 | ||
|
|
eadb5678b3 | ||
|
|
54e3e60796 | ||
|
|
2a05494abe | ||
|
|
bc89e58def | ||
|
|
3a009b97f6 | ||
|
|
a105f6d5e9 | ||
|
|
5db241c0c0 | ||
|
|
d38dca10e5 | ||
|
|
54fc723126 | ||
|
|
9b8ca17ee4 | ||
|
|
cddc95b39b | ||
|
|
5676529793 | ||
|
|
ce68156cf4 | ||
|
|
5032ad9593 | ||
|
|
b55f765f2e | ||
|
|
856078d435 | ||
|
|
c74c262d2f | ||
|
|
787e29e374 | ||
|
|
e439896c9b | ||
|
|
15b508f1fb | ||
|
|
5651ebfc76 | ||
|
|
593bfc1ce8 | ||
|
|
28953cda7a | ||
|
|
516f3f545d | ||
|
|
83aff65a42 | ||
|
|
5bd97df957 | ||
|
|
8772711181 | ||
|
|
dc9526f4c6 | ||
|
|
9ab36e7ae0 | ||
|
|
e8d30841e7 | ||
|
|
9faf29374e | ||
|
|
75e4818d36 | ||
|
|
a65144e9e0 | ||
|
|
4f29548526 | ||
|
|
528db2cbd8 | ||
|
|
84e6bcc1e6 | ||
|
|
0dc9ff518d | ||
|
|
a2e3bd44aa | ||
|
|
163a0e7caf | ||
|
|
49a86db5f3 | ||
|
|
2640953d8b | ||
|
|
7eb7d67f7a | ||
|
|
e28860ba7f | ||
|
|
49a96b1d91 | ||
|
|
3130812693 | ||
|
|
71ae69aea8 | ||
|
|
9e34d697c7 | ||
|
|
8fa9125d02 | ||
|
|
4b4488c3e4 | ||
|
|
248db7d301 | ||
|
|
e199f2949b | ||
|
|
456b5450a4 | ||
|
|
d8e629c4a3 | ||
|
|
4898c4f297 | ||
|
|
7cd578bbc6 | ||
|
|
1e91df628a | ||
|
|
b110549cbd | ||
|
|
971047835a | ||
|
|
dd4d9eb032 | ||
|
|
8b94f1e480 | ||
|
|
c89610a5c7 | ||
|
|
217963cbed | ||
|
|
c4f4e18340 | ||
|
|
8a7c0e7345 | ||
|
|
52e304d450 | ||
|
|
cfc0eeca53 | ||
|
|
ebd3dd9228 | ||
|
|
cb40e4e7ef | ||
|
|
662dba55fd | ||
|
|
8760ce023c | ||
|
|
b86e148bb7 | ||
|
|
9e83721e5e | ||
|
|
dc2d6c2e60 | ||
|
|
4ada6f6762 |
No files matched your search
@@ -276,6 +276,7 @@ NotificationController::DropMutationEvent(AccTreeMutationEvent* aEvent)
|
||||
MOZ_ASSERT(hideEvent);
|
||||
|
||||
if (hideEvent->NeedsShutdown()) {
|
||||
mDocument->UncacheChildrenInSubtree(aEvent->GetAccessible());
|
||||
mDocument->ShutdownChildrenInSubtree(aEvent->GetAccessible());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1307,6 +1307,8 @@ DocAccessible::UnbindFromDocument(Accessible* aAccessible)
|
||||
{
|
||||
NS_ASSERTION(mAccessibleCache.GetWeak(aAccessible->UniqueID()),
|
||||
"Unbinding the unbound accessible!");
|
||||
MOZ_ASSERT(!mARIAOwnsHash.Contains(aAccessible),
|
||||
"Container still lingering in mARIAOwnsHash");
|
||||
|
||||
// Fire focus event on accessible having DOM focus if active item was removed
|
||||
// from the tree.
|
||||
|
||||
@@ -23,7 +23,6 @@ SOURCES += [
|
||||
'DocAccessibleWrap.cpp',
|
||||
'EnumVariant.cpp',
|
||||
'HTMLTableAccessibleWrap.cpp',
|
||||
'HTMLWin32ObjectAccessible.cpp',
|
||||
'HyperTextAccessibleWrap.cpp',
|
||||
'ImageAccessibleWrap.cpp',
|
||||
'IUnknownImpl.cpp',
|
||||
|
||||
Vendored
+1
-1
@@ -26,6 +26,6 @@
|
||||
global DATA_SYMBOL
|
||||
%endif
|
||||
|
||||
SECTION .rodata align=16
|
||||
SECTION .rodata data readable align=16
|
||||
DATA_SYMBOL:
|
||||
incbin ICU_DATA_FILE
|
||||
+6
@@ -6,7 +6,13 @@
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
.global ICU_DATA_SYMBOL
|
||||
#if defined(__APPLE__)
|
||||
.const
|
||||
#elif defined(__GNUC__) && !defined(XP_SOLARIS)
|
||||
.section .rodata
|
||||
#else
|
||||
.data
|
||||
#endif
|
||||
.balign 16
|
||||
ICU_DATA_SYMBOL:
|
||||
.incbin ICU_DATA_FILE
|
||||
Vendored
+2
@@ -17,6 +17,8 @@ DEFINES.update(
|
||||
UCONFIG_NO_LEGACY_CONVERSION = True,
|
||||
UCONFIG_NO_TRANSLITERATION = True,
|
||||
UCONFIG_NO_REGULAR_EXPRESSIONS = True,
|
||||
UCONFIG_NO_BREAK_ITERATION = True,
|
||||
UCONFIG_NO_MF2 = True,
|
||||
|
||||
# We don't need to pass data to and from legacy char* APIs.
|
||||
U_CHARSET_IS_UTF8 = True,
|
||||
|
||||
+17230
-8908
File diff suppressed because it is too large.
Load diff
+969
-295
File diff suppressed because it is too large.
Load diff
@@ -31,6 +31,7 @@ public:
|
||||
void
|
||||
Unfollow();
|
||||
|
||||
/* Should this be WeakRef? */
|
||||
RefPtr<AbortSignal> mFollowingSignal;
|
||||
};
|
||||
|
||||
|
||||
@@ -40,12 +40,14 @@ NS_IMPL_CYCLE_COLLECTION_CLASS(Timeout)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Timeout)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTimer)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptHandler)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Timeout)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimer)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@@ -25,6 +25,22 @@ VisualViewport::~VisualViewport()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(VisualViewport)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VisualViewport,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VisualViewport,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VisualViewport)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(VisualViewport, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(VisualViewport, DOMEventTargetHelper)
|
||||
|
||||
/* virtual */
|
||||
JSObject*
|
||||
VisualViewport::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
|
||||
@@ -21,6 +21,9 @@ class VisualViewport final: public mozilla::DOMEventTargetHelper
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(VisualViewport, DOMEventTargetHelper)
|
||||
|
||||
explicit VisualViewport(nsPIDOMWindowInner* aWindow);
|
||||
explicit VisualViewport(nsIGlobalObject* aGlobal);
|
||||
|
||||
|
||||
@@ -695,7 +695,7 @@ nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
|
||||
!MayContainRelevantNodes(aContainer) ||
|
||||
(!aFirstNewContent->HasChildren() &&
|
||||
!aFirstNewContent->GetNextSibling() &&
|
||||
!MatchSelf(aFirstNewContent))) {
|
||||
!MatchSelf<MatchSelfMode::Insertion>(aFirstNewContent))) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -731,7 +731,7 @@ nsContentList::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer,
|
||||
// The new stuff is somewhere in the middle of our list; check
|
||||
// whether we need to invalidate
|
||||
for (nsIContent* cur = aFirstNewContent; cur; cur = cur->GetNextSibling()) {
|
||||
if (MatchSelf(cur)) {
|
||||
if (MatchSelf<MatchSelfMode::Insertion>(cur)) {
|
||||
// Uh-oh. We're gonna have to add elements into the middle
|
||||
// of our list. That's not worth the effort.
|
||||
SetDirty();
|
||||
@@ -788,7 +788,7 @@ nsContentList::ContentInserted(nsIDocument *aDocument,
|
||||
if (mState != LIST_DIRTY &&
|
||||
MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
|
||||
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
|
||||
MatchSelf(aChild)) {
|
||||
MatchSelf<MatchSelfMode::Insertion>(aChild)) {
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
@@ -808,7 +808,7 @@ nsContentList::ContentRemoved(nsIDocument *aDocument,
|
||||
if (mState != LIST_DIRTY &&
|
||||
MayContainRelevantNodes(NODE_FROM(aContainer, aDocument)) &&
|
||||
nsContentUtils::IsInSameAnonymousTree(mRootNode, aChild) &&
|
||||
MatchSelf(aChild)) {
|
||||
MatchSelf<MatchSelfMode::Removal>(aChild)) {
|
||||
SetDirty();
|
||||
}
|
||||
|
||||
@@ -853,6 +853,7 @@ nsContentList::Match(Element *aElement)
|
||||
ni->Equals(mXMLMatchAtom, mMatchNameSpaceId);
|
||||
}
|
||||
|
||||
template <nsContentList::MatchSelfMode Mode>
|
||||
bool
|
||||
nsContentList::MatchSelf(nsIContent *aContent)
|
||||
{
|
||||
@@ -864,8 +865,20 @@ nsContentList::MatchSelf(nsIContent *aContent)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Match(aContent->AsElement()))
|
||||
auto matches = [&](Element* aElement) {
|
||||
if (Match(aElement)) {
|
||||
return true;
|
||||
}
|
||||
if constexpr (Mode == MatchSelfMode::Removal) {
|
||||
return mFunc == nsContentUtils::MatchClassNames &&
|
||||
aElement->IsSVGElement() && aElement->MayHaveClass();
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (matches(aContent->AsElement())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!mDeep)
|
||||
return false;
|
||||
@@ -873,7 +886,7 @@ nsContentList::MatchSelf(nsIContent *aContent)
|
||||
for (nsIContent* cur = aContent->GetFirstChild();
|
||||
cur;
|
||||
cur = cur->GetNextNode(aContent)) {
|
||||
if (cur->IsElement() && Match(cur->AsElement())) {
|
||||
if (cur->IsElement() && matches(cur->AsElement())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,6 +367,15 @@ protected:
|
||||
* @return whether we match
|
||||
*/
|
||||
bool Match(mozilla::dom::Element *aElement);
|
||||
|
||||
enum class MatchSelfMode : uint8_t {
|
||||
Insertion,
|
||||
// Also accept SVG elements that may have a class. SMIL can change their
|
||||
// class without notification, so they can be in the list without
|
||||
// matching now. Needed when aContent leaves the subtree.
|
||||
Removal,
|
||||
};
|
||||
|
||||
/**
|
||||
* See if anything in the subtree rooted at aContent, including
|
||||
* aContent itself, matches our criterion.
|
||||
@@ -374,6 +383,7 @@ protected:
|
||||
* @param aContent the root of the subtree to match against
|
||||
* @return whether we match something in the tree rooted at aContent
|
||||
*/
|
||||
template <MatchSelfMode Mode>
|
||||
bool MatchSelf(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
|
||||
@@ -2073,6 +2073,10 @@ public:
|
||||
aClasses);
|
||||
}
|
||||
|
||||
static bool MatchClassNames(mozilla::dom::Element* aElement,
|
||||
int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
|
||||
/**
|
||||
* Returns a presshell for this document, if there is one. This will be
|
||||
* aDoc's direct presshell if there is one, otherwise we'll look at all
|
||||
@@ -3012,9 +3016,6 @@ private:
|
||||
|
||||
static void DropFragmentParsers();
|
||||
|
||||
static bool MatchClassNames(mozilla::dom::Element* aElement,
|
||||
int32_t aNamespaceID,
|
||||
nsIAtom* aAtom, void* aData);
|
||||
static void DestroyClassNameArray(void* aData);
|
||||
static void* AllocClassMatchingInfo(nsINode* aRootNode,
|
||||
const nsString* aClasses);
|
||||
|
||||
@@ -921,7 +921,7 @@ private:
|
||||
// List of nodes referred to by mEntryTable so we can sort them
|
||||
// For a specific pseudo element, we use its parent element as the
|
||||
// batch target, so they will be put in the same EntryArray.
|
||||
nsTArray<nsINode*> mBatchTargets;
|
||||
nsTArray<nsCOMPtr<nsINode>> mBatchTargets;
|
||||
};
|
||||
|
||||
inline
|
||||
|
||||
@@ -1738,8 +1738,9 @@ nsFocusManager::Blur(nsPIDOMWindowOuter* aWindowToClear,
|
||||
if (mActiveWindow)
|
||||
window->UpdateCommands(NS_LITERAL_STRING("focus"), nullptr, 0);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = content->GetComposedDoc();
|
||||
SendFocusOrBlurEvent(eBlur, presShell,
|
||||
content->GetComposedDoc(), content, 1,
|
||||
doc, content, 1,
|
||||
false, false, aContentToFocus);
|
||||
}
|
||||
|
||||
|
||||
@@ -2176,6 +2176,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVisualViewport)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
|
||||
@@ -2254,6 +2255,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocation)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHistory)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCustomElements)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVisualViewport)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLocalStorage)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSessionStorage)
|
||||
if (tmp->mApplicationCache) {
|
||||
|
||||
@@ -682,16 +682,19 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
return NS_ERROR_DOM_INDEX_SIZE_ERR;
|
||||
}
|
||||
|
||||
nsAutoString format;
|
||||
GetRealFormat(aFormat, format);
|
||||
|
||||
// Don't allow the custom type to be assigned.
|
||||
if (aFormat.EqualsLiteral(kCustomTypesMime)) {
|
||||
if (format.EqualsLiteral(kCustomTypesMime)) {
|
||||
return NS_ERROR_TYPE_ERR;
|
||||
}
|
||||
|
||||
if (!PrincipalMaySetData(aFormat, aData, aSubjectPrincipal)) {
|
||||
if (!PrincipalMaySetData(format, aData, aSubjectPrincipal)) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
return SetDataWithPrincipal(aFormat, aData, aIndex, aSubjectPrincipal);
|
||||
return SetDataWithPrincipal(format, aData, aIndex, aSubjectPrincipal);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -29,18 +29,19 @@ using namespace workers;
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Request)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Request)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Request)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Request)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Request)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Request)
|
||||
|
||||
@@ -30,12 +30,12 @@ namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(Response)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(Response)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(Response)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSignal)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchStreamReader)
|
||||
|
||||
tmp->mReadableStreamBody = nullptr;
|
||||
@@ -47,6 +47,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Response)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHeaders)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSignal)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchStreamReader)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
|
||||
@@ -1132,6 +1132,7 @@ void HTMLMediaElement::AbortExistingLoads()
|
||||
|
||||
RemoveMediaElementFromURITable();
|
||||
mLoadingSrc = nullptr;
|
||||
mCORSMode = CORS_NONE;
|
||||
mMediaSource = nullptr;
|
||||
|
||||
if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_LOADING ||
|
||||
@@ -1370,6 +1371,9 @@ void HTMLMediaElement::SelectResource()
|
||||
// If we have a 'src' attribute, use that exclusively.
|
||||
nsAutoString src;
|
||||
if (mSrcAttrStream) {
|
||||
// Media provider objects use local mode, so a previous URL load's CORS
|
||||
// mode does not apply.
|
||||
mCORSMode = CORS_NONE;
|
||||
SetupSrcMediaStreamPlayback(mSrcAttrStream);
|
||||
} else if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
|
||||
@@ -117,11 +117,6 @@ public:
|
||||
|
||||
int32_t Index();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLOptionElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
/**
|
||||
* Get the select content element that contains this option, this
|
||||
* intentionally does not return nsresult, all we care about is if
|
||||
@@ -129,6 +124,11 @@ protected:
|
||||
*/
|
||||
HTMLSelectElement* GetSelect();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLOptionElement();
|
||||
|
||||
virtual JSObject* WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
bool mSelectedChanged;
|
||||
bool mIsSelected;
|
||||
|
||||
|
||||
@@ -732,10 +732,10 @@ bool
|
||||
HTMLSelectElement::MatchSelectedOptions(Element* aElement,
|
||||
int32_t /* unused */,
|
||||
nsIAtom* /* unused */,
|
||||
void* /* unused*/)
|
||||
void* aData)
|
||||
{
|
||||
HTMLOptionElement* option = HTMLOptionElement::FromContent(aElement);
|
||||
return option && option->Selected();
|
||||
return option && option->Selected() && option->GetSelect() == static_cast<HTMLSelectElement*>(aData);
|
||||
}
|
||||
|
||||
nsIHTMLCollection*
|
||||
@@ -743,7 +743,7 @@ HTMLSelectElement::SelectedOptions()
|
||||
{
|
||||
if (!mSelectedOptions) {
|
||||
mSelectedOptions = new nsContentList(this, MatchSelectedOptions, nullptr,
|
||||
nullptr, /* deep */ true);
|
||||
this, /* deep */ true);
|
||||
}
|
||||
return mSelectedOptions;
|
||||
}
|
||||
|
||||
@@ -1415,6 +1415,7 @@ BackgroundFactoryRequestChild::BackgroundFactoryRequestChild(
|
||||
uint64_t aRequestedVersion)
|
||||
: BackgroundRequestChildBase(aOpenRequest)
|
||||
, mFactory(aFactory)
|
||||
, mDatabaseActor(nullptr)
|
||||
, mRequestedVersion(aRequestedVersion)
|
||||
, mIsDeleteOp(aIsDeleteOp)
|
||||
{
|
||||
@@ -1439,6 +1440,15 @@ BackgroundFactoryRequestChild::GetOpenDBRequest() const
|
||||
return static_cast<IDBOpenDBRequest*>(mRequest.get());
|
||||
}
|
||||
|
||||
void
|
||||
BackgroundFactoryRequestChild::SetDatabaseActor(BackgroundDatabaseChild* aActor)
|
||||
{
|
||||
AssertIsOnOwningThread();
|
||||
MOZ_ASSERT(!aActor || !mDatabaseActor);
|
||||
|
||||
mDatabaseActor = aActor;
|
||||
}
|
||||
|
||||
bool
|
||||
BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse)
|
||||
{
|
||||
@@ -1450,6 +1460,11 @@ BackgroundFactoryRequestChild::HandleResponse(nsresult aResponse)
|
||||
|
||||
DispatchErrorEvent(mRequest, aResponse);
|
||||
|
||||
if (mDatabaseActor) {
|
||||
mDatabaseActor->ReleaseDOMObject();
|
||||
MOZ_ASSERT(!mDatabaseActor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1468,6 +1483,7 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
IDBDatabase* database = databaseActor->GetDOMObject();
|
||||
if (!database) {
|
||||
databaseActor->EnsureDOMObject();
|
||||
MOZ_ASSERT(mDatabaseActor);
|
||||
|
||||
database = databaseActor->GetDOMObject();
|
||||
MOZ_ASSERT(database);
|
||||
@@ -1475,6 +1491,8 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
MOZ_ASSERT(!database->IsClosed());
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDatabaseActor == databaseActor);
|
||||
|
||||
if (database->IsClosed()) {
|
||||
// If the database was closed already, which is only possible if we fired an
|
||||
// "upgradeneeded" event, then we shouldn't fire a "success" event here.
|
||||
@@ -1487,6 +1505,7 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
}
|
||||
|
||||
databaseActor->ReleaseDOMObject();
|
||||
MOZ_ASSERT(!mDatabaseActor);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1507,6 +1526,8 @@ BackgroundFactoryRequestChild::HandleResponse(
|
||||
|
||||
DispatchSuccessEvent(&helper, successEvent);
|
||||
|
||||
MOZ_ASSERT(!mDatabaseActor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1737,6 +1758,8 @@ BackgroundDatabaseChild::EnsureDOMObject()
|
||||
|
||||
mDatabase = mTemporaryStrongDatabase;
|
||||
mSpec.forget();
|
||||
|
||||
mOpenRequestActor->SetDatabaseActor(this);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1748,6 +1771,8 @@ BackgroundDatabaseChild::ReleaseDOMObject()
|
||||
MOZ_ASSERT(mOpenRequestActor);
|
||||
MOZ_ASSERT(mDatabase == mTemporaryStrongDatabase);
|
||||
|
||||
mOpenRequestActor->SetDatabaseActor(nullptr);
|
||||
|
||||
mOpenRequestActor = nullptr;
|
||||
|
||||
// This may be the final reference to the IDBDatabase object so we may end up
|
||||
|
||||
@@ -254,6 +254,20 @@ class BackgroundFactoryRequestChild final
|
||||
friend class PermissionRequestParent;
|
||||
|
||||
RefPtr<IDBFactory> mFactory;
|
||||
|
||||
// Normally when opening of a database is successful, we receive a database
|
||||
// actor in request response, so we can use it to call ReleaseDOMObject()
|
||||
// which clears temporary strong reference to IDBDatabase.
|
||||
// However, when there's an error, we don't receive a database actor and
|
||||
// IDBRequest::mTransaction is already cleared (must be). So the only way how
|
||||
// to call ReleaseDOMObject() is to have a back-reference to database actor.
|
||||
// This creates a weak ref cycle between
|
||||
// BackgroundFactoryRequestChild (using mDatabaseActor member) and
|
||||
// BackgroundDatabaseChild actor (using mOpenRequestActor member).
|
||||
// mDatabaseActor is set in EnsureDOMObject() and cleared in
|
||||
// ReleaseDOMObject().
|
||||
BackgroundDatabaseChild* mDatabaseActor;
|
||||
|
||||
const uint64_t mRequestedVersion;
|
||||
const bool mIsDeleteOp;
|
||||
|
||||
@@ -271,6 +285,9 @@ private:
|
||||
// Only destroyed by BackgroundFactoryChild.
|
||||
~BackgroundFactoryRequestChild();
|
||||
|
||||
void
|
||||
SetDatabaseActor(BackgroundDatabaseChild* aActor);
|
||||
|
||||
bool
|
||||
HandleResponse(nsresult aResponse);
|
||||
|
||||
|
||||
@@ -138,7 +138,9 @@ GetJSValFromKeyPathString(JSContext* aCx,
|
||||
// only through getters but we still want to support them for key
|
||||
// extraction. So they need to be handled manually.
|
||||
Blob* blob;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &obj, blob))) {
|
||||
// UNWRAP_OBJECT calls might mutate this.
|
||||
JS::Rooted<JSObject*> blobObj(aCx, obj);
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, &blobObj, blob))) {
|
||||
if (token.EqualsLiteral("size")) {
|
||||
ErrorResult rv;
|
||||
uint64_t size = blob->GetSize(rv);
|
||||
|
||||
@@ -265,6 +265,10 @@ VideoData::SetVideoDataToImage(PlanarYCbCrImage* aVideoImage,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ValidateBufferAndPicture(aBuffer, aPicture)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||
|
||||
aVideoImage->SetDelayedConversion(true);
|
||||
|
||||
+21
-7
@@ -187,7 +187,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
explicit VideoInfo(int32_t aWidth, int32_t aHeight)
|
||||
VideoInfo(int32_t aWidth, int32_t aHeight)
|
||||
: VideoInfo(nsIntSize(aWidth, aHeight))
|
||||
{
|
||||
}
|
||||
@@ -201,7 +201,6 @@ public:
|
||||
, mCodecSpecificConfig(new MediaByteBuffer)
|
||||
, mExtraData(new MediaByteBuffer)
|
||||
, mRotation(kDegree_0)
|
||||
, mImageRect(nsIntRect(nsIntPoint(), aSize))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -263,15 +262,28 @@ public:
|
||||
|
||||
nsIntRect ImageRect() const
|
||||
{
|
||||
if (mImageRect.width < 0 || mImageRect.height < 0) {
|
||||
if (!mImageRect) {
|
||||
return nsIntRect(0, 0, mImage.width, mImage.height);
|
||||
}
|
||||
return mImageRect;
|
||||
return *mImageRect;
|
||||
}
|
||||
|
||||
void SetImageRect(const nsIntRect& aRect)
|
||||
{
|
||||
mImageRect = aRect;
|
||||
mImageRect = Some(aRect);
|
||||
}
|
||||
void ResetImageRect() {
|
||||
mImageRect.reset();
|
||||
}
|
||||
|
||||
// Adopts an image size decoded from the bitstream. The picture rectangle is
|
||||
// expressed relative to the image size, so a change in size invalidates it
|
||||
// and it is discarded; an unchanged size keeps the existing rectangle.
|
||||
void AdoptImageSize(const gfx::IntSize& aImage) {
|
||||
if (mImage != aImage) {
|
||||
ResetImageRect();
|
||||
}
|
||||
mImage = aImage;
|
||||
}
|
||||
|
||||
// Returned the crop rectangle scaled to aWidth/aHeight size relative to
|
||||
@@ -332,9 +344,11 @@ public:
|
||||
uint8_t mBitDepth = 8;
|
||||
|
||||
private:
|
||||
friend struct IPC::ParamTraits<VideoInfo>;
|
||||
|
||||
// mImage may be cropped; currently only used with the WebM container.
|
||||
// A negative width or height indicate that no cropping is to occur.
|
||||
nsIntRect mImageRect;
|
||||
// If unset, no cropping is to occur.
|
||||
Maybe<nsIntRect> mImageRect;
|
||||
|
||||
// Indicates whether or not frames may contain alpha information.
|
||||
bool mAlphaPresent = false;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace IPC {
|
||||
WriteParam(aMsg, aParam.mDisplay);
|
||||
WriteParam(aMsg, aParam.mStereoMode);
|
||||
WriteParam(aMsg, aParam.mImage);
|
||||
WriteParam(aMsg, aParam.ImageRect());
|
||||
WriteParam(aMsg, aParam.mImageRect);
|
||||
}
|
||||
|
||||
static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult)
|
||||
@@ -35,8 +35,7 @@ namespace IPC {
|
||||
ReadParam(aMsg, aIter, &aResult->mDisplay) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mStereoMode) &&
|
||||
ReadParam(aMsg, aIter, &aResult->mImage) &&
|
||||
ReadParam(aMsg, aIter, &imageRect)) {
|
||||
aResult->SetImageRect(imageRect);
|
||||
ReadParam(aMsg, aIter, &aResult->mImageRect)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -847,12 +847,15 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
|
||||
RefPtr<layers::PlanarYCbCrImage> image =
|
||||
new IMFYCbCrImage(buffer, twoDBuffer);
|
||||
|
||||
VideoData::SetVideoDataToImage(image,
|
||||
mVideoInfo,
|
||||
b,
|
||||
pictureRegion,
|
||||
false);
|
||||
|
||||
if (!VideoData::SetVideoDataToImage(image,
|
||||
mVideoInfo,
|
||||
b,
|
||||
pictureRegion,
|
||||
false)) {
|
||||
LOG("CreateBasicVideoFrame: failed to set video data to image (shmem path)");
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
RefPtr<VideoData> v =
|
||||
VideoData::CreateFromImage(mVideoInfo,
|
||||
aStreamOffset,
|
||||
|
||||
@@ -307,8 +307,7 @@ H264Converter::UpdateConfigFromExtraData(MediaByteBuffer* aExtraData)
|
||||
if (mp4_demuxer::H264::DecodeSPSFromExtraData(aExtraData, spsdata) &&
|
||||
spsdata.pic_width > 0 && spsdata.pic_height > 0) {
|
||||
mp4_demuxer::H264::EnsureSPSIsSane(spsdata);
|
||||
mCurrentConfig.mImage.width = spsdata.pic_width;
|
||||
mCurrentConfig.mImage.height = spsdata.pic_height;
|
||||
mCurrentConfig.AdoptImageSize(gfx::IntSize(spsdata.pic_width, spsdata.pic_height));
|
||||
mCurrentConfig.mDisplay.width = spsdata.display_width;
|
||||
mCurrentConfig.mDisplay.height = spsdata.display_height;
|
||||
}
|
||||
|
||||
@@ -295,11 +295,11 @@ nsXMLContentSink::DidBuildModel(bool aTerminated)
|
||||
}
|
||||
|
||||
mXSLTProcessor->SetSourceContentModel(mDocument, mDocumentChildren);
|
||||
mDocumentChildren.Clear();
|
||||
// Since the processor now holds a reference to us we drop our reference
|
||||
// to it to avoid owning cycles
|
||||
mXSLTProcessor = nullptr;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Kick off layout for non-XSLT transformed documents.
|
||||
|
||||
// Check if we want to prettyprint
|
||||
@@ -881,6 +881,12 @@ nsXMLContentSink::SetDocElement(int32_t aNameSpaceID,
|
||||
|
||||
if (!mDocumentChildren.IsEmpty()) {
|
||||
for (nsIContent* child : mDocumentChildren) {
|
||||
if (MOZ_UNLIKELY(child->GetParentNode())) {
|
||||
child->Remove();
|
||||
if (MOZ_UNLIKELY(child->GetParentNode())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mDocument->AppendChildTo(child, false);
|
||||
}
|
||||
mDocumentChildren.Clear();
|
||||
@@ -991,6 +997,12 @@ nsXMLContentSink::HandleStartElement(const char16_t *aName,
|
||||
if (!SetDocElement(nameSpaceID, localName, content) && appendContent) {
|
||||
NS_ENSURE_TRUE(parent, NS_ERROR_UNEXPECTED);
|
||||
|
||||
if (MOZ_UNLIKELY(content->GetParentNode())) {
|
||||
content->Remove();
|
||||
if (MOZ_UNLIKELY(content->GetParentNode())) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
parent->AppendChildTo(content, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5159,7 +5159,7 @@ HTMLEditor::IsAcceptableInputEvent(WidgetGUIEvent* aGUIEvent)
|
||||
// If the event is a mouse event, we need to check if the target content is
|
||||
// the focused editing host or its descendant.
|
||||
if (aGUIEvent->AsMouseEventBase()) {
|
||||
nsIContent* editingHost = GetActiveEditingHost();
|
||||
RefPtr<nsIContent> editingHost = GetActiveEditingHost();
|
||||
// If there is no active editing host, we cannot handle the mouse event
|
||||
// correctly.
|
||||
if (!editingHost) {
|
||||
|
||||
@@ -1082,6 +1082,9 @@ ChromeTooltipListener::ChromeTooltipListener(nsWebBrowser* aInBrowser,
|
||||
|
||||
ChromeTooltipListener::~ChromeTooltipListener()
|
||||
{
|
||||
if (mTooltipTimer) {
|
||||
mTooltipTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// Hook up things to the chrome like context menus and tooltips, if the chrome
|
||||
@@ -1329,7 +1332,7 @@ void
|
||||
ChromeTooltipListener::sTooltipCallback(nsITimer* aTimer,
|
||||
void* aChromeTooltipListener)
|
||||
{
|
||||
auto self = static_cast<ChromeTooltipListener*>(aChromeTooltipListener);
|
||||
RefPtr<ChromeTooltipListener> self = static_cast<ChromeTooltipListener*>(aChromeTooltipListener);
|
||||
if (self && self->mPossibleTooltipNode) {
|
||||
// The actual coordinates we want to put the tooltip at are relative to the
|
||||
// toplevel docshell of our mWebBrowser. We know what the screen
|
||||
@@ -1374,7 +1377,7 @@ ChromeTooltipListener::sTooltipCallback(nsITimer* aTimer,
|
||||
self->mPossibleTooltipNode, getter_Copies(tooltipText),
|
||||
getter_Copies(directionText), &textFound);
|
||||
|
||||
if (textFound) {
|
||||
if (self->mPossibleTooltipNode && textFound) {
|
||||
nsString tipText(tooltipText);
|
||||
nsString dirText(directionText);
|
||||
LayoutDeviceIntPoint screenDot = widget->WidgetToScreenOffset();
|
||||
|
||||
@@ -1554,8 +1554,7 @@ FilterNodeTileSoftware::SetAttribute(uint32_t aIndex,
|
||||
const IntRect &aSourceRect)
|
||||
{
|
||||
MOZ_ASSERT(aIndex == ATT_TILE_SOURCE_RECT);
|
||||
mSourceRect = IntRect(int32_t(aSourceRect.x), int32_t(aSourceRect.y),
|
||||
int32_t(aSourceRect.width), int32_t(aSourceRect.height));
|
||||
mSourceRect = aSourceRect;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
@@ -1595,14 +1594,24 @@ FilterNodeTileSoftware::Render(const IntRect& aRect)
|
||||
typedef std::map<IntRect, RefPtr<DataSourceSurface>, CompareIntRects> InputMap;
|
||||
InputMap inputs;
|
||||
|
||||
auto IntRectToInt64Rect = [](const IntRect& aRect) {
|
||||
return RectTyped<UnknownUnits, int64_t>(aRect.X(), aRect.Y(), aRect.Width(),
|
||||
aRect.Height());
|
||||
};
|
||||
|
||||
IntPoint startIndex = TileIndex(mSourceRect, aRect.TopLeft());
|
||||
IntPoint endIndex = TileIndex(mSourceRect, aRect.BottomRight());
|
||||
for (int32_t ix = startIndex.x; ix <= endIndex.x; ix++) {
|
||||
for (int32_t iy = startIndex.y; iy <= endIndex.y; iy++) {
|
||||
IntPoint sourceToDestOffset(ix * mSourceRect.width,
|
||||
iy * mSourceRect.height);
|
||||
IntRect destRect = aRect.Intersect(mSourceRect + sourceToDestOffset);
|
||||
IntRect srcRect = destRect - sourceToDestOffset;
|
||||
auto sourceToDestOffset = PointTyped<UnknownUnits, int64_t>(
|
||||
ix * mSourceRect.Width(), iy * mSourceRect.Height());
|
||||
auto destRect64 = IntRectToInt64Rect(aRect).Intersect(
|
||||
IntRectToInt64Rect(mSourceRect) + sourceToDestOffset);
|
||||
auto srcRect64 = destRect64 - sourceToDestOffset;
|
||||
IntRect destRect, srcRect;
|
||||
if (!destRect64.ToIntRect(&destRect) || !srcRect64.ToIntRect(&srcRect)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (srcRect.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -358,7 +358,8 @@ gl::Error Image9::setManagedSurface(IDirect3DSurface9 *surface)
|
||||
surface->GetDesc(&desc);
|
||||
ASSERT(desc.Pool == D3DPOOL_MANAGED);
|
||||
|
||||
if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight)
|
||||
if ((GLsizei)desc.Width == mWidth && (GLsizei)desc.Height == mHeight &&
|
||||
desc.Format == mD3DFormat)
|
||||
{
|
||||
if (mSurface)
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ static void SK_BLITBWMASK_NAME(const SkPixmap& dst, const SkMask& srcMask,
|
||||
const uint8_t* bits = srcMask.getAddr1(cx, cy);
|
||||
SK_BLITBWMASK_DEVTYPE* device = dst.SK_BLITBWMASK_GETADDR(cx, cy);
|
||||
|
||||
if (cx == maskLeft && clip.fRight == srcMask.fBounds.fRight)
|
||||
if (cx == maskLeft && clip.fRight == srcMask.fBounds.fRight && (clip.width() & 7) == 0)
|
||||
{
|
||||
do {
|
||||
SK_BLITBWMASK_DEVTYPE* dst = device;
|
||||
|
||||
@@ -702,17 +702,16 @@ void SkScalerContext_CairoFT::generateMetrics(SkGlyph* glyph)
|
||||
case FT_GLYPH_FORMAT_BITMAP:
|
||||
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
|
||||
glyph->fMaskFormat = SkMask::kARGB32_Format;
|
||||
}
|
||||
|
||||
if (isLCD(fRec)) {
|
||||
fRec.fMaskFormat = SkMask::kA8_Format;
|
||||
} else if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY ||
|
||||
isLCD(fRec)) {
|
||||
glyph->fMaskFormat = SkMask::kA8_Format;
|
||||
}
|
||||
|
||||
if (fHaveShape) {
|
||||
// Ensure filtering is preserved when the bitmap is transformed.
|
||||
// Otherwise, the result will look horrifically aliased.
|
||||
if (fRec.fMaskFormat == SkMask::kBW_Format) {
|
||||
fRec.fMaskFormat = SkMask::kA8_Format;
|
||||
if (glyph->fMaskFormat == SkMask::kBW_Format) {
|
||||
glyph->fMaskFormat = SkMask::kA8_Format;
|
||||
}
|
||||
|
||||
// Apply the shape matrix to the glyph's bounding box.
|
||||
|
||||
@@ -94,8 +94,6 @@ RasterImage::RasterImage(ImageURL* aURI /* = nullptr */) :
|
||||
//******************************************************************************
|
||||
RasterImage::~RasterImage()
|
||||
{
|
||||
mIsBeingDestroyed = true;
|
||||
|
||||
// Make sure our SourceBuffer is marked as complete. This will ensure that any
|
||||
// outstanding decoders terminate.
|
||||
if (!mSourceBuffer->IsComplete()) {
|
||||
@@ -431,15 +429,17 @@ RasterImage::OnSurfaceDiscarded(const SurfaceKey& aSurfaceKey)
|
||||
{
|
||||
MOZ_ASSERT(mProgressTracker);
|
||||
|
||||
if (mIsBeingDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool animatedFramesDiscarded = aSurfaceKey.Playback() == PlaybackType::eAnimated;
|
||||
|
||||
RefPtr<RasterImage> image = this;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction([=]() -> void {
|
||||
image->OnSurfaceDiscardedInternal(animatedFramesDiscarded);
|
||||
RefPtr<ProgressTracker> progressTracker = mProgressTracker;
|
||||
NS_DispatchToMainThread(NS_NewRunnableFunction(
|
||||
[progressTracker, animatedFramesDiscarded]() -> void {
|
||||
RefPtr<Image> image = progressTracker->GetImage();
|
||||
if (!image) {
|
||||
return;
|
||||
}
|
||||
static_cast<RasterImage*>(image.get())
|
||||
->OnSurfaceDiscardedInternal(animatedFramesDiscarded);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#ifndef mozilla_image_RasterImage_h
|
||||
#define mozilla_image_RasterImage_h
|
||||
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "Image.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "imgIContainer.h"
|
||||
@@ -403,8 +402,6 @@ private: // data
|
||||
// This is currently only used for statistics
|
||||
int32_t mDecodeCount;
|
||||
|
||||
Atomic<bool> mIsBeingDestroyed{false};
|
||||
|
||||
// A weak pointer to our ImageContainer, which stays alive only as long as
|
||||
// the layer system needs it.
|
||||
WeakPtr<layers::ImageContainer> mImageContainer;
|
||||
|
||||
@@ -214,6 +214,7 @@ def update_data_file(topsrcdir):
|
||||
'-DUCONFIG_NO_TRANSLITERATION ' +
|
||||
'-DUCONFIG_NO_REGULAR_EXPRESSIONS ' +
|
||||
'-DUCONFIG_NO_BREAK_ITERATION ' +
|
||||
'-DUCONFIG_NO_MF2 ' +
|
||||
'-DU_CHARSET_IS_UTF8')
|
||||
})
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsReadLine.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include <algorithm>
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
|
||||
using mozilla::dom::EncodingUtils;
|
||||
|
||||
@@ -184,17 +184,8 @@ sub genTest {
|
||||
<p>
|
||||
__END__
|
||||
foreach my $key (sort { $a <=> $b } keys %$hash) {
|
||||
# Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack
|
||||
# of widespread font support for the corresponding Mtavruli characters
|
||||
# at this time (July 2018).
|
||||
# This condition is to be removed once the major platforms ship with
|
||||
# fonts that support U+1C90..1CBF.
|
||||
my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF;
|
||||
print OUT "<!-- " if $skippedGeorgian;
|
||||
printf OUT "&#x%04X;", $key;
|
||||
print OUT " -->" if $skippedGeorgian;
|
||||
print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
|
||||
print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian;
|
||||
print OUT "\n";
|
||||
}
|
||||
print OUT <<__END__;
|
||||
@@ -220,17 +211,8 @@ __END__
|
||||
<p>
|
||||
__END__
|
||||
foreach my $key (sort { $a <=> $b } keys %$hash) {
|
||||
# Bug 1476304: we exclude Georgian letters U+10D0..10FF because of lack
|
||||
# of widespread font support for the corresponding Mtavruli characters
|
||||
# at this time (July 2018).
|
||||
# This condition is to be removed once the major platforms ship with
|
||||
# fonts that support U+1C90..1CBF.
|
||||
my $skippedGeorgian = $whichMapping eq "upper" && $key >= 0x10D0 && $key <= 0x10FF;
|
||||
print OUT "<!-- " if $skippedGeorgian;
|
||||
print OUT join('', map { sprintf("&#x%s;", $_) } split(/ /, $hash->{$key}));
|
||||
print OUT " -->" if $skippedGeorgian;
|
||||
print OUT " <!-- $charName{$key} -->" if exists $charName{$key};
|
||||
print OUT " <!-- Temporarily skipped, see bug 1476304. -->" if $skippedGeorgian;
|
||||
print OUT "\n";
|
||||
}
|
||||
print OUT <<__END__;
|
||||
|
||||
@@ -54,8 +54,6 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
|
||||
// activation (if any) comes around.
|
||||
void* savedPrevJitTop_;
|
||||
|
||||
JS::AutoCheckCannotGC nogc_;
|
||||
|
||||
static const unsigned StorageSpace = 8 * sizeof(void*);
|
||||
|
||||
alignas(void*) unsigned char storage_[StorageSpace];
|
||||
@@ -144,7 +142,7 @@ class MOZ_NON_PARAM JS_PUBLIC_API(ProfilingFrameIterator)
|
||||
void iteratorConstruct();
|
||||
void iteratorDestroy();
|
||||
bool iteratorDone();
|
||||
};
|
||||
} JS_HAZ_GC_INVALIDATED;
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
IsProfilingEnabledForContext(JSContext* cx);
|
||||
|
||||
@@ -69,7 +69,11 @@ WeakRef_deref_impl(JSContext* cx, const CallArgs& args)
|
||||
}
|
||||
|
||||
if (data->isObject()) {
|
||||
JSObject* target = data->objectTarget.get();
|
||||
// Use unbarrieredGet() to avoid barriers on potentially invalid memory.
|
||||
JSObject* target = data->objectTarget.unbarrieredGet();
|
||||
|
||||
// Ensure pointer is not null.
|
||||
// During WeakRef deref, if the target was collected, it will be nullptr.
|
||||
if (target) {
|
||||
RootedValue kept(cx, ObjectValue(*target));
|
||||
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
|
||||
@@ -80,7 +84,9 @@ WeakRef_deref_impl(JSContext* cx, const CallArgs& args)
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(data->isSymbol());
|
||||
JS::Symbol* target = data->symbolTarget.get();
|
||||
JS::Symbol* target = data->symbolTarget.unbarrieredGet();
|
||||
|
||||
// Ensure pointer is not null.
|
||||
if (target) {
|
||||
RootedValue kept(cx, SymbolValue(target));
|
||||
if (!cx->runtime()->addWeakRefKeptObject(cx, kept))
|
||||
|
||||
@@ -1235,10 +1235,9 @@ def writeCLDRLanguageTagLikelySubtagsTest(println, data, url):
|
||||
|
||||
# Step 2: Lookup.
|
||||
searches = ((language, script, region),
|
||||
(language, None, region),
|
||||
(language, script, None),
|
||||
(language, None, None),
|
||||
("und", script, None))
|
||||
(language, None, region),
|
||||
(language, None, None))
|
||||
search = next(search for search in searches if search in likely_subtags)
|
||||
|
||||
(language_s, script_s, region_s) = search
|
||||
|
||||
@@ -714,13 +714,18 @@ class GCRuntime
|
||||
#endif // DEBUG
|
||||
|
||||
bool isInsideUnsafeRegion() { return inUnsafeRegion != 0; }
|
||||
void enterUnsafeRegion() { ++inUnsafeRegion; }
|
||||
void enterUnsafeRegion() {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
++inUnsafeRegion;
|
||||
}
|
||||
void leaveUnsafeRegion() {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
MOZ_ASSERT(inUnsafeRegion > 0);
|
||||
--inUnsafeRegion;
|
||||
}
|
||||
|
||||
void verifyIsSafeToGC() {
|
||||
MOZ_ASSERT(CurrentThreadCanAccessRuntime(rt));
|
||||
MOZ_DIAGNOSTIC_ASSERT(!isInsideUnsafeRegion(),
|
||||
"[AutoAssertNoGC] possible GC in GC-unsafe region");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
|
||||
static void
|
||||
IterateCompartmentsArenasCells(JSContext* cx, Zone* zone, void* data,
|
||||
IterateCompartmentsArenasCellsUnbarriered(JSContext* cx, Zone* zone, void* data,
|
||||
JSIterateCompartmentCallback compartmentCallback,
|
||||
IterateArenaCallback arenaCallback,
|
||||
IterateCellCallback cellCallback)
|
||||
@@ -34,14 +34,14 @@ IterateCompartmentsArenasCells(JSContext* cx, Zone* zone, void* data,
|
||||
for (ArenaIter aiter(zone, thingKind); !aiter.done(); aiter.next()) {
|
||||
Arena* arena = aiter.get();
|
||||
(*arenaCallback)(cx, data, arena, traceKind, thingSize);
|
||||
for (ArenaCellIter iter(arena); !iter.done(); iter.next())
|
||||
for (ArenaCellIterUnbarriered iter(arena); !iter.done(); iter.next())
|
||||
(*cellCallback)(cx, data, iter.getCell(), traceKind, thingSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::IterateZonesCompartmentsArenasCells(JSContext* cx, void* data,
|
||||
js::IterateHeapUnbarriered(JSContext* cx, void* data,
|
||||
IterateZoneCallback zoneCallback,
|
||||
JSIterateCompartmentCallback compartmentCallback,
|
||||
IterateArenaCallback arenaCallback,
|
||||
@@ -51,13 +51,13 @@ js::IterateZonesCompartmentsArenasCells(JSContext* cx, void* data,
|
||||
|
||||
for (ZonesIter zone(cx, WithAtoms); !zone.done(); zone.next()) {
|
||||
(*zoneCallback)(cx, data, zone);
|
||||
IterateCompartmentsArenasCells(cx, zone, data,
|
||||
IterateCompartmentsArenasCellsUnbarriered(cx, zone, data,
|
||||
compartmentCallback, arenaCallback, cellCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
js::IterateZoneCompartmentsArenasCells(JSContext* cx, Zone* zone, void* data,
|
||||
js::IterateHeapUnbarrieredForZone(JSContext* cx, Zone* zone, void* data,
|
||||
IterateZoneCallback zoneCallback,
|
||||
JSIterateCompartmentCallback compartmentCallback,
|
||||
IterateArenaCallback arenaCallback,
|
||||
@@ -66,7 +66,7 @@ js::IterateZoneCompartmentsArenasCells(JSContext* cx, Zone* zone, void* data,
|
||||
AutoPrepareForTracing prop(cx, WithAtoms);
|
||||
|
||||
(*zoneCallback)(cx, data, zone);
|
||||
IterateCompartmentsArenasCells(cx, zone, data,
|
||||
IterateCompartmentsArenasCellsUnbarriered(cx, zone, data,
|
||||
compartmentCallback, arenaCallback, cellCallback);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
static uint32_t CountPhysBits(FloatRegisters::SetType bits) {
|
||||
MOZ_ASSERT((bits & ~FloatRegisters::AllPhysMask) == 0);
|
||||
return mozilla::CountPopulation32(uint32_t(bits));
|
||||
}
|
||||
|
||||
Registers::Code Registers::FromName(const char* name) {
|
||||
for (size_t i = 0; i < TotalPhys; i++) {
|
||||
if (strcmp(GetName(i), name) == 0) {
|
||||
@@ -37,43 +42,47 @@ FloatRegisters::Code FloatRegisters::FromName(const char* name) {
|
||||
}
|
||||
|
||||
FloatRegisterSet FloatRegister::ReduceSetForPush(const FloatRegisterSet& s) {
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
SetType bits = s.bits();
|
||||
|
||||
LiveFloatRegisterSet ret;
|
||||
for (FloatRegisterIterator iter(s); iter.more(); ++iter) {
|
||||
ret.addUnchecked(FromCode((*iter).encoding()));
|
||||
}
|
||||
return ret.set();
|
||||
// Exclude registers already represented by a wider alias. Higher alias banks
|
||||
// are wider, so preserve only the widest live view of each physical register.
|
||||
bits &= ~(bits >> (1 * FloatRegisters::TotalPhys));
|
||||
bits &= ~(bits >> (2 * FloatRegisters::TotalPhys));
|
||||
|
||||
return FloatRegisterSet(bits);
|
||||
}
|
||||
|
||||
uint32_t FloatRegister::GetSizeInBytes(const FloatRegisterSet& s) {
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
|
||||
return s.size() * sizeof(double);
|
||||
return s.size() * sizeof(FloatRegisters::RegisterContent);
|
||||
}
|
||||
|
||||
uint32_t FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s) {
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
SetType all = s.bits();
|
||||
SetType set128b =
|
||||
(all >> (uint32_t(FloatRegisters::Simd128) * FloatRegisters::TotalPhys)) &
|
||||
FloatRegisters::AllPhysMask;
|
||||
SetType doubleSet =
|
||||
(all >> (uint32_t(FloatRegisters::Double) * FloatRegisters::TotalPhys)) &
|
||||
FloatRegisters::AllPhysMask;
|
||||
SetType singleSet =
|
||||
(all >> (uint32_t(FloatRegisters::Single) * FloatRegisters::TotalPhys)) &
|
||||
FloatRegisters::AllPhysMask;
|
||||
|
||||
return s.size() * sizeof(double);
|
||||
SetType set64b = doubleSet & ~set128b;
|
||||
SetType set32b = singleSet & ~set64b & ~set128b;
|
||||
|
||||
return CountPhysBits(set128b) * (4 * sizeof(int32_t)) +
|
||||
CountPhysBits(set64b) * sizeof(double) +
|
||||
CountPhysBits(set32b) * sizeof(float);
|
||||
}
|
||||
|
||||
uint32_t FloatRegister::getRegisterDumpOffsetInBytes() {
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
|
||||
return encoding() * sizeof(double);
|
||||
return encoding() * sizeof(FloatRegisters::RegisterContent);
|
||||
}
|
||||
|
||||
bool CPUFlagsHaveBeenComputed() {
|
||||
// TODO(loongarch64): Add CPU flags support.
|
||||
// The LoongArch64 backend does not currently gate code generation on
|
||||
// optional CPU features.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -249,9 +249,9 @@ class FloatRegisters {
|
||||
// Eight bits: (invalid << 7) | (kind << 5) | encoding
|
||||
typedef uint8_t Code;
|
||||
typedef FPRegisterID Encoding;
|
||||
typedef uint64_t SetType;
|
||||
typedef unsigned __int128 SetType;
|
||||
|
||||
enum Kind : uint8_t { Double, Single, NumTypes };
|
||||
enum Kind : uint8_t { Double, Single, Simd128, NumTypes };
|
||||
|
||||
static constexpr Code Invalid = 0x80;
|
||||
|
||||
@@ -285,7 +285,11 @@ class FloatRegisters {
|
||||
<< (uint32_t(Single) * TotalPhys);
|
||||
static const SetType SpreadDouble = SetType(1)
|
||||
<< (uint32_t(Double) * TotalPhys);
|
||||
static const SetType Spread = SpreadSingle | SpreadDouble;
|
||||
static const SetType SpreadSimd128 = SetType(1)
|
||||
<< (uint32_t(Simd128) * TotalPhys);
|
||||
static const SetType SpreadScalar = SpreadSingle | SpreadDouble;
|
||||
static const SetType SpreadVector = SpreadSimd128;
|
||||
static const SetType Spread = SpreadScalar | SpreadVector;
|
||||
|
||||
static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
|
||||
static const SetType AllMask = AllPhysMask * Spread;
|
||||
@@ -293,13 +297,16 @@ class FloatRegisters {
|
||||
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
|
||||
static const SetType NoneMask = SetType(0);
|
||||
|
||||
// TODO(loongarch64): Much less than ARM64 here.
|
||||
// LoongArch64 callee-saved floating-point registers are f24-f31.
|
||||
static const SetType NonVolatileMask =
|
||||
SetType((1 << FloatRegisters::f24) | (1 << FloatRegisters::f25) |
|
||||
(1 << FloatRegisters::f26) | (1 << FloatRegisters::f27) |
|
||||
(1 << FloatRegisters::f28) | (1 << FloatRegisters::f29) |
|
||||
(1 << FloatRegisters::f30) | (1 << FloatRegisters::f31)) *
|
||||
Spread;
|
||||
((SetType(1) << FloatRegisters::f24) |
|
||||
(SetType(1) << FloatRegisters::f25) |
|
||||
(SetType(1) << FloatRegisters::f26) |
|
||||
(SetType(1) << FloatRegisters::f27) |
|
||||
(SetType(1) << FloatRegisters::f28) |
|
||||
(SetType(1) << FloatRegisters::f29) |
|
||||
(SetType(1) << FloatRegisters::f30) |
|
||||
(SetType(1) << FloatRegisters::f31)) * Spread;
|
||||
|
||||
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
|
||||
|
||||
@@ -317,6 +324,8 @@ class FloatRegisters {
|
||||
union RegisterContent {
|
||||
float s;
|
||||
double d;
|
||||
int32_t i4[4];
|
||||
float s4[4];
|
||||
};
|
||||
|
||||
static constexpr Encoding encoding(Code c) {
|
||||
@@ -359,26 +368,35 @@ struct FloatRegister {
|
||||
typedef Codes::SetType SetType;
|
||||
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
static_assert(sizeof(SetType) == 16, "SetType must be 128 bits");
|
||||
x |= x >> FloatRegisters::TotalPhys;
|
||||
x |= x >> (2 * FloatRegisters::TotalPhys);
|
||||
x &= FloatRegisters::AllPhysMask;
|
||||
return mozilla::CountPopulation32(x);
|
||||
}
|
||||
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType");
|
||||
return mozilla::CountTrailingZeroes64(x);
|
||||
MOZ_ASSERT(x != 0);
|
||||
uint64_t low = uint64_t(x);
|
||||
if (low) {
|
||||
return mozilla::CountTrailingZeroes64(low);
|
||||
}
|
||||
return 64 + mozilla::CountTrailingZeroes64(uint64_t(x >> 64));
|
||||
}
|
||||
static uint32_t LastBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType");
|
||||
return 63 - mozilla::CountLeadingZeroes64(x);
|
||||
MOZ_ASSERT(x != 0);
|
||||
uint64_t high = uint64_t(x >> 64);
|
||||
if (high) {
|
||||
return 127 - mozilla::CountLeadingZeroes64(high);
|
||||
}
|
||||
return 63 - mozilla::CountLeadingZeroes64(uint64_t(x));
|
||||
}
|
||||
|
||||
private:
|
||||
// These fields only hold valid values: an invalid register is always
|
||||
// represented as a valid encoding and kind with the invalid_ bit set.
|
||||
uint8_t encoding_; // 32 encodings
|
||||
uint8_t kind_; // Double, Single; more later
|
||||
uint8_t kind_; // Double, Single, Simd128
|
||||
bool invalid_;
|
||||
|
||||
typedef Codes::Kind Kind;
|
||||
@@ -387,6 +405,8 @@ struct FloatRegister {
|
||||
union RegisterContent {
|
||||
float s;
|
||||
double d;
|
||||
int32_t i4[4];
|
||||
float s4[4];
|
||||
};
|
||||
|
||||
constexpr FloatRegister(Encoding encoding, Kind kind)
|
||||
@@ -417,7 +437,7 @@ struct FloatRegister {
|
||||
}
|
||||
bool isSimd128() const {
|
||||
MOZ_ASSERT(!invalid_);
|
||||
return false;
|
||||
return kind_ == FloatRegisters::Simd128;
|
||||
}
|
||||
bool isInvalid() const { return invalid_; }
|
||||
|
||||
@@ -430,13 +450,19 @@ struct FloatRegister {
|
||||
return FloatRegister(Encoding(encoding_), FloatRegisters::Double);
|
||||
}
|
||||
FloatRegister doubleOverlay() const { return asDouble(); }
|
||||
FloatRegister asSimd128() const { MOZ_CRASH(); }
|
||||
FloatRegister asSimd128() const {
|
||||
MOZ_ASSERT(!invalid_);
|
||||
return FloatRegister(Encoding(encoding_), FloatRegisters::Simd128);
|
||||
}
|
||||
|
||||
constexpr uint32_t size() const {
|
||||
MOZ_ASSERT(!invalid_);
|
||||
if (kind_ == FloatRegisters::Double) {
|
||||
return sizeof(double);
|
||||
}
|
||||
if (kind_ == FloatRegisters::Simd128) {
|
||||
return 4 * sizeof(int32_t);
|
||||
}
|
||||
MOZ_ASSERT(kind_ == FloatRegisters::Single);
|
||||
return sizeof(float);
|
||||
}
|
||||
|
||||
@@ -49,11 +49,6 @@ void js::jit::PatchJump(CodeLocationJump& jump_, CodeLocationLabel label,
|
||||
// Note this is used for inter-wasm calls and may pass arguments and results
|
||||
// in floating point registers even if the system ABI does not.
|
||||
|
||||
// TODO(loongarch64): Inconsistent with LoongArch's calling convention.
|
||||
// LoongArch floating-point parameters calling convention:
|
||||
// The first eight floating-point parameters should be passed in f0-f7, and
|
||||
// the other floating point parameters will be passed like integer parameters.
|
||||
// But we just pass the other floating-point parameters on stack here.
|
||||
ABIArg ABIArgGenerator::next(MIRType type) {
|
||||
switch (type) {
|
||||
case MIRType::Int32:
|
||||
@@ -70,16 +65,40 @@ ABIArg ABIArgGenerator::next(MIRType type) {
|
||||
}
|
||||
case MIRType::Float32:
|
||||
case MIRType::Double: {
|
||||
if (floatRegIndex_ == NumFloatArgRegs) {
|
||||
if (floatRegIndex_ < NumFloatArgRegs) {
|
||||
current_ = ABIArg(FloatRegister(
|
||||
FloatRegisters::Encoding(floatRegIndex_ + f0.encoding()),
|
||||
type == MIRType::Double ? FloatRegisters::Double
|
||||
: FloatRegisters::Single));
|
||||
floatRegIndex_++;
|
||||
break;
|
||||
}
|
||||
if (intRegIndex_ == NumIntArgRegs) {
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += sizeof(double);
|
||||
break;
|
||||
}
|
||||
current_ = ABIArg(FloatRegister(
|
||||
FloatRegisters::Encoding(floatRegIndex_ + f0.encoding()),
|
||||
type == MIRType::Double ? FloatRegisters::Double
|
||||
: FloatRegisters::Single));
|
||||
floatRegIndex_++;
|
||||
current_ = ABIArg(Register::FromCode(intRegIndex_ + a0.encoding()));
|
||||
intRegIndex_++;
|
||||
break;
|
||||
}
|
||||
case MIRType::Int8x16:
|
||||
case MIRType::Int16x8:
|
||||
case MIRType::Int32x4:
|
||||
case MIRType::Float32x4:
|
||||
case MIRType::Bool8x16:
|
||||
case MIRType::Bool16x8:
|
||||
case MIRType::Bool32x4: {
|
||||
if (floatRegIndex_ < NumFloatArgRegs) {
|
||||
current_ = ABIArg(FloatRegister(
|
||||
FloatRegisters::Encoding(floatRegIndex_ + f0.encoding()),
|
||||
FloatRegisters::Simd128));
|
||||
floatRegIndex_++;
|
||||
break;
|
||||
}
|
||||
stackOffset_ = AlignBytes(stackOffset_, SimdMemoryAlignment);
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += Simd128DataSize;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -334,8 +353,19 @@ void AssemblerLOONGARCH64::WriteInstStatic(uint32_t x, uint32_t* dest) {
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::haltingAlign(int alignment) {
|
||||
// TODO(loongarch64): Implement a proper halting align.
|
||||
return nopAlign(alignment);
|
||||
BufferOffset ret;
|
||||
MOZ_ASSERT(m_buffer.isAligned(4));
|
||||
MOZ_ASSERT((alignment & (alignment - 1)) == 0);
|
||||
|
||||
while (size() & (alignment - 1)) {
|
||||
BufferOffset tmp(size());
|
||||
as_break(WASM_TRAP);
|
||||
if (!ret.assigned()) {
|
||||
ret = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::nopAlign(int alignment) {
|
||||
@@ -436,10 +466,30 @@ InstImm AssemblerLOONGARCH64::getBranchCode(JumpOrCall jumpOrCall) {
|
||||
}
|
||||
|
||||
InstImm AssemblerLOONGARCH64::getBranchCode(Register rj, Register rd, Condition c) {
|
||||
// beq, bne
|
||||
MOZ_ASSERT(c == AssemblerLOONGARCH64::Equal || c == AssemblerLOONGARCH64::NotEqual);
|
||||
return InstImm(c == AssemblerLOONGARCH64::Equal ? op_beq : op_bne, BOffImm16(0),
|
||||
rj, rd);
|
||||
switch (c) {
|
||||
case AssemblerLOONGARCH64::Equal:
|
||||
return InstImm(op_beq, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::NotEqual:
|
||||
return InstImm(op_bne, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::Above:
|
||||
return InstImm(op_bltu, BOffImm16(0), rd, rj);
|
||||
case AssemblerLOONGARCH64::AboveOrEqual:
|
||||
return InstImm(op_bgeu, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::Below:
|
||||
return InstImm(op_bltu, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::BelowOrEqual:
|
||||
return InstImm(op_bgeu, BOffImm16(0), rd, rj);
|
||||
case AssemblerLOONGARCH64::GreaterThan:
|
||||
return InstImm(op_blt, BOffImm16(0), rd, rj);
|
||||
case AssemblerLOONGARCH64::GreaterThanOrEqual:
|
||||
return InstImm(op_bge, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::LessThan:
|
||||
return InstImm(op_blt, BOffImm16(0), rj, rd);
|
||||
case AssemblerLOONGARCH64::LessThanOrEqual:
|
||||
return InstImm(op_bge, BOffImm16(0), rd, rj);
|
||||
default:
|
||||
MOZ_CRASH("Condition not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
InstImm AssemblerLOONGARCH64::getBranchCode(Register rj, Condition c) {
|
||||
@@ -1010,6 +1060,118 @@ BufferOffset AssemblerLOONGARCH64::as_st_d(Register rd, Register rj, int32_t si1
|
||||
return writeInst(InstImm(op_st_d, si12, rj, rd, 12).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vld(FloatRegister vd, Register rj,
|
||||
int32_t si12) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(is_intN(si12, 12));
|
||||
spew("vld %3s,%3s,0x%x", vd.name(), rj.name(), si12);
|
||||
return writeInst(InstImm(op_vld, si12, rj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vst(FloatRegister vd, Register rj,
|
||||
int32_t si12) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(is_intN(si12, 12));
|
||||
spew("vst %3s,%3s,0x%x", vd.name(), rj.name(), si12);
|
||||
return writeInst(InstImm(op_vst, si12, rj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_clt_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.clt.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_clt_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_ceq_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.ceq.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_ceq_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_cle_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.cle.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_cle_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_cun_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.cun.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_cun_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_cult_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.cult.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_cult_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_cule_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.cule.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_cule_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfcmp_cune_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfcmp.cune.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfcmp_cune_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vbitsel_v(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk,
|
||||
FloatRegister va) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
MOZ_ASSERT(va.isSimd128());
|
||||
spew("vbitsel.v %3s,%3s,%3s,%3s", vd.name(), vj.name(), vk.name(),
|
||||
va.name());
|
||||
return writeInst(InstReg(op_vbitsel_v, va, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vshuf_b(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk,
|
||||
FloatRegister va) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
MOZ_ASSERT(va.isSimd128());
|
||||
spew("vshuf.b %3s,%3s,%3s,%3s", vd.name(), vj.name(), vk.name(),
|
||||
va.name());
|
||||
return writeInst(InstReg(op_vshuf_b, va, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_ldx_b(Register rd, Register rj, Register rk) {
|
||||
spew("ldx_b %3s,%3s,%3s", rd.name(), rj.name(), rk.name());
|
||||
return writeInst(InstReg(op_ldx_b, rk, rj, rd).encode());
|
||||
@@ -1068,6 +1230,425 @@ BufferOffset AssemblerLOONGARCH64::as_stx_d(Register rd, Register rj, Register r
|
||||
return writeInst(InstReg(op_stx_d, rk, rj, rd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vldx(FloatRegister vd, Register rj,
|
||||
Register rk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
spew("vldx %3s,%3s,%3s", vd.name(), rj.name(), rk.name());
|
||||
return writeInst(InstReg(op_vldx, rk, rj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vstx(FloatRegister vd, Register rj,
|
||||
Register rk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
spew("vstx %3s,%3s,%3s", vd.name(), rj.name(), rk.name());
|
||||
return writeInst(InstReg(op_vstx, rk, rj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vseq_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vseq.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vseq_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsle_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsle.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsle_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsle_wu(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsle.wu %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsle_wu, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vslt_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vslt.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vslt_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vslt_wu(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vslt.wu %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vslt_wu, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vadd_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vadd.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vadd_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsub_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsub.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsub_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vmax_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vmax.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vmax_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vmin_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vmin.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vmin_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vmax_wu(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vmax.wu %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vmax_wu, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vmin_wu(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vmin.wu %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vmin_wu, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vmul_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vmul.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vmul_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsll_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsll.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsll_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsrl_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsrl.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsrl_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsra_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vsra.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vsra_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vilvl_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vilvl.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vilvl_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vilvh_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vilvh.w %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vilvh_w, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vand_v(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vand.v %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vand_v, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vor_v(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vor.v %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vor_v, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vxor_v(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vxor.v %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vxor_v, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vnor_v(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vnor.v %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vnor_v, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vandn_v(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vandn.v %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vandn_v, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfadd_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfadd.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfadd_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfsub_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfsub.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfsub_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfmul_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfmul.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfmul_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfmax_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfmax.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfmax_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfmin_s(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
FloatRegister vk) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(vk.isSimd128());
|
||||
spew("vfmin.s %3s,%3s,%3s", vd.name(), vj.name(), vk.name());
|
||||
return writeInst(InstReg(op_vfmin_s, vk, vj, vd).encode());
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vneg_w(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vneg.w %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vneg_w | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfsqrt_s(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vfsqrt.s %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vfsqrt_s | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfrecip_s(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vfrecip.s %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vfrecip_s | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfrsqrt_s(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vfrsqrt.s %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vfrsqrt_s | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vfrint_s(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vfrint.s %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vfrint_s | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vffint_s_w(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vffint.s.w %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vffint_s_w | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vftint_w_s(FloatRegister vd,
|
||||
FloatRegister vj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
spew("vftint.w.s %3s,%3s", vd.name(), vj.name());
|
||||
return writeInst(op_vftint_w_s | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vreplgr2vr_w(FloatRegister vd,
|
||||
Register rj) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
spew("vreplgr2vr.w %3s,%3s", vd.name(), rj.name());
|
||||
return writeInst(op_vreplgr2vr_w | RJ(rj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vreplvei_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
uint32_t lane) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(lane < 4);
|
||||
spew("vreplvei.w %3s,%3s,%u", vd.name(), vj.name(), lane);
|
||||
return writeInst(op_vreplvei_w | (lane << RKShift) | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vinsgr2vr_w(FloatRegister vd,
|
||||
Register rj,
|
||||
uint32_t lane) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(lane < 4);
|
||||
spew("vinsgr2vr.w %3s,%3s,%u", vd.name(), rj.name(), lane);
|
||||
return writeInst(op_vinsgr2vr_w | (lane << RKShift) | RJ(rj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vpickve2gr_w(Register rd,
|
||||
FloatRegister vj,
|
||||
uint32_t lane) {
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(lane < 4);
|
||||
spew("vpickve2gr.w %3s,%3s,%u", rd.name(), vj.name(), lane);
|
||||
return writeInst(op_vpickve2gr_w | (lane << RKShift) | FJ(vj) | RD(rd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vpickve2gr_wu(Register rd,
|
||||
FloatRegister vj,
|
||||
uint32_t lane) {
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(lane < 4);
|
||||
spew("vpickve2gr.wu %3s,%3s,%u", rd.name(), vj.name(), lane);
|
||||
return writeInst(op_vpickve2gr_wu | (lane << RKShift) | FJ(vj) | RD(rd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vslli_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
uint32_t imm) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(imm < 32);
|
||||
spew("vslli.w %3s,%3s,%u", vd.name(), vj.name(), imm);
|
||||
return writeInst(op_vslli_w | (imm << RKShift) | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsrli_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
uint32_t imm) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(imm < 32);
|
||||
spew("vsrli.w %3s,%3s,%u", vd.name(), vj.name(), imm);
|
||||
return writeInst(op_vsrli_w | (imm << RKShift) | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vsrai_w(FloatRegister vd,
|
||||
FloatRegister vj,
|
||||
uint32_t imm) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(vj.isSimd128());
|
||||
MOZ_ASSERT(imm < 32);
|
||||
spew("vsrai.w %3s,%3s,%u", vd.name(), vj.name(), imm);
|
||||
return writeInst(op_vsrai_w | (imm << RKShift) | FJ(vj) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_vldi(FloatRegister vd, int32_t imm) {
|
||||
MOZ_ASSERT(vd.isSimd128());
|
||||
MOZ_ASSERT(is_intN(imm, 13));
|
||||
spew("vldi %3s,%d", vd.name(), imm);
|
||||
return writeInst(op_vldi | ((imm & Imm13Mask) << Imm13Shift) | FD(vd));
|
||||
}
|
||||
|
||||
BufferOffset AssemblerLOONGARCH64::as_ldptr_w(Register rd, Register rj,
|
||||
int32_t si14) {
|
||||
MOZ_ASSERT(is_intN(si14, 16) && ((si14 & 0x3) == 0));
|
||||
|
||||
@@ -101,7 +101,8 @@ static constexpr Register64 ReturnReg64(ReturnReg);
|
||||
static constexpr FloatRegister ReturnFloat32Reg{FloatRegisters::f0,
|
||||
FloatRegisters::Single};
|
||||
static constexpr FloatRegister ReturnDoubleReg = f0;
|
||||
static constexpr FloatRegister ReturnSimd128Reg = InvalidFloatReg;
|
||||
static constexpr FloatRegister ReturnSimd128Reg{FloatRegisters::f0,
|
||||
FloatRegisters::Simd128};
|
||||
|
||||
static constexpr Register ScratchRegister = t7;
|
||||
static constexpr Register SecondScratchReg = t8;
|
||||
@@ -121,7 +122,8 @@ struct SecondScratchRegisterScope : public AutoRegisterScope {
|
||||
static constexpr FloatRegister ScratchFloat32Reg{FloatRegisters::f23,
|
||||
FloatRegisters::Single};
|
||||
static constexpr FloatRegister ScratchDoubleReg = f23;
|
||||
static constexpr FloatRegister ScratchSimd128Reg = InvalidFloatReg;
|
||||
static constexpr FloatRegister ScratchSimd128Reg{FloatRegisters::f23,
|
||||
FloatRegisters::Simd128};
|
||||
|
||||
struct ScratchFloat32Scope : public AutoFloatRegisterScope {
|
||||
explicit ScratchFloat32Scope(MacroAssembler& masm)
|
||||
@@ -226,11 +228,20 @@ static constexpr Register WasmJitEntryReturnScratch = t1;
|
||||
static constexpr uint32_t ABIStackAlignment = 16;
|
||||
static constexpr uint32_t CodeAlignment = 16;
|
||||
|
||||
// Does this architecture support SIMD conversions between Uint32x4 and
|
||||
// Float32x4?
|
||||
static constexpr bool SupportsUint32x4FloatConversions = false;
|
||||
|
||||
// Does this architecture support comparisons of unsigned integer vectors?
|
||||
static constexpr bool SupportsUint8x16Compares = false;
|
||||
static constexpr bool SupportsUint16x8Compares = false;
|
||||
static constexpr bool SupportsUint32x4Compares = false;
|
||||
|
||||
// This boolean indicates whether we support SIMD instructions flavoured for
|
||||
// this architecture or not. Rather than a method in the LIRGenerator, it is
|
||||
// here such that it is accessible from the entire codebase. Once full support
|
||||
// for SIMD is reached on all tier-1 platforms, this constant can be deleted.
|
||||
static constexpr bool SupportsSimd = false;
|
||||
static constexpr bool SupportsSimd = true;
|
||||
static constexpr uint32_t JitStackAlignment = 16;
|
||||
|
||||
static constexpr uint32_t JitStackValueAlignment =
|
||||
@@ -239,8 +250,8 @@ static_assert(JitStackAlignment % sizeof(Value) == 0 &&
|
||||
JitStackValueAlignment >= 1,
|
||||
"Stack alignment should be a non-zero multiple of sizeof(Value)");
|
||||
|
||||
// TODO(loongarch64): this is just a filler to prevent a build failure. The
|
||||
// LoongArch SIMD alignment requirements still need to be explored.
|
||||
// LoongArch LSX SIMD vectors are 128 bits wide, so use 16-byte alignment for
|
||||
// SIMD constants and wasm stack alignment even while SIMD codegen is disabled.
|
||||
static constexpr uint32_t SimdMemoryAlignment = 16;
|
||||
|
||||
static_assert(CodeAlignment % SimdMemoryAlignment == 0,
|
||||
@@ -260,9 +271,8 @@ static constexpr uint32_t WasmCheckedTailEntryOffset = 16u;
|
||||
|
||||
static constexpr Scale ScalePointer = TimesEight;
|
||||
|
||||
// TODO(loongarch64): Add LoongArch instruction types description.
|
||||
|
||||
// LoongArch instruction encoding constants.
|
||||
// LoongArch instruction encoding constants. The assembler models the encodings
|
||||
// used by this backend as register, immediate, and jump instruction records.
|
||||
static const uint32_t RJShift = 5;
|
||||
static const uint32_t RJBits = 5;
|
||||
static const uint32_t RKShift = 10;
|
||||
@@ -303,6 +313,8 @@ static const uint32_t Imm6Shift = 10;
|
||||
static const uint32_t Imm6Bits = 6;
|
||||
static const uint32_t Imm12Shift = 10;
|
||||
static const uint32_t Imm12Bits = 12;
|
||||
static const uint32_t Imm13Shift = 5;
|
||||
static const uint32_t Imm13Bits = 13;
|
||||
static const uint32_t Imm14Shift = 10;
|
||||
static const uint32_t Imm14Bits = 14;
|
||||
static const uint32_t Imm15Shift = 0;
|
||||
@@ -333,6 +345,7 @@ static const uint32_t CODEMask = (1 << CODEBits) - 1;
|
||||
static const uint32_t Imm5Mask = (1 << Imm5Bits) - 1;
|
||||
static const uint32_t Imm6Mask = (1 << Imm6Bits) - 1;
|
||||
static const uint32_t Imm12Mask = (1 << Imm12Bits) - 1;
|
||||
static const uint32_t Imm13Mask = (1 << Imm13Bits) - 1;
|
||||
static const uint32_t Imm14Mask = (1 << Imm14Bits) - 1;
|
||||
static const uint32_t Imm15Mask = (1 << Imm15Bits) - 1;
|
||||
static const uint32_t Imm16Mask = (1 << Imm16Bits) - 1;
|
||||
@@ -344,11 +357,11 @@ static const uint32_t BOffImm21Mask = ((1 << Imm21Bits) - 1) << Imm21Shift;
|
||||
static const uint32_t BOffImm26Mask = ((1 << Imm26Bits) - 1) << Imm26Shift;
|
||||
static const uint32_t RegMask = Registers::Total - 1;
|
||||
|
||||
// TODO(loongarch64) Change to syscall?
|
||||
static const uint32_t MAX_BREAK_CODE = 1024 - 1;
|
||||
// Use LoongArch BRK for wasm traps and debug breakpoints. Signal handling code
|
||||
// decodes the BRK immediate to recover the wasm trap kind.
|
||||
static const uint32_t WASM_TRAP = 6; // BRK_OVERFLOW
|
||||
|
||||
// TODO(loongarch64) Change to LoongArch instruction type.
|
||||
class Instruction;
|
||||
class InstReg;
|
||||
class InstImm;
|
||||
@@ -428,6 +441,17 @@ enum OpcodeField {
|
||||
op_fst_s = 0xadU << 22,
|
||||
op_fld_d = 0xaeU << 22,
|
||||
op_fst_d = 0xafU << 22,
|
||||
op_vld = 0x2c000000,
|
||||
op_vst = 0x2c400000,
|
||||
op_vfcmp_clt_s = 0x0c510000,
|
||||
op_vfcmp_ceq_s = 0x0c520000,
|
||||
op_vfcmp_cle_s = 0x0c530000,
|
||||
op_vfcmp_cun_s = 0x0c540000,
|
||||
op_vfcmp_cult_s = 0x0c550000,
|
||||
op_vfcmp_cule_s = 0x0c570000,
|
||||
op_vfcmp_cune_s = 0x0c5c0000,
|
||||
op_vbitsel_v = 0x0d100000,
|
||||
op_vshuf_b = 0x0d500000,
|
||||
op_bstr_w = 0x3U << 21, // BSTRINS_W & BSTRPICK_W
|
||||
op_fmadd_s = 0x81U << 20,
|
||||
op_fmadd_d = 0x82U << 20,
|
||||
@@ -530,6 +554,51 @@ enum OpcodeField {
|
||||
op_fldx_d = 0x7068U << 15,
|
||||
op_fstx_s = 0x7070U << 15,
|
||||
op_fstx_d = 0x7078U << 15,
|
||||
op_vldx = 0x38400000,
|
||||
op_vstx = 0x38440000,
|
||||
op_vseq_w = 0x70010000,
|
||||
op_vsle_w = 0x70030000,
|
||||
op_vsle_wu = 0x70050000,
|
||||
op_vslt_w = 0x70070000,
|
||||
op_vslt_wu = 0x70090000,
|
||||
op_vadd_w = 0x700b0000,
|
||||
op_vsub_w = 0x700d0000,
|
||||
op_vmax_w = 0x70710000,
|
||||
op_vmin_w = 0x70730000,
|
||||
op_vmax_wu = 0x70750000,
|
||||
op_vmin_wu = 0x70770000,
|
||||
op_vmul_w = 0x70850000,
|
||||
op_vsll_w = 0x70e90000,
|
||||
op_vsrl_w = 0x70eb0000,
|
||||
op_vsra_w = 0x70ed0000,
|
||||
op_vilvl_w = 0x711b0000,
|
||||
op_vilvh_w = 0x711d0000,
|
||||
op_vand_v = 0x71260000,
|
||||
op_vor_v = 0x71268000,
|
||||
op_vxor_v = 0x71270000,
|
||||
op_vnor_v = 0x71278000,
|
||||
op_vandn_v = 0x71280000,
|
||||
op_vfadd_s = 0x71308000,
|
||||
op_vfsub_s = 0x71328000,
|
||||
op_vfmul_s = 0x71388000,
|
||||
op_vfmax_s = 0x713c8000,
|
||||
op_vfmin_s = 0x713e8000,
|
||||
op_vneg_w = 0x729c3800,
|
||||
op_vfsqrt_s = 0x729ce400,
|
||||
op_vfrecip_s = 0x729cf400,
|
||||
op_vfrsqrt_s = 0x729d0400,
|
||||
op_vfrint_s = 0x729d3400,
|
||||
op_vffint_s_w = 0x729e0000,
|
||||
op_vftint_w_s = 0x729e3000,
|
||||
op_vreplgr2vr_w = 0x729f0800,
|
||||
op_vreplvei_w = 0x72f7e000,
|
||||
op_vinsgr2vr_w = 0x72ebe000,
|
||||
op_vpickve2gr_w = 0x72efe000,
|
||||
op_vpickve2gr_wu = 0x72f3e000,
|
||||
op_vslli_w = 0x732c8000,
|
||||
op_vsrli_w = 0x73308000,
|
||||
op_vsrai_w = 0x73348000,
|
||||
op_vldi = 0x73e00000,
|
||||
op_amswap_w = 0x70c0U << 15,
|
||||
op_amswap_d = 0x70c1U << 15,
|
||||
op_amadd_w = 0x70c2U << 15,
|
||||
@@ -866,7 +935,8 @@ class LOONGBufferWithExecutableCopy : public LOONGBuffer {
|
||||
|
||||
class AssemblerLOONGARCH64 : public AssemblerShared {
|
||||
public:
|
||||
// TODO(loongarch64): Should we remove these conditions here?
|
||||
// Keep the shared condition vocabulary so shared MacroAssembler and
|
||||
// CodeGenerator code can lower comparisons without per-use remapping.
|
||||
enum Condition {
|
||||
Equal,
|
||||
NotEqual,
|
||||
@@ -1251,6 +1321,26 @@ class AssemblerLOONGARCH64 : public AssemblerShared {
|
||||
BufferOffset as_st_h(Register rd, Register rj, int32_t si12);
|
||||
BufferOffset as_st_w(Register rd, Register rj, int32_t si12);
|
||||
BufferOffset as_st_d(Register rd, Register rj, int32_t si12);
|
||||
BufferOffset as_vld(FloatRegister vd, Register rj, int32_t si12);
|
||||
BufferOffset as_vst(FloatRegister vd, Register rj, int32_t si12);
|
||||
BufferOffset as_vfcmp_clt_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_ceq_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_cle_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_cun_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_cult_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_cule_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vfcmp_cune_s(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk);
|
||||
BufferOffset as_vbitsel_v(FloatRegister vd, FloatRegister vj,
|
||||
FloatRegister vk, FloatRegister va);
|
||||
BufferOffset as_vshuf_b(FloatRegister vd, FloatRegister vj, FloatRegister vk,
|
||||
FloatRegister va);
|
||||
|
||||
BufferOffset as_ldx_b(Register rd, Register rj, Register rk);
|
||||
BufferOffset as_ldx_h(Register rd, Register rj, Register rk);
|
||||
@@ -1263,6 +1353,51 @@ class AssemblerLOONGARCH64 : public AssemblerShared {
|
||||
BufferOffset as_stx_h(Register rd, Register rj, Register rk);
|
||||
BufferOffset as_stx_w(Register rd, Register rj, Register rk);
|
||||
BufferOffset as_stx_d(Register rd, Register rj, Register rk);
|
||||
BufferOffset as_vldx(FloatRegister vd, Register rj, Register rk);
|
||||
BufferOffset as_vstx(FloatRegister vd, Register rj, Register rk);
|
||||
BufferOffset as_vseq_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsle_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsle_wu(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vslt_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vslt_wu(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vadd_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsub_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vmax_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vmin_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vmax_wu(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vmin_wu(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vmul_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsll_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsrl_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vsra_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vilvl_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vilvh_w(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vand_v(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vor_v(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vxor_v(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vnor_v(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vandn_v(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vfadd_s(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vfsub_s(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vfmul_s(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vfmax_s(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vfmin_s(FloatRegister vd, FloatRegister vj, FloatRegister vk);
|
||||
BufferOffset as_vneg_w(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vfsqrt_s(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vfrecip_s(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vfrsqrt_s(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vfrint_s(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vffint_s_w(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vftint_w_s(FloatRegister vd, FloatRegister vj);
|
||||
BufferOffset as_vreplgr2vr_w(FloatRegister vd, Register rj);
|
||||
BufferOffset as_vreplvei_w(FloatRegister vd, FloatRegister vj, uint32_t lane);
|
||||
BufferOffset as_vinsgr2vr_w(FloatRegister vd, Register rj, uint32_t lane);
|
||||
BufferOffset as_vpickve2gr_w(Register rd, FloatRegister vj, uint32_t lane);
|
||||
BufferOffset as_vpickve2gr_wu(Register rd, FloatRegister vj, uint32_t lane);
|
||||
BufferOffset as_vslli_w(FloatRegister vd, FloatRegister vj, uint32_t imm);
|
||||
BufferOffset as_vsrli_w(FloatRegister vd, FloatRegister vj, uint32_t imm);
|
||||
BufferOffset as_vsrai_w(FloatRegister vd, FloatRegister vj, uint32_t imm);
|
||||
BufferOffset as_vldi(FloatRegister vd, int32_t imm);
|
||||
|
||||
BufferOffset as_ldptr_w(Register rd, Register rj, int32_t si14);
|
||||
BufferOffset as_ldptr_d(Register rd, Register rj, int32_t si14);
|
||||
@@ -1479,7 +1614,7 @@ class AssemblerLOONGARCH64 : public AssemblerShared {
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
static bool SupportsSimd() { return false; }
|
||||
static bool SupportsSimd() { return true; }
|
||||
static bool SupportsUnalignedAccesses() { return true; }
|
||||
static bool SupportsFastUnalignedFPAccesses() { return true; }
|
||||
|
||||
|
||||
@@ -833,7 +833,14 @@ CodeGeneratorLoongArch64::visitWrapInt64ToInt32(LWrapInt64ToInt32* lir)
|
||||
else
|
||||
masm.ma_sll(output, ToRegister(input), Imm32(0));
|
||||
} else {
|
||||
MOZ_CRASH("Not implemented.");
|
||||
if (input->isMemory())
|
||||
masm.load32(Address(ToAddress(input).base,
|
||||
ToAddress(input).offset + sizeof(int32_t)),
|
||||
output);
|
||||
else {
|
||||
masm.ma_dsrl(output, ToRegister(input), Imm32(32));
|
||||
masm.ma_sll(output, output, Imm32(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1010,15 +1017,37 @@ CodeGeneratorLoongArch64::visitTestI64AndBranch(LTestI64AndBranch* lir)
|
||||
emitBranch(input.reg, Imm32(0), Assembler::NonZero, ifTrue, ifFalse);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorLoongArch64::visitWasmStackArg(LWasmStackArg* ins)
|
||||
{
|
||||
MIRType type = ins->mir()->input()->type();
|
||||
|
||||
if (IsSimdType(type)) {
|
||||
MOZ_ASSERT(ins->arg()->isFloatReg());
|
||||
Address dst(StackPointer, ins->mir()->spOffset());
|
||||
FloatRegister src = ToFloatRegister(ins->arg()).asSimd128();
|
||||
|
||||
if (type == MIRType::Float32x4)
|
||||
masm.storeAlignedSimd128Float(src, dst);
|
||||
else
|
||||
masm.storeAlignedSimd128Int(src, dst);
|
||||
return;
|
||||
}
|
||||
|
||||
CodeGeneratorMIPSShared::visitWasmStackArg(ins);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorLoongArch64::setReturnDoubleRegs(LiveRegisterSet* regs)
|
||||
{
|
||||
MOZ_ASSERT(ReturnFloat32Reg.encoding() == FloatRegisters::f0);
|
||||
MOZ_ASSERT(ReturnDoubleReg.encoding() == FloatRegisters::f0);
|
||||
MOZ_ASSERT(ReturnSimd128Reg.encoding() == FloatRegisters::f0);
|
||||
FloatRegister f1 = { FloatRegisters::f1, FloatRegisters::Single };
|
||||
regs->add(ReturnFloat32Reg);
|
||||
regs->add(f1);
|
||||
regs->add(ReturnDoubleReg);
|
||||
regs->add(ReturnSimd128Reg);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -65,6 +65,7 @@ class CodeGeneratorLoongArch64 : public CodeGeneratorMIPSShared
|
||||
void visitWasmUnalignedLoadI64(LWasmUnalignedLoadI64* lir);
|
||||
void visitWasmStoreI64(LWasmStoreI64* ins);
|
||||
void visitWasmUnalignedStoreI64(LWasmUnalignedStoreI64* ins);
|
||||
void visitWasmStackArg(LWasmStackArg* ins);
|
||||
void visitWasmLoadGlobalVarI64(LWasmLoadGlobalVarI64* ins);
|
||||
void visitWasmStoreGlobalVarI64(LWasmStoreGlobalVarI64* ins);
|
||||
void visitWasmSelectI64(LWasmSelectI64* ins);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "jit/loongarch64/MacroAssembler-loongarch64.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "jsmath.h"
|
||||
|
||||
#include "jit/Bailouts.h"
|
||||
@@ -955,8 +957,13 @@ void MacroAssemblerLOONGARCH64::ma_subPtrTestOverflow(Register rd, Register rj,
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_subPtrTestOverflow(Register rd, Register rj,
|
||||
Imm32 imm, Label* overflow) {
|
||||
// TODO(loongarch64): Check subPtrTestOverflow
|
||||
MOZ_ASSERT(imm.value != INT32_MIN);
|
||||
if (imm.value == INT32_MIN) {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
ma_li(scratch2, imm);
|
||||
ma_subPtrTestOverflow(rd, rj, scratch2, overflow);
|
||||
return;
|
||||
}
|
||||
|
||||
ma_addPtrTestOverflow(rd, rj, Imm32(-imm.value), overflow);
|
||||
}
|
||||
|
||||
@@ -1294,10 +1301,20 @@ void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Register rj, ImmPtr imm,
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Address address, Imm32 imm,
|
||||
Condition c) {
|
||||
// TODO(loongarch64): 32-bit ma_cmp_set?
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
ma_ld_w(scratch2, address);
|
||||
ma_cmp_set(rd, Register(scratch2), imm, c);
|
||||
switch (c) {
|
||||
case Above:
|
||||
case AboveOrEqual:
|
||||
case Below:
|
||||
case BelowOrEqual:
|
||||
ma_ld_wu(scratch2, address);
|
||||
ma_cmp_set(rd, Register(scratch2), ImmWord(uint32_t(imm.value)), c);
|
||||
break;
|
||||
default:
|
||||
ma_ld_w(scratch2, address);
|
||||
ma_cmp_set(rd, Register(scratch2), imm, c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_cmp_set(Register rd, Address address,
|
||||
@@ -1384,6 +1401,36 @@ void MacroAssemblerLOONGARCH64::ma_fst_d(FloatRegister src, Address address) {
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_vld(FloatRegister dest, Address address) {
|
||||
MOZ_ASSERT(dest.isSimd128());
|
||||
int32_t offset = address.offset;
|
||||
Register base = address.base;
|
||||
|
||||
if (is_intN(offset, 12)) {
|
||||
as_vld(dest, base, offset);
|
||||
} else {
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
MOZ_ASSERT(base != scratch);
|
||||
ma_li(scratch, Imm32(offset));
|
||||
as_vldx(dest, base, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_vst(FloatRegister src, Address address) {
|
||||
MOZ_ASSERT(src.isSimd128());
|
||||
int32_t offset = address.offset;
|
||||
Register base = address.base;
|
||||
|
||||
if (is_intN(offset, 12)) {
|
||||
as_vst(src, base, offset);
|
||||
} else {
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
MOZ_ASSERT(base != scratch);
|
||||
ma_li(scratch, Imm32(offset));
|
||||
as_vstx(src, base, scratch);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_pop(FloatRegister f) {
|
||||
if (f.isDouble()) {
|
||||
as_fld_d(f, StackPointer, 0);
|
||||
@@ -1847,12 +1894,19 @@ void MacroAssemblerLOONGARCH64::storeUnalignedFloat32(
|
||||
}
|
||||
|
||||
// Branches when done from within loongarch-specific code.
|
||||
// TODO(loongarch64) Optimize ma_b
|
||||
void MacroAssemblerLOONGARCH64::ma_b(Register lhs, Register rhs, Label* label,
|
||||
Condition c, JumpKind jumpKind) {
|
||||
switch (c) {
|
||||
case Equal:
|
||||
case NotEqual:
|
||||
case Above:
|
||||
case AboveOrEqual:
|
||||
case Below:
|
||||
case BelowOrEqual:
|
||||
case GreaterThan:
|
||||
case GreaterThanOrEqual:
|
||||
case LessThan:
|
||||
case LessThanOrEqual:
|
||||
asMasm().branchWithCode(getBranchCode(lhs, rhs, c), label, jumpKind);
|
||||
break;
|
||||
case Always:
|
||||
@@ -1865,12 +1919,8 @@ void MacroAssemblerLOONGARCH64::ma_b(Register lhs, Register rhs, Label* label,
|
||||
MOZ_ASSERT(lhs == rhs);
|
||||
asMasm().branchWithCode(getBranchCode(lhs, c), label, jumpKind);
|
||||
break;
|
||||
default: {
|
||||
Condition cond = ma_cmp(ScratchRegister, lhs, rhs, c);
|
||||
asMasm().branchWithCode(getBranchCode(ScratchRegister, cond), label,
|
||||
jumpKind);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Invalid condition.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2046,6 +2096,12 @@ void MacroAssemblerLOONGARCH64::ma_fst_s(FloatRegister ft, BaseIndex address) {
|
||||
asMasm().ma_fst_s(ft, Address(scratch2, address.offset));
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_vst(FloatRegister ft, BaseIndex address) {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
asMasm().computeScaledAddress(address, scratch2);
|
||||
asMasm().ma_vst(ft, Address(scratch2, address.offset));
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_fld_d(FloatRegister ft, const BaseIndex& src) {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
asMasm().computeScaledAddress(src, scratch2);
|
||||
@@ -2058,6 +2114,12 @@ void MacroAssemblerLOONGARCH64::ma_fld_s(FloatRegister ft, const BaseIndex& src)
|
||||
asMasm().ma_fld_s(ft, Address(scratch2, src.offset));
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_vld(FloatRegister ft, const BaseIndex& src) {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
asMasm().computeScaledAddress(src, scratch2);
|
||||
asMasm().ma_vld(ft, Address(scratch2, src.offset));
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::ma_bc_s(FloatRegister lhs, FloatRegister rhs,
|
||||
Label* label, DoubleCondition c,
|
||||
JumpKind jumpKind, FPConditionBit fcc) {
|
||||
@@ -2390,6 +2452,390 @@ void MacroAssemblerLOONGARCH64::loadFloat32(const BaseIndex& src,
|
||||
asMasm().ma_fld_s(dest, src);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::loadUnalignedSimd128Float(const Address& src,
|
||||
FloatRegister dest) {
|
||||
asMasm().ma_vld(dest.asSimd128(), src);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::loadUnalignedSimd128Float(const BaseIndex& src,
|
||||
FloatRegister dest) {
|
||||
asMasm().ma_vld(dest.asSimd128(), src);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::storeUnalignedSimd128Float(FloatRegister src,
|
||||
const Address& dest) {
|
||||
asMasm().ma_vst(src.asSimd128(), dest);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::storeUnalignedSimd128Float(FloatRegister src,
|
||||
const BaseIndex& dest) {
|
||||
asMasm().ma_vst(src.asSimd128(), dest);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::loadConstantSimd128Int(const SimdConstant& v,
|
||||
FloatRegister dest) {
|
||||
uint64_t words[2];
|
||||
memcpy(words, v.bytes(), sizeof(words));
|
||||
|
||||
ma_add_d(StackPointer, StackPointer, Imm32(-Simd128DataSize));
|
||||
{
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
ma_li(scratch, ImmWord(words[0]));
|
||||
ma_st_d(scratch, Address(StackPointer, 0));
|
||||
ma_li(scratch, ImmWord(words[1]));
|
||||
ma_st_d(scratch, Address(StackPointer, sizeof(uint64_t)));
|
||||
}
|
||||
loadAlignedSimd128Int(Address(StackPointer, 0), dest);
|
||||
ma_add_d(StackPointer, StackPointer, Imm32(Simd128DataSize));
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::loadConstantSimd128Float(const SimdConstant& v,
|
||||
FloatRegister dest) {
|
||||
loadConstantSimd128Int(v, dest);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::moveSimd128Float(FloatRegister src,
|
||||
FloatRegister dest) {
|
||||
src = src.asSimd128();
|
||||
dest = dest.asSimd128();
|
||||
if (src == dest) {
|
||||
return;
|
||||
}
|
||||
as_vor_v(dest, src, src);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::zeroSimd128Float(FloatRegister dest) {
|
||||
dest = dest.asSimd128();
|
||||
as_vxor_v(dest, dest, dest);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::createInt32x4(Register lane0, Register lane1,
|
||||
Register lane2, Register lane3,
|
||||
FloatRegister dest) {
|
||||
dest = dest.asSimd128();
|
||||
as_vreplgr2vr_w(dest, lane0);
|
||||
as_vinsgr2vr_w(dest, lane1, 1);
|
||||
as_vinsgr2vr_w(dest, lane2, 2);
|
||||
as_vinsgr2vr_w(dest, lane3, 3);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::splatX4(Register input, FloatRegister output) {
|
||||
as_vreplgr2vr_w(output.asSimd128(), input);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::splatX4(FloatRegister input,
|
||||
FloatRegister output) {
|
||||
as_vreplvei_w(output.asSimd128(), input.asSimd128(), 0);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::extractLaneInt32x4(FloatRegister input,
|
||||
Register output,
|
||||
unsigned lane) {
|
||||
as_vpickve2gr_w(output, input.asSimd128(), lane);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::extractLaneFloat32x4(FloatRegister input,
|
||||
FloatRegister output,
|
||||
unsigned lane,
|
||||
bool canonicalize) {
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
as_vpickve2gr_w(scratch, input.asSimd128(), lane);
|
||||
moveToFloat32(scratch, output);
|
||||
if (canonicalize) {
|
||||
asMasm().canonicalizeFloat(output);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::insertLaneSimdInt(FloatRegister input,
|
||||
Register value,
|
||||
FloatRegister output,
|
||||
unsigned lane,
|
||||
unsigned numLanes) {
|
||||
MOZ_ASSERT(numLanes == 4);
|
||||
if (input != output) {
|
||||
moveSimd128Int(input, output);
|
||||
}
|
||||
as_vinsgr2vr_w(output.asSimd128(), value, lane);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::insertLaneFloat32x4(FloatRegister input,
|
||||
FloatRegister value,
|
||||
FloatRegister output,
|
||||
unsigned lane) {
|
||||
if (input != output) {
|
||||
moveSimd128Float(input, output);
|
||||
}
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
moveFromFloat32(value, scratch);
|
||||
as_vinsgr2vr_w(output.asSimd128(), scratch, lane);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::addInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vadd_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::subInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsub_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::mulInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vmul_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::minInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vmin_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::maxInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vmax_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::minUint32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vmin_wu(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::maxUint32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vmax_wu(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::negInt32x4(FloatRegister input,
|
||||
FloatRegister dest) {
|
||||
as_vneg_w(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::shiftLeftInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsll_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::shiftRightInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsra_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::unsignedShiftRightInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsrl_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::shiftLeftInt32x4(FloatRegister lhs, Imm32 rhs,
|
||||
FloatRegister dest) {
|
||||
as_vslli_w(dest.asSimd128(), lhs.asSimd128(), rhs.value & 31);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::shiftRightInt32x4(FloatRegister lhs, Imm32 rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsrai_w(dest.asSimd128(), lhs.asSimd128(), rhs.value & 31);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::unsignedShiftRightInt32x4(FloatRegister lhs,
|
||||
Imm32 rhs,
|
||||
FloatRegister dest) {
|
||||
as_vsrli_w(dest.asSimd128(), lhs.asSimd128(), rhs.value & 31);
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareInt32x4Equal(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vseq_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareInt32x4LessThan(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vslt_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareInt32x4LessThanOrEqual(
|
||||
FloatRegister lhs, FloatRegister rhs, FloatRegister dest) {
|
||||
as_vsle_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareUint32x4LessThan(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vslt_wu(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareUint32x4LessThanOrEqual(
|
||||
FloatRegister lhs, FloatRegister rhs, FloatRegister dest) {
|
||||
as_vsle_wu(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::addFloat32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfadd_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::subFloat32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfsub_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::mulFloat32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfmul_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::minFloat32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfmin_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::maxFloat32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfmax_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::sqrtFloat32x4(FloatRegister input,
|
||||
FloatRegister dest) {
|
||||
as_vfsqrt_s(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::reciprocalApproximationFloat32x4(
|
||||
FloatRegister input, FloatRegister dest) {
|
||||
as_vfrecip_s(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::reciprocalSqrtApproximationFloat32x4(
|
||||
FloatRegister input, FloatRegister dest) {
|
||||
as_vfrsqrt_s(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::roundFloat32x4(FloatRegister input,
|
||||
FloatRegister dest) {
|
||||
as_vfrint_s(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::convertInt32x4ToFloat32x4(FloatRegister input,
|
||||
FloatRegister dest) {
|
||||
as_vffint_s_w(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::convertFloat32x4ToInt32x4(FloatRegister input,
|
||||
FloatRegister dest) {
|
||||
as_vftint_w_s(dest.asSimd128(), input.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4Equal(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfcmp_ceq_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4NotEqual(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfcmp_cune_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4LessThan(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfcmp_clt_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4LessThanOrEqual(
|
||||
FloatRegister lhs, FloatRegister rhs, FloatRegister dest) {
|
||||
as_vfcmp_cle_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4Unordered(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vfcmp_cun_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4UnorderedLessThan(
|
||||
FloatRegister lhs, FloatRegister rhs, FloatRegister dest) {
|
||||
as_vfcmp_cult_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::compareFloat32x4UnorderedLessThanOrEqual(
|
||||
FloatRegister lhs, FloatRegister rhs, FloatRegister dest) {
|
||||
as_vfcmp_cule_s(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::interleaveLowInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vilvl_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::interleaveHighInt32x4(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vilvh_w(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitselectSimd128(FloatRegister mask,
|
||||
FloatRegister onTrue,
|
||||
FloatRegister onFalse,
|
||||
FloatRegister dest) {
|
||||
as_vbitsel_v(dest.asSimd128(), onFalse.asSimd128(), onTrue.asSimd128(),
|
||||
mask.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::shuffleBytesSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister control,
|
||||
FloatRegister dest) {
|
||||
as_vshuf_b(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128(),
|
||||
control.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitwiseAndSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vand_v(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitwiseOrSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vor_v(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitwiseXorSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vxor_v(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitwiseNorSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vnor_v(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::bitwiseAndNotSimd128(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest) {
|
||||
as_vandn_v(dest.asSimd128(), lhs.asSimd128(), rhs.asSimd128());
|
||||
}
|
||||
|
||||
void MacroAssemblerLOONGARCH64::wasmLoadImpl(const wasm::MemoryAccessDesc& access,
|
||||
Register memoryBase, Register ptr,
|
||||
Register ptrScratch,
|
||||
@@ -2516,7 +2962,8 @@ void MacroAssemblerLOONGARCH64Compat::wasmLoadI64Impl(
|
||||
as_ldx_w(output.reg, memoryBase, ptr);
|
||||
break;
|
||||
case Scalar::Uint32:
|
||||
// TODO(loongarch64): Why need zero-extension here?
|
||||
// Uint32 loads must clear the upper 32 bits before the value is consumed
|
||||
// by 64-bit wasm operations.
|
||||
as_ldx_wu(output.reg, memoryBase, ptr);
|
||||
break;
|
||||
case Scalar::Int64:
|
||||
@@ -2617,14 +3064,18 @@ void MacroAssembler::PushRegsInMask(LiveRegisterSet set) {
|
||||
storePtr(*iter, Address(StackPointer, diff));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
|
||||
for (FloatRegisterBackwardIterator iter(set.fpus().reduceSetForPush());
|
||||
iter.more(); ++iter) {
|
||||
diff -= sizeof(double);
|
||||
storeDouble(*iter, Address(StackPointer, diff));
|
||||
FloatRegister reg = *iter;
|
||||
diff -= reg.size();
|
||||
if (reg.isSingle()) {
|
||||
storeFloat32(reg, Address(StackPointer, diff));
|
||||
} else if (reg.isSimd128()) {
|
||||
storeUnalignedSimd128Float(reg, Address(StackPointer, diff));
|
||||
} else {
|
||||
MOZ_ASSERT(reg.isDouble());
|
||||
storeDouble(reg, Address(StackPointer, diff));
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(diff == 0);
|
||||
}
|
||||
@@ -2642,15 +3093,19 @@ void MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_SIMD
|
||||
# error "Needs more careful logic if SIMD is enabled"
|
||||
#endif
|
||||
|
||||
for (FloatRegisterBackwardIterator iter(set.fpus().reduceSetForPush());
|
||||
iter.more(); ++iter) {
|
||||
diff -= sizeof(double);
|
||||
FloatRegister reg = *iter;
|
||||
diff -= reg.size();
|
||||
if (!ignore.has(*iter)) {
|
||||
loadDouble(Address(StackPointer, diff), *iter);
|
||||
if (reg.isSingle()) {
|
||||
loadFloat32(Address(StackPointer, diff), reg);
|
||||
} else if (reg.isSimd128()) {
|
||||
loadUnalignedSimd128Float(Address(StackPointer, diff), reg);
|
||||
} else {
|
||||
MOZ_ASSERT(reg.isDouble());
|
||||
loadDouble(Address(StackPointer, diff), reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(diff == 0);
|
||||
|
||||
@@ -199,6 +199,8 @@ class MacroAssemblerLOONGARCH64 : public Assembler {
|
||||
void ma_fld_d(FloatRegister ft, Address address);
|
||||
void ma_fst_d(FloatRegister ft, Address address);
|
||||
void ma_fst_s(FloatRegister ft, Address address);
|
||||
void ma_vld(FloatRegister vt, Address address);
|
||||
void ma_vst(FloatRegister vt, Address address);
|
||||
|
||||
void ma_pop(FloatRegister f);
|
||||
void ma_push(FloatRegister f);
|
||||
@@ -451,9 +453,11 @@ class MacroAssemblerLOONGARCH64 : public Assembler {
|
||||
|
||||
void ma_fst_d(FloatRegister src, BaseIndex address);
|
||||
void ma_fst_s(FloatRegister src, BaseIndex address);
|
||||
void ma_vst(FloatRegister src, BaseIndex address);
|
||||
|
||||
void ma_fld_d(FloatRegister dest, const BaseIndex& src);
|
||||
void ma_fld_s(FloatRegister dest, const BaseIndex& src);
|
||||
void ma_vld(FloatRegister dest, const BaseIndex& src);
|
||||
|
||||
// FP branches
|
||||
void ma_bc_s(FloatRegister lhs, FloatRegister rhs, Label* label,
|
||||
@@ -631,6 +635,139 @@ class MacroAssemblerLOONGARCH64 : public Assembler {
|
||||
void loadFloat32(const Address& addr, FloatRegister dest);
|
||||
void loadFloat32(const BaseIndex& src, FloatRegister dest);
|
||||
|
||||
void loadUnalignedSimd128Float(const Address& src, FloatRegister dest);
|
||||
void loadUnalignedSimd128Float(const BaseIndex& src, FloatRegister dest);
|
||||
void storeUnalignedSimd128Float(FloatRegister src, const Address& dest);
|
||||
void storeUnalignedSimd128Float(FloatRegister src, const BaseIndex& dest);
|
||||
void loadAlignedSimd128Float(const Address& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void loadAlignedSimd128Float(const BaseIndex& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeAlignedSimd128Float(FloatRegister src, const Address& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeAlignedSimd128Float(FloatRegister src, const BaseIndex& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void loadConstantSimd128Float(const SimdConstant& v, FloatRegister dest);
|
||||
void loadConstantSimd128Int(const SimdConstant& v, FloatRegister dest);
|
||||
void moveSimd128Float(FloatRegister src, FloatRegister dest);
|
||||
void moveSimd128Int(FloatRegister src, FloatRegister dest) {
|
||||
moveSimd128Float(src, dest);
|
||||
}
|
||||
void zeroSimd128Float(FloatRegister dest);
|
||||
void zeroSimd128Int(FloatRegister dest) { zeroSimd128Float(dest); }
|
||||
void createInt32x4(Register lane0, Register lane1, Register lane2,
|
||||
Register lane3, FloatRegister dest);
|
||||
void splatX4(Register input, FloatRegister output);
|
||||
void splatX4(FloatRegister input, FloatRegister output);
|
||||
void extractLaneInt32x4(FloatRegister input, Register output, unsigned lane);
|
||||
void extractLaneFloat32x4(FloatRegister input, FloatRegister output,
|
||||
unsigned lane, bool canonicalize);
|
||||
void insertLaneSimdInt(FloatRegister input, Register value,
|
||||
FloatRegister output, unsigned lane,
|
||||
unsigned numLanes);
|
||||
void insertLaneFloat32x4(FloatRegister input, FloatRegister value,
|
||||
FloatRegister output, unsigned lane);
|
||||
void addInt32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void subInt32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void mulInt32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void minInt32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void maxInt32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void minUint32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void maxUint32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void negInt32x4(FloatRegister input, FloatRegister dest);
|
||||
void shiftLeftInt32x4(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void shiftRightInt32x4(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void unsignedShiftRightInt32x4(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void shiftLeftInt32x4(FloatRegister lhs, Imm32 rhs, FloatRegister dest);
|
||||
void shiftRightInt32x4(FloatRegister lhs, Imm32 rhs, FloatRegister dest);
|
||||
void unsignedShiftRightInt32x4(FloatRegister lhs, Imm32 rhs,
|
||||
FloatRegister dest);
|
||||
void compareInt32x4Equal(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareInt32x4LessThan(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareInt32x4LessThanOrEqual(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareUint32x4LessThan(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareUint32x4LessThanOrEqual(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void addFloat32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void subFloat32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void mulFloat32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void minFloat32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void maxFloat32x4(FloatRegister lhs, FloatRegister rhs, FloatRegister dest);
|
||||
void sqrtFloat32x4(FloatRegister input, FloatRegister dest);
|
||||
void reciprocalApproximationFloat32x4(FloatRegister input, FloatRegister dest);
|
||||
void reciprocalSqrtApproximationFloat32x4(FloatRegister input,
|
||||
FloatRegister dest);
|
||||
void roundFloat32x4(FloatRegister input, FloatRegister dest);
|
||||
void convertInt32x4ToFloat32x4(FloatRegister input, FloatRegister dest);
|
||||
void convertFloat32x4ToInt32x4(FloatRegister input, FloatRegister dest);
|
||||
void compareFloat32x4Equal(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4NotEqual(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4LessThan(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4LessThanOrEqual(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4Unordered(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4UnorderedLessThan(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void compareFloat32x4UnorderedLessThanOrEqual(FloatRegister lhs,
|
||||
FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void interleaveLowInt32x4(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void interleaveHighInt32x4(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void bitselectSimd128(FloatRegister mask, FloatRegister onTrue,
|
||||
FloatRegister onFalse, FloatRegister dest);
|
||||
void shuffleBytesSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister control, FloatRegister dest);
|
||||
void bitwiseAndSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void bitwiseOrSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void bitwiseXorSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void bitwiseNorSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void bitwiseAndNotSimd128(FloatRegister lhs, FloatRegister rhs,
|
||||
FloatRegister dest);
|
||||
void loadUnalignedSimd128Int(const Address& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void loadUnalignedSimd128Int(const BaseIndex& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void loadAlignedSimd128Int(const Address& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void loadAlignedSimd128Int(const BaseIndex& src, FloatRegister dest) {
|
||||
loadUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeUnalignedSimd128Int(FloatRegister src, const Address& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeUnalignedSimd128Int(FloatRegister src, const BaseIndex& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeAlignedSimd128Int(FloatRegister src, const Address& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
void storeAlignedSimd128Int(FloatRegister src, const BaseIndex& dest) {
|
||||
storeUnalignedSimd128Float(src, dest);
|
||||
}
|
||||
|
||||
protected:
|
||||
void wasmLoadImpl(const wasm::MemoryAccessDesc& access, Register memoryBase,
|
||||
|
||||
@@ -10,6 +10,75 @@
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
Address
|
||||
MoveEmitterLoongArch64::cycleSlot(uint32_t slot, uint32_t subslot) const
|
||||
{
|
||||
int32_t offset = masm.framePushed() - pushedAtCycle_;
|
||||
MOZ_ASSERT(Imm16::IsInSignedRange(offset));
|
||||
return Address(StackPointer, offset + slot * Simd128DataSize + subslot);
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::emit(const MoveResolver& moves)
|
||||
{
|
||||
if (moves.numCycles()) {
|
||||
masm.reserveStack(moves.numCycles() * Simd128DataSize);
|
||||
pushedAtCycle_ = masm.framePushed();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < moves.numMoves(); i++)
|
||||
emit(moves.getMove(i));
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::emit(const MoveOp& move)
|
||||
{
|
||||
const MoveOperand& from = move.from();
|
||||
const MoveOperand& to = move.to();
|
||||
|
||||
if (move.isCycleEnd() && move.isCycleBegin()) {
|
||||
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
|
||||
completeCycle(from, to, move.type(), move.cycleEndSlot());
|
||||
return;
|
||||
}
|
||||
|
||||
if (move.isCycleEnd()) {
|
||||
MOZ_ASSERT(inCycle_);
|
||||
completeCycle(from, to, move.type(), move.cycleEndSlot());
|
||||
MOZ_ASSERT(inCycle_ > 0);
|
||||
inCycle_--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (move.isCycleBegin()) {
|
||||
breakCycle(from, to, move.endCycleType(), move.cycleBeginSlot());
|
||||
inCycle_++;
|
||||
}
|
||||
|
||||
switch (move.type()) {
|
||||
case MoveOp::FLOAT32:
|
||||
emitFloat32Move(from, to);
|
||||
break;
|
||||
case MoveOp::DOUBLE:
|
||||
emitDoubleMove(from, to);
|
||||
break;
|
||||
case MoveOp::INT32:
|
||||
emitInt32Move(from, to);
|
||||
break;
|
||||
case MoveOp::GENERAL:
|
||||
emitMove(from, to);
|
||||
break;
|
||||
case MoveOp::SIMD128INT:
|
||||
emitSimd128IntMove(from, to);
|
||||
break;
|
||||
case MoveOp::SIMD128FLOAT:
|
||||
emitSimd128FloatMove(from, to);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected move type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
MoveOp::Type type, uint32_t slotId)
|
||||
@@ -33,6 +102,24 @@ MoveEmitterLoongArch64::breakCycle(const MoveOperand& from, const MoveOperand& t
|
||||
masm.storeDouble(to.floatReg(), cycleSlot(slotId));
|
||||
}
|
||||
break;
|
||||
case MoveOp::SIMD128INT:
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Int(getAdjustedAddress(to), temp);
|
||||
masm.storeAlignedSimd128Int(temp, cycleSlot(slotId));
|
||||
} else {
|
||||
masm.storeAlignedSimd128Int(to.floatReg(), cycleSlot(slotId));
|
||||
}
|
||||
break;
|
||||
case MoveOp::SIMD128FLOAT:
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Float(getAdjustedAddress(to), temp);
|
||||
masm.storeAlignedSimd128Float(temp, cycleSlot(slotId));
|
||||
} else {
|
||||
masm.storeAlignedSimd128Float(to.floatReg(), cycleSlot(slotId));
|
||||
}
|
||||
break;
|
||||
case MoveOp::INT32:
|
||||
if (to.isMemory()) {
|
||||
Register temp = tempReg();
|
||||
@@ -81,6 +168,24 @@ MoveEmitterLoongArch64::completeCycle(const MoveOperand& from, const MoveOperand
|
||||
masm.loadDouble(cycleSlot(slotId), to.floatReg());
|
||||
}
|
||||
break;
|
||||
case MoveOp::SIMD128INT:
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Int(cycleSlot(slotId), temp);
|
||||
masm.storeAlignedSimd128Int(temp, getAdjustedAddress(to));
|
||||
} else {
|
||||
masm.loadAlignedSimd128Int(cycleSlot(slotId), to.floatReg());
|
||||
}
|
||||
break;
|
||||
case MoveOp::SIMD128FLOAT:
|
||||
if (to.isMemory()) {
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Float(cycleSlot(slotId), temp);
|
||||
masm.storeAlignedSimd128Float(temp, getAdjustedAddress(to));
|
||||
} else {
|
||||
masm.loadAlignedSimd128Float(cycleSlot(slotId), to.floatReg());
|
||||
}
|
||||
break;
|
||||
case MoveOp::INT32:
|
||||
MOZ_ASSERT(slotId == 0);
|
||||
if (to.isMemory()) {
|
||||
@@ -108,6 +213,56 @@ MoveEmitterLoongArch64::completeCycle(const MoveOperand& from, const MoveOperand
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::emitSimd128IntMove(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg().isSimd128());
|
||||
MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg().isSimd128());
|
||||
|
||||
if (from.isFloatReg()) {
|
||||
if (to.isFloatReg()) {
|
||||
masm.moveSimd128Int(from.floatReg(), to.floatReg());
|
||||
} else {
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
masm.storeAlignedSimd128Int(from.floatReg(), getAdjustedAddress(to));
|
||||
}
|
||||
} else if (to.isFloatReg()) {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
masm.loadAlignedSimd128Int(getAdjustedAddress(from), to.floatReg());
|
||||
} else {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Int(getAdjustedAddress(from), temp);
|
||||
masm.storeAlignedSimd128Int(temp, getAdjustedAddress(to));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::emitSimd128FloatMove(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
MOZ_ASSERT_IF(from.isFloatReg(), from.floatReg().isSimd128());
|
||||
MOZ_ASSERT_IF(to.isFloatReg(), to.floatReg().isSimd128());
|
||||
|
||||
if (from.isFloatReg()) {
|
||||
if (to.isFloatReg()) {
|
||||
masm.moveSimd128Float(from.floatReg(), to.floatReg());
|
||||
} else {
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
masm.storeAlignedSimd128Float(from.floatReg(), getAdjustedAddress(to));
|
||||
}
|
||||
} else if (to.isFloatReg()) {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
masm.loadAlignedSimd128Float(getAdjustedAddress(from), to.floatReg());
|
||||
} else {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
FloatRegister temp = ScratchSimd128Reg;
|
||||
masm.loadAlignedSimd128Float(getAdjustedAddress(from), temp);
|
||||
masm.storeAlignedSimd128Float(temp, getAdjustedAddress(to));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MoveEmitterLoongArch64::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
|
||||
@@ -13,7 +13,13 @@ namespace jit {
|
||||
|
||||
class MoveEmitterLoongArch64 : public MoveEmitterMIPSShared
|
||||
{
|
||||
Address cycleSlot(uint32_t slot, uint32_t subslot = 0) const;
|
||||
|
||||
void emitDoubleMove(const MoveOperand& from, const MoveOperand& to);
|
||||
void emitSimd128IntMove(const MoveOperand& from, const MoveOperand& to);
|
||||
void emitSimd128FloatMove(const MoveOperand& from, const MoveOperand& to);
|
||||
void emit(const MoveOp& move);
|
||||
|
||||
void breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
MoveOp::Type type, uint32_t slot);
|
||||
void completeCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
@@ -23,6 +29,8 @@ class MoveEmitterLoongArch64 : public MoveEmitterMIPSShared
|
||||
MoveEmitterLoongArch64(MacroAssembler& masm)
|
||||
: MoveEmitterMIPSShared(masm)
|
||||
{ }
|
||||
|
||||
void emit(const MoveResolver& moves);
|
||||
};
|
||||
|
||||
typedef MoveEmitterLoongArch64 MoveEmitter;
|
||||
|
||||
@@ -85,8 +85,9 @@ CodeGeneratorShared::CodeGeneratorShared(MIRGenerator* gen, LIRGraph* graph, Mac
|
||||
MOZ_ASSERT(graph->argumentSlotCount() == 0);
|
||||
frameDepth_ += gen->wasmMaxStackArgBytes();
|
||||
|
||||
static_assert(!SupportsSimd, "we need padding so that local slots are SIMD-aligned and "
|
||||
"the stack must be kept SIMD-aligned too.");
|
||||
if (SupportsSimd) {
|
||||
frameDepth_ = AlignBytes(frameDepth_, SimdMemoryAlignment);
|
||||
}
|
||||
|
||||
if (gen->performsCall()) {
|
||||
// An MWasmCall does not align the stack pointer at calls sites but
|
||||
|
||||
+22
-2
@@ -902,8 +902,28 @@ namespace js {
|
||||
// scheduledForDestruction will be set on the compartment, which will cause
|
||||
// some extra GC activity to try to free the compartment.
|
||||
template<typename T> inline void SetMaybeAliveFlag(T* thing) {}
|
||||
template<> inline void SetMaybeAliveFlag(JSObject* thing) {thing->compartment()->maybeAlive = true;}
|
||||
template<> inline void SetMaybeAliveFlag(JSScript* thing) {thing->compartment()->maybeAlive = true;}
|
||||
|
||||
template<> inline void SetMaybeAliveFlag(JSObject* thing) {
|
||||
// During GC marking of WeakRefs, 'thing' might be an invalid/dangling
|
||||
// pointer. Verify compartment is accessible.
|
||||
if (MOZ_LIKELY(thing)) {
|
||||
JSCompartment* comp = thing->compartment();
|
||||
if (MOZ_LIKELY(comp)) {
|
||||
comp->maybeAlive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void SetMaybeAliveFlag(JSScript* thing) {
|
||||
// During GC marking of WeakRefs, 'thing' might be an invalid/dangling
|
||||
// pointer. Verify compartment is accessible.
|
||||
if (MOZ_LIKELY(thing)) {
|
||||
JSCompartment* comp = thing->compartment();
|
||||
if (MOZ_LIKELY(comp)) {
|
||||
comp->maybeAlive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline js::Handle<js::GlobalObject*>
|
||||
ExclusiveContext::global() const
|
||||
|
||||
@@ -1148,7 +1148,7 @@ js::DumpHeap(JSContext* cx, FILE* fp, js::DumpHeapNurseryBehaviour nurseryBehavi
|
||||
fprintf(dtrc.output, "==========\n");
|
||||
|
||||
dtrc.prefix = "> ";
|
||||
IterateZonesCompartmentsArenasCells(cx, &dtrc,
|
||||
IterateHeapUnbarriered(cx, &dtrc,
|
||||
DumpHeapVisitZone,
|
||||
DumpHeapVisitCompartment,
|
||||
DumpHeapVisitArena,
|
||||
|
||||
+19
-10
@@ -3646,14 +3646,22 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
|
||||
}
|
||||
|
||||
/*
|
||||
* Atoms are not in the cross-compartment map. So if there are any
|
||||
* zones that are not being collected, we are not allowed to collect
|
||||
* atoms. Otherwise, the non-collected zones could contain pointers
|
||||
* to atoms that we would miss.
|
||||
* Atoms are not in the cross-compartment map. If there are any zones that
|
||||
* are not being collected then we cannot collect the atoms zone, otherwise
|
||||
* the non-collected zones could contain pointers to atoms that we would
|
||||
* miss.
|
||||
*
|
||||
* keepAtoms() will only change on the main thread, which we are currently
|
||||
* on. If the value of keepAtoms() changes between GC slices, then we'll
|
||||
* cancel the incremental GC. See IsIncrementalGCSafe.
|
||||
* If keepAtoms() is true then either an instance of AutoKeepAtoms is
|
||||
* currently on the stack or parsing is currently happening on another
|
||||
* thread. In either case we don't have information about which atoms are
|
||||
* roots, so we must skip collecting atoms.
|
||||
*
|
||||
* Note that only affects the first slice of an incremental GC since root
|
||||
* marking is completed before we return to the mutator.
|
||||
*
|
||||
* Off-main-thread parsing is inhibited after the start of GC which prevents
|
||||
* races between creating atoms during parsing and sweeping atoms on the
|
||||
* main thread.
|
||||
*/
|
||||
|
||||
if (isFull && !rt->keepAtoms()) {
|
||||
@@ -5610,9 +5618,6 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt)
|
||||
{
|
||||
MOZ_ASSERT(!rt->mainThread.suppressGC);
|
||||
|
||||
if (rt->keepAtoms())
|
||||
return gc::AbortReason::KeepAtomsSet;
|
||||
|
||||
if (!rt->gc.isIncrementalGCAllowed())
|
||||
return gc::AbortReason::IncrementalDisabled;
|
||||
|
||||
@@ -5786,6 +5791,10 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
|
||||
|
||||
State prevState = incrementalState;
|
||||
|
||||
// We don't allow off-main-thread parsing to start while we're doing an
|
||||
// incremental GC.
|
||||
MOZ_ASSERT_IF(rt->activeGCInAtomsZone(), !rt->exclusiveThreadsPresent());
|
||||
|
||||
if (nonincrementalByAPI) {
|
||||
// Reset any in progress incremental GC if this was triggered via the
|
||||
// API. This isn't required for correctness, but sometimes during tests
|
||||
|
||||
+6
-3
@@ -56,7 +56,7 @@ enum class State {
|
||||
D(None) \
|
||||
D(NonIncrementalRequested) \
|
||||
D(AbortRequested) \
|
||||
D(KeepAtomsSet) \
|
||||
D(Unused1) \
|
||||
D(IncrementalDisabled) \
|
||||
D(ModeChange) \
|
||||
D(MallocBytesTrigger) \
|
||||
@@ -1065,9 +1065,12 @@ typedef void (*IterateCellCallback)(JSRuntime* rt, void* data, void* thing,
|
||||
* This function calls |zoneCallback| on every zone, |compartmentCallback| on
|
||||
* every compartment, |arenaCallback| on every in-use arena, and |cellCallback|
|
||||
* on every in-use cell in the GC heap.
|
||||
*
|
||||
* Note that no read barrier is triggered on the cells passed to cellCallback,
|
||||
* so no these pointers must not escape the callback.
|
||||
*/
|
||||
extern void
|
||||
IterateZonesCompartmentsArenasCells(JSContext* cx, void* data,
|
||||
IterateHeapUnbarriered(JSContext* cx, void* data,
|
||||
IterateZoneCallback zoneCallback,
|
||||
JSIterateCompartmentCallback compartmentCallback,
|
||||
IterateArenaCallback arenaCallback,
|
||||
@@ -1078,7 +1081,7 @@ IterateZonesCompartmentsArenasCells(JSContext* cx, void* data,
|
||||
* single zone.
|
||||
*/
|
||||
extern void
|
||||
IterateZoneCompartmentsArenasCells(JSContext* cx, Zone* zone, void* data,
|
||||
IterateHeapUnbarrieredForZone(JSContext* cx, Zone* zone, void* data,
|
||||
IterateZoneCallback zoneCallback,
|
||||
JSIterateCompartmentCallback compartmentCallback,
|
||||
IterateArenaCallback arenaCallback,
|
||||
|
||||
@@ -147,8 +147,6 @@ class ArenaCellIterImpl
|
||||
void init(Arena* arena, CellIterNeedsBarrier mayNeedBarrier) {
|
||||
MOZ_ASSERT(!initialized);
|
||||
MOZ_ASSERT(arena);
|
||||
MOZ_ASSERT_IF(!mayNeedBarrier,
|
||||
CurrentThreadIsPerformingGC() || CurrentThreadIsGCSweeping());
|
||||
initialized = true;
|
||||
AllocKind kind = arena->getAllocKind();
|
||||
firstThingOffset = Arena::firstThingOffset(kind);
|
||||
@@ -236,6 +234,14 @@ class ArenaCellIterUnderFinalize : public ArenaCellIterImpl
|
||||
}
|
||||
};
|
||||
|
||||
class ArenaCellIterUnbarriered : public ArenaCellIterImpl
|
||||
{
|
||||
public:
|
||||
explicit ArenaCellIterUnbarriered(Arena* arena)
|
||||
: ArenaCellIterImpl(arena, CellIterDoesntNeedBarrier)
|
||||
{}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class ZoneCellIter;
|
||||
|
||||
|
||||
@@ -3940,6 +3940,8 @@ js::Unbox(JSContext* cx, HandleObject obj, MutableHandleValue vp)
|
||||
vp.setString(obj->as<StringObject>().unbox());
|
||||
else if (obj->is<DateObject>())
|
||||
vp.set(obj->as<DateObject>().UTCTime());
|
||||
else if (obj->is<BigIntObject>())
|
||||
vp.setBigInt(obj->as<BigIntObject>().unbox());
|
||||
else
|
||||
vp.setUndefined();
|
||||
|
||||
|
||||
+3
-7
@@ -158,6 +158,8 @@ class JSObject : public js::gc::Cell
|
||||
* object will have its group constructed lazily as needed by analysis.
|
||||
*/
|
||||
bool isSingleton() const {
|
||||
// In some cases, group_ might be null.
|
||||
if (!group_) return false;
|
||||
return group_->singleton();
|
||||
}
|
||||
|
||||
@@ -895,10 +897,6 @@ GetElementNoGC(JSContext* cx, JSObject* obj, JSObject* receiver, uint32_t index,
|
||||
* try. Long story short, if you just want bog-standard assignment, pass
|
||||
* `ObjectValue(*obj)` as receiver. Or better, use one of the signatures that
|
||||
* doesn't have a receiver parameter.
|
||||
*
|
||||
* Callers pass obj != receiver e.g. when a proxy is involved, obj is the
|
||||
* proxy's target, and the proxy is using SetProperty to finish an assignment
|
||||
* that started out as `receiver[id] = v`, by delegating it to obj.
|
||||
*/
|
||||
inline bool
|
||||
SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
|
||||
@@ -1269,9 +1267,7 @@ FromPropertyDescriptorToObject(JSContext* cx, Handle<JS::PropertyDescriptor> des
|
||||
extern bool
|
||||
IsDelegate(JSContext* cx, HandleObject obj, const Value& v, bool* result);
|
||||
|
||||
// obj is a JSObject*, but we root it immediately up front. We do it
|
||||
// that way because we need a Rooted temporary in this method anyway.
|
||||
extern bool
|
||||
bool
|
||||
IsDelegateOfObject(JSContext* cx, HandleObject protoObj, JSObject* obj, bool* result);
|
||||
|
||||
/* Wrap boolean, number or string as Boolean, Number or String object. */
|
||||
|
||||
+3
-1
@@ -3954,7 +3954,9 @@ JSScript::traceChildren(JSTracer* trc)
|
||||
|
||||
if (hasObjects()) {
|
||||
ObjectArray* objarray = objects();
|
||||
TraceRange(trc, objarray->length, objarray->vector, "objects");
|
||||
if (objarray && objarray->length > 0 && objarray->vector) {
|
||||
TraceRange(trc, objarray->length, objarray->vector, "objects");
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(sourceObject(), MaybeForwarded(sourceObject())->compartment() == compartment());
|
||||
|
||||
@@ -940,7 +940,14 @@ GlobalHelperThreadState::maxParseThreads() const
|
||||
if (IsHelperThreadSimulatingOOM(js::oom::THREAD_TYPE_PARSE))
|
||||
return 1;
|
||||
// Use the number of logical processors in a system.
|
||||
return cpuCount;
|
||||
if (cpuCount < 4)
|
||||
return 2;
|
||||
//return cpuCount - 2;
|
||||
// XXX Issue #3172 XXX
|
||||
// For the time being, return a hard-coded value of 2 on all targets and CPUs.
|
||||
// It's unclear where the contention happens, but it has shown to be detrimental
|
||||
// especially on *nixes and older hardware.
|
||||
return 2;
|
||||
}
|
||||
|
||||
size_t
|
||||
|
||||
@@ -770,7 +770,7 @@ CollectRuntimeStatsHelper(JSContext* cx, RuntimeStats* rtStats, ObjectPrivateVis
|
||||
StatsClosure closure(rtStats, opv, anonymize);
|
||||
if (!closure.init())
|
||||
return false;
|
||||
IterateZonesCompartmentsArenasCells(cx, &closure,
|
||||
IterateHeapUnbarriered(cx, &closure,
|
||||
StatsZoneCallback,
|
||||
StatsCompartmentCallback,
|
||||
StatsArenaCallback,
|
||||
@@ -916,7 +916,7 @@ AddSizeOfTab(JSContext* cx, HandleObject obj, MallocSizeOf mallocSizeOf, ObjectP
|
||||
StatsClosure closure(&rtStats, opv, /* anonymize = */ false);
|
||||
if (!closure.init())
|
||||
return false;
|
||||
IterateZoneCompartmentsArenasCells(cx, zone, &closure,
|
||||
IterateHeapUnbarrieredForZone(cx, zone, &closure,
|
||||
StatsZoneCallback,
|
||||
StatsCompartmentCallback,
|
||||
StatsArenaCallback,
|
||||
|
||||
@@ -1373,16 +1373,18 @@ intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp)
|
||||
MOZ_ASSERT((UINT32_MAX >> ElementShift) >= count);
|
||||
uint32_t byteSize = count << ElementShift;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
uint32_t viewByteLength = tarray->byteLength();
|
||||
MOZ_ASSERT(byteSize <= viewByteLength);
|
||||
MOZ_ASSERT(byteDest < viewByteLength);
|
||||
MOZ_ASSERT(byteSrc < viewByteLength);
|
||||
MOZ_ASSERT(byteDest <= viewByteLength - byteSize);
|
||||
MOZ_ASSERT(byteSrc <= viewByteLength - byteSize);
|
||||
if (byteSize > viewByteLength ||
|
||||
byteDest >= viewByteLength ||
|
||||
byteSrc >= viewByteLength ||
|
||||
byteDest > viewByteLength - byteSize ||
|
||||
byteSrc > viewByteLength - byteSize) {
|
||||
JS_ReportErrorNumberASCII(
|
||||
cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
SharedMem<uint8_t*> data = tarray->viewDataEither().cast<uint8_t*>();
|
||||
jit::AtomicOperations::memmoveSafeWhenRacy(data + byteDest, data + byteSrc, byteSize);
|
||||
|
||||
+1
-2
@@ -1740,8 +1740,7 @@ JS::ProfilingFrameIterator::ProfilingFrameIterator(JSContext* cx, const Register
|
||||
: rt_(cx),
|
||||
sampleBufferGen_(sampleBufferGen),
|
||||
activation_(nullptr),
|
||||
savedPrevJitTop_(nullptr),
|
||||
nogc_(cx)
|
||||
savedPrevJitTop_(nullptr)
|
||||
{
|
||||
if (!cx->spsProfiler.enabled())
|
||||
MOZ_CRASH("ProfilingFrameIterator called when spsProfiler not enabled for runtime.");
|
||||
|
||||
@@ -1059,7 +1059,6 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
|
||||
// jump scratch to resume execution.
|
||||
masm.subFromStackPtr(Imm32(sizeof(intptr_t)));
|
||||
masm.setFramePushed(0);
|
||||
static_assert(!SupportsSimd, "high lanes of SIMD registers need to be saved too.");
|
||||
masm.PushRegsInMask(AllRegsExceptSP);
|
||||
|
||||
// Save the unaligned stack pointer in a non-volatile register, then align
|
||||
|
||||
@@ -261,7 +261,7 @@ RestyleManager::ContentStateChanged(nsIContent* aContent,
|
||||
ContentStateChangedInternal(aElement, aStateMask, &changeHint, &restyleHint);
|
||||
|
||||
PostRestyleEvent(aElement, restyleHint, changeHint);
|
||||
RestyleForHasPseudoClassChange(aElement);
|
||||
RestyleForHasPseudoClassChange(aElement, aStateMask);
|
||||
}
|
||||
|
||||
// Forwarded nsIMutationObserver method, to handle restyling.
|
||||
@@ -282,6 +282,12 @@ RestyleManager::AttributeWillChange(Element* aElement,
|
||||
aNewValue,
|
||||
rsdata);
|
||||
PostRestyleEvent(aElement, rshint, nsChangeHint(0), &rsdata);
|
||||
// Class values are preparsed by Element before this notification. Compare
|
||||
// membership now: AttributeChanged need not receive the previous value.
|
||||
if (aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::_class) {
|
||||
RestyleForHasPseudoClassChange(aElement, EventStates(), aAttribute,
|
||||
aNewValue, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Forwarded nsIMutationObserver method, to handle restyling (and
|
||||
@@ -373,30 +379,68 @@ RestyleManager::AttributeChanged(Element* aElement,
|
||||
aOldValue,
|
||||
rsdata);
|
||||
PostRestyleEvent(aElement, rshint, hint, &rsdata);
|
||||
RestyleForHasPseudoClassChange(aElement);
|
||||
if (aNameSpaceID != kNameSpaceID_None || aAttribute != nsGkAtoms::_class) {
|
||||
RestyleForHasPseudoClassChange(aElement, EventStates(), aAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RestyleManager::RestyleForHasPseudoClassChange(nsINode* aNode)
|
||||
void
|
||||
RestyleManager::RestyleForHasPseudoClassChange(nsINode* aNode,
|
||||
EventStates aStateMask,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses)
|
||||
{
|
||||
Element* affectedRoot = nullptr;
|
||||
MOZ_ASSERT(!aAttribute || aNode->IsElement());
|
||||
if (!aNode->OwnerDoc()->GetProperty(nsGkAtoms::hasSelectorDependency)) {
|
||||
return;
|
||||
}
|
||||
|
||||
using Dependency = nsCSSRuleUtils::HasSelectorDependency;
|
||||
auto restyleAnchor = [&](Element* aAnchor, Dependency* aDependency) {
|
||||
nsRestyleHint hint = eRestyle_Subtree;
|
||||
if (aDependency->mRestyleLaterSiblings) {
|
||||
hint = nsRestyleHint(hint | eRestyle_LaterSiblings);
|
||||
}
|
||||
PostRestyleEvent(aAnchor, hint, nsChangeHint(0));
|
||||
};
|
||||
|
||||
for (nsINode* node = aNode; node; node = node->GetParentNode()) {
|
||||
if (!node->GetProperty(nsGkAtoms::hasSelectorDependency)) {
|
||||
auto* dependency = static_cast<Dependency*>(
|
||||
node->GetProperty(nsGkAtoms::hasSelectorDependency));
|
||||
if (!dependency) {
|
||||
continue;
|
||||
}
|
||||
if (node->IsElement()) {
|
||||
affectedRoot = node->AsElement();
|
||||
} else if (ShadowRoot* shadow = ShadowRoot::FromNode(node)) {
|
||||
affectedRoot = shadow->GetHost();
|
||||
if (node->IsElement() && dependency->MightDependOnChange(
|
||||
node->AsElement(), aNode, aStateMask, aAttribute, aNewClasses,
|
||||
aCompareClasses, false)) {
|
||||
restyleAnchor(node->AsElement(), dependency);
|
||||
}
|
||||
if (!dependency->MightAffectSiblingAnchor(
|
||||
node, aNode, aStateMask, aAttribute, aNewClasses, aCompareClasses)) {
|
||||
continue;
|
||||
}
|
||||
// The parent is an index of sibling anchors, not itself an anchor. Keep
|
||||
// unrelated subtrees out of the restyle, including mutations deep inside
|
||||
// a sibling whose :has() argument only inspects the sibling element.
|
||||
bool nodeIsFollowingSibling = true;
|
||||
for (nsIContent* child = node->GetFirstChild(); child;
|
||||
child = child->GetNextSibling()) {
|
||||
if (child == aNode) {
|
||||
nodeIsFollowingSibling = false;
|
||||
}
|
||||
if (!child->IsElement()) {
|
||||
continue;
|
||||
}
|
||||
auto* siblingDependency = static_cast<Dependency*>(
|
||||
child->GetProperty(nsGkAtoms::hasSelectorDependency));
|
||||
if (siblingDependency && siblingDependency->MightDependOnChange(
|
||||
child->AsElement(), aNode, aStateMask, aAttribute, aNewClasses,
|
||||
aCompareClasses, true, nodeIsFollowingSibling)) {
|
||||
restyleAnchor(child->AsElement(), siblingDependency);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!affectedRoot) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PostRestyleEvent(affectedRoot, eRestyle_Subtree, nsChangeHint(0));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ uint64_t
|
||||
@@ -425,9 +469,7 @@ RestyleManager::RestyleForAppend(nsIContent* aContainer,
|
||||
nsIContent* aFirstNewContent)
|
||||
{
|
||||
// The container cannot be a document, but might be a ShadowRoot.
|
||||
if (RestyleForHasPseudoClassChange(aContainer)) {
|
||||
return;
|
||||
}
|
||||
RestyleForHasPseudoClassChange(aContainer);
|
||||
|
||||
if (!aContainer->IsElement()) {
|
||||
return;
|
||||
@@ -518,9 +560,7 @@ RestyleManager::RestyleForInsertOrChange(nsINode* aContainer,
|
||||
nsIContent* aChild)
|
||||
{
|
||||
// The container might be a document or a ShadowRoot.
|
||||
if (RestyleForHasPseudoClassChange(aContainer)) {
|
||||
return;
|
||||
}
|
||||
RestyleForHasPseudoClassChange(aContainer);
|
||||
|
||||
if (!aContainer->IsElement()) {
|
||||
return;
|
||||
@@ -612,9 +652,7 @@ RestyleManager::ContentRemoved(nsINode* aContainer,
|
||||
nsIContent* aFollowingSibling)
|
||||
{
|
||||
// The container might be a document or a ShadowRoot.
|
||||
if (RestyleForHasPseudoClassChange(aContainer)) {
|
||||
return;
|
||||
}
|
||||
RestyleForHasPseudoClassChange(aContainer);
|
||||
|
||||
if (!aContainer->IsElement()) {
|
||||
return;
|
||||
|
||||
@@ -314,9 +314,14 @@ public:
|
||||
// the container is null, no work is needed.
|
||||
void RestyleForAppend(nsIContent* aContainer, nsIContent* aFirstNewContent);
|
||||
|
||||
// Restyle a subtree containing any :has() anchor affected by a change at
|
||||
// or below aNode. Returns true when such a restyle was posted.
|
||||
bool RestyleForHasPseudoClassChange(nsINode* aNode);
|
||||
// Restyle affected :has() anchors, retaining normal mutation invalidation.
|
||||
// With no state/attribute, aNode is the container of a content mutation.
|
||||
// Class changes are compared before mutation, while both values are known.
|
||||
void RestyleForHasPseudoClassChange(nsINode* aNode,
|
||||
EventStates aStateMask = EventStates(),
|
||||
nsIAtom* aAttribute = nullptr,
|
||||
const nsAttrValue* aNewClasses = nullptr,
|
||||
bool aCompareClasses = false);
|
||||
|
||||
// Process any pending restyles. This should be called after
|
||||
// CreateNeededFrames.
|
||||
|
||||
@@ -185,15 +185,18 @@ struct InlineBackgroundData
|
||||
mPIStartBorderData.SetCoord(joinedBorderArea.x);
|
||||
}
|
||||
} else if (mPIStartBorderData.mFrame) {
|
||||
// Copy data to a temporary object so that computing the
|
||||
// continous rect here doesn't clobber our normal state.
|
||||
InlineBackgroundData temp = *this;
|
||||
if (mVertical) {
|
||||
mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).y);
|
||||
mPIStartBorderData.SetCoord(temp.GetContinuousRect(mPIStartBorderData.mFrame).y);
|
||||
} else {
|
||||
mPIStartBorderData.SetCoord(GetContinuousRect(mPIStartBorderData.mFrame).x);
|
||||
mPIStartBorderData.SetCoord(temp.GetContinuousRect(mPIStartBorderData.mFrame).x);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ... and restore it when possible.
|
||||
mPIStartBorderData.mCoord = saved.mCoord;
|
||||
mPIStartBorderData.SetCoord(saved.mCoord);
|
||||
}
|
||||
if (mVertical) {
|
||||
if (joinedBorderArea.y > mPIStartBorderData.mCoord) {
|
||||
@@ -342,6 +345,7 @@ protected:
|
||||
// Start with the previous flow frame as our continuation point
|
||||
// is the total of the widths of the previous frames.
|
||||
nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
|
||||
bool changedLines = false;
|
||||
while (inlineFrame) {
|
||||
if (!mPIStartBorderData.mFrame &&
|
||||
!(mVertical ? inlineFrame->GetSkipSides().Top()
|
||||
@@ -350,8 +354,9 @@ protected:
|
||||
}
|
||||
nsRect rect = inlineFrame->GetRect();
|
||||
mContinuationPoint += mVertical ? rect.height : rect.width;
|
||||
if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
|
||||
if (mBidiEnabled && (changedLines || !AreOnSameLine(aFrame, inlineFrame))) {
|
||||
mLineContinuationPoint += mVertical ? rect.height : rect.width;
|
||||
changedLines = true;
|
||||
}
|
||||
mUnbrokenMeasure += mVertical ? rect.height : rect.width;
|
||||
mBoundingBox.UnionRect(mBoundingBox, rect);
|
||||
|
||||
@@ -164,9 +164,9 @@ nsFileControlFrame::CreateAnonymousContent(nsTArray<ContentInfo>& aElements)
|
||||
|
||||
// We should be able to interact with the element by doing drag and drop.
|
||||
mContent->AddSystemEventListener(NS_LITERAL_STRING("drop"),
|
||||
mMouseListener, false);
|
||||
mMouseListener, false, false);
|
||||
mContent->AddSystemEventListener(NS_LITERAL_STRING("dragover"),
|
||||
mMouseListener, false);
|
||||
mMouseListener, false, false);
|
||||
|
||||
SyncDisabledState();
|
||||
|
||||
|
||||
@@ -235,18 +235,17 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
|
||||
WritingMode wm = GetWritingMode();
|
||||
LogicalSize availSize = aButtonReflowInput.ComputedSize(wm);
|
||||
|
||||
// The anonymous button-content frame cannot have a continuation. Give it
|
||||
// unconstrained available block-size so flex/grid layout does not treat a
|
||||
// definite button block-size as a fragmentainer constraint. Its computed
|
||||
// block-size is overridden separately below when it needs to be definite.
|
||||
availSize.BSize(wm) = NS_INTRINSICSIZE;
|
||||
|
||||
// Identify if the inner anonymous block is actually functioning as a flex or grid container.
|
||||
nsIAtom* kidType = aFirstKid->GetType();
|
||||
bool isFlexOrGrid = (kidType == nsGkAtoms::flexContainerFrame ||
|
||||
kidType == nsGkAtoms::gridContainerFrame);
|
||||
|
||||
// Preserve the button's definite BSize ONLY for flex/grid children so they
|
||||
// see a definite containing block main size. For standard buttons, clobber
|
||||
// to intrinsic so standard vertical centering (extraSpace) calculations work.
|
||||
if (!isFlexOrGrid || aButtonReflowInput.ComputedBSize() == NS_INTRINSICSIZE) {
|
||||
availSize.BSize(wm) = NS_INTRINSICSIZE;
|
||||
}
|
||||
|
||||
// shorthand for a value we need to use in a bunch of places
|
||||
const LogicalMargin& clbp = aButtonReflowInput.ComputedLogicalBorderPadding();
|
||||
|
||||
@@ -260,7 +259,7 @@ nsHTMLButtonControlFrame::ReflowButtonContents(nsPresContext* aPresContext,
|
||||
availSize);
|
||||
|
||||
// Apply the definite BSize directly on the inner reflow input ONLY if it's
|
||||
// a flex or grid container, allowing it to be used as-is.
|
||||
// a flex or grid container, without constraining its available BSize.
|
||||
if (isFlexOrGrid && aButtonReflowInput.ComputedBSize() != NS_INTRINSICSIZE) {
|
||||
contentsReflowInput.SetComputedBSize(aButtonReflowInput.ComputedBSize());
|
||||
}
|
||||
|
||||
@@ -2166,20 +2166,20 @@ nsFrameSelection::CommonPageMove(bool aForward,
|
||||
//get the frame from the scrollable view
|
||||
|
||||
nsIFrame* scrolledFrame = aScrollableFrame->GetScrolledFrame();
|
||||
if (!scrolledFrame) [[unlikely]] {
|
||||
if MOZ_UNLIKELY(!scrolledFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find out where the caret is.
|
||||
// we should know mDesiredPos value of nsFrameSelection, but I havent seen that behavior in other windows applications yet.
|
||||
nsISelection* domSel = GetSelection(SelectionType::eNormal);
|
||||
if (!domSel) [[unlikely]] {
|
||||
if MOZ_UNLIKELY(!domSel) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRect caretPos;
|
||||
nsIFrame* caretFrame = nsCaret::GetGeometry(domSel, &caretPos);
|
||||
if (!caretFrame) [[unlikely]] {
|
||||
if MOZ_UNLIKELY(!caretFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2200,7 +2200,7 @@ nsFrameSelection::CommonPageMove(bool aForward,
|
||||
desiredPoint.y = caretPos.y + caretPos.height/2;
|
||||
nsIFrame::ContentOffsets offsets = scrolledFrame->GetContentOffsetsFromPoint(desiredPoint);
|
||||
|
||||
if (!offsets.content) [[unlikely]] {
|
||||
if MOZ_UNLIKELY(!offsets.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2846,7 +2846,12 @@ nsFrameSelection::UnselectCells(nsIContent *aTableContent,
|
||||
if (!mDomSelections[index])
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsTableWrapperFrame* tableFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
|
||||
// This is needed as an nsTableWrapperFrame as we use this to know we can
|
||||
// static cast tableFrame to nsTableWrapperFrame.
|
||||
nsTableWrapperFrame* tableWrapperFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
|
||||
|
||||
// Declared as weak frame, as the frame may be freed during a call to a listener.
|
||||
nsWeakFrame tableFrame(tableWrapperFrame);
|
||||
if (!tableFrame)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -2878,6 +2883,9 @@ nsFrameSelection::UnselectCells(nsIContent *aTableContent,
|
||||
curColIndex < minColIndex || curColIndex > maxColIndex) {
|
||||
|
||||
mDomSelections[index]->RemoveRange(range);
|
||||
if (!tableFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Since we've removed the range, decrement pointer to next range
|
||||
mSelectedCellIndex--;
|
||||
}
|
||||
@@ -2885,21 +2893,30 @@ nsFrameSelection::UnselectCells(nsIContent *aTableContent,
|
||||
} else {
|
||||
// Remove cell from selection if it belongs to the given cells range or
|
||||
// it is spanned onto the cells range.
|
||||
|
||||
MOZ_ASSERT(tableFrame.IsAlive());
|
||||
// In general, static casting to another table type is not a good idea,
|
||||
// but it is valid here due to the earlier do_QueryFrame() that
|
||||
// established that tableFrame is an nsTableWrapperFrame*.
|
||||
auto tempTableFrame = static_cast<nsTableWrapperFrame*>(tableFrame.GetFrame());
|
||||
nsTableCellFrame* cellFrame =
|
||||
tableFrame->GetCellFrameAt(curRowIndex, curColIndex);
|
||||
tempTableFrame->GetCellFrameAt(curRowIndex, curColIndex);
|
||||
|
||||
uint32_t origRowIndex = cellFrame->RowIndex();
|
||||
uint32_t origColIndex = cellFrame->ColIndex();
|
||||
uint32_t actualRowSpan =
|
||||
tableFrame->GetEffectiveRowSpanAt(origRowIndex, origColIndex);
|
||||
tempTableFrame->GetEffectiveRowSpanAt(origRowIndex, origColIndex);
|
||||
uint32_t actualColSpan =
|
||||
tableFrame->GetEffectiveColSpanAt(curRowIndex, curColIndex);
|
||||
tempTableFrame->GetEffectiveColSpanAt(curRowIndex, curColIndex);
|
||||
if (origRowIndex <= static_cast<uint32_t>(maxRowIndex) && maxRowIndex >= 0 &&
|
||||
origRowIndex + actualRowSpan - 1 >= static_cast<uint32_t>(minRowIndex) &&
|
||||
origColIndex <= static_cast<uint32_t>(maxColIndex) && maxColIndex >= 0 &&
|
||||
origColIndex + actualColSpan - 1 >= static_cast<uint32_t>(minColIndex)) {
|
||||
|
||||
mDomSelections[index]->RemoveRange(range);
|
||||
if (!tableFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
// Since we've removed the range, decrement pointer to next range
|
||||
mSelectedCellIndex--;
|
||||
}
|
||||
@@ -2925,7 +2942,12 @@ nsFrameSelection::AddCellsToSelection(nsIContent *aTableContent,
|
||||
if (!mDomSelections[index])
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
nsTableWrapperFrame* tableFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
|
||||
// This is needed as an nsTableWrapperFrame as we use this to know we can
|
||||
// static cast tableFrame to nsTableWrapperFrame.
|
||||
nsTableWrapperFrame* tableWrapperFrame = do_QueryFrame(aTableContent->GetPrimaryFrame());
|
||||
|
||||
// Declared as weak frame, as the frame may be freed during a call to a listener.
|
||||
nsWeakFrame tableFrame(tableWrapperFrame);
|
||||
if (!tableFrame) // Check that |table| is a table.
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@@ -2936,7 +2958,12 @@ nsFrameSelection::AddCellsToSelection(nsIContent *aTableContent,
|
||||
uint32_t col = aStartColumnIndex;
|
||||
while(true)
|
||||
{
|
||||
nsTableCellFrame* cellFrame = tableFrame->GetCellFrameAt(row, col);
|
||||
MOZ_ASSERT(tableFrame.IsAlive());
|
||||
// In general, static casting to another table type is not a good idea,
|
||||
// but it is valid here due to the earlier do_QueryFrame() that
|
||||
// established that tableFrame is an nsTableWrapperFrame*.
|
||||
nsTableCellFrame* cellFrame =
|
||||
static_cast<nsTableWrapperFrame*>(tableFrame.GetFrame())->GetCellFrameAt(row, col);
|
||||
|
||||
// Skip cells that are spanned from previous locations or are already selected
|
||||
if (cellFrame) {
|
||||
@@ -2944,7 +2971,9 @@ nsFrameSelection::AddCellsToSelection(nsIContent *aTableContent,
|
||||
uint32_t origCol = cellFrame->ColIndex();
|
||||
if (origRow == row && origCol == col && !cellFrame->IsSelected()) {
|
||||
result = SelectCellElement(cellFrame->GetContent());
|
||||
if (NS_FAILED(result)) return result;
|
||||
if (NS_FAILED(result) || !tableFrame.IsAlive()) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Done when we reach end column
|
||||
|
||||
@@ -1871,7 +1871,9 @@ CSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
|
||||
RefPtr<css::Rule> rule;
|
||||
aRv = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI,
|
||||
mInner->mPrincipal, getter_AddRefs(rule));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
// A syntax error from web content is an expected insertRule() outcome. The
|
||||
// binding reports it to script; do not flood debug stderr as well.
|
||||
if (aRv.Failed()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -639,8 +639,12 @@ Declaration::GetPropertyValueInternal(
|
||||
}
|
||||
if (revertCount == totalCount) {
|
||||
// Simplify serialization below by serializing revert up-front.
|
||||
nsCSSValue(eCSSUnit_Revert).AppendToString(eCSSProperty_UNKNOWN, aValue,
|
||||
nsCSSValue::eNormalized);
|
||||
// eCSSUnit_Revert carries the cascade origin, so it cannot use the
|
||||
// nsCSSValue constructor reserved for valueless units.
|
||||
nsCSSValue revert;
|
||||
revert.SetRevertValue(SheetType::Unknown);
|
||||
revert.AppendToString(eCSSProperty_UNKNOWN, aValue,
|
||||
nsCSSValue::eNormalized);
|
||||
return;
|
||||
}
|
||||
if (revertLayerCount == totalCount) {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsXMLNameSpaceMap.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsCSSRuleUtils.h"
|
||||
#include "nsCSSPseudoClasses.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsTArray.h"
|
||||
@@ -1009,6 +1010,7 @@ nsCSSSelectorList::~nsCSSSelectorList()
|
||||
nsCSSSelector*
|
||||
nsCSSSelectorList::AddSelector(char16_t aOperator)
|
||||
{
|
||||
mHasSelectorData = nullptr;
|
||||
nsCSSSelector* newSel = new nsCSSSelector();
|
||||
|
||||
if (mSelectors) {
|
||||
@@ -1026,6 +1028,7 @@ nsCSSSelectorList::AddSelector(char16_t aOperator)
|
||||
void
|
||||
nsCSSSelectorList::RemoveRightmostSelector()
|
||||
{
|
||||
mHasSelectorData = nullptr;
|
||||
nsCSSSelector* current = mSelectors;
|
||||
mSelectors = mSelectors->mNext;
|
||||
MOZ_ASSERT(mSelectors,
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
class nsIAtom;
|
||||
struct nsCSSSelectorList;
|
||||
struct nsCSSHasSelectorData;
|
||||
|
||||
namespace mozilla {
|
||||
enum class CSSPseudoClassType : uint8_t;
|
||||
@@ -318,6 +319,9 @@ struct nsCSSSelectorList {
|
||||
// stored as their leftmost selector. This flag keeps that implementation
|
||||
// detail out of serialization and is preserved by cloning.
|
||||
bool mIsRelativeSelector;
|
||||
// Immutable dependency metadata, collected lazily for a :has() argument.
|
||||
// Nodes retain this data independently of the stylesheet's lifetime.
|
||||
RefPtr<nsCSSHasSelectorData> mHasSelectorData;
|
||||
protected:
|
||||
friend class inDOMUtils;
|
||||
nsCSSSelectorList* Clone(bool aDeep) const;
|
||||
|
||||
@@ -13454,18 +13454,16 @@ bool
|
||||
CSSParserImpl::ParseAspectRatioRatio(nsCSSValue& aValue)
|
||||
{
|
||||
nsCSSValue width;
|
||||
if (!ParseSingleTokenNonNegativeVariant(width,
|
||||
VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr)) {
|
||||
if (ParseNonNegativeVariant(width, VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr) != CSSParseResult::Ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCSSValue height;
|
||||
height.SetFloatValue(1.0f, eCSSUnit_Number);
|
||||
if (ExpectSymbol('/', true)) {
|
||||
if (!ParseSingleTokenNonNegativeVariant(height,
|
||||
VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr)) {
|
||||
if (ParseNonNegativeVariant(height, VARIANT_NUMBER | VARIANT_CALC,
|
||||
nullptr) != CSSParseResult::Ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +77,9 @@ CSS_PSEUDO_CLASS(is, ":is", 0, "layout.css.is-where-pseudo.enabled")
|
||||
CSS_PSEUDO_CLASS(matches, ":matches", 0, "layout.css.is-where-pseudo.enabled")
|
||||
CSS_PSEUDO_CLASS(any, ":any", 0, "layout.css.is-where-pseudo.enabled")
|
||||
CSS_PSEUDO_CLASS(where, ":where", 0, "layout.css.is-where-pseudo.enabled")
|
||||
CSS_PSEUDO_CLASS(has, ":has", 0, "")
|
||||
CSS_PSEUDO_CLASS(has, ":has", 0, "layout.css.has-pseudo.enabled")
|
||||
CSS_PSEUDO_CLASS(mozHasRelativeAnchor, ":-moz-has-relative-anchor",
|
||||
CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "")
|
||||
CSS_PSEUDO_CLASS_ENABLED_IN_UA_SHEETS_AND_CHROME, "layout.css.has-pseudo.enabled")
|
||||
|
||||
CSS_PSEUDO_CLASS(firstChild, ":first-child", 0, "")
|
||||
CSS_PSEUDO_CLASS(firstNode, ":-moz-first-node", 0, "")
|
||||
|
||||
+331
-10
@@ -642,6 +642,10 @@ nsCSSRuleUtils::SelectorMatches(Element* aElement,
|
||||
{
|
||||
NS_PRECONDITION(!aSelector->IsPseudoElement(),
|
||||
"Pseudo-element snuck into SelectorMatches?");
|
||||
AutoRestore<bool> laterSiblingsRestorer(
|
||||
aTreeMatchContext.mHasSelectorLaterSiblings);
|
||||
aTreeMatchContext.mHasSelectorLaterSiblings |=
|
||||
aSelector->mOperator == '+' || aSelector->mOperator == '~';
|
||||
MOZ_ASSERT(aTreeMatchContext.mForStyling ||
|
||||
!aNodeMatchContext.mIsRelevantLink,
|
||||
"mIsRelevantLink should be set to false when mForStyling "
|
||||
@@ -1722,6 +1726,291 @@ matchesSubtree(nsIContent* aRoot,
|
||||
return false;
|
||||
}
|
||||
|
||||
using HasSelectorDependency = nsCSSRuleUtils::HasSelectorDependency;
|
||||
|
||||
static void
|
||||
AddHasDependencyAtom(nsTArray<nsCOMPtr<nsIAtom>>& aAtoms, nsIAtom* aAtom)
|
||||
{
|
||||
if (!aAtoms.Contains(aAtom)) {
|
||||
aAtoms.AppendElement(aAtom);
|
||||
}
|
||||
}
|
||||
|
||||
// Collect every branch before matching, including :is() and legacy :not().
|
||||
void
|
||||
nsCSSHasSelectorData::Branch::AddSelector(nsCSSSelector* aSelector)
|
||||
{
|
||||
for (nsCSSSelector* selector = aSelector; selector; selector = selector->mNext) {
|
||||
if (selector->mIDList) {
|
||||
AddHasDependencyAtom(mAttributes, nsGkAtoms::id);
|
||||
}
|
||||
for (nsAtomList* cls = selector->mClassList; cls; cls = cls->mNext) {
|
||||
AddHasDependencyAtom(mClasses, cls->mAtom);
|
||||
}
|
||||
for (nsAttrSelector* attr = selector->mAttrList; attr; attr = attr->mNext) {
|
||||
// Include both spellings and conservatively ignore namespaces here.
|
||||
AddHasDependencyAtom(mAttributes, attr->mLowercaseAttr);
|
||||
AddHasDependencyAtom(mAttributes, attr->mCasedAttr);
|
||||
}
|
||||
for (nsPseudoClassList* pseudo = selector->mPseudoClassList;
|
||||
pseudo; pseudo = pseudo->mNext) {
|
||||
mStates |= nsCSSPseudoClasses::sPseudoClassStateDependences[
|
||||
static_cast<CSSPseudoClassTypeBase>(pseudo->mType)];
|
||||
if (nsCSSPseudoClasses::HasSelectorListArg(pseudo->mType)) {
|
||||
for (nsCSSSelectorList* list = pseudo->u.mSelectorList;
|
||||
list; list = list->mNext) {
|
||||
AddSelector(list->mSelectors);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
switch (pseudo->mType) {
|
||||
case CSSPseudoClassType::mozHasRelativeAnchor:
|
||||
case CSSPseudoClassType::empty:
|
||||
case CSSPseudoClassType::mozOnlyWhitespace:
|
||||
case CSSPseudoClassType::mozEmptyExceptChildrenWithLocalname:
|
||||
case CSSPseudoClassType::root:
|
||||
case CSSPseudoClassType::scope:
|
||||
case CSSPseudoClassType::firstChild:
|
||||
case CSSPseudoClassType::lastChild:
|
||||
case CSSPseudoClassType::onlyChild:
|
||||
case CSSPseudoClassType::firstNode:
|
||||
case CSSPseudoClassType::lastNode:
|
||||
case CSSPseudoClassType::firstOfType:
|
||||
case CSSPseudoClassType::lastOfType:
|
||||
case CSSPseudoClassType::onlyOfType:
|
||||
case CSSPseudoClassType::nthChild:
|
||||
case CSSPseudoClassType::nthLastChild:
|
||||
case CSSPseudoClassType::nthOfType:
|
||||
case CSSPseudoClassType::nthLastOfType:
|
||||
break;
|
||||
default:
|
||||
// Pseudo-classes can depend on attributes implicitly (:lang(),
|
||||
// :dir(), form states, etc.). Keep those cases conservative.
|
||||
mAllAttributes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (selector->mNegations) {
|
||||
AddSelector(selector->mNegations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSHasSelectorData::Branch::Merge(const Branch& aOther)
|
||||
{
|
||||
MOZ_ASSERT(mCombinator == aOther.mCombinator && mIsLocal == aOther.mIsLocal);
|
||||
mStates |= aOther.mStates;
|
||||
mAllAttributes |= aOther.mAllAttributes;
|
||||
for (nsIAtom* attr : aOther.mAttributes) {
|
||||
AddHasDependencyAtom(mAttributes, attr);
|
||||
}
|
||||
for (nsIAtom* cls : aOther.mClasses) {
|
||||
AddHasDependencyAtom(mClasses, cls);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HasSelectorDependency::AddSelectorData(nsCSSHasSelectorData* aData, bool aSibling)
|
||||
{
|
||||
auto& lastSelector = aSibling ? mLastSiblingSelector : mLastSelector;
|
||||
if (lastSelector == aData) {
|
||||
return;
|
||||
}
|
||||
auto& branches = aSibling ? mSiblingBranches : mBranches;
|
||||
for (const auto& source : aData->mBranches) {
|
||||
if (aSibling && !source.IsSibling()) {
|
||||
continue;
|
||||
}
|
||||
nsCSSHasSelectorData::Branch* destination = nullptr;
|
||||
for (auto& branch : branches) {
|
||||
if (branch.mCombinator == source.mCombinator &&
|
||||
branch.mIsLocal == source.mIsLocal) {
|
||||
destination = &branch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (destination) {
|
||||
destination->Merge(source);
|
||||
} else {
|
||||
branches.AppendElement(source);
|
||||
}
|
||||
}
|
||||
lastSelector = aData;
|
||||
}
|
||||
|
||||
// A local compound cannot observe children, ancestors, or state propagated
|
||||
// from descendants. Keep structural/state/complex functional arguments on the
|
||||
// conservative path; plain :is()/:not() compounds are safe to narrow.
|
||||
static bool
|
||||
IsLocalHasCompound(nsCSSSelector* aSelector)
|
||||
{
|
||||
for (nsPseudoClassList* pseudo = aSelector->mPseudoClassList;
|
||||
pseudo; pseudo = pseudo->mNext) {
|
||||
switch (pseudo->mType) {
|
||||
case CSSPseudoClassType::is:
|
||||
case CSSPseudoClassType::matches:
|
||||
case CSSPseudoClassType::any:
|
||||
case CSSPseudoClassType::where:
|
||||
case CSSPseudoClassType::mozAny:
|
||||
case CSSPseudoClassType::mozAnyPrivate:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
for (nsCSSSelectorList* list = pseudo->u.mSelectorList;
|
||||
list; list = list->mNext) {
|
||||
if (list->mSelectors &&
|
||||
(list->mSelectors->mNext || !IsLocalHasCompound(list->mSelectors))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (nsCSSSelector* negation = aSelector->mNegations;
|
||||
negation; negation = negation->mNegations) {
|
||||
if (negation->mNext || !IsLocalHasCompound(negation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCSSHasSelectorData::nsCSSHasSelectorData(nsCSSSelectorList* aList)
|
||||
{
|
||||
for (nsCSSSelectorList* list = aList; list; list = list->mNext) {
|
||||
Branch* branch = mBranches.AppendElement();
|
||||
branch->AddSelector(list->mSelectors);
|
||||
nsCSSSelector* anchor = list->mSelectors;
|
||||
while (anchor->mNext) {
|
||||
anchor = anchor->mNext;
|
||||
}
|
||||
branch->mCombinator = anchor->mOperator;
|
||||
branch->mIsLocal = list->mSelectors->mNext == anchor &&
|
||||
IsLocalHasCompound(list->mSelectors);
|
||||
mHasSibling |= branch->IsSibling();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsCSSHasSelectorData::Branch::MightDependOnAttribute(
|
||||
Element* aElement, nsIAtom* aAttribute, const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses) const
|
||||
{
|
||||
if (mAllAttributes || mAttributes.Contains(aAttribute)) {
|
||||
return true;
|
||||
}
|
||||
if (aAttribute != nsGkAtoms::_class) {
|
||||
return false;
|
||||
}
|
||||
const nsAttrValue* classes = aElement->GetClasses();
|
||||
nsCaseTreatment caseTreatment =
|
||||
aElement->OwnerDoc()->GetCompatibilityMode() == eCompatibility_NavQuirks
|
||||
? eIgnoreCase : eCaseMatters;
|
||||
for (nsIAtom* cls : mClasses) {
|
||||
bool hadClass = classes && classes->Contains(cls, caseTreatment);
|
||||
if (aCompareClasses) {
|
||||
bool hasClass = aNewClasses && aNewClasses->Contains(cls, caseTreatment);
|
||||
if (hadClass != hasClass) {
|
||||
return true;
|
||||
}
|
||||
} else if (hadClass) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
HasSelectorDependency::MightDependOnChange(
|
||||
Element* aAnchor, nsINode* aNode, EventStates aStateMask,
|
||||
nsIAtom* aAttribute, const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses, bool aSibling, bool aNodeIsFollowingSibling) const
|
||||
{
|
||||
bool contentChange = !aAttribute && aStateMask.IsEmpty();
|
||||
for (const auto& branch : mBranches) {
|
||||
if (branch.IsSibling() != aSibling ||
|
||||
(!aStateMask.IsEmpty() &&
|
||||
!branch.mStates.HasAtLeastOneOfStates(aStateMask)) ||
|
||||
(aAttribute && !branch.MightDependOnAttribute(
|
||||
aNode->AsElement(), aAttribute, aNewClasses, aCompareClasses))) {
|
||||
continue;
|
||||
}
|
||||
if (branch.mIsLocal) {
|
||||
if (aSibling) {
|
||||
nsINode* parent = aAnchor->GetParentNode();
|
||||
if (contentChange) {
|
||||
// Changing a sibling's contents cannot affect a local compound.
|
||||
if (aNode != parent) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (aNode->GetParentNode() != parent) {
|
||||
continue;
|
||||
}
|
||||
if (branch.mCombinator == '+') {
|
||||
if (aAnchor->GetNextElementSibling() != aNode) {
|
||||
continue;
|
||||
}
|
||||
} else if (!aNodeIsFollowingSibling) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (branch.mCombinator == '>') {
|
||||
if (contentChange ? aNode != aAnchor
|
||||
: aNode->GetParentNode() != aAnchor) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
HasSelectorDependency::MightAffectSiblingAnchor(
|
||||
nsINode* aParent, nsINode* aNode, EventStates aStateMask,
|
||||
nsIAtom* aAttribute, const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses) const
|
||||
{
|
||||
bool contentChange = !aAttribute && aStateMask.IsEmpty();
|
||||
for (const auto& branch : mSiblingBranches) {
|
||||
if (!branch.IsSibling() ||
|
||||
(branch.mIsLocal && (contentChange ? aNode != aParent
|
||||
: aNode->GetParentNode() != aParent)) ||
|
||||
(!aStateMask.IsEmpty() &&
|
||||
!branch.mStates.HasAtLeastOneOfStates(aStateMask)) ||
|
||||
(aAttribute && !branch.MightDependOnAttribute(
|
||||
aNode->AsElement(), aAttribute, aNewClasses, aCompareClasses))) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
DeleteHasSelectorDependency(void*, nsIAtom*, void* aValue, void*)
|
||||
{
|
||||
delete static_cast<HasSelectorDependency*>(aValue);
|
||||
}
|
||||
|
||||
static HasSelectorDependency*
|
||||
EnsureHasSelectorDependency(nsINode* aNode)
|
||||
{
|
||||
auto* dependency = static_cast<HasSelectorDependency*>(
|
||||
aNode->GetProperty(nsGkAtoms::hasSelectorDependency));
|
||||
if (!dependency) {
|
||||
dependency = new HasSelectorDependency;
|
||||
if (NS_FAILED(aNode->SetProperty(nsGkAtoms::hasSelectorDependency, dependency,
|
||||
DeleteHasSelectorDependency))) {
|
||||
delete dependency;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return dependency;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
nsCSSRuleUtils::RelativeSelectorListMatches(
|
||||
Element* aAnchor,
|
||||
@@ -1731,17 +2020,23 @@ nsCSSRuleUtils::RelativeSelectorListMatches(
|
||||
MOZ_ASSERT(aAnchor);
|
||||
MOZ_ASSERT(aList);
|
||||
|
||||
// :has() reverses the usual direction of selector invalidation. The
|
||||
// restyle manager uses these conservative markers to promote changes in the
|
||||
// anchor's descendants, or in following sibling subtrees, back to a subtree
|
||||
// that contains the anchor.
|
||||
if (aTreeMatchContext.mForStyling) {
|
||||
aAnchor->SetProperty(nsGkAtoms::hasSelectorDependency,
|
||||
reinterpret_cast<void*>(1));
|
||||
nsIContent* parent = aAnchor->GetParent();
|
||||
if (parent) {
|
||||
parent->SetProperty(nsGkAtoms::hasSelectorDependency,
|
||||
reinterpret_cast<void*>(1));
|
||||
if (!aList->mHasSelectorData) {
|
||||
aList->mHasSelectorData = new nsCSSHasSelectorData(aList);
|
||||
}
|
||||
const auto& data = aList->mHasSelectorData;
|
||||
// The document marker makes mutations in documents without styled :has()
|
||||
// selectors a constant-time no-op. All markers use the same property type.
|
||||
EnsureHasSelectorDependency(aAnchor->OwnerDoc());
|
||||
if (auto* dependency = EnsureHasSelectorDependency(aAnchor)) {
|
||||
dependency->AddSelectorData(data, false);
|
||||
dependency->mRestyleLaterSiblings |=
|
||||
aTreeMatchContext.mHasSelectorLaterSiblings;
|
||||
}
|
||||
if (data->mHasSibling && aAnchor->GetParent()) {
|
||||
if (auto* dependency = EnsureHasSelectorDependency(aAnchor->GetParent())) {
|
||||
dependency->AddSelectorData(data, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1764,6 +2059,26 @@ nsCSSRuleUtils::RelativeSelectorListMatches(
|
||||
}
|
||||
MOZ_ASSERT(leftmost->mNext);
|
||||
|
||||
// A single compound cannot move beyond the leading relationship.
|
||||
// Avoid scanning descendants for >, and all following subtrees for +/~.
|
||||
if (leftmost == relative->mSelectors) {
|
||||
char combinator = leftmost->mNext->mOperator;
|
||||
if (combinator == '>' || combinator == '+' || combinator == '~') {
|
||||
Element* candidate = combinator == '>'
|
||||
? aAnchor->GetFirstElementChild()
|
||||
: aAnchor->GetNextElementSibling();
|
||||
for (; candidate; candidate = candidate->GetNextElementSibling()) {
|
||||
if (matchesCandidate(candidate, relative, aTreeMatchContext)) {
|
||||
return true;
|
||||
}
|
||||
if (combinator == '+') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (leftmost->mNext->mOperator) {
|
||||
// Even for a leading adjacent-sibling combinator, a later combinator in
|
||||
// the relative selector can move the rightmost matching element into a
|
||||
@@ -1778,6 +2093,12 @@ nsCSSRuleUtils::RelativeSelectorListMatches(
|
||||
if (matchesSubtree(sibling, relative, aTreeMatchContext)) {
|
||||
return true;
|
||||
}
|
||||
// Once + .a enters .a's descendants, later combinators cannot
|
||||
// leave that subtree. + .a + .b still needs the broader search.
|
||||
if (leftmost->mNext->mOperator == '+' &&
|
||||
NS_IS_ANCESTOR_OPERATOR(leftmost->mOperator)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/RefCountType.h"
|
||||
#include "mozilla/RefCountType.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/SheetType.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
@@ -20,8 +21,64 @@
|
||||
#include "nsTArray.h"
|
||||
#include "StyleRule.h"
|
||||
|
||||
struct nsCSSRuleUtils
|
||||
{
|
||||
// No selector or DOM pointers: nodes can safely keep this after a rule is
|
||||
// removed, without keeping either the stylesheet or an anchor alive.
|
||||
struct nsCSSHasSelectorData : public mozilla::RefCounted<nsCSSHasSelectorData> {
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(nsCSSHasSelectorData)
|
||||
|
||||
struct Branch {
|
||||
mozilla::EventStates mStates;
|
||||
nsTArray<nsCOMPtr<nsIAtom>> mAttributes;
|
||||
nsTArray<nsCOMPtr<nsIAtom>> mClasses;
|
||||
bool mAllAttributes = false;
|
||||
bool mIsLocal = false;
|
||||
char16_t mCombinator = ' ';
|
||||
|
||||
void AddSelector(nsCSSSelector* aSelector);
|
||||
void Merge(const Branch& aOther);
|
||||
bool MightDependOnAttribute(mozilla::dom::Element* aElement,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses) const;
|
||||
bool IsSibling() const {
|
||||
return mCombinator == '+' || mCombinator == '~';
|
||||
}
|
||||
};
|
||||
|
||||
explicit nsCSSHasSelectorData(nsCSSSelectorList* aList);
|
||||
nsTArray<Branch> mBranches;
|
||||
bool mHasSibling = false;
|
||||
};
|
||||
|
||||
struct nsCSSRuleUtils
|
||||
{
|
||||
// Stored on nodes under hasSelectorDependency. Dependencies accumulate
|
||||
// across matching passes, so a failed/short-circuited branch stays watched.
|
||||
struct HasSelectorDependency {
|
||||
// Merge rules with the same search relationship. Retaining a reference
|
||||
// to every rule ever matched would grow without bound on long-lived pages
|
||||
// that replace stylesheets. Only the most recent registration is cached.
|
||||
nsTArray<nsCSSHasSelectorData::Branch> mBranches;
|
||||
nsTArray<nsCSSHasSelectorData::Branch> mSiblingBranches;
|
||||
RefPtr<nsCSSHasSelectorData> mLastSelector;
|
||||
RefPtr<nsCSSHasSelectorData> mLastSiblingSelector;
|
||||
bool mRestyleLaterSiblings = false;
|
||||
|
||||
void AddSelectorData(nsCSSHasSelectorData* aData, bool aSibling);
|
||||
bool MightDependOnChange(Element* aAnchor, nsINode* aNode,
|
||||
mozilla::EventStates aStateMask,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses,
|
||||
bool aSibling,
|
||||
bool aNodeIsFollowingSibling = false) const;
|
||||
bool MightAffectSiblingAnchor(nsINode* aParent, nsINode* aNode,
|
||||
mozilla::EventStates aStateMask,
|
||||
nsIAtom* aAttribute,
|
||||
const nsAttrValue* aNewClasses,
|
||||
bool aCompareClasses) const;
|
||||
};
|
||||
|
||||
static void Startup();
|
||||
static void Shutdown();
|
||||
static void FreeSystemMetrics();
|
||||
|
||||
@@ -450,6 +450,7 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
||||
, mIsTopmostScope(false)
|
||||
, mForAssignedSlot(false)
|
||||
, mRelativeSelectorAnchor(nullptr)
|
||||
, mHasSelectorLaterSiblings(false)
|
||||
{
|
||||
if (aMatchVisited != eNeverMatchVisited) {
|
||||
nsILoadContext* loadContext = mDocument->GetLoadContext();
|
||||
@@ -472,6 +473,8 @@ struct MOZ_STACK_CLASS TreeMatchContext {
|
||||
// relative selector. This is deliberately separate from mScopes: an
|
||||
// explicit :scope inside :has() still refers to the API/style scope.
|
||||
mozilla::dom::Element* mRelativeSelectorAnchor;
|
||||
// Propagate an outer sibling combinator through :is(), :not(), etc.
|
||||
bool mHasSelectorLaterSiblings;
|
||||
};
|
||||
|
||||
struct MOZ_STACK_CLASS RuleProcessorData {
|
||||
|
||||
@@ -333,12 +333,10 @@ void vp8_build_inter16x16_predictors_mb(MACROBLOCKD *x, unsigned char *dst_y,
|
||||
_16x16mv.as_mv.row &= x->fullpixel_mask;
|
||||
_16x16mv.as_mv.col &= x->fullpixel_mask;
|
||||
|
||||
if (2 * _16x16mv.as_mv.col < (x->mb_to_left_edge - (19 << 3)) ||
|
||||
2 * _16x16mv.as_mv.col > x->mb_to_right_edge + (18 << 3) ||
|
||||
2 * _16x16mv.as_mv.row < (x->mb_to_top_edge - (19 << 3)) ||
|
||||
2 * _16x16mv.as_mv.row > x->mb_to_bottom_edge + (18 << 3)) {
|
||||
return;
|
||||
}
|
||||
/* Rounding to full-pel can move the chroma MV outside the border tap
|
||||
* window even though the luma MV was already clamped, so clamp again to
|
||||
* keep the reference read in bounds and ensure dst_u/dst_v are written. */
|
||||
clamp_uvmv_to_umv_border(&_16x16mv.as_mv, x);
|
||||
|
||||
pre_stride >>= 1;
|
||||
offset = (_16x16mv.as_mv.row >> 3) * pre_stride + (_16x16mv.as_mv.col >> 3);
|
||||
|
||||
@@ -379,12 +379,12 @@ template<typename T>
|
||||
static MOZ_ALWAYS_INLINE bool
|
||||
NumberEqualsInt32(T aValue, int32_t* aInt32)
|
||||
{
|
||||
/*
|
||||
* XXX Casting a floating-point value that doesn't truncate to int32_t, to
|
||||
* int32_t, induces undefined behavior. We should definitely fix this
|
||||
* (bug 744965), but as apparently it "works" in practice, it's not a
|
||||
* pressing concern now.
|
||||
*/
|
||||
// Check the range before casting: an out-of-range float-to-integer cast is
|
||||
// undefined behavior. Use an exclusive upper bound of 2^31, since converting
|
||||
// INT32_MAX to float rounds up to 2^31. This also rejects NaN and infinities.
|
||||
if (!(aValue >= T(INT32_MIN) && aValue < -T(INT32_MIN))) {
|
||||
return false;
|
||||
}
|
||||
return aValue == (*aInt32 = int32_t(aValue));
|
||||
}
|
||||
|
||||
|
||||
@@ -111,9 +111,11 @@ nsJARProtocolHandler::GetDefaultPort(int32_t *result)
|
||||
NS_IMETHODIMP
|
||||
nsJARProtocolHandler::GetProtocolFlags(uint32_t *result)
|
||||
{
|
||||
// URI_LOADABLE_BY_ANYONE, since it's our inner URI that will matter
|
||||
// anyway.
|
||||
*result = URI_NORELATIVE | URI_NOAUTH | URI_LOADABLE_BY_ANYONE;
|
||||
// A jar: URI is only ever as loadable as the inner URI it
|
||||
// wraps, and security checks consult the innermost URI. Claim
|
||||
// the restrictive flag here so that consumers which look at the
|
||||
// jar: handler alone don't treat it as web-loadable.
|
||||
*result = URI_NORELATIVE | URI_NOAUTH | URI_IS_LOCAL_FILE;
|
||||
/* Although jar uris have their own concept of relative urls
|
||||
it is very different from the standard behaviour, so we
|
||||
have to say norelative here! */
|
||||
|
||||
@@ -2572,6 +2572,9 @@ pref("layout.css.legacy-negation-pseudo.enabled", false);
|
||||
// Is support for the :is() and :where() selectors enabled?
|
||||
pref("layout.css.is-where-pseudo.enabled", true);
|
||||
|
||||
// Is support for the :has() selector enabled?
|
||||
pref("layout.css.has-pseudo.enabled", false);
|
||||
|
||||
// Is support for the ::slotted() selector enabled?
|
||||
pref("layout.css.slotted-pseudo.enabled", true);
|
||||
|
||||
@@ -4513,6 +4516,9 @@ pref("html5.flushtimer.initialdelay", 120);
|
||||
// Time in milliseconds between the time a network buffer is seen and the
|
||||
// timer firing when the timer has already fired previously in this parse.
|
||||
pref("html5.flushtimer.subsequentdelay", 120);
|
||||
// Determine whether strict (standards-compliant) subtree node checking is
|
||||
// enabled for forms. See UXP issue #3197
|
||||
pref("html5.forms.standards_compliant", true);
|
||||
|
||||
// Push/Pop/Replace State prefs
|
||||
pref("browser.history.maxStateObjectSize", 655360);
|
||||
|
||||
@@ -3,11 +3,17 @@
|
||||
* 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 "nsMIMEHeaderParamImpl.h"
|
||||
|
||||
#include <string.h>
|
||||
#include "prmem.h"
|
||||
|
||||
#include "mozilla/Base64.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/TextUtils.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
#include "plbase64.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsMemory.h"
|
||||
#include "nsTArray.h"
|
||||
@@ -16,18 +22,20 @@
|
||||
#include "nsIUTF8ConverterService.h"
|
||||
#include "nsUConvCID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsMIMEHeaderParamImpl.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsNativeCharsetUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsIUnicodeDecoder.h"
|
||||
#include "mozilla/dom/EncodingUtils.h"
|
||||
|
||||
using mozilla::dom::EncodingUtils;
|
||||
using mozilla::Maybe;
|
||||
using mozilla::Nothing;
|
||||
using mozilla::Some;
|
||||
|
||||
|
||||
// static functions declared below are moved from mailnews/mime/src/comi18n.cpp
|
||||
|
||||
static char *DecodeQ(const char *, uint32_t);
|
||||
static Maybe<nsCString> DecodeQ(const char *, uint32_t);
|
||||
static bool Is7bitNonAsciiString(const char *, uint32_t);
|
||||
static void CopyRawHeader(const char *, uint32_t, const char *, nsACString &);
|
||||
static nsresult DecodeRFC2047Str(const char *, const char *, bool, nsACString&);
|
||||
@@ -48,8 +56,7 @@ nsMIMEHeaderParamImpl::GetParameter(const nsACString& aHeaderVal,
|
||||
const char *aParamName,
|
||||
const nsACString& aFallbackCharset,
|
||||
bool aTryLocaleCharset,
|
||||
char **aLang, nsAString& aResult)
|
||||
{
|
||||
char **aLang, nsAString& aResult) {
|
||||
return DoGetParameter(aHeaderVal, aParamName, MIME_FIELD_ENCODING,
|
||||
aFallbackCharset, aTryLocaleCharset, aLang, aResult);
|
||||
}
|
||||
@@ -59,8 +66,7 @@ nsMIMEHeaderParamImpl::GetParameterHTTP(const nsACString& aHeaderVal,
|
||||
const char *aParamName,
|
||||
const nsACString& aFallbackCharset,
|
||||
bool aTryLocaleCharset,
|
||||
char **aLang, nsAString& aResult)
|
||||
{
|
||||
char **aLang, nsAString& aResult) {
|
||||
return DoGetParameter(aHeaderVal, aParamName, HTTP_FIELD_ENCODING,
|
||||
aFallbackCharset, aTryLocaleCharset, aLang, aResult);
|
||||
}
|
||||
@@ -94,76 +100,75 @@ nsMIMEHeaderParamImpl::DoGetParameter(const nsACString& aHeaderVal,
|
||||
ParamDecoding aDecoding,
|
||||
const nsACString& aFallbackCharset,
|
||||
bool aTryLocaleCharset,
|
||||
char **aLang, nsAString& aResult)
|
||||
{
|
||||
aResult.Truncate();
|
||||
nsresult rv;
|
||||
char **aLang, nsAString& aResult) {
|
||||
aResult.Truncate();
|
||||
nsresult rv;
|
||||
|
||||
// get parameter (decode RFC 2231/5987 when applicable, as specified by
|
||||
// aDecoding (5987 being a subset of 2231) and return charset.)
|
||||
nsXPIDLCString med;
|
||||
nsXPIDLCString charset;
|
||||
rv = DoParameterInternal(aHeaderVal, aParamName, aDecoding,
|
||||
getter_Copies(charset), aLang, getter_Copies(med));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
// get parameter (decode RFC 2231/5987 when applicable, as specified by
|
||||
// aDecoding (5987 being a subset of 2231) and return charset.)
|
||||
nsXPIDLCString med;
|
||||
nsXPIDLCString charset;
|
||||
rv = DoParameterInternal(aHeaderVal, aParamName, aDecoding,
|
||||
getter_Copies(charset), aLang, getter_Copies(med));
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// convert to UTF-8 after charset conversion and RFC 2047 decoding
|
||||
// if necessary.
|
||||
// convert to UTF-8 after charset conversion and RFC 2047 decoding
|
||||
// if necessary.
|
||||
|
||||
nsAutoCString str1;
|
||||
rv = internalDecodeParameter(med, charset.get(), nullptr, false,
|
||||
// was aDecoding == MIME_FIELD_ENCODING
|
||||
// see bug 875615
|
||||
true,
|
||||
str1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsAutoCString str1;
|
||||
rv = internalDecodeParameter(med, charset.get(), nullptr, false,
|
||||
// was aDecoding == MIME_FIELD_ENCODING
|
||||
// see bug 875615
|
||||
true,
|
||||
str1);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!aFallbackCharset.IsEmpty())
|
||||
{
|
||||
nsAutoCString charset;
|
||||
EncodingUtils::FindEncodingForLabel(aFallbackCharset, charset);
|
||||
nsAutoCString str2;
|
||||
nsCOMPtr<nsIUTF8ConverterService>
|
||||
cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
|
||||
if (cvtUTF8 &&
|
||||
NS_SUCCEEDED(cvtUTF8->ConvertStringToUTF8(str1,
|
||||
PromiseFlatCString(aFallbackCharset).get(), false,
|
||||
!charset.EqualsLiteral("UTF-8"),
|
||||
1, str2))) {
|
||||
CopyUTF8toUTF16(str2, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsUTF8(str1)) {
|
||||
CopyUTF8toUTF16(str1, aResult);
|
||||
if (!aFallbackCharset.IsEmpty()) {
|
||||
nsAutoCString charset;
|
||||
EncodingUtils::FindEncodingForLabel(aFallbackCharset, charset);
|
||||
nsAutoCString str2;
|
||||
nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
|
||||
if (cvtUTF8 &&
|
||||
NS_SUCCEEDED(cvtUTF8->ConvertStringToUTF8(str1,
|
||||
PromiseFlatCString(aFallbackCharset).get(),
|
||||
false,
|
||||
!charset.EqualsLiteral("UTF-8"),
|
||||
1,
|
||||
str2))) {
|
||||
CopyUTF8toUTF16(str2, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (aTryLocaleCharset && !NS_IsNativeUTF8())
|
||||
return NS_CopyNativeToUnicode(str1, aResult);
|
||||
|
||||
CopyASCIItoUTF16(str1, aResult);
|
||||
if (IsUTF8(str1)) {
|
||||
CopyUTF8toUTF16(str1, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aTryLocaleCharset && !NS_IsNativeUTF8()) {
|
||||
return NS_CopyNativeToUnicode(str1, aResult);
|
||||
}
|
||||
|
||||
CopyASCIItoUTF16(str1, aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// remove backslash-encoded sequences from quoted-strings
|
||||
// modifies string in place, potentially shortening it
|
||||
void RemoveQuotedStringEscapes(char *src)
|
||||
{
|
||||
char *dst = src;
|
||||
// modifies aValue, potentially shortening it
|
||||
void RemoveQuotedStringEscapes(nsCString& aValue) {
|
||||
nsAutoCString unescaped;
|
||||
unescaped.SetCapacity(aValue.Length());
|
||||
|
||||
for (char *c = src; *c; ++c)
|
||||
{
|
||||
if (c[0] == '\\' && c[1])
|
||||
{
|
||||
for (uint32_t i = 0; i < aValue.Length(); ++i) {
|
||||
if (aValue[i] == '\\' && i + 1 < aValue.Length()) {
|
||||
// skip backslash if not at end
|
||||
++c;
|
||||
++i;
|
||||
}
|
||||
*dst++ = *c;
|
||||
unescaped.Append(aValue[i]);
|
||||
}
|
||||
*dst = 0;
|
||||
aValue = std::move(unescaped);
|
||||
}
|
||||
|
||||
// true is character is a hex digit
|
||||
@@ -176,12 +181,13 @@ bool IsHexDigit(char aChar)
|
||||
(c >= '0' && c <= '9');
|
||||
}
|
||||
|
||||
// validate that a C String containing %-escapes is syntactically valid
|
||||
bool IsValidPercentEscaped(const char *aValue, int32_t len)
|
||||
{
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
// validate that a string containing %-escapes is syntactically valid
|
||||
bool IsValidPercentEscaped(const nsACString& aValue) {
|
||||
for (uint32_t i = 0; i < aValue.Length(); i++) {
|
||||
if (aValue[i] == '%') {
|
||||
if (!IsHexDigit(aValue[i + 1]) || !IsHexDigit(aValue[i + 2])) {
|
||||
if (i + 2 >= aValue.Length() ||
|
||||
!IsHexDigit(aValue[i + 1]) ||
|
||||
!IsHexDigit(aValue[i + 2])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -189,6 +195,21 @@ bool IsValidPercentEscaped(const char *aValue, int32_t len)
|
||||
return true;
|
||||
}
|
||||
|
||||
// A NUL anywhere in a decoded value would silently truncate it in any later
|
||||
// C-string based processing. Note that this is stricter than
|
||||
// ContainsTrailingCharPastNull, which tolerates a value whose tail past the
|
||||
// NUL is only more NULs.
|
||||
static bool ContainsNull(const nsACString& aValue) {
|
||||
return aValue.Contains('\0');
|
||||
}
|
||||
|
||||
// Percent-decode aValue in place (which happens whether or not this succeeds),
|
||||
// returning false if the decoded value contains a NUL.
|
||||
static bool UnescapeRejectingNull(nsCString& aValue) {
|
||||
NS_UnescapeURL(aValue);
|
||||
return !ContainsNull(aValue);
|
||||
}
|
||||
|
||||
// Support for continuations (RFC 2231, Section 3)
|
||||
|
||||
// only a sane number supported
|
||||
@@ -220,59 +241,41 @@ class Continuation {
|
||||
bool wasQuotedString;
|
||||
};
|
||||
|
||||
// combine segments into a single string, returning the allocated string
|
||||
// (or nullptr) while emptying the list
|
||||
char *combineContinuations(nsTArray<Continuation>& aArray)
|
||||
{
|
||||
// Sanity check
|
||||
if (aArray.Length() == 0)
|
||||
return nullptr;
|
||||
// combine segments into a single string, up to the first segment that is
|
||||
// missing. Returns Nothing() if that leaves nothing at all, or, with
|
||||
// aContainedNull set, if percent-decoding a segment produced a NUL.
|
||||
Maybe<nsCString> combineContinuations(const nsTArray<Continuation>& aArray,
|
||||
bool& aContainedNull) {
|
||||
nsCString result;
|
||||
|
||||
// Get an upper bound for the length
|
||||
uint32_t length = 0;
|
||||
for (uint32_t i = 0; i < aArray.Length(); i++) {
|
||||
length += aArray[i].length;
|
||||
}
|
||||
for (const Continuation& cont : aArray) {
|
||||
if (!cont.value) break;
|
||||
|
||||
// Allocate
|
||||
char *result = (char *) moz_xmalloc(length + 1);
|
||||
|
||||
// Concatenate
|
||||
if (result) {
|
||||
*result = '\0';
|
||||
|
||||
for (uint32_t i = 0; i < aArray.Length(); i++) {
|
||||
Continuation cont = aArray[i];
|
||||
if (! cont.value) break;
|
||||
|
||||
char *c = result + strlen(result);
|
||||
strncat(result, cont.value, cont.length);
|
||||
if (cont.needsPercentDecoding) {
|
||||
nsUnescape(c);
|
||||
}
|
||||
if (cont.wasQuotedString) {
|
||||
RemoveQuotedStringEscapes(c);
|
||||
nsAutoCString segment(cont.value, cont.length);
|
||||
if (cont.needsPercentDecoding) {
|
||||
if (!UnescapeRejectingNull(segment)) {
|
||||
aContainedNull = true;
|
||||
return Nothing();
|
||||
}
|
||||
}
|
||||
|
||||
// return null if empty value
|
||||
if (*result == '\0') {
|
||||
free(result);
|
||||
result = nullptr;
|
||||
if (cont.wasQuotedString) {
|
||||
RemoveQuotedStringEscapes(segment);
|
||||
}
|
||||
} else {
|
||||
// Handle OOM
|
||||
NS_WARNING("Out of memory\n");
|
||||
result.Append(segment);
|
||||
}
|
||||
|
||||
return result;
|
||||
// no result if empty value
|
||||
if (result.IsEmpty()) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
return Some(std::move(result));
|
||||
}
|
||||
|
||||
// add a continuation, return false on error if segment already has been seen
|
||||
bool addContinuation(nsTArray<Continuation>& aArray, uint32_t aIndex,
|
||||
const char *aValue, uint32_t aLength,
|
||||
bool aNeedsPercentDecoding, bool aWasQuotedString)
|
||||
{
|
||||
bool aNeedsPercentDecoding, bool aWasQuotedString) {
|
||||
if (aIndex < aArray.Length() && aArray[aIndex].value) {
|
||||
NS_WARNING("duplicate RC2231 continuation segment #\n");
|
||||
return false;
|
||||
@@ -299,8 +302,7 @@ bool addContinuation(nsTArray<Continuation>& aArray, uint32_t aIndex,
|
||||
}
|
||||
|
||||
// parse a segment number; return -1 on error
|
||||
int32_t parseSegmentNumber(const char *aValue, int32_t aLen)
|
||||
{
|
||||
int32_t parseSegmentNumber(const char *aValue, int32_t aLen) {
|
||||
if (aLen < 1) {
|
||||
NS_WARNING("segment number missing\n");
|
||||
return -1;
|
||||
@@ -332,20 +334,16 @@ int32_t parseSegmentNumber(const char *aValue, int32_t aLen)
|
||||
|
||||
// validate a given octet sequence for compliance with the specified
|
||||
// encoding
|
||||
bool IsValidOctetSequenceForCharset(nsACString& aCharset, const char *aOctets)
|
||||
{
|
||||
nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService
|
||||
(NS_UTF8CONVERTERSERVICE_CONTRACTID));
|
||||
bool IsValidOctetSequenceForCharset(nsACString& aCharset, const nsACString& aOctets) {
|
||||
nsCOMPtr<nsIUTF8ConverterService> cvtUTF8(do_GetService(NS_UTF8CONVERTERSERVICE_CONTRACTID));
|
||||
if (!cvtUTF8) {
|
||||
NS_WARNING("Can't get UTF8ConverterService\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoCString tmpRaw;
|
||||
tmpRaw.Assign(aOctets);
|
||||
nsAutoCString tmpDecoded;
|
||||
|
||||
nsresult rv = cvtUTF8->ConvertStringToUTF8(tmpRaw,
|
||||
nsresult rv = cvtUTF8->ConvertStringToUTF8(aOctets,
|
||||
PromiseFlatCString(aCharset).get(),
|
||||
false, false, 1, tmpDecoded);
|
||||
|
||||
@@ -371,8 +369,7 @@ nsMIMEHeaderParamImpl::GetParameterInternal(const nsACString& aHeaderValue,
|
||||
const char* aParamName,
|
||||
char** aCharset,
|
||||
char** aLang,
|
||||
char** aResult)
|
||||
{
|
||||
char** aResult) {
|
||||
return DoParameterInternal(aHeaderValue, aParamName, MIME_FIELD_ENCODING,
|
||||
aCharset, aLang, aResult);
|
||||
}
|
||||
@@ -384,9 +381,7 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
ParamDecoding aDecoding,
|
||||
char** aCharset,
|
||||
char** aLang,
|
||||
char** aResult)
|
||||
{
|
||||
|
||||
char** aResult) {
|
||||
if (aHeaderValue.IsEmpty() || !aResult) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
@@ -405,8 +400,12 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
|
||||
*aResult = nullptr;
|
||||
|
||||
if (aCharset) *aCharset = nullptr;
|
||||
if (aLang) *aLang = nullptr;
|
||||
if (aCharset) {
|
||||
*aCharset = nullptr;
|
||||
}
|
||||
if (aLang) {
|
||||
*aLang = nullptr;
|
||||
}
|
||||
|
||||
nsAutoCString charset;
|
||||
|
||||
@@ -415,8 +414,8 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
bool acceptContinuations = true;
|
||||
|
||||
// skip leading white space.
|
||||
for (; *str && nsCRT::IsAsciiSpace(*str); ++str)
|
||||
;
|
||||
for (; *str && nsCRT::IsAsciiSpace(*str); ++str) { }
|
||||
|
||||
const char *start = str;
|
||||
|
||||
// aParamName is empty. return the first (possibly) _unnamed_ 'parameter'
|
||||
@@ -429,9 +428,7 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
if (str == start)
|
||||
return NS_ERROR_FIRST_HEADER_FIELD_COMPONENT_EMPTY;
|
||||
|
||||
*aResult = (char *) nsMemory::Clone(start, (str - start) + 1);
|
||||
NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
|
||||
(*aResult)[str - start] = '\0'; // null-terminate
|
||||
*aResult = ToNewCString(Substring(start, str - start));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -465,9 +462,14 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
// collect results for the different algorithms (plain filename,
|
||||
// RFC5987/2231-encoded filename, + continuations) separately and decide
|
||||
// which to use at the end
|
||||
char *caseAResult = nullptr;
|
||||
char *caseBResult = nullptr;
|
||||
char *caseCDResult = nullptr;
|
||||
Maybe<nsCString> caseAResult;
|
||||
Maybe<nsCString> caseBResult;
|
||||
Maybe<nsCString> caseCDResult;
|
||||
|
||||
// set when percent-decoding produced a NUL, which makes us reject the
|
||||
// parameter outright rather than fall back to a value the sender did not
|
||||
// intend to be used
|
||||
bool containedNull = false;
|
||||
|
||||
// collect continuation segments
|
||||
nsTArray<Continuation> segments;
|
||||
@@ -548,15 +550,14 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
|
||||
// if the parameter spans across multiple lines we have to strip out the
|
||||
// line continuation -- jht 4/29/98
|
||||
nsAutoCString tempStr(valueStart, valueEnd - valueStart);
|
||||
nsCString tempStr(valueStart, valueEnd - valueStart);
|
||||
tempStr.StripChars("\r\n");
|
||||
char *res = ToNewCString(tempStr);
|
||||
NS_ENSURE_TRUE(res, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
if (isQuotedString)
|
||||
RemoveQuotedStringEscapes(res);
|
||||
if (isQuotedString) {
|
||||
RemoveQuotedStringEscapes(tempStr);
|
||||
}
|
||||
|
||||
caseAResult = res;
|
||||
caseAResult.emplace(std::move(tempStr));
|
||||
// keep going, we may find a RFC 2231/5987 encoded alternative
|
||||
}
|
||||
// case B, C, and D
|
||||
@@ -645,19 +646,16 @@ nsMIMEHeaderParamImpl::DoParameterInternal(const nsACString& aHeaderValue,
|
||||
// non-empty value part
|
||||
if (rawValLength > 0) {
|
||||
if (!caseBResult && caseB) {
|
||||
if (!IsValidPercentEscaped(rawValStart, rawValLength)) {
|
||||
nsCString rawVal(rawValStart, rawValLength);
|
||||
if (!IsValidPercentEscaped(rawVal)) {
|
||||
goto increment_str;
|
||||
}
|
||||
|
||||
// allocate buffer for the raw value
|
||||
char *tmpResult = (char *) nsMemory::Clone(rawValStart, rawValLength + 1);
|
||||
if (!tmpResult) {
|
||||
goto increment_str;
|
||||
if (!UnescapeRejectingNull(rawVal)) {
|
||||
containedNull = true;
|
||||
break;
|
||||
}
|
||||
*(tmpResult + rawValLength) = 0;
|
||||
|
||||
nsUnescape(tmpResult);
|
||||
caseBResult = tmpResult;
|
||||
caseBResult.emplace(std::move(rawVal));
|
||||
} else {
|
||||
// caseC
|
||||
bool added = addContinuation(segments, 0, rawValStart,
|
||||
@@ -701,44 +699,45 @@ increment_str:
|
||||
while (nsCRT::IsAsciiSpace(*str)) ++str;
|
||||
}
|
||||
|
||||
caseCDResult = combineContinuations(segments);
|
||||
if (!containedNull) {
|
||||
caseCDResult = combineContinuations(segments, containedNull);
|
||||
}
|
||||
|
||||
if (containedNull) {
|
||||
// Percent-decoding produced a NUL, which would truncate the value.
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (caseBResult && !charsetB.IsEmpty()) {
|
||||
// check that the 2231/5987 result decodes properly given the
|
||||
// specified character set
|
||||
if (!IsValidOctetSequenceForCharset(charsetB, caseBResult))
|
||||
caseBResult = nullptr;
|
||||
if (!IsValidOctetSequenceForCharset(charsetB, *caseBResult)) {
|
||||
caseBResult.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (caseCDResult && !charsetCD.IsEmpty()) {
|
||||
// check that the 2231/5987 result decodes properly given the
|
||||
// specified character set
|
||||
if (!IsValidOctetSequenceForCharset(charsetCD, caseCDResult))
|
||||
caseCDResult = nullptr;
|
||||
if (!IsValidOctetSequenceForCharset(charsetCD, *caseCDResult)) {
|
||||
caseCDResult.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (caseBResult) {
|
||||
// prefer simple 5987 format over 2231 with continuations
|
||||
*aResult = caseBResult;
|
||||
caseBResult = nullptr;
|
||||
*aResult = ToNewCString(*caseBResult);
|
||||
charset.Assign(charsetB);
|
||||
}
|
||||
else if (caseCDResult) {
|
||||
// prefer 2231/5987 with or without continuations over plain format
|
||||
*aResult = caseCDResult;
|
||||
caseCDResult = nullptr;
|
||||
*aResult = ToNewCString(*caseCDResult);
|
||||
charset.Assign(charsetCD);
|
||||
}
|
||||
else if (caseAResult) {
|
||||
*aResult = caseAResult;
|
||||
caseAResult = nullptr;
|
||||
*aResult = ToNewCString(*caseAResult);
|
||||
}
|
||||
|
||||
// free unused stuff
|
||||
free(caseAResult);
|
||||
free(caseBResult);
|
||||
free(caseCDResult);
|
||||
|
||||
// if we have a result
|
||||
if (*aResult) {
|
||||
// then return charset and lang as well
|
||||
@@ -825,23 +824,6 @@ bool IsRFC5987AttrChar(char aChar)
|
||||
c == '_' || c == '`' || c == '|' || c == '~');
|
||||
}
|
||||
|
||||
// percent-decode a value
|
||||
// returns false on failure
|
||||
bool PercentDecode(nsACString& aValue)
|
||||
{
|
||||
char *c = (char *) moz_xmalloc(aValue.Length() + 1);
|
||||
if (!c) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(c, PromiseFlatCString(aValue).get());
|
||||
nsUnescape(c);
|
||||
aValue.Assign(c);
|
||||
free(c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decode a parameter value using the encoding defined in RFC 5987
|
||||
//
|
||||
// charset "'" [ language ] "'" value-chars
|
||||
@@ -909,8 +891,8 @@ nsMIMEHeaderParamImpl::DecodeRFC5987Param(const nsACString& aParamVal,
|
||||
}
|
||||
|
||||
// percent-decode
|
||||
if (!PercentDecode(value)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
if (!UnescapeRejectingNull(value)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
// return the encoding
|
||||
@@ -999,52 +981,44 @@ nsMIMEHeaderParamImpl::DecodeParameter(const nsACString& aParamValue,
|
||||
(0x41 <= uint8_t(c) && uint8_t(c) <= 0x46) || \
|
||||
(0x61 <= uint8_t(c) && uint8_t(c) <= 0x66))
|
||||
|
||||
// Decode Q encoding (RFC 2047).
|
||||
// Decode Q encoding (RFC 2047). Returns Nothing() on bad syntax.
|
||||
// static
|
||||
char *DecodeQ(const char *in, uint32_t length)
|
||||
{
|
||||
char *out, *dest = 0;
|
||||
Maybe<nsCString> DecodeQ(const char* in, uint32_t length) {
|
||||
nsCString dest;
|
||||
dest.SetCapacity(length);
|
||||
|
||||
out = dest = (char *)PR_Calloc(length + 1, sizeof(char));
|
||||
if (dest == nullptr)
|
||||
return nullptr;
|
||||
while (length > 0) {
|
||||
unsigned c = 0;
|
||||
switch (*in) {
|
||||
case '=':
|
||||
// check if |in| in the form of '=hh' where h is [0-9a-fA-F].
|
||||
if (length < 3 || !ISHEXCHAR(in[1]) || !ISHEXCHAR(in[2]))
|
||||
goto badsyntax;
|
||||
PR_sscanf(in + 1, "%2X", &c);
|
||||
*out++ = (char) c;
|
||||
in += 3;
|
||||
length -= 3;
|
||||
break;
|
||||
case '=':
|
||||
// check if |in| in the form of '=hh' where h is [0-9a-fA-F].
|
||||
if (length < 3 || !ISHEXCHAR(in[1]) || !ISHEXCHAR(in[2])) {
|
||||
return Nothing();
|
||||
}
|
||||
PR_sscanf(in + 1, "%2X", &c);
|
||||
dest.Append((char)c);
|
||||
in += 3;
|
||||
length -= 3;
|
||||
break;
|
||||
|
||||
case '_':
|
||||
*out++ = ' ';
|
||||
in++;
|
||||
length--;
|
||||
break;
|
||||
case '_':
|
||||
dest.Append(' ');
|
||||
in++;
|
||||
length--;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (*in & 0x80) goto badsyntax;
|
||||
*out++ = *in++;
|
||||
length--;
|
||||
default:
|
||||
if (*in & 0x80) {
|
||||
return Nothing();
|
||||
}
|
||||
dest.Append(*in++);
|
||||
length--;
|
||||
}
|
||||
}
|
||||
*out++ = '\0';
|
||||
|
||||
for (out = dest; *out ; ++out) {
|
||||
if (*out == '\t')
|
||||
*out = ' ';
|
||||
}
|
||||
dest.ReplaceChar('\t', ' ');
|
||||
|
||||
return dest;
|
||||
|
||||
badsyntax:
|
||||
PR_Free(dest);
|
||||
return nullptr;
|
||||
return Some(std::move(dest));
|
||||
}
|
||||
|
||||
// check if input is HZ (a 7bit encoding for simplified Chinese : RFC 1842))
|
||||
@@ -1154,17 +1128,25 @@ void CopyRawHeader(const char *aInput, uint32_t aLen,
|
||||
nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64,
|
||||
const char *aCharset, nsACString &aResult)
|
||||
{
|
||||
char *decodedText;
|
||||
nsCString decodedText;
|
||||
NS_ASSERTION(aQOrBase64 == 'Q' || aQOrBase64 == 'B', "Should be 'Q' or 'B'");
|
||||
if(aQOrBase64 == 'Q')
|
||||
decodedText = DecodeQ(aEncoded, aLen);
|
||||
else if (aQOrBase64 == 'B') {
|
||||
decodedText = PL_Base64Decode(aEncoded, aLen, nullptr);
|
||||
if(aQOrBase64 == 'Q') {
|
||||
Maybe<nsCString> decoded = DecodeQ(aEncoded, aLen);
|
||||
if (!decoded) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
decodedText = std::move(*decoded);
|
||||
} else if (aQOrBase64 == 'B') {
|
||||
if (NS_FAILED(
|
||||
mozilla::Base64Decode(Substring(aEncoded, aLen), decodedText))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
} else {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!decodedText) {
|
||||
if (ContainsNull(decodedText)) {
|
||||
// a NUL would truncate the decoded value
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
@@ -1174,12 +1156,11 @@ nsresult DecodeQOrBase64Str(const char *aEncoded, size_t aLen, char aQOrBase64,
|
||||
nsAutoCString utf8Text;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// skip ASCIIness/UTF8ness test if aCharset is 7bit non-ascii charset.
|
||||
rv = cvtUTF8->ConvertStringToUTF8(nsDependentCString(decodedText),
|
||||
rv = cvtUTF8->ConvertStringToUTF8(decodedText,
|
||||
aCharset,
|
||||
IS_7BIT_NON_ASCII_CHARSET(aCharset),
|
||||
true, 1, utf8Text);
|
||||
}
|
||||
PR_Free(decodedText);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -825,6 +825,13 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
|
||||
// as restartable.
|
||||
mAuthChannel->ConnectionRestartable(mConnectionBased && !authAtProgress);
|
||||
|
||||
if (identFromURI &&
|
||||
(authFlags & nsIHttpAuthenticator::IDENTITY_INCLUDES_DOMAIN)) {
|
||||
LOG((" ignoring URL identity for a domain-identity scheme\n"));
|
||||
ident->Clear();
|
||||
identFromURI = false;
|
||||
}
|
||||
|
||||
if (identityInvalid) {
|
||||
if (entry) {
|
||||
if (ident->Equals(entry->Identity())) {
|
||||
|
||||
@@ -110,22 +110,27 @@ nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
|
||||
count = mLineBuf.Length();
|
||||
}
|
||||
|
||||
// NUL is illegal in a chunk-size or trailer field line (RFC 9110 section
|
||||
// 5.5).
|
||||
if (memchr(buf, '\0', count)) {
|
||||
LOG(("chunked line contains embedded NUL; rejecting\n"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mWaitEOF) {
|
||||
if (*buf) {
|
||||
if (count) {
|
||||
LOG(("got trailer: %s\n", buf));
|
||||
// allocate a header array for the trailers on demand
|
||||
if (!mTrailers) {
|
||||
mTrailers = new nsHttpHeaderArray();
|
||||
}
|
||||
mTrailers->ParseHeaderLine(nsDependentCSubstring(buf, count));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mWaitEOF = false;
|
||||
mReachedEOF = true;
|
||||
LOG(("reached end of chunked-body\n"));
|
||||
}
|
||||
}
|
||||
else if (*buf) {
|
||||
} else if (count) {
|
||||
char *endptr;
|
||||
unsigned long parsedval; // could be 64 bit, could be 32
|
||||
|
||||
@@ -151,8 +156,7 @@ nsHttpChunkedDecoder::ParseChunkRemaining(char *buf,
|
||||
|
||||
// ensure that the line buffer is clear
|
||||
mLineBuf.Truncate();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// save the partial line; wait for more data
|
||||
*bytesConsumed = count;
|
||||
// ignore a trailing CR
|
||||
|
||||
@@ -279,6 +279,7 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel *channel,
|
||||
if (PL_strcasecmp(challenge, "NTLM") == 0) {
|
||||
nsCOMPtr<nsISupports> module;
|
||||
|
||||
mAllowDefaultCredentials = CanUseDefaultCredentials(channel, isProxyAuth);
|
||||
// Check to see if we should default to our generic NTLM auth module
|
||||
// through UseGenericNTLM. (We use native auth by default if the
|
||||
// system provides it.) If *sessionState is non-null, we failed to
|
||||
@@ -288,7 +289,7 @@ nsHttpNTLMAuth::ChallengeReceived(nsIHttpAuthenticableChannel *channel,
|
||||
// Check for approved default credentials hosts and proxies. If
|
||||
// *continuationState is non-null, the last authentication attempt
|
||||
// failed so skip default credential use.
|
||||
if (!*continuationState && CanUseDefaultCredentials(channel, isProxyAuth)) {
|
||||
if (!*continuationState && mAllowDefaultCredentials) {
|
||||
// Try logging in with the user's default credentials. If
|
||||
// successful, |identityInvalid| is false, which will trigger
|
||||
// a default credentials attempt once we return.
|
||||
@@ -399,6 +400,13 @@ nsHttpNTLMAuth::GenerateCredentials(nsIHttpAuthenticableChannel *authChannel,
|
||||
|
||||
// initial challenge
|
||||
if (PL_strcasecmp(challenge, "NTLM") == 0) {
|
||||
// An empty user or password makes nsAuthSSPI::Init authenticate as the
|
||||
// logged-in user, which only CanUseDefaultCredentials() hosts may do.
|
||||
if (mUseNative && !mAllowDefaultCredentials &&
|
||||
(!*user || !*pass)) {
|
||||
LOG(("Not using default credentials for an untrusted host\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
// NTLM service name format is 'HTTP@host' for both http and https
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = authChannel->GetURI(getter_AddRefs(uri));
|
||||
|
||||
@@ -22,7 +22,11 @@ private:
|
||||
|
||||
// This flag indicates whether we are using the native NTLM implementation
|
||||
// or the internal one.
|
||||
bool mUseNative;
|
||||
bool mUseNative;
|
||||
|
||||
// Whether the prefs let this host use the logged-in user's identity. Set by
|
||||
// ChallengeReceived, read by GenerateCredentials.
|
||||
bool mAllowDefaultCredentials = false;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
diff --git a/lib/xmltok.c b/lib/xmltok.c
|
||||
--- a/lib/xmltok.c
|
||||
+++ b/lib/xmltok.c
|
||||
@@ -700,17 +700,19 @@ unicode_byte_type(char hi, char lo) {
|
||||
static enum XML_Convert_Result PTRCALL E##toUtf16( \
|
||||
const ENCODING *enc, const char **fromP, const char *fromLim, \
|
||||
unsigned short **toP, const unsigned short *toLim) { \
|
||||
enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
|
||||
UNUSED_P(enc); \
|
||||
fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \
|
||||
/* Avoid copying first half only of surrogate */ \
|
||||
if (fromLim - *fromP > ((toLim - *toP) << 1) \
|
||||
- && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
|
||||
+/* BEGIN MCP CHANGE (Only high surrogate mask) */ \
|
||||
+ && (GET_HI(fromLim - 2) & 0xFC) == 0xD8) { \
|
||||
+/* END MCP CHANGE */ \
|
||||
fromLim -= 2; \
|
||||
res = XML_CONVERT_INPUT_INCOMPLETE; \
|
||||
} \
|
||||
for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
|
||||
*(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
|
||||
if ((*toP == toLim) && (*fromP < fromLim)) \
|
||||
return XML_CONVERT_OUTPUT_EXHAUSTED; \
|
||||
else \
|
||||
@@ -705,7 +705,9 @@ unicode_byte_type(char hi, char lo) {
|
||||
fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \
|
||||
/* Avoid copying first half only of surrogate */ \
|
||||
if (fromLim - *fromP > ((toLim - *toP) << 1) \
|
||||
&& (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
|
||||
/* BEGIN MCP CHANGE (Only high surrogate mask) */ \
|
||||
&& (GET_HI(fromLim - 2) & 0xFC) == 0xD8) { \
|
||||
/* END MCP CHANGE */ \
|
||||
fromLim -= 2; \
|
||||
res = XML_CONVERT_INPUT_INCOMPLETE; \
|
||||
} \
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "nsIHTMLDocument.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "nsTextNode.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@@ -690,7 +691,9 @@ nsHtml5TreeOperation::CreateMathMLElement(nsIAtom* aName,
|
||||
void
|
||||
nsHtml5TreeOperation::SetFormElement(nsIContent* aNode, nsIContent* aParent)
|
||||
{
|
||||
if (aNode->SubtreeRoot() != aParent->SubtreeRoot()) {
|
||||
// sFormSubtreeStrict is a pref to temporarily disable this check. See UXP #3197
|
||||
bool sFormSubtreeStrict = mozilla::Preferences::GetBool("html5.forms.standards_compliant", true);
|
||||
if (sFormSubtreeStrict && aNode->SubtreeRoot() != aParent->SubtreeRoot()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(aNode));
|
||||
|
||||
Loaded 100 of 121 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user