mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2026-01-03 23:21:39 +01:00
Compare commits
515 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59c39ab95b | ||
|
|
11ebb5c7eb | ||
|
|
6f6f2aa2a6 | ||
|
|
3bae631183 | ||
|
|
7d51d86423 | ||
|
|
8d993129fd | ||
|
|
f708d89406 | ||
|
|
d60559a9fd | ||
|
|
09c48646b5 | ||
|
|
991696a08a | ||
|
|
5aaab63fe8 | ||
|
|
a4129d8c99 | ||
|
|
65eb4b5741 | ||
|
|
76ea2ae340 | ||
|
|
97b3f43ad1 | ||
|
|
c863cc986b | ||
|
|
ae967cef1a | ||
|
|
3c17252da0 | ||
|
|
85cfe70b20 | ||
|
|
481f3c9b98 | ||
|
|
68f8b8fa75 | ||
|
|
121d8c5e5b | ||
|
|
2a96f49ef8 | ||
|
|
7663d1a3ac | ||
|
|
891886b622 | ||
|
|
7686e87155 | ||
|
|
8d6d43c33b | ||
|
|
70d5cac961 | ||
|
|
e0d5b5f7f2 | ||
|
|
e29c3f6123 | ||
|
|
e0c8d4420c | ||
|
|
cc5039e19e | ||
|
|
55c7e769c8 | ||
|
|
5f76deb2e0 | ||
|
|
1262ae36af | ||
|
|
d0f4366a85 | ||
|
|
4b3a0b789e | ||
|
|
3e81b3ad48 | ||
|
|
5d2e79e2c3 | ||
|
|
15af276157 | ||
|
|
8f36580594 | ||
|
|
9b5a9b6189 | ||
|
|
0dadf81e14 | ||
|
|
e25f2a5715 | ||
|
|
ae5a6dde2d | ||
|
|
a9e78595f0 | ||
|
|
4e6a4af186 | ||
|
|
49a9d49dbd | ||
|
|
933f90fbfa | ||
|
|
850d62301c | ||
|
|
76f0588aaf | ||
|
|
57a27a6fb9 | ||
|
|
43d36857d0 | ||
|
|
35ea00085f | ||
|
|
a951a15379 | ||
|
|
aab706c66f | ||
|
|
869b05169f | ||
|
|
38cd5d0936 | ||
|
|
c61204b3f3 | ||
|
|
261eb76ea2 | ||
|
|
a588752fd6 | ||
|
|
f3597c4a54 | ||
|
|
737ae7742a | ||
|
|
4c73e045ce | ||
|
|
7282d0deb5 | ||
|
|
02049ee6c3 | ||
|
|
ac2b1ae5e2 | ||
|
|
553f3b1497 | ||
|
|
f01e6261a2 | ||
|
|
f9e6f26ca4 | ||
|
|
75a69333f8 | ||
|
|
c8257ea4e2 | ||
|
|
be5ed8666c | ||
|
|
1e4f886107 | ||
|
|
ca3374253c | ||
|
|
4fe6a3da68 | ||
|
|
de49337060 | ||
|
|
b3e264187a | ||
|
|
64e2c67e7b | ||
|
|
dc549663d7 | ||
|
|
a4ab61339b | ||
|
|
2914064cf4 | ||
|
|
c89ee9b0a1 | ||
|
|
9d71814dca | ||
|
|
4e3d9e3944 | ||
|
|
79d12507b3 | ||
|
|
dd89c92c50 | ||
|
|
a616bc979b | ||
|
|
62cc45c3df | ||
|
|
1a480ab570 | ||
|
|
22bb597d0d | ||
|
|
8d30bb03ee | ||
|
|
8f98911c7b | ||
|
|
24e9d356df | ||
|
|
178c2ff5eb | ||
|
|
1605edfcc3 | ||
|
|
3d7b524593 | ||
|
|
acb329cd0e | ||
|
|
31cccbe016 | ||
|
|
c8b6cfbdc5 | ||
|
|
33ee441df1 | ||
|
|
50cc54c730 | ||
|
|
bfabf1279d | ||
|
|
5490b03160 | ||
|
|
b957d802e6 | ||
|
|
f0b30a5d24 | ||
|
|
02062b34ad | ||
|
|
09e86303ab | ||
|
|
24578630cf | ||
|
|
0f64d4bead | ||
|
|
e1d29cd6fb | ||
|
|
507ec8ab30 | ||
|
|
07a879a9f7 | ||
|
|
f0acabc64b | ||
|
|
26b48999df | ||
|
|
7df86108cb | ||
|
|
925d275a62 | ||
|
|
30c2dbea95 | ||
|
|
31f2426821 | ||
|
|
80d889189a | ||
|
|
13918a4519 | ||
|
|
4b1b547020 | ||
|
|
9523001f65 | ||
|
|
b6c6b4a89a | ||
|
|
00452d32f5 | ||
|
|
c58de6c6ff | ||
|
|
e19022e515 | ||
|
|
9924c45fae | ||
|
|
5ca47be633 | ||
|
|
0e42d5c4ae | ||
|
|
6428c693f0 | ||
|
|
2c4fbbca23 | ||
|
|
0d1aa3cbc8 | ||
|
|
a1176dc8c9 | ||
|
|
ba7f7fe417 | ||
|
|
235ef8e6df | ||
|
|
edf36d90c3 | ||
|
|
0504064717 | ||
|
|
79dd472913 | ||
|
|
e0989c0068 | ||
|
|
4b8ea58b76 | ||
|
|
fa31c0de68 | ||
|
|
0643f3aa4c | ||
|
|
4d4161a57e | ||
|
|
e11ce6d5fe | ||
|
|
c663323043 | ||
|
|
01dc2644c3 | ||
|
|
6ed221cb9a | ||
|
|
484864c932 | ||
|
|
b6c861f9f8 | ||
|
|
8bf5b1d18b | ||
|
|
fb8ceae0a7 | ||
|
|
6612598a13 | ||
|
|
31d108c1af | ||
|
|
ca6d6385f8 | ||
|
|
5db57dc1a5 | ||
|
|
d1ab20c633 | ||
|
|
4ee601c870 | ||
|
|
6a85e1454d | ||
|
|
56d8e8a0a1 | ||
|
|
08310982f4 | ||
|
|
16d8f5f6ef | ||
|
|
0351595ba8 | ||
|
|
84d2c2678a | ||
|
|
c31bcc58b0 | ||
|
|
124db3be8e | ||
|
|
0483ff56a0 | ||
|
|
7a702ae55e | ||
|
|
c98fd38979 | ||
|
|
f586b6c0cd | ||
|
|
d4e6262f3c | ||
|
|
a6f41d513e | ||
|
|
88f93f3214 | ||
|
|
f879698c63 | ||
|
|
0df797de94 | ||
|
|
55dd4401ce | ||
|
|
6c4a27ccb1 | ||
|
|
84e62e8597 | ||
|
|
b978ebee46 | ||
|
|
0c20de1954 | ||
|
|
b4787e6c3f | ||
|
|
7856c1a311 | ||
|
|
25af8d8f69 | ||
|
|
27b5007ad5 | ||
|
|
2847cd5e66 | ||
|
|
2462995662 | ||
|
|
ef614ed8af | ||
|
|
03f2ab325d | ||
|
|
fc19aa9263 | ||
|
|
b2da6e1a90 | ||
|
|
51a3b25d71 | ||
|
|
6160353be3 | ||
|
|
99c9b39058 | ||
|
|
17bc6915a1 | ||
|
|
b29c1fbbd1 | ||
|
|
b9a37e48e2 | ||
|
|
49e7609da2 | ||
|
|
93c00472eb | ||
|
|
8e4a4cdbe0 | ||
|
|
ecfb2914d0 | ||
|
|
3fb8f4364d | ||
|
|
9fc76c2b2c | ||
|
|
fcd005c417 | ||
|
|
fc0d883a13 | ||
|
|
e56002c7d3 | ||
|
|
fac22ce20c | ||
|
|
9d00332ee5 | ||
|
|
fe8439f0d4 | ||
|
|
8a56d7e00d | ||
|
|
f189db2813 | ||
|
|
10fb6f9c4b | ||
|
|
e6a0c6cf4d | ||
|
|
d8d3cc3ab6 | ||
|
|
b328bc14a0 | ||
|
|
67b3cbff2e | ||
|
|
c2ee432602 | ||
|
|
f1e0780668 | ||
|
|
a1c29335a8 | ||
|
|
fbad5a0d5b | ||
|
|
69c0df6b8f | ||
|
|
2ef86262e0 | ||
|
|
0cf76bde34 | ||
|
|
d6348691ee | ||
|
|
4264cd9f46 | ||
|
|
a0d6a8a174 | ||
|
|
8d432d29b8 | ||
|
|
087cbbfd69 | ||
|
|
65b99c7b1a | ||
|
|
5732032707 | ||
|
|
a963aab1a8 | ||
|
|
9573ef8bda | ||
|
|
552a73301c | ||
|
|
50f1b87a97 | ||
|
|
fe8fcfb4be | ||
|
|
d2d5bc7038 | ||
|
|
3148072079 | ||
|
|
dce1aee4ef | ||
|
|
62a67c5d90 | ||
|
|
63b3498733 | ||
|
|
5d2f6e737b | ||
|
|
d6bd183b84 | ||
|
|
b16a01bb67 | ||
|
|
28f963f6fc | ||
|
|
315ae4c51c | ||
|
|
23ed3a9e91 | ||
|
|
91926e262c | ||
|
|
b83ea8b391 | ||
|
|
092389e3c9 | ||
|
|
6cfe3fea08 | ||
|
|
e64a25b256 | ||
|
|
5e9702d390 | ||
|
|
929ffca471 | ||
|
|
714db70bf3 | ||
|
|
ae912be86f | ||
|
|
f797e19e3d | ||
|
|
9871f3a27a | ||
|
|
74cb1b4e75 | ||
|
|
54490d30c8 | ||
|
|
e8d284faac | ||
|
|
f779affda0 | ||
|
|
70c0815335 | ||
|
|
daffaa8376 | ||
|
|
74ae13716b | ||
|
|
cc8d52020d | ||
|
|
61e42ed85d | ||
|
|
39c9560cbf | ||
|
|
38f4f06ccc | ||
|
|
c190193eac | ||
|
|
89d7530411 | ||
|
|
57d2c86985 | ||
|
|
5dbcdbbef7 | ||
|
|
35421399a4 | ||
|
|
51c8ac362e | ||
|
|
34949494e4 | ||
|
|
5d9c1e45dc | ||
|
|
2631422bc5 | ||
|
|
ea73b5b0d9 | ||
|
|
55e3560abc | ||
|
|
f1a5cbb11e | ||
|
|
fb300a3ff3 | ||
|
|
77522d1270 | ||
|
|
50c37fc749 | ||
|
|
d1b6691295 | ||
|
|
79a4a019bb | ||
|
|
f70fc149b5 | ||
|
|
90f0612ada | ||
|
|
35e3226df8 | ||
|
|
7638580477 | ||
|
|
0db838628c | ||
|
|
473fa82000 | ||
|
|
3498a10a2b | ||
|
|
9f090cb6f8 | ||
|
|
e44575ad3e | ||
|
|
d8355e0281 | ||
|
|
03e5f256ca | ||
|
|
12ae68b197 | ||
|
|
19a08080e4 | ||
|
|
9edcdf12a0 | ||
|
|
a096c0a83f | ||
|
|
e648a907b3 | ||
|
|
191e1e6075 | ||
|
|
51b3bd2c2e | ||
|
|
0615eac2e6 | ||
|
|
2c00d740d4 | ||
|
|
764b50a7e3 | ||
|
|
c32923e06f | ||
|
|
44c6537b57 | ||
|
|
18d5626e25 | ||
|
|
13946835b5 | ||
|
|
0019679c69 | ||
|
|
c798b3d040 | ||
|
|
96f56eb4fc | ||
|
|
97bbbbba51 | ||
|
|
c200b4f1cb | ||
|
|
1066357887 | ||
|
|
7f74c7dd7f | ||
|
|
3a0741afa1 | ||
|
|
61ebb6adb7 | ||
|
|
a53ecac07c | ||
|
|
30c8811d11 | ||
|
|
6b8c16cf41 | ||
|
|
45c4d9d519 | ||
|
|
36b129fe84 | ||
|
|
eaf70e0ab8 | ||
|
|
1cc09ccaef | ||
|
|
ed5696dd2c | ||
|
|
688e5d9071 | ||
|
|
d0d925c13a | ||
|
|
b5f785ba9b | ||
|
|
db1e207a72 | ||
|
|
55e381b32f | ||
|
|
8e687450d6 | ||
|
|
b35a3bdee9 | ||
|
|
c57d89ad1a | ||
|
|
c2fa441d8d | ||
|
|
7332181372 | ||
|
|
1d480a7b96 | ||
|
|
660272ce7c | ||
|
|
032a4d6b9f | ||
|
|
970e251a54 | ||
|
|
c1093dc244 | ||
|
|
ee060c777c | ||
|
|
6df465de73 | ||
|
|
b5d775f115 | ||
|
|
3ed56830b4 | ||
|
|
084e15bca3 | ||
|
|
c79e6346d0 | ||
|
|
84e397b4de | ||
|
|
d7c7f70a6a | ||
|
|
f4de95a97c | ||
|
|
38af8be984 | ||
|
|
b0ceab23dd | ||
|
|
39616b4d7c | ||
|
|
00d223cff6 | ||
|
|
bafa476135 | ||
|
|
15a9c29036 | ||
|
|
4bd94fb9ea | ||
|
|
54bed60bfe | ||
|
|
d12fdfa3b7 | ||
|
|
1e535dfa53 | ||
|
|
9385203fbd | ||
|
|
42f4170b2a | ||
|
|
696b9e1847 | ||
|
|
e15e30fef2 | ||
|
|
d9abf606d9 | ||
|
|
ddb726d4a0 | ||
|
|
aab365f746 | ||
|
|
13a335722f | ||
|
|
9390446081 | ||
|
|
b76a154c6d | ||
|
|
ee5dc7cbb4 | ||
|
|
e03ca73dc1 | ||
|
|
a9ad296a55 | ||
|
|
024fa0969a | ||
|
|
dc71097c2e | ||
|
|
229f41808d | ||
|
|
58107e52a8 | ||
|
|
0f5e57aa8c | ||
|
|
7fd5cb6117 | ||
|
|
2dda9965cd | ||
|
|
1cc8d3a34b | ||
|
|
38636a8c96 | ||
|
|
c4bb35ef33 | ||
|
|
52117c6f62 | ||
|
|
0ea0338055 | ||
|
|
13c176bee4 | ||
|
|
afce1f4ebd | ||
|
|
5585e6f63a | ||
|
|
9e6782d24b | ||
|
|
d4626d89cc | ||
|
|
eaeddeddb1 | ||
|
|
8ebe591a28 | ||
|
|
58a3e40a5c | ||
|
|
8ce2053723 | ||
|
|
97f8261e41 | ||
|
|
e4eaa2377b | ||
|
|
56881d6465 | ||
|
|
d5c4c292a0 | ||
|
|
e3c6574ac0 | ||
|
|
72b530aac4 | ||
|
|
d6035a522e | ||
|
|
39892bf43f | ||
|
|
9798a0846b | ||
|
|
d3776c7d30 | ||
|
|
07c3021936 | ||
|
|
60745d14ec | ||
|
|
5735fce331 | ||
|
|
ee2e61d7e0 | ||
|
|
c55e52e01f | ||
|
|
7f0777ae88 | ||
|
|
831f23ee86 | ||
|
|
c540da3c4c | ||
|
|
6a5203877e | ||
|
|
d502554467 | ||
|
|
9885ac18ac | ||
|
|
178eea6065 | ||
|
|
a5ae1e306e | ||
|
|
fe5817aae8 | ||
|
|
832d896443 | ||
|
|
dc8026d66d | ||
|
|
7ca448b4fc | ||
|
|
fff8122978 | ||
|
|
8812113984 | ||
|
|
74eb250e36 | ||
|
|
846d21961c | ||
|
|
6986d53af9 | ||
|
|
11a8c9c13e | ||
|
|
7efa6090e8 | ||
|
|
03cf1c3a83 | ||
|
|
3a8a15b5d0 | ||
|
|
3c276ce1fe | ||
|
|
4ac45a3b50 | ||
|
|
c8c4d8377a | ||
|
|
9852a6f75c | ||
|
|
1ad1659413 | ||
|
|
e800cc2d2d | ||
|
|
77c46ea911 | ||
|
|
45c89daf72 | ||
|
|
0c9e0c2e7f | ||
|
|
4d3baa2d37 | ||
|
|
c148c2c176 | ||
|
|
555f0e6e2a | ||
|
|
12879e91b4 | ||
|
|
ef86f06c42 | ||
|
|
70885cae5e | ||
|
|
d02e7d55e8 | ||
|
|
db46b297fa | ||
|
|
c202bd705e | ||
|
|
111ba18ac6 | ||
|
|
c02b75705f | ||
|
|
9886b7e9e9 | ||
|
|
deaadfad52 | ||
|
|
99c7b2b85b | ||
|
|
db4d59cc0c | ||
|
|
b0e4e9a2e4 | ||
|
|
2d3372c8b5 | ||
|
|
dc86b2e22b | ||
|
|
b37b1a391a | ||
|
|
65577cf58a | ||
|
|
3ea5fdc9ac | ||
|
|
339016a0f2 | ||
|
|
fcd5d414d6 | ||
|
|
922ba8da30 | ||
|
|
8a9d2b08a0 | ||
|
|
a28f4100ce | ||
|
|
4d13bf33d4 | ||
|
|
79f02a67ce | ||
|
|
a4eaf9536c | ||
|
|
cf345fd768 | ||
|
|
d86ab942f6 | ||
|
|
0417fcf13f | ||
|
|
257809d744 | ||
|
|
7685e53426 | ||
|
|
bd843673a8 | ||
|
|
0aefe6f20a | ||
|
|
4946a162aa | ||
|
|
6e32338330 | ||
|
|
eef2e1e3fc | ||
|
|
e6517d1ae2 | ||
|
|
10b9d0b6a6 | ||
|
|
27a9a2f64a | ||
|
|
b37228e11f | ||
|
|
17035efe87 | ||
|
|
6af643e5a1 | ||
|
|
3349e10b7f | ||
|
|
a72a8984a9 | ||
|
|
25d1305f7e | ||
|
|
76baa501fa | ||
|
|
64d130efc4 | ||
|
|
77a10a182f | ||
|
|
0b42b1cf15 | ||
|
|
f4301530b4 | ||
|
|
99ae9558fe | ||
|
|
816a7060ba | ||
|
|
ab729d7075 | ||
|
|
1a5ef6606f | ||
|
|
8a9675663f | ||
|
|
31368cd1f0 | ||
|
|
aff80ee900 | ||
|
|
42ac8e1856 | ||
|
|
0ebcf5c59d | ||
|
|
5b99c6ae1f | ||
|
|
e7289aa4d4 | ||
|
|
188ad9714d | ||
|
|
2aa291ad2c | ||
|
|
f2e69156c8 | ||
|
|
277ec3d260 | ||
|
|
ed7f796494 | ||
|
|
761a92d7c9 | ||
|
|
31753ef9bf | ||
|
|
6c2ff1781b | ||
|
|
af8c3b4a7e | ||
|
|
417e8e449d | ||
|
|
f84b5d2f80 | ||
|
|
4a588d89f0 |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* -text
|
||||
10
.hgtags
10
.hgtags
@@ -652,3 +652,13 @@ a32f58c6b8be81877411767de7ba9c4cf087c1b5 jdk-15+31
|
||||
4a8fd81d64bafa523cddb45f82805536edace106 jdk-16+6
|
||||
6b65f4e7a975628df51ef755b02642075390041d jdk-15+33
|
||||
c3a4a7ea7c304cabdacdc31741eb94c51351668d jdk-16+7
|
||||
b0817631d2f4395508cb10e81c3858a94d9ae4de jdk-15+34
|
||||
0a73d6f3aab48ff6d7e61e47f0bc2d87a054f217 jdk-16+8
|
||||
fd60c3146a024037cdd9be34c645bb793995a7cc jdk-15+35
|
||||
c075a286cc7df767cce28e8057d6ec5051786490 jdk-16+9
|
||||
b01985b4f88f554f97901e53e1ba314681dd9c19 jdk-16+10
|
||||
e3f940bd3c8fcdf4ca704c6eb1ac745d155859d5 jdk-15+36
|
||||
5c18d696c7ce724ca36df13933aa53f50e12b9e0 jdk-16+11
|
||||
fc8e62b399bd93d06e8d13dc3b384c450e853dcd jdk-16+12
|
||||
fd07cdb26fc70243ef23d688b545514f4ddf1c2b jdk-16+13
|
||||
36b29df125dc88f11657ce93b4998aa9ff5f5d41 jdk-16+14
|
||||
|
||||
30
.jcheck/conf
30
.jcheck/conf
@@ -1,2 +1,30 @@
|
||||
[general]
|
||||
project=jdk
|
||||
bugids=dup
|
||||
jbs=JDK
|
||||
|
||||
[checks]
|
||||
error=blacklist.author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace
|
||||
|
||||
[repository]
|
||||
tags=(?:jdk-(?:[1-9]([0-9]*)(?:\\.(?:0|[1-9][0-9]*)){0,4})(?:\\+(?:(?:[0-9]+))|(?:-ga)))|(?:jdk[4-9](?:u\\d{1,3})?-(?:(?:b\\d{2,3})|(?:ga)))|(?:hs\\d\\d(?:\\.\\d{1,2})?-b\\d\\d)
|
||||
branches=
|
||||
|
||||
[census]
|
||||
version=0
|
||||
domain=openjdk.org
|
||||
|
||||
[checks "whitespace"]
|
||||
files=.*\.cpp|.*\.hpp|.*\.c|.*\.h|.*\.java
|
||||
|
||||
[checks "merge"]
|
||||
message=Merge
|
||||
|
||||
[checks "reviewers"]
|
||||
reviewers=1
|
||||
ignore=duke
|
||||
|
||||
[checks "committer"]
|
||||
role=committer
|
||||
|
||||
[checks "issues"]
|
||||
pattern=^([124-8][0-9]{6}): (\S.*)$
|
||||
|
||||
3
CONTRIBUTING.md
Normal file
3
CONTRIBUTING.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Contributing to the JDK
|
||||
|
||||
Please see <https://openjdk.java.net/contribute/> for how to contribute.
|
||||
12
README
12
README
@@ -1,12 +0,0 @@
|
||||
|
||||
Welcome to the JDK!
|
||||
===================
|
||||
|
||||
For information about building the JDK, including how to retrieve all
|
||||
of the source code, please see either of these files:
|
||||
|
||||
* doc/building.html (html version)
|
||||
* doc/building.md (markdown version)
|
||||
|
||||
See http://openjdk.java.net/ for more information about the OpenJDK
|
||||
Community and the JDK.
|
||||
11
README.md
Normal file
11
README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Welcome to the JDK!
|
||||
|
||||
For build instructions please see the
|
||||
[online documentation](https://openjdk.java.net/groups/build/doc/building.html),
|
||||
or either of these files:
|
||||
|
||||
- [doc/building.html](doc/building.html) (html version)
|
||||
- [doc/building.md](doc/building.md) (markdown version)
|
||||
|
||||
See <https://openjdk.java.net/> for more information about
|
||||
the OpenJDK Community and the JDK.
|
||||
69
bin/idea.sh
69
bin/idea.sh
@@ -147,13 +147,7 @@ add_replacement() {
|
||||
add_replacement "###MODULE_NAMES###" "$MODULE_NAMES"
|
||||
add_replacement "###VCS_TYPE###" "$VCS_TYPE"
|
||||
SPEC_DIR=`dirname $SPEC`
|
||||
if [ "x$CYGPATH" = "x" ]; then
|
||||
add_replacement "###BUILD_DIR###" "$SPEC_DIR"
|
||||
add_replacement "###JTREG_HOME###" "$JT_HOME"
|
||||
add_replacement "###IMAGES_DIR###" "$SPEC_DIR/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
|
||||
add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
|
||||
else
|
||||
if [ "x$CYGPATH" != "x" ]; then
|
||||
add_replacement "###BUILD_DIR###" "`cygpath -am $SPEC_DIR`"
|
||||
add_replacement "###IMAGES_DIR###" "`cygpath -am $SPEC_DIR`/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "`cygpath -am $TOPLEVEL_DIR`"
|
||||
@@ -163,6 +157,22 @@ else
|
||||
else
|
||||
add_replacement "###JTREG_HOME###" "`cygpath -am $JT_HOME`"
|
||||
fi
|
||||
elif [ "x$WSL_DISTRO_NAME" != "x" ]; then
|
||||
add_replacement "###BUILD_DIR###" "`wslpath -am $SPEC_DIR`"
|
||||
add_replacement "###IMAGES_DIR###" "`wslpath -am $SPEC_DIR`/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "`wslpath -am $TOPLEVEL_DIR`"
|
||||
add_replacement "###IDEA_DIR###" "`wslpath -am $IDEA_OUTPUT`"
|
||||
if [ "x$JT_HOME" = "x" ]; then
|
||||
add_replacement "###JTREG_HOME###" ""
|
||||
else
|
||||
add_replacement "###JTREG_HOME###" "`wslpath -am $JT_HOME`"
|
||||
fi
|
||||
else
|
||||
add_replacement "###BUILD_DIR###" "$SPEC_DIR"
|
||||
add_replacement "###JTREG_HOME###" "$JT_HOME"
|
||||
add_replacement "###IMAGES_DIR###" "$SPEC_DIR/images/jdk"
|
||||
add_replacement "###ROOT_DIR###" "$TOPLEVEL_DIR"
|
||||
add_replacement "###IDEA_DIR###" "$IDEA_OUTPUT"
|
||||
fi
|
||||
|
||||
SOURCE_PREFIX="<sourceFolder url=\"file://"
|
||||
@@ -170,9 +180,22 @@ SOURCE_POSTFIX="\" isTestSource=\"false\" />"
|
||||
|
||||
for root in $MODULE_ROOTS; do
|
||||
if [ "x$CYGPATH" != "x" ]; then
|
||||
root=`cygpath -am $root`
|
||||
root=`cygpath -am $root`
|
||||
elif [ "x$WSL_DISTRO_NAME" != "x" ]; then
|
||||
root=`wslpath -am $root`
|
||||
fi
|
||||
|
||||
VM_CI="jdk.internal.vm.ci/share/classes"
|
||||
VM_COMPILER="src/jdk.internal.vm.compiler/share/classes"
|
||||
if test "${root#*$VM_CI}" != "$root" || test "${root#*$VM_COMPILER}" != "$root"; then
|
||||
for subdir in "$root"/*; do
|
||||
if [ -d "$subdir" ]; then
|
||||
SOURCES=$SOURCES" $SOURCE_PREFIX""$subdir"/src"$SOURCE_POSTFIX"
|
||||
fi
|
||||
done
|
||||
else
|
||||
SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX"
|
||||
fi
|
||||
SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX"
|
||||
done
|
||||
|
||||
add_replacement "###SOURCE_ROOTS###" "$SOURCES"
|
||||
@@ -196,16 +219,30 @@ fi
|
||||
CP=$ANT_HOME/lib/ant.jar
|
||||
rm -rf $CLASSES; mkdir $CLASSES
|
||||
|
||||
if [ "x$CYGPATH" = "x" ] ; then ## CYGPATH may be set in env.cfg
|
||||
JAVAC_SOURCE_FILE=$IDEA_OUTPUT/src/idea/IdeaLoggerWrapper.java
|
||||
JAVAC_SOURCE_PATH=$IDEA_OUTPUT/src
|
||||
JAVAC_CLASSES=$CLASSES
|
||||
JAVAC_CP=$CP
|
||||
else
|
||||
if [ "x$CYGPATH" != "x" ] ; then ## CYGPATH may be set in env.cfg
|
||||
JAVAC_SOURCE_FILE=`cygpath -am $IDEA_OUTPUT/src/idea/IdeaLoggerWrapper.java`
|
||||
JAVAC_SOURCE_PATH=`cygpath -am $IDEA_OUTPUT/src`
|
||||
JAVAC_CLASSES=`cygpath -am $CLASSES`
|
||||
JAVAC_CP=`cygpath -am $CP`
|
||||
JAVAC=javac
|
||||
elif [ "x$WSL_DISTRO_NAME" != "x" ]; then
|
||||
JAVAC_SOURCE_FILE=`realpath --relative-to=./ $IDEA_OUTPUT/src/idea/IdeaLoggerWrapper.java`
|
||||
JAVAC_SOURCE_PATH=`realpath --relative-to=./ $IDEA_OUTPUT/src`
|
||||
JAVAC_CLASSES=`realpath --relative-to=./ $CLASSES`
|
||||
ANT_TEMP=`mktemp -d -p ./`
|
||||
cp $ANT_HOME/lib/ant.jar $ANT_TEMP/ant.jar
|
||||
JAVAC_CP=$ANT_TEMP/ant.jar
|
||||
JAVAC=javac.exe
|
||||
else
|
||||
JAVAC_SOURCE_FILE=$IDEA_OUTPUT/src/idea/IdeaLoggerWrapper.java
|
||||
JAVAC_SOURCE_PATH=$IDEA_OUTPUT/src
|
||||
JAVAC_CLASSES=$CLASSES
|
||||
JAVAC_CP=$CP
|
||||
JAVAC=javac
|
||||
fi
|
||||
|
||||
$BOOT_JDK/bin/javac -d $JAVAC_CLASSES -sourcepath $JAVAC_SOURCE_PATH -cp $JAVAC_CP $JAVAC_SOURCE_FILE
|
||||
$BOOT_JDK/bin/$JAVAC -d $JAVAC_CLASSES -sourcepath $JAVAC_SOURCE_PATH -cp $JAVAC_CP $JAVAC_SOURCE_FILE
|
||||
|
||||
if [ "x$WSL_DISTRO_NAME" != "x" ]; then
|
||||
rm -rf $ANT_TEMP
|
||||
fi
|
||||
329
doc/hotspot-style.html
Normal file
329
doc/hotspot-style.html
Normal file
@@ -0,0 +1,329 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
<title>HotSpot Coding Style</title>
|
||||
<style type="text/css">
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
span.underline{text-decoration: underline;}
|
||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||||
</style>
|
||||
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css" />
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<header id="title-block-header">
|
||||
<h1 class="title">HotSpot Coding Style</h1>
|
||||
</header>
|
||||
<nav id="TOC">
|
||||
<ul>
|
||||
<li><a href="#introduction">Introduction</a><ul>
|
||||
<li><a href="#why-care-about-style">Why Care About Style?</a></li>
|
||||
<li><a href="#counterexamples-and-updates">Counterexamples and Updates</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#structure-and-formatting">Structure and Formatting</a><ul>
|
||||
<li><a href="#factoring-and-class-design">Factoring and Class Design</a></li>
|
||||
<li><a href="#source-files">Source Files</a></li>
|
||||
<li><a href="#jtreg-tests">JTReg Tests</a></li>
|
||||
<li><a href="#naming">Naming</a></li>
|
||||
<li><a href="#commenting">Commenting</a></li>
|
||||
<li><a href="#macros">Macros</a></li>
|
||||
<li><a href="#whitespace">Whitespace</a></li>
|
||||
<li><a href="#miscellaneous">Miscellaneous</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#use-of-c-features">Use of C++ Features</a><ul>
|
||||
<li><a href="#error-handling">Error Handling</a></li>
|
||||
<li><a href="#rtti-runtime-type-information">RTTI (Runtime Type Information)</a></li>
|
||||
<li><a href="#memory-allocation">Memory Allocation</a></li>
|
||||
<li><a href="#class-inheritance">Class Inheritance</a></li>
|
||||
<li><a href="#namespaces">Namespaces</a></li>
|
||||
<li><a href="#c-standard-library">C++ Standard Library</a></li>
|
||||
<li><a href="#type-deduction">Type Deduction</a></li>
|
||||
<li><a href="#expression-sfinae">Expression SFINAE</a></li>
|
||||
<li><a href="#enum">enum</a></li>
|
||||
<li><a href="#thread_local">thread_local</a></li>
|
||||
<li><a href="#nullptr">nullptr</a></li>
|
||||
<li><a href="#atomic"><atomic></a></li>
|
||||
<li><a href="#additional-permitted-features">Additional Permitted Features</a></li>
|
||||
<li><a href="#excluded-features">Excluded Features</a></li>
|
||||
<li><a href="#undecided-features">Undecided Features</a></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<h2 id="introduction">Introduction</h2>
|
||||
<p>This is a collection of rules, guidelines, and suggestions for writing HotSpot code. Following these will help new code fit in with existing HotSpot code, making it easier to read and maintain. Failure to follow these guidelines may lead to discussion during code reviews, if not outright rejection of a change.</p>
|
||||
<h3 id="why-care-about-style">Why Care About Style?</h3>
|
||||
<p>Some programmers seem to have lexers and even C preprocessors installed directly behind their eyeballs. The rest of us require code that is not only functionally correct but also easy to read. More than that, since there is no one style for easy-to-read code, and since a mashup of many styles is just as confusing as no style at all, it is important for coders to be conscious of the many implicit stylistic choices that historically have gone into the HotSpot code base.</p>
|
||||
<p>Some of these guidelines are driven by the cross-platform requirements for HotSpot. Shared code must work on a variety of platforms, and may encounter deficiencies in some. Using platform conditionalization in shared code is usually avoided, while shared code is strongly preferred to multiple platform-dependent implementations, so some language features may be recommended against.</p>
|
||||
<p>Some of the guidelines here are relatively arbitrary choices among equally plausible alternatives. The purpose of stating and enforcing these rules is largely to provide a consistent look to the code. That consistency makes the code more readable by avoiding non-functional distractions from the interesting functionality.</p>
|
||||
<p>When changing pre-existing code, it is reasonable to adjust it to match these conventions. Exception: If the pre-existing code clearly conforms locally to its own peculiar conventions, it is not worth reformatting the whole thing. Also consider separating changes that make extensive stylistic updates from those which make functional changes.</p>
|
||||
<h3 id="counterexamples-and-updates">Counterexamples and Updates</h3>
|
||||
<p>Many of the guidelines mentioned here have (sometimes widespread) counterexamples in the HotSpot code base. Finding a counterexample is not sufficient justification for new code to follow the counterexample as a precedent, since readers of your code will rightfully expect your code to follow the greater bulk of precedents documented here.</p>
|
||||
<p>Occasionally a guideline mentioned here may be just out of synch with the actual HotSpot code base. If you find that a guideline is consistently contradicted by a large number of counterexamples, please bring it up for discussion and possible change. The architectural rule, of course, is "When in Rome do as the Romans". Sometimes in the suburbs of Rome the rules are a little different; these differences can be pointed out here.</p>
|
||||
<p>Proposed changes should be discussed on the <a href="mailto:hotspot-dev@openjdk.java.net">HotSpot Developers</a> mailing list, and approved by <a href="https://en.wikipedia.org/wiki/Rough_consensus">rough consensus</a> of the <a href="https://openjdk.java.net/census#hotspot">HotSpot Group</a> Members. The Group Lead determines whether consensus has been reached. Changes are likely to be cautious and incremental, since HotSpot coders have been using these guidelines for years.</p>
|
||||
<h2 id="structure-and-formatting">Structure and Formatting</h2>
|
||||
<h3 id="factoring-and-class-design">Factoring and Class Design</h3>
|
||||
<ul>
|
||||
<li><p>Group related code together, so readers can concentrate on one section of one file.</p></li>
|
||||
<li><p>Classes are the primary code structuring mechanism. Place related functionality in a class, or a set of related classes. Use of either namespaces or public non-member functions is rare in HotSpot code. Static non-member functions are not uncommon.</p></li>
|
||||
<li><p>If a class <code>FooBar</code> is going to be used in more than one place, put it a file named fooBar.hpp and fooBar.cpp. If the class is a sidekick to a more important class <code>BazBat</code>, it can go in bazBat.hpp.</p></li>
|
||||
<li><p>Put a member function <code>FooBar::bang</code> into the same file that defined <code>FooBar</code>, or its associated <em>.inline.hpp or </em>.cpp file.</p></li>
|
||||
<li><p>Use public accessor functions for member variables accessed outside the class.</p></li>
|
||||
<li><p>Assign names to constant literals and use the names instead.</p></li>
|
||||
<li><p>Keep functions small, a screenful at most. Split out chunks of logic into file-local classes or static functions if needed.</p></li>
|
||||
<li><p>Factor away nonessential complexity into local inline helper functions and helper classes.</p></li>
|
||||
<li><p>Think clearly about internal invariants that apply to each class, and document them in the form of asserts within member functions.</p></li>
|
||||
<li><p>Make simple, self-evident contracts for member functions. If you cannot communicate a simple contract, redesign the class.</p></li>
|
||||
<li><p>Implement classes as if expecting rough usage by clients. Check for incorrect usage of a class using <code>assert(...)</code>, <code>guarantee(...)</code>, <code>ShouldNotReachHere()</code> and comments wherever needed. Performance is almost never a reason to omit asserts.</p></li>
|
||||
<li><p>When possible, design as if for reusability. This forces a clear design of the class's externals, and clean hiding of its internals.</p></li>
|
||||
<li><p>Initialize all variables and data structures to a known state. If a class has a constructor, initialize it there.</p></li>
|
||||
<li><p>Do no optimization before its time. Prove the need to optimize.</p></li>
|
||||
<li><p>When you must defactor to optimize, preserve as much structure as possible. If you must hand-inline some name, label the local copy with the original name.</p></li>
|
||||
<li><p>If you need to use a hidden detail (e.g., a structure offset), name it (as a constant or function) in the class that owns it.</p></li>
|
||||
<li><p>Don't use the Copy and Paste keys to replicate more than a couple lines of code. Name what you must repeat.</p></li>
|
||||
<li><p>If a class needs a member function to change a user-visible attribute, the change should be done with a "setter" accessor matched to the simple "getter".</p></li>
|
||||
</ul>
|
||||
<h3 id="source-files">Source Files</h3>
|
||||
<ul>
|
||||
<li><p>All source files must have a globally unique basename. The build system depends on this uniqueness.</p></li>
|
||||
<li><p>Do not put non-trivial function implementations in .hpp files. If the implementation depends on other .hpp files, put it in a .cpp or a .inline.hpp file.</p></li>
|
||||
<li><p>.inline.hpp files should only be included in .cpp or .inline.hpp files.</p></li>
|
||||
<li><p>All .cpp files include precompiled.hpp as the first include line.</p></li>
|
||||
<li><p>precompiled.hpp is just a build time optimization, so don't rely on it to resolve include problems.</p></li>
|
||||
<li><p>Keep the include lines alphabetically sorted.</p></li>
|
||||
<li><p>Put conditional inclusions (<code>#if ...</code>) at the end of the include list.</p></li>
|
||||
</ul>
|
||||
<h3 id="jtreg-tests">JTReg Tests</h3>
|
||||
<ul>
|
||||
<li><p>JTReg tests should have meaningful names.</p></li>
|
||||
<li><p>JTReg tests associated with specific bugs should be tagged with the <code>@bug</code> keyword in the test description.</p></li>
|
||||
<li><p>JTReg tests should be organized by component or feature under <code>test/</code>, in a directory hierarchy that generally follows that of the <code>src/</code> directory. There may be additional subdirectories to further categorize tests by feature. This structure makes it easy to run a collection of tests associated with a specific feature by specifying the associated directory as the source of the tests to run.</p>
|
||||
<ul>
|
||||
<li>Some (older) tests use the associated bug number in the directory name, the test name, or both. That naming style should no longer be used, with existing tests using that style being candidates for migration.</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<h3 id="naming">Naming</h3>
|
||||
<ul>
|
||||
<li><p>The length of a name may be correlated to the size of its scope. In particular, short names (even single letter names) may be fine in a small scope, but are usually inappropriate for larger scopes.</p></li>
|
||||
<li><p>Prefer whole words rather than abbreviations, unless the abbreviation is more widely used than the long form in the code's domain.</p></li>
|
||||
<li><p>Choose names consistently. Do not introduce spurious variations. Abbreviate corresponding terms to a consistent length.</p></li>
|
||||
<li><p>Global names must be unique, to avoid <a href="https://en.cppreference.com/w/cpp/language/definition" title="One Definition Rule">One Definition Rule</a> (ODR) violations. A common prefixing scheme for related global names is often used. (This is instead of using namespaces, which are mostly avoided in HotSpot.)</p></li>
|
||||
<li><p>Don't give two names to the semantically same thing. But use different names for semantically different things, even if they are representationally the same. (So use meaningful <code>typedef</code> or template alias names where appropriate.)</p></li>
|
||||
<li><p>When choosing names, avoid categorical nouns like "variable", "field", "parameter", "value", and verbs like "compute", "get". (<code>storeValue(int param)</code> is bad.)</p></li>
|
||||
<li><p>Type names and global names should use mixed-case with the first letter of each word capitalized (<code>FooBar</code>).</p></li>
|
||||
<li><p>Embedded abbreviations in otherwise mixed-case names are usually capitalized entirely rather than being treated as a single word with only the initial letter capitalized, e.g. "HTML" rather than "Html".</p></li>
|
||||
<li><p>Function and local variable names use lowercase with words separated by a single underscore (<code>foo_bar</code>).</p></li>
|
||||
<li><p>Class data member names have a leading underscore, and use lowercase with words separated by a single underscore (<code>_foo_bar</code>).</p></li>
|
||||
<li><p>Constant names may be upper-case or mixed-case, according to historical necessity. (Note: There are many examples of constants with lowercase names.)</p></li>
|
||||
<li><p>Constant names should follow an existing pattern, and must have a distinct appearance from other names in related APIs.</p></li>
|
||||
<li><p>Class and type names should be noun phrases. Consider an "er" suffix for a class that represents an action.</p></li>
|
||||
<li><p>Function names should be verb phrases that reflect changes of state known to a class's user, or else noun phrases if they cause no change of state visible to the class's user.</p></li>
|
||||
<li><p>Getter accessor names are noun phrases, with no "<code>get_</code>" noise word. Boolean getters can also begin with "<code>is_</code>" or "<code>has_</code>". Member function for reading data members usually have the same name as the data member, exclusive of the leading underscore.</p></li>
|
||||
<li><p>Setter accessor names prepend "<code>set_</code>" to the getter name.</p></li>
|
||||
<li><p>Other member function names are verb phrases, as if commands to the receiver.</p></li>
|
||||
<li><p>Avoid leading underscores (as "<code>_oop</code>") except in cases required above. (Names with leading underscores can cause portability problems.)</p></li>
|
||||
</ul>
|
||||
<h3 id="commenting">Commenting</h3>
|
||||
<ul>
|
||||
<li><p>Clearly comment subtle fixes.</p></li>
|
||||
<li><p>Clearly comment tricky classes and functions.</p></li>
|
||||
<li><p>If you have to choose between commenting code and writing wiki content, comment the code. Link from the wiki to the source file if it makes sense.</p></li>
|
||||
<li><p>As a general rule don't add bug numbers to comments (they would soon overwhelm the code). But if the bug report contains significant information that can't reasonably be added as a comment, then refer to the bug report.</p></li>
|
||||
<li><p>Personal names are discouraged in the source code, which is a team product.</p></li>
|
||||
</ul>
|
||||
<h3 id="macros">Macros</h3>
|
||||
<ul>
|
||||
<li><p>You can almost always use an inline function or class instead of a macro. Use a macro only when you really need it.</p></li>
|
||||
<li><p>Templates may be preferable to multi-line macros. (There may be subtle performance effects with templates on some platforms; revert to macros if absolutely necessary.)</p></li>
|
||||
<li><p><code>#ifdef</code>s should not be used to introduce platform-specific code into shared code (except for <code>_LP64</code>). They must be used to manage header files, in the pattern found at the top of every source file. They should be used mainly for major build features, including <code>PRODUCT</code>, <code>ASSERT</code>, <code>_LP64</code>, <code>INCLUDE_SERIALGC</code>, <code>COMPILER1</code>, etc.</p></li>
|
||||
<li><p>For build features such as <code>PRODUCT</code>, use <code>#ifdef PRODUCT</code> for multiple-line inclusions or exclusions.</p></li>
|
||||
<li><p>For short inclusions or exclusions based on build features, use macros like <code>PRODUCT_ONLY</code> and <code>NOT_PRODUCT</code>. But avoid using them with multiple-line arguments, since debuggers do not handle that well.</p></li>
|
||||
<li><p>Use <code>CATCH</code>, <code>THROW</code>, etc. for HotSpot-specific exception processing.</p></li>
|
||||
</ul>
|
||||
<h3 id="whitespace">Whitespace</h3>
|
||||
<ul>
|
||||
<li><p>In general, don't change whitespace unless it improves readability or consistency. Gratuitous whitespace changes will make integrations and backports more difficult.</p></li>
|
||||
<li><p>Use One-True-Brace-Style. The opening brace for a function or class is normally at the end of the line; it is sometimes moved to the beginning of the next line for emphasis. Substatements are enclosed in braces, even if there is only a single statement. Extremely simple one-line statements may drop braces around a substatement.</p></li>
|
||||
<li><p>Indentation levels are two columns.</p></li>
|
||||
<li><p>There is no hard line length limit. That said, bear in mind that excessively long lines can cause difficulties. Some people like to have multiple side-by-side windows in their editors, and long lines may force them to choose among unpleasant options. They can use wide windows, reducing the number that can fit across the screen, and wasting a lot of screen real estate because most lines are not that long. Alternatively, they can have more windows across the screen, with long lines wrapping (or worse, requiring scrolling to see in their entirety), which is harder to read. Similar issues exist for side-by-side code reviews.</p></li>
|
||||
<li><p>Tabs are not allowed in code. Set your editor accordingly.<br> (Emacs: <code>(setq-default indent-tabs-mode nil)</code>.)</p></li>
|
||||
<li><p>Use good taste to break lines and align corresponding tokens on adjacent lines.</p></li>
|
||||
<li><p>Use spaces around operators, especially comparisons and assignments. (Relaxable for boolean expressions and high-precedence operators in classic math-style formulas.)</p></li>
|
||||
<li><p>Put spaces on both sides of control flow keywords <code>if</code>, <code>else</code>, <code>for</code>, <code>switch</code>, etc. Don't add spaces around the associated <em>control</em> expressions. Examples:</p>
|
||||
<pre><code>while (test_foo(args...)) { // Yes
|
||||
while(test_foo(args...)) { // No, missing space after while
|
||||
while ( test_foo(args...) ) { // No, excess spaces around control</code></pre></li>
|
||||
<li><p>Use extra parentheses in expressions whenever operator precedence seems doubtful. Always use parentheses in shift/mask expressions (<code><<</code>, <code>&</code>, <code>|</code>). Don't add whitespace immediately inside parentheses.</p></li>
|
||||
<li><p>Use more spaces and blank lines between larger constructs, such as classes or function definitions.</p></li>
|
||||
<li><p>If the surrounding code has any sort of vertical organization, adjust new lines horizontally to be consistent with that organization. (E.g., trailing backslashes on long macro definitions often align.)</p></li>
|
||||
</ul>
|
||||
<h3 id="miscellaneous">Miscellaneous</h3>
|
||||
<ul>
|
||||
<li><p>Use the <a href="https://en.cppreference.com/w/cpp/language/raii" title="Resource Acquisition Is Initialization">Resource Acquisition Is Initialization</a> (RAII) design pattern to manage bracketed critical sections. See class <code>ResourceMark</code> for an example.</p></li>
|
||||
<li>Avoid implicit conversions to <code>bool</code>.
|
||||
<ul>
|
||||
<li>Use <code>bool</code> for boolean values.</li>
|
||||
<li>Do not use ints or pointers as (implicit) booleans with <code>&&</code>, <code>||</code>, <code>if</code>, <code>while</code>. Instead, compare explicitly, i.e. <code>if (x != 0)</code> or <code>if (ptr != nullptr)</code>, etc.</li>
|
||||
<li>Do not use declarations in <em>condition</em> forms, i.e. don't use <code>if (T v = value) { ... }</code>.</li>
|
||||
</ul></li>
|
||||
<li><p>Use functions from globalDefinitions.hpp and related files when performing bitwise operations on integers. Do not code directly as C operators, unless they are extremely simple. (Examples: <code>align_up</code>, <code>is_power_of_2</code>, <code>exact_log2</code>.)</p></li>
|
||||
<li><p>Use arrays with abstractions supporting range checks.</p></li>
|
||||
<li><p>Always enumerate all cases in a switch statement or provide a default case. It is ok to have an empty default with comment.</p></li>
|
||||
</ul>
|
||||
<h2 id="use-of-c-features">Use of C++ Features</h2>
|
||||
<p>HotSpot was originally written in a subset of the C++98/03 language. More recently, support for C++14 is provided, though again, HotSpot only uses a subset. (Backports to JDK versions lacking support for more recent Standards must of course stick with the original C++98/03 subset.)</p>
|
||||
<p>This section describes that subset. Features from the C++98/03 language may be used unless explicitly excluded here. Features from C++11 and C++14 may be explicitly permitted or explicitly excluded, and discussed accordingly here. There is a third category, undecided features, about which HotSpot developers have not yet reached a consensus, or perhaps have not discussed at all. Use of these features is also excluded.</p>
|
||||
<p>(The use of some features may not be immediately obvious and may slip in anyway, since the compiler will accept them. The code review process is the main defense against this.)</p>
|
||||
<p>Some features are discussed in their own subsection, typically to provide more extensive discussion or rationale for limitations. Features that don't have their own subsection are listed in omnibus feature sections for permitted, excluded, and undecided features.</p>
|
||||
<p>Lists of new features for C++11 and C++14, along with links to their descriptions, can be found in the online documentation for some of the compilers and libraries. The C++14 Standard is the definitive description.</p>
|
||||
<ul>
|
||||
<li><a href="https://gcc.gnu.org/projects/cxx-status.html">C++ Standards Support in GCC</a></li>
|
||||
<li><a href="https://clang.llvm.org/cxx_status.html">C++ Support in Clang</a></li>
|
||||
<li><a href="https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance">Visual C++ Language Conformance</a></li>
|
||||
<li><a href="https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html">libstdc++ Status</a></li>
|
||||
<li><a href="https://libcxx.llvm.org/cxx1y_status.html">libc++ Status</a></li>
|
||||
</ul>
|
||||
<p>As a rule of thumb, permitting features which simplify writing code and, especially, reading code, is encouraged.</p>
|
||||
<p>Similar discussions for some other projects:</p>
|
||||
<ul>
|
||||
<li><p><a href="https://google.github.io/styleguide/cppguide.html">Google C++ Style Guide</a> — Currently (2020) targeting C++17.</p></li>
|
||||
<li><p><a href="https://chromium-cpp.appspot.com">C++11 and C++14 use in Chromium</a> — Categorizes features as allowed, banned, or to be discussed.</p></li>
|
||||
<li><p><a href="https://llvm.org/docs/CodingStandards.html">llvm Coding Standards</a> — Currently (2020) targeting C++14.</p></li>
|
||||
<li><p><a href="https://firefox-source-docs.mozilla.org/code-quality/coding-style/using_cxx_in_firefox_code.html">Using C++ in Mozilla code</a> — C++17 support is required for recent versions (2020).</p></li>
|
||||
</ul>
|
||||
<h3 id="error-handling">Error Handling</h3>
|
||||
<p>Do not use exceptions. Exceptions are disabled by the build configuration for some platforms.</p>
|
||||
<p>Rationale: There is significant concern over the performance cost of exceptions and their usage model and implications for maintainable code. That's not just a matter of history that has been fixed; there remain questions and problems even today (2019). See, for example, <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf">Zero cost deterministic exceptions</a>. Because of this, HotSpot has always used a build configuration that disables exceptions where that is available. As a result, HotSpot code uses error handling mechanisms such as two-phase construction, factory functions, returning error codes, and immediate termination. Even if the cost of exceptions were not a concern, the existing body of code was not written with exception safety in mind. Making HotSpot exception safe would be a very large undertaking.</p>
|
||||
<p>In addition to the usual alternatives to exceptions, HotSpot provides its own exception mechanism. This is based on a set of macros defined in utilities/exceptions.hpp.</p>
|
||||
<h3 id="rtti-runtime-type-information">RTTI (Runtime Type Information)</h3>
|
||||
<p>Do not use <a href="https://en.wikipedia.org/wiki/Run-time_type_information" title="Runtime Type Information">Runtime Type Information</a> (RTTI). <a href="https://en.wikipedia.org/wiki/Run-time_type_information" title="Runtime Type Information">RTTI</a> is disabled by the build configuration for some platforms. Among other things, this means <code>dynamic_cast</code> cannot be used.</p>
|
||||
<p>Rationale: Other than to implement exceptions (which HotSpot doesn't use), most potential uses of <a href="https://en.wikipedia.org/wiki/Run-time_type_information" title="Runtime Type Information">RTTI</a> are better done via virtual functions. Some of the remainder can be replaced by bespoke mechanisms. The cost of the additional runtime data structures needed to support <a href="https://en.wikipedia.org/wiki/Run-time_type_information" title="Runtime Type Information">RTTI</a> are deemed not worthwhile, given the alternatives.</p>
|
||||
<h3 id="memory-allocation">Memory Allocation</h3>
|
||||
<p>Do not use the standard global allocation and deallocation functions (operator new and related functions). Use of these functions by HotSpot code is disabled for some platforms.</p>
|
||||
<p>Rationale: HotSpot often uses "resource" or "arena" allocation. Even where heap allocation is used, the standard global functions are avoided in favor of wrappers around malloc and free that support the VM's Native Memory Tracking (NMT) feature.</p>
|
||||
<p>Native memory allocation failures are often treated as non-recoverable. The place where "out of memory" is (first) detected may be an innocent bystander, unrelated to the actual culprit.</p>
|
||||
<h3 id="class-inheritance">Class Inheritance</h3>
|
||||
<p>Use public single inheritance.</p>
|
||||
<p>Prefer composition rather than non-public inheritance.</p>
|
||||
<p>Restrict inheritance to the "is-a" case; use composition rather than non-is-a related inheritance.</p>
|
||||
<p>Avoid multiple inheritance. Never use virtual inheritance.</p>
|
||||
<h3 id="namespaces">Namespaces</h3>
|
||||
<p>Avoid using namespaces. HotSpot code normally uses "all static" classes rather than namespaces for grouping. An "all static" class is not instantiable, has only static members, and is normally derived (possibly indirectly) from the helper class <code>AllStatic</code>.</p>
|
||||
<p>Benefits of using such classes include:</p>
|
||||
<ul>
|
||||
<li><p>Provides access control for members, which is unavailable with namespaces.</p></li>
|
||||
<li><p>Avoids <a href="https://en.cppreference.com/w/cpp/language/adl" title="Argument Dependent Lookup">Argument Dependent Lookup</a> (ADL).</p></li>
|
||||
<li><p>Closed for additional members. Namespaces allow names to be added in multiple contexts, making it harder to see the complete API.</p></li>
|
||||
</ul>
|
||||
<p>Namespaces should be used only in cases where one of those "benefits" is actually a hindrance.</p>
|
||||
<p>In particular, don't use anonymous namespaces. They seem like they should be useful, and indeed have some real benefits for naming and generated code size on some platforms. Unfortunately, debuggers don't seem to like them at all.</p>
|
||||
<p><a href="https://groups.google.com/forum/#!topic/mozilla.dev.platform/KsaG3lEEaRM" class="uri">https://groups.google.com/forum/#!topic/mozilla.dev.platform/KsaG3lEEaRM</a><br> Suggests Visual Studio debugger might not be able to refer to anonymous namespace symbols, so can't set breakpoints in them. Though the discussion seems to go back and forth on that.</p>
|
||||
<p><a href="https://firefox-source-docs.mozilla.org/code-quality/coding-style/coding_style_cpp.html" class="uri">https://firefox-source-docs.mozilla.org/code-quality/coding-style/coding_style_cpp.html</a><br> Search for "Anonymous namespaces" Suggests preferring "static" to anonymous namespaces where applicable, because of poor debugger support for anonymous namespaces.</p>
|
||||
<p><a href="https://sourceware.org/bugzilla/show_bug.cgi?id=16874" class="uri">https://sourceware.org/bugzilla/show_bug.cgi?id=16874</a><br> Bug for similar gdb problems.</p>
|
||||
<h3 id="c-standard-library">C++ Standard Library</h3>
|
||||
<p>Avoid using the C++ Standard Library.</p>
|
||||
<p>Historically, HotSpot has mostly avoided use of the Standard Library.</p>
|
||||
<p>(It used to be impossible to use most of it in shared code, because the build configuration for Solaris with Solaris Studio made all but a couple of pieces inaccessible. Support for header-only parts was added in mid-2017. Support for Solaris was removed in 2020.)</p>
|
||||
<p>Some reasons for this include</p>
|
||||
<ul>
|
||||
<li><p>Exceptions. Perhaps the largest core issue with adopting the use of Standard Library facilities is exceptions. HotSpot does not use exceptions and, for platforms which allow doing so, builds with them turned off. Many Standard Library facilities implicitly or explicitly use exceptions.</p></li>
|
||||
<li><p><code>assert</code>. An issue that is quickly encountered is the <code>assert</code> macro name collision (<a href="https://bugs.openjdk.java.net/browse/JDK-8007770">JDK-8007770</a>). Some mechanism for addressing this would be needed before much of the Standard Library could be used. (Not all Standard Library implementations use assert in header files, but some do.)</p></li>
|
||||
<li><p>Memory allocation. HotSpot requires explicit control over where allocations occur. The C++98/03 <code>std::allocator</code> class is too limited to support our usage. (Changes in more recent Standards may remove this limitation.)</p></li>
|
||||
<li><p>Implementation vagaries. Bugs, or simply different implementation choices, can lead to different behaviors among the various Standard Libraries we need to deal with.</p></li>
|
||||
<li><p>Inconsistent naming conventions. HotSpot and the C++ Standard use different naming conventions. The coexistence of those different conventions might appear jarring and reduce readability.</p></li>
|
||||
</ul>
|
||||
<p>There are a few exceptions to this rule.</p>
|
||||
<ul>
|
||||
<li><code>#include <new></code> to use placement <code>new</code>, <code>std::nothrow</code>, and <code>std::nothrow_t</code>.</li>
|
||||
<li><code>#include <limits></code> to use <code>std::numeric_limits</code>.</li>
|
||||
<li><code>#include <type_traits></code>.</li>
|
||||
<li><code>#include <cstddef></code> to use <code>std::nullptr_t</code>.</li>
|
||||
</ul>
|
||||
<p>TODO: Rather than directly #including (permitted) Standard Library headers, use a convention of #including wrapper headers (in some location like hotspot/shared/stdcpp). This provides a single place for dealing with issues we might have for any given header, esp. platform-specific issues.</p>
|
||||
<h3 id="type-deduction">Type Deduction</h3>
|
||||
<p>Use type deduction only if it makes the code clearer or safer. Do not use it merely to avoid the inconvenience of writing an explicit type, unless that type is itself difficult to write. An example of the latter is a function template return type that depends on template parameters in a non-trivial way.</p>
|
||||
<p>There are several contexts where types are deduced.</p>
|
||||
<ul>
|
||||
<li><p>Function argument deduction. This is always permitted, and indeed encouraged. It is nearly always better to allow the type of a function template argument to be deduced rather than explicitly specified.</p></li>
|
||||
<li><p><code>auto</code> variable declarations (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf">n1984</a>)<br> For local variables, this can be used to make the code clearer by eliminating type information that is obvious or irrelevant. Excessive use can make code much harder to understand.</p></li>
|
||||
<li><p>Function return type deduction (<a href="https://isocpp.org/files/papers/N3638.html">n3638</a>)<br> Only use if the function body has a very small number of <code>return</code> statements, and generally relatively little other code.</p></li>
|
||||
<li><p>Generic lambdas. Lambdas are not (yet) permitted.</p></li>
|
||||
<li><p>Lambda init captures. Lambdas are not (yet) permitted.</p></li>
|
||||
</ul>
|
||||
<h3 id="expression-sfinae">Expression SFINAE</h3>
|
||||
<p><a href="https://en.cppreference.com/w/cpp/language/sfinae" title="Substitution Failure Is Not An Error">Substitution Failure Is Not An Error</a> (SFINAE) is a template metaprogramming technique that makes use of template parameter substitution failures to make compile-time decisions.</p>
|
||||
<p>C++11 relaxed the rules for what constitutes a hard-error when attempting to substitute template parameters with template arguments, making most deduction errors be substitution errors; see (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html">n2634</a>). This makes <a href="https://en.cppreference.com/w/cpp/language/sfinae" title="Substitution Failure Is Not An Error">SFINAE</a> more powerful and easier to use. However, the implementation complexity for this change is significant, and this seems to be a place where obscure corner-case bugs in various compilers can be found. So while this feature can (and indeed should) be used (and would be difficult to avoid), caution should be used when pushing to extremes.</p>
|
||||
<p>Here are a few closely related example bugs:<br> <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468" class="uri">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468</a><br> <a href="https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html" class="uri">https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html</a></p>
|
||||
<h3 id="enum">enum</h3>
|
||||
<p>Where appropriate, <em>scoped-enums</em> should be used. (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf">n2347</a>)</p>
|
||||
<p>Use of <em>unscoped-enums</em> is permitted, though ordinary constants may be preferable when the automatic initializer feature isn't used.</p>
|
||||
<p>The underlying type (the <em>enum-base</em>) of an unscoped enum type should always be specified explicitly. When unspecified, the underlying type is dependent on the range of the enumerator values and the platform.</p>
|
||||
<p>The underlying type of a <em>scoped-enum</em> should also be specified explicitly if conversions may be applied to values of that type.</p>
|
||||
<p>Due to bugs in certain (very old) compilers, there is widespread use of enums and avoidance of in-class initialization of static integral constant members. Compilers having such bugs are no longer supported. Except where an enum is semantically appropriate, new code should use integral constants.</p>
|
||||
<h3 id="thread_local">thread_local</h3>
|
||||
<p>Do not use <code>thread_local</code> (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm">n2659</a>); instead, use the HotSpot macro <code>THREAD_LOCAL</code>. The initializer must be a constant expression.</p>
|
||||
<p>As was discussed in the review for <a href="https://mail.openjdk.java.net/pipermail/hotspot-dev/2019-September/039487.html">JDK-8230877</a>, <code>thread_local</code> allows dynamic initialization and destruction semantics. However, that support requires a run-time penalty for references to non-function-local <code>thread_local</code> variables defined in a different translation unit, even if they don't need dynamic initialization. Dynamic initialization and destruction of namespace-scoped thread local variables also has the same ordering problems as for ordinary namespace-scoped variables.</p>
|
||||
<h3 id="nullptr">nullptr</h3>
|
||||
<p>Prefer <code>nullptr</code> (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf">n2431</a>) to <code>NULL</code>. Don't use (constexpr or literal) 0 for pointers.</p>
|
||||
<p>For historical reasons there are widespread uses of both <code>NULL</code> and of integer 0 as a pointer value.</p>
|
||||
<h3 id="atomic"><atomic></h3>
|
||||
<p>Do not use facilities provided by the <code><atomic></code> header (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html">n2427</a>), (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm">n2752</a>); instead, use the HotSpot <code>Atomic</code> class and related facilities.</p>
|
||||
<p>Atomic operations in HotSpot code must have semantics which are consistent with those provided by the JDK's compilers for Java. There are platform-specific implementation choices that a C++ compiler might make or change that are outside the scope of the C++ Standard, and might differ from what the Java compilers implement.</p>
|
||||
<p>In addition, HotSpot <code>Atomic</code> has a concept of "conservative" memory ordering, which may differ from (may be stronger than) sequentially consistent. There are algorithms in HotSpot that are believed to rely on that ordering.</p>
|
||||
<h3 id="additional-permitted-features">Additional Permitted Features</h3>
|
||||
<ul>
|
||||
<li><p><code>constexpr</code> (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf">n2235</a>) (<a href="https://isocpp.org/files/papers/N3652.html">n3652</a>)</p></li>
|
||||
<li><p>Sized deallocation (<a href="https://isocpp.org/files/papers/n3778.html">n3778</a>)</p></li>
|
||||
<li><p>Variadic templates (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf">n2242</a>) (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf">n2555</a>)</p></li>
|
||||
<li><p>Static assertions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html">n1720</a>)</p></li>
|
||||
<li><p><code>decltype</code> (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf">n2343</a>) (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf">n3276</a>)</p></li>
|
||||
<li><p>Right angle brackets (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html">n1757</a>)</p></li>
|
||||
<li><p>Default template arguments for function templates (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226">CWG D226</a>)</p></li>
|
||||
<li><p>Template aliases (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">n2258</a>)</p></li>
|
||||
<li><p>Delegating constructors (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf">n1986</a>)</p></li>
|
||||
<li><p>Explicit conversion operators (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf">n2437</a>)</p></li>
|
||||
<li><p>Standard Layout Types (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm">n2342</a>)</p></li>
|
||||
<li><p>Defaulted and deleted functions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm">n2346</a>)</p></li>
|
||||
<li><p>Dynamic initialization and destruction with concurrency (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm">n2660</a>)</p></li>
|
||||
<li><p><code>final</code> virtual specifiers for classes and virtual functions (<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm">n2928</a>), (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm">n3206</a>), (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm">n3272</a>)</p></li>
|
||||
<li><p>Local and unnamed types as template parameters (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm">n2657</a>)</p></li>
|
||||
</ul>
|
||||
<h3 id="excluded-features">Excluded Features</h3>
|
||||
<ul>
|
||||
<li>New string and character literals
|
||||
<ul>
|
||||
<li>New character types (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html">n2249</a>)</li>
|
||||
<li>Unicode string literals (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">n2442</a>)</li>
|
||||
<li>Raw string literals (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm">n2442</a>)</li>
|
||||
<li>Universal character name literals (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html">n2170</a>)</li>
|
||||
</ul>
|
||||
<p>HotSpot doesn't need any of the new character and string literal types.</p></li>
|
||||
<li><p>User-defined literals (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf">n2765</a>) — User-defined literals should not be added casually, but only through a proposal to add a specific UDL.</p></li>
|
||||
<li><p>Inline namespaces (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm">n2535</a>) — HotSpot makes very limited use of namespaces.</p></li>
|
||||
<li><p><code>using namespace</code> directives. In particular, don't use <code>using namespace std;</code> to avoid needing to qualify Standard Library names.</p></li>
|
||||
<li><p>Propagating exceptions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html">n2179</a>) — HotSpot does not permit the use of exceptions, so this feature isn't useful.</p></li>
|
||||
<li><p>Avoid namespace-scoped variables with non-constexpr initialization. In particular, avoid variables with types requiring non-trivial initialization or destruction. Initialization order problems can be difficult to deal with and lead to surprises, as can destruction ordering. HotSpot doesn't generally try to cleanup on exit, and running destructors at exit can also lead to problems.</p></li>
|
||||
<li><p><code>[[deprecated]]</code> attribute (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html">n3760</a>) — Not relevant in HotSpot code.</p></li>
|
||||
<li><p>Avoid most operator overloading, preferring named functions. When operator overloading is used, ensure the semantics conform to the normal expected behavior of the operation.</p></li>
|
||||
<li><p>Avoid most implicit conversion constructors and (implicit or explicit) conversion operators. (Note that conversion to <code>bool</code> isn't needed in HotSpot code because of the "no implicit boolean" guideline.)</p></li>
|
||||
<li><p>Avoid covariant return types.</p></li>
|
||||
<li><p>Avoid <code>goto</code> statements.</p></li>
|
||||
</ul>
|
||||
<h3 id="undecided-features">Undecided Features</h3>
|
||||
<p>This list is incomplete; it serves to explicitly call out some features that have not yet been discussed.</p>
|
||||
<ul>
|
||||
<li><p><code>overrides</code> virtual specifiers for virtual functions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm">n3272</a>)</p></li>
|
||||
<li><p>Trailing return type syntax for functions (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm">n2541</a>)</p></li>
|
||||
<li><p>Variable templates (<a href="https://isocpp.org/files/papers/N3651.pdf">n3651</a>)</p></li>
|
||||
<li><p>Member initializers and aggregates (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html">n3653</a>)</p></li>
|
||||
<li><p><code>[[noreturn]]</code> attribute (<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf">n2761</a>)</p></li>
|
||||
<li><p>Rvalue references and move semantics</p></li>
|
||||
<li><p>Lambdas</p></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
828
doc/hotspot-style.md
Normal file
828
doc/hotspot-style.md
Normal file
@@ -0,0 +1,828 @@
|
||||
% HotSpot Coding Style
|
||||
|
||||
## Introduction
|
||||
|
||||
This is a collection of rules, guidelines, and suggestions for writing
|
||||
HotSpot code. Following these will help new code fit in with existing
|
||||
HotSpot code, making it easier to read and maintain. Failure to
|
||||
follow these guidelines may lead to discussion during code reviews, if
|
||||
not outright rejection of a change.
|
||||
|
||||
### Why Care About Style?
|
||||
|
||||
Some programmers seem to have lexers and even C preprocessors
|
||||
installed directly behind their eyeballs. The rest of us require code
|
||||
that is not only functionally correct but also easy to read. More than
|
||||
that, since there is no one style for easy-to-read code, and since a
|
||||
mashup of many styles is just as confusing as no style at all, it is
|
||||
important for coders to be conscious of the many implicit stylistic
|
||||
choices that historically have gone into the HotSpot code base.
|
||||
|
||||
Some of these guidelines are driven by the cross-platform requirements
|
||||
for HotSpot. Shared code must work on a variety of platforms, and may
|
||||
encounter deficiencies in some. Using platform conditionalization in
|
||||
shared code is usually avoided, while shared code is strongly
|
||||
preferred to multiple platform-dependent implementations, so some
|
||||
language features may be recommended against.
|
||||
|
||||
Some of the guidelines here are relatively arbitrary choices among
|
||||
equally plausible alternatives. The purpose of stating and enforcing
|
||||
these rules is largely to provide a consistent look to the code. That
|
||||
consistency makes the code more readable by avoiding non-functional
|
||||
distractions from the interesting functionality.
|
||||
|
||||
When changing pre-existing code, it is reasonable to adjust it to
|
||||
match these conventions. Exception: If the pre-existing code clearly
|
||||
conforms locally to its own peculiar conventions, it is not worth
|
||||
reformatting the whole thing. Also consider separating changes that
|
||||
make extensive stylistic updates from those which make functional
|
||||
changes.
|
||||
|
||||
### Counterexamples and Updates
|
||||
|
||||
Many of the guidelines mentioned here have (sometimes widespread)
|
||||
counterexamples in the HotSpot code base. Finding a counterexample is
|
||||
not sufficient justification for new code to follow the counterexample
|
||||
as a precedent, since readers of your code will rightfully expect your
|
||||
code to follow the greater bulk of precedents documented here.
|
||||
|
||||
Occasionally a guideline mentioned here may be just out of synch with
|
||||
the actual HotSpot code base. If you find that a guideline is
|
||||
consistently contradicted by a large number of counterexamples, please
|
||||
bring it up for discussion and possible change. The architectural
|
||||
rule, of course, is "When in Rome do as the Romans". Sometimes in the
|
||||
suburbs of Rome the rules are a little different; these differences
|
||||
can be pointed out here.
|
||||
|
||||
Proposed changes should be discussed on the
|
||||
[HotSpot Developers](mailto:hotspot-dev@openjdk.java.net) mailing
|
||||
list, and approved by
|
||||
[rough consensus](https://en.wikipedia.org/wiki/Rough_consensus) of
|
||||
the [HotSpot Group](https://openjdk.java.net/census#hotspot) Members.
|
||||
The Group Lead determines whether consensus has been reached.
|
||||
Changes are likely to be cautious and incremental, since HotSpot
|
||||
coders have been using these guidelines for years.
|
||||
|
||||
## Structure and Formatting
|
||||
|
||||
### Factoring and Class Design
|
||||
|
||||
* Group related code together, so readers can concentrate on one
|
||||
section of one file.
|
||||
|
||||
* Classes are the primary code structuring mechanism. Place related
|
||||
functionality in a class, or a set of related classes. Use of either
|
||||
namespaces or public non-member functions is rare in HotSpot code.
|
||||
Static non-member functions are not uncommon.
|
||||
|
||||
* If a class `FooBar` is going to be used in more than one place, put it
|
||||
a file named fooBar.hpp and fooBar.cpp. If the class is a sidekick
|
||||
to a more important class `BazBat`, it can go in bazBat.hpp.
|
||||
|
||||
* Put a member function `FooBar::bang` into the same file that defined
|
||||
`FooBar`, or its associated *.inline.hpp or *.cpp file.
|
||||
|
||||
* Use public accessor functions for member variables accessed
|
||||
outside the class.
|
||||
|
||||
* Assign names to constant literals and use the names instead.
|
||||
|
||||
* Keep functions small, a screenful at most. Split out chunks of
|
||||
logic into file-local classes or static functions if needed.
|
||||
|
||||
* Factor away nonessential complexity into local inline helper
|
||||
functions and helper classes.
|
||||
|
||||
* Think clearly about internal invariants that apply to each class,
|
||||
and document them in the form of asserts within member functions.
|
||||
|
||||
* Make simple, self-evident contracts for member functions. If you cannot
|
||||
communicate a simple contract, redesign the class.
|
||||
|
||||
* Implement classes as if expecting rough usage by clients. Check for
|
||||
incorrect usage of a class using `assert(...)`, `guarantee(...)`,
|
||||
`ShouldNotReachHere()` and comments wherever needed. Performance is
|
||||
almost never a reason to omit asserts.
|
||||
|
||||
* When possible, design as if for reusability. This forces a clear
|
||||
design of the class's externals, and clean hiding of its internals.
|
||||
|
||||
* Initialize all variables and data structures to a known state. If a
|
||||
class has a constructor, initialize it there.
|
||||
|
||||
* Do no optimization before its time. Prove the need to optimize.
|
||||
|
||||
* When you must defactor to optimize, preserve as much structure as
|
||||
possible. If you must hand-inline some name, label the local copy with
|
||||
the original name.
|
||||
|
||||
* If you need to use a hidden detail (e.g., a structure offset), name
|
||||
it (as a constant or function) in the class that owns it.
|
||||
|
||||
* Don't use the Copy and Paste keys to replicate more than a couple
|
||||
lines of code. Name what you must repeat.
|
||||
|
||||
* If a class needs a member function to change a user-visible attribute, the
|
||||
change should be done with a "setter" accessor matched to the simple
|
||||
"getter".
|
||||
|
||||
### Source Files
|
||||
|
||||
* All source files must have a globally unique basename. The build
|
||||
system depends on this uniqueness.
|
||||
|
||||
* Do not put non-trivial function implementations in .hpp files. If
|
||||
the implementation depends on other .hpp files, put it in a .cpp or
|
||||
a .inline.hpp file.
|
||||
|
||||
* .inline.hpp files should only be included in .cpp or .inline.hpp
|
||||
files.
|
||||
|
||||
* All .cpp files include precompiled.hpp as the first include line.
|
||||
|
||||
* precompiled.hpp is just a build time optimization, so don't rely on
|
||||
it to resolve include problems.
|
||||
|
||||
* Keep the include lines alphabetically sorted.
|
||||
|
||||
* Put conditional inclusions (`#if ...`) at the end of the include list.
|
||||
|
||||
### JTReg Tests
|
||||
|
||||
* JTReg tests should have meaningful names.
|
||||
|
||||
* JTReg tests associated with specific bugs should be tagged with the
|
||||
`@bug` keyword in the test description.
|
||||
|
||||
* JTReg tests should be organized by component or feature under
|
||||
`test/`, in a directory hierarchy that generally follows that of the
|
||||
`src/` directory. There may be additional subdirectories to further
|
||||
categorize tests by feature. This structure makes it easy to run a
|
||||
collection of tests associated with a specific feature by specifying
|
||||
the associated directory as the source of the tests to run.
|
||||
|
||||
* Some (older) tests use the associated bug number in the directory
|
||||
name, the test name, or both. That naming style should no longer be
|
||||
used, with existing tests using that style being candidates for migration.
|
||||
|
||||
### Naming
|
||||
|
||||
* The length of a name may be correlated to the size of its scope. In
|
||||
particular, short names (even single letter names) may be fine in a
|
||||
small scope, but are usually inappropriate for larger scopes.
|
||||
|
||||
* Prefer whole words rather than abbreviations, unless the
|
||||
abbreviation is more widely used than the long form in the code's
|
||||
domain.
|
||||
|
||||
* Choose names consistently. Do not introduce spurious
|
||||
variations. Abbreviate corresponding terms to a consistent length.
|
||||
|
||||
* Global names must be unique, to avoid [One Definition Rule][ODR] (ODR)
|
||||
violations. A common prefixing scheme for related global names is
|
||||
often used. (This is instead of using namespaces, which are mostly
|
||||
avoided in HotSpot.)
|
||||
|
||||
* Don't give two names to the semantically same thing. But use
|
||||
different names for semantically different things, even if they are
|
||||
representationally the same. (So use meaningful `typedef` or template
|
||||
alias names where appropriate.)
|
||||
|
||||
* When choosing names, avoid categorical nouns like "variable",
|
||||
"field", "parameter", "value", and verbs like "compute", "get".
|
||||
(`storeValue(int param)` is bad.)
|
||||
|
||||
* Type names and global names should use mixed-case with the first
|
||||
letter of each word capitalized (`FooBar`).
|
||||
|
||||
* Embedded abbreviations in
|
||||
otherwise mixed-case names are usually capitalized entirely rather
|
||||
than being treated as a single word with only the initial letter
|
||||
capitalized, e.g. "HTML" rather than "Html".
|
||||
|
||||
* Function and local variable names use lowercase with words separated
|
||||
by a single underscore (`foo_bar`).
|
||||
|
||||
* Class data member names have a leading underscore, and use lowercase
|
||||
with words separated by a single underscore (`_foo_bar`).
|
||||
|
||||
* Constant names may be upper-case or mixed-case, according to
|
||||
historical necessity. (Note: There are many examples of constants
|
||||
with lowercase names.)
|
||||
|
||||
* Constant names should follow an existing pattern, and must have a
|
||||
distinct appearance from other names in related APIs.
|
||||
|
||||
* Class and type names should be noun phrases. Consider an "er" suffix
|
||||
for a class that represents an action.
|
||||
|
||||
* Function names should be verb phrases that reflect changes of state
|
||||
known to a class's user, or else noun phrases if they cause no change
|
||||
of state visible to the class's user.
|
||||
|
||||
* Getter accessor names are noun phrases, with no "`get_`" noise
|
||||
word. Boolean getters can also begin with "`is_`" or "`has_`". Member
|
||||
function for reading data members usually have the same name as the
|
||||
data member, exclusive of the leading underscore.
|
||||
|
||||
* Setter accessor names prepend "`set_`" to the getter name.
|
||||
|
||||
* Other member function names are verb phrases, as if commands to the receiver.
|
||||
|
||||
* Avoid leading underscores (as "`_oop`") except in cases required
|
||||
above. (Names with leading underscores can cause portability
|
||||
problems.)
|
||||
|
||||
### Commenting
|
||||
|
||||
* Clearly comment subtle fixes.
|
||||
|
||||
* Clearly comment tricky classes and functions.
|
||||
|
||||
* If you have to choose between commenting code and writing wiki
|
||||
content, comment the code. Link from the wiki to the source file if
|
||||
it makes sense.
|
||||
|
||||
* As a general rule don't add bug numbers to comments (they would soon
|
||||
overwhelm the code). But if the bug report contains significant
|
||||
information that can't reasonably be added as a comment, then refer to
|
||||
the bug report.
|
||||
|
||||
* Personal names are discouraged in the source code, which is a team
|
||||
product.
|
||||
|
||||
### Macros
|
||||
|
||||
* You can almost always use an inline function or class instead of a
|
||||
macro. Use a macro only when you really need it.
|
||||
|
||||
* Templates may be preferable to multi-line macros. (There may be
|
||||
subtle performance effects with templates on some platforms; revert
|
||||
to macros if absolutely necessary.)
|
||||
|
||||
* `#ifdef`s should not be used to introduce platform-specific code
|
||||
into shared code (except for `_LP64`). They must be used to manage
|
||||
header files, in the pattern found at the top of every source
|
||||
file. They should be used mainly for major build features, including
|
||||
`PRODUCT`, `ASSERT`, `_LP64`, `INCLUDE_SERIALGC`, `COMPILER1`, etc.
|
||||
|
||||
* For build features such as `PRODUCT`, use `#ifdef PRODUCT` for
|
||||
multiple-line inclusions or exclusions.
|
||||
|
||||
* For short inclusions or exclusions based on build features, use
|
||||
macros like `PRODUCT_ONLY` and `NOT_PRODUCT`. But avoid using them
|
||||
with multiple-line arguments, since debuggers do not handle that
|
||||
well.
|
||||
|
||||
* Use `CATCH`, `THROW`, etc. for HotSpot-specific exception processing.
|
||||
|
||||
### Whitespace
|
||||
|
||||
* In general, don't change whitespace unless it improves readability
|
||||
or consistency. Gratuitous whitespace changes will make integrations
|
||||
and backports more difficult.
|
||||
|
||||
* Use One-True-Brace-Style. The opening brace for a function or class
|
||||
is normally at the end of the line; it is sometimes moved to the
|
||||
beginning of the next line for emphasis. Substatements are enclosed
|
||||
in braces, even if there is only a single statement. Extremely simple
|
||||
one-line statements may drop braces around a substatement.
|
||||
|
||||
* Indentation levels are two columns.
|
||||
|
||||
* There is no hard line length limit. That said, bear in mind that
|
||||
excessively long lines can cause difficulties. Some people like to
|
||||
have multiple side-by-side windows in their editors, and long lines
|
||||
may force them to choose among unpleasant options. They can use wide
|
||||
windows, reducing the number that can fit across the screen, and
|
||||
wasting a lot of screen real estate because most lines are not that
|
||||
long. Alternatively, they can have more windows across the screen,
|
||||
with long lines wrapping (or worse, requiring scrolling to see in
|
||||
their entirety), which is harder to read. Similar issues exist for
|
||||
side-by-side code reviews.
|
||||
|
||||
* Tabs are not allowed in code. Set your editor accordingly.<br>
|
||||
(Emacs: `(setq-default indent-tabs-mode nil)`.)
|
||||
|
||||
* Use good taste to break lines and align corresponding tokens on
|
||||
adjacent lines.
|
||||
|
||||
* Use spaces around operators, especially comparisons and
|
||||
assignments. (Relaxable for boolean expressions and high-precedence
|
||||
operators in classic math-style formulas.)
|
||||
|
||||
* Put spaces on both sides of control flow keywords `if`, `else`,
|
||||
`for`, `switch`, etc. Don't add spaces around the associated
|
||||
_control_ expressions. Examples:
|
||||
|
||||
```
|
||||
while (test_foo(args...)) { // Yes
|
||||
while(test_foo(args...)) { // No, missing space after while
|
||||
while ( test_foo(args...) ) { // No, excess spaces around control
|
||||
```
|
||||
|
||||
* Use extra parentheses in expressions whenever operator precedence
|
||||
seems doubtful. Always use parentheses in shift/mask expressions
|
||||
(`<<`, `&`, `|`). Don't add whitespace immediately inside
|
||||
parentheses.
|
||||
|
||||
* Use more spaces and blank lines between larger constructs, such as
|
||||
classes or function definitions.
|
||||
|
||||
* If the surrounding code has any sort of vertical organization,
|
||||
adjust new lines horizontally to be consistent with that
|
||||
organization. (E.g., trailing backslashes on long macro definitions
|
||||
often align.)
|
||||
|
||||
### Miscellaneous
|
||||
|
||||
* Use the [Resource Acquisition Is Initialization][RAII] (RAII)
|
||||
design pattern to manage bracketed critical
|
||||
sections. See class `ResourceMark` for an example.
|
||||
|
||||
* Avoid implicit conversions to `bool`.
|
||||
* Use `bool` for boolean values.
|
||||
* Do not use ints or pointers as (implicit) booleans with `&&`, `||`,
|
||||
`if`, `while`. Instead, compare explicitly, i.e. `if (x != 0)` or
|
||||
`if (ptr != nullptr)`, etc.
|
||||
* Do not use declarations in _condition_ forms, i.e. don't use
|
||||
`if (T v = value) { ... }`.
|
||||
|
||||
* Use functions from globalDefinitions.hpp and related files when
|
||||
performing bitwise
|
||||
operations on integers. Do not code directly as C operators, unless
|
||||
they are extremely simple. (Examples: `align_up`, `is_power_of_2`,
|
||||
`exact_log2`.)
|
||||
|
||||
* Use arrays with abstractions supporting range checks.
|
||||
|
||||
* Always enumerate all cases in a switch statement or provide a default
|
||||
case. It is ok to have an empty default with comment.
|
||||
|
||||
|
||||
## Use of C++ Features
|
||||
|
||||
HotSpot was originally written in a subset of the C++98/03 language.
|
||||
More recently, support for C++14 is provided, though again,
|
||||
HotSpot only uses a subset. (Backports to JDK versions lacking
|
||||
support for more recent Standards must of course stick with the
|
||||
original C++98/03 subset.)
|
||||
|
||||
This section describes that subset. Features from the C++98/03
|
||||
language may be used unless explicitly excluded here. Features from
|
||||
C++11 and C++14 may be explicitly permitted or explicitly excluded,
|
||||
and discussed accordingly here. There is a third category, undecided
|
||||
features, about which HotSpot developers have not yet reached a
|
||||
consensus, or perhaps have not discussed at all. Use of these
|
||||
features is also excluded.
|
||||
|
||||
(The use of some features may not be immediately obvious and may slip
|
||||
in anyway, since the compiler will accept them. The code review
|
||||
process is the main defense against this.)
|
||||
|
||||
Some features are discussed in their own subsection, typically to provide
|
||||
more extensive discussion or rationale for limitations. Features that
|
||||
don't have their own subsection are listed in omnibus feature sections
|
||||
for permitted, excluded, and undecided features.
|
||||
|
||||
Lists of new features for C++11 and C++14, along with links to their
|
||||
descriptions, can be found in the online documentation for some of the
|
||||
compilers and libraries. The C++14 Standard is the definitive
|
||||
description.
|
||||
|
||||
* [C++ Standards Support in GCC](https://gcc.gnu.org/projects/cxx-status.html)
|
||||
* [C++ Support in Clang](https://clang.llvm.org/cxx_status.html)
|
||||
* [Visual C++ Language Conformance](https://docs.microsoft.com/en-us/cpp/visual-cpp-language-conformance)
|
||||
* [libstdc++ Status](https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html)
|
||||
* [libc++ Status](https://libcxx.llvm.org/cxx1y_status.html)
|
||||
|
||||
As a rule of thumb, permitting features which simplify writing code
|
||||
and, especially, reading code, is encouraged.
|
||||
|
||||
Similar discussions for some other projects:
|
||||
|
||||
* [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) —
|
||||
Currently (2020) targeting C++17.
|
||||
|
||||
* [C++11 and C++14 use in Chromium](https://chromium-cpp.appspot.com) —
|
||||
Categorizes features as allowed, banned, or to be discussed.
|
||||
|
||||
* [llvm Coding Standards](https://llvm.org/docs/CodingStandards.html) —
|
||||
Currently (2020) targeting C++14.
|
||||
|
||||
* [Using C++ in Mozilla code](https://firefox-source-docs.mozilla.org/code-quality/coding-style/using_cxx_in_firefox_code.html) —
|
||||
C++17 support is required for recent versions (2020).
|
||||
|
||||
### Error Handling
|
||||
|
||||
Do not use exceptions. Exceptions are disabled by the build configuration
|
||||
for some platforms.
|
||||
|
||||
Rationale: There is significant concern over the performance cost of
|
||||
exceptions and their usage model and implications for maintainable code.
|
||||
That's not just a matter of history that has been fixed; there remain
|
||||
questions and problems even today (2019). See, for example, [Zero cost
|
||||
deterministic
|
||||
exceptions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0709r0.pdf).
|
||||
Because of this, HotSpot has always used a build configuration that disables
|
||||
exceptions where that is available. As a result, HotSpot code uses error
|
||||
handling mechanisms such as two-phase construction, factory functions,
|
||||
returning error codes, and immediate termination. Even if the cost of
|
||||
exceptions were not a concern, the existing body of code was not written with
|
||||
exception safety in mind. Making HotSpot exception safe would be a very large
|
||||
undertaking.
|
||||
|
||||
In addition to the usual alternatives to exceptions, HotSpot provides its
|
||||
own exception mechanism. This is based on a set of macros defined in
|
||||
utilities/exceptions.hpp.
|
||||
|
||||
### RTTI (Runtime Type Information)
|
||||
|
||||
Do not use [Runtime Type Information][RTTI] (RTTI).
|
||||
[RTTI][] is disabled by the build configuration for some
|
||||
platforms. Among other things, this means `dynamic_cast` cannot be used.
|
||||
|
||||
Rationale: Other than to implement exceptions (which HotSpot doesn't use),
|
||||
most potential uses of [RTTI][] are better done via virtual functions. Some of
|
||||
the remainder can be replaced by bespoke mechanisms. The cost of the
|
||||
additional runtime data structures needed to support [RTTI][] are deemed not
|
||||
worthwhile, given the alternatives.
|
||||
|
||||
### Memory Allocation
|
||||
|
||||
Do not use the standard global allocation and deallocation functions
|
||||
(operator new and related functions). Use of these functions by HotSpot
|
||||
code is disabled for some platforms.
|
||||
|
||||
Rationale: HotSpot often uses "resource" or "arena" allocation. Even
|
||||
where heap allocation is used, the standard global functions are
|
||||
avoided in favor of wrappers around malloc and free that support the
|
||||
VM's Native Memory Tracking (NMT) feature.
|
||||
|
||||
Native memory allocation failures are often treated as non-recoverable.
|
||||
The place where "out of memory" is (first) detected may be an innocent
|
||||
bystander, unrelated to the actual culprit.
|
||||
|
||||
### Class Inheritance
|
||||
|
||||
Use public single inheritance.
|
||||
|
||||
Prefer composition rather than non-public inheritance.
|
||||
|
||||
Restrict inheritance to the "is-a" case; use composition rather than
|
||||
non-is-a related inheritance.
|
||||
|
||||
Avoid multiple inheritance. Never use virtual inheritance.
|
||||
|
||||
### Namespaces
|
||||
|
||||
Avoid using namespaces. HotSpot code normally uses "all static"
|
||||
classes rather than namespaces for grouping. An "all static" class is
|
||||
not instantiable, has only static members, and is normally derived
|
||||
(possibly indirectly) from the helper class `AllStatic`.
|
||||
|
||||
Benefits of using such classes include:
|
||||
|
||||
* Provides access control for members, which is unavailable with
|
||||
namespaces.
|
||||
|
||||
* Avoids [Argument Dependent Lookup][ADL] (ADL).
|
||||
|
||||
* Closed for additional members. Namespaces allow names to be added in
|
||||
multiple contexts, making it harder to see the complete API.
|
||||
|
||||
Namespaces should be used only in cases where one of those "benefits"
|
||||
is actually a hindrance.
|
||||
|
||||
In particular, don't use anonymous namespaces. They seem like they should
|
||||
be useful, and indeed have some real benefits for naming and generated code
|
||||
size on some platforms. Unfortunately, debuggers don't seem to like them at
|
||||
all.
|
||||
|
||||
<https://groups.google.com/forum/#!topic/mozilla.dev.platform/KsaG3lEEaRM><br>
|
||||
Suggests Visual Studio debugger might not be able to refer to
|
||||
anonymous namespace symbols, so can't set breakpoints in them.
|
||||
Though the discussion seems to go back and forth on that.
|
||||
|
||||
<https://firefox-source-docs.mozilla.org/code-quality/coding-style/coding_style_cpp.html><br>
|
||||
Search for "Anonymous namespaces"
|
||||
Suggests preferring "static" to anonymous namespaces where applicable,
|
||||
because of poor debugger support for anonymous namespaces.
|
||||
|
||||
<https://sourceware.org/bugzilla/show_bug.cgi?id=16874><br>
|
||||
Bug for similar gdb problems.
|
||||
|
||||
### C++ Standard Library
|
||||
|
||||
Avoid using the C++ Standard Library.
|
||||
|
||||
Historically, HotSpot has mostly avoided use of the Standard
|
||||
Library.
|
||||
|
||||
(It used to be impossible to use most of it in shared code,
|
||||
because the build configuration for Solaris with Solaris Studio made
|
||||
all but a couple of pieces inaccessible. Support for header-only
|
||||
parts was added in mid-2017. Support for Solaris was removed
|
||||
in 2020.)
|
||||
|
||||
Some reasons for this include
|
||||
|
||||
* Exceptions. Perhaps the largest core issue with adopting the use of
|
||||
Standard Library facilities is exceptions. HotSpot does not use
|
||||
exceptions and, for platforms which allow doing so, builds with them
|
||||
turned off. Many Standard Library facilities implicitly or explicitly
|
||||
use exceptions.
|
||||
|
||||
* `assert`. An issue that is quickly encountered is the `assert` macro name
|
||||
collision ([JDK-8007770](https://bugs.openjdk.java.net/browse/JDK-8007770)).
|
||||
Some mechanism for addressing this would be needed before much of the
|
||||
Standard Library could be used. (Not all Standard Library implementations
|
||||
use assert in header files, but some do.)
|
||||
|
||||
* Memory allocation. HotSpot requires explicit control over where
|
||||
allocations occur. The C++98/03 `std::allocator` class is too limited
|
||||
to support our usage. (Changes in more recent Standards may remove
|
||||
this limitation.)
|
||||
|
||||
* Implementation vagaries. Bugs, or simply different implementation choices,
|
||||
can lead to different behaviors among the various Standard Libraries we need
|
||||
to deal with.
|
||||
|
||||
* Inconsistent naming conventions. HotSpot and the C++ Standard use
|
||||
different naming conventions. The coexistence of those different conventions
|
||||
might appear jarring and reduce readability.
|
||||
|
||||
There are a few exceptions to this rule.
|
||||
|
||||
* `#include <new>` to use placement `new`, `std::nothrow`, and `std::nothrow_t`.
|
||||
* `#include <limits>` to use `std::numeric_limits`.
|
||||
* `#include <type_traits>`.
|
||||
* `#include <cstddef>` to use `std::nullptr_t`.
|
||||
|
||||
TODO: Rather than directly \#including (permitted) Standard Library
|
||||
headers, use a convention of \#including wrapper headers (in some
|
||||
location like hotspot/shared/stdcpp). This provides a single place
|
||||
for dealing with issues we might have for any given header, esp.
|
||||
platform-specific issues.
|
||||
|
||||
### Type Deduction
|
||||
|
||||
Use type deduction only if it makes the code clearer or safer. Do not
|
||||
use it merely to avoid the inconvenience of writing an explicit type,
|
||||
unless that type is itself difficult to write. An example of the
|
||||
latter is a function template return type that depends on template
|
||||
parameters in a non-trivial way.
|
||||
|
||||
There are several contexts where types are deduced.
|
||||
|
||||
* Function argument deduction. This is always permitted, and indeed
|
||||
encouraged. It is nearly always better to allow the type of a
|
||||
function template argument to be deduced rather than explicitly
|
||||
specified.
|
||||
|
||||
* `auto` variable declarations
|
||||
([n1984](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf))<br>
|
||||
For local variables, this can be used to make the code clearer by
|
||||
eliminating type information that is obvious or irrelevant. Excessive
|
||||
use can make code much harder to understand.
|
||||
|
||||
* Function return type deduction
|
||||
([n3638](https://isocpp.org/files/papers/N3638.html))<br>
|
||||
Only use if the function body has a very small number of `return`
|
||||
statements, and generally relatively little other code.
|
||||
|
||||
* Generic lambdas. Lambdas are not (yet) permitted.
|
||||
|
||||
* Lambda init captures. Lambdas are not (yet) permitted.
|
||||
|
||||
### Expression SFINAE
|
||||
|
||||
[Substitution Failure Is Not An Error][SFINAE] (SFINAE)
|
||||
is a template metaprogramming technique that makes use of
|
||||
template parameter substitution failures to make compile-time decisions.
|
||||
|
||||
C++11 relaxed the rules for what constitutes a hard-error when
|
||||
attempting to substitute template parameters with template arguments,
|
||||
making most deduction errors be substitution errors; see
|
||||
([n2634](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html)).
|
||||
This makes [SFINAE][] more powerful and easier to use. However, the
|
||||
implementation complexity for this change is significant, and this
|
||||
seems to be a place where obscure corner-case bugs in various
|
||||
compilers can be found. So while this feature can (and indeed should)
|
||||
be used (and would be difficult to avoid), caution should be used when
|
||||
pushing to extremes.
|
||||
|
||||
Here are a few closely related example bugs:<br>
|
||||
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95468><br>
|
||||
<https://developercommunity.visualstudio.com/content/problem/396562/sizeof-deduced-type-is-sometimes-not-a-constant-ex.html>
|
||||
|
||||
### enum
|
||||
|
||||
Where appropriate, _scoped-enums_ should be used.
|
||||
([n2347](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf))
|
||||
|
||||
Use of _unscoped-enums_ is permitted, though ordinary constants may be
|
||||
preferable when the automatic initializer feature isn't used.
|
||||
|
||||
The underlying type (the _enum-base_) of an unscoped enum type should
|
||||
always be specified explicitly. When unspecified, the underlying type
|
||||
is dependent on the range of the enumerator values and the platform.
|
||||
|
||||
The underlying type of a _scoped-enum_ should also be specified
|
||||
explicitly if conversions may be applied to values of that type.
|
||||
|
||||
Due to bugs in certain (very old) compilers, there is widespread use
|
||||
of enums and avoidance of in-class initialization of static integral
|
||||
constant members. Compilers having such bugs are no longer supported.
|
||||
Except where an enum is semantically appropriate, new code should use
|
||||
integral constants.
|
||||
|
||||
### thread_local
|
||||
|
||||
Do not use `thread_local`
|
||||
([n2659](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm));
|
||||
instead, use the HotSpot macro `THREAD_LOCAL`. The initializer must
|
||||
be a constant expression.
|
||||
|
||||
As was discussed in the review for
|
||||
[JDK-8230877](https://mail.openjdk.java.net/pipermail/hotspot-dev/2019-September/039487.html),
|
||||
`thread_local` allows dynamic initialization and destruction
|
||||
semantics. However, that support requires a run-time penalty for
|
||||
references to non-function-local `thread_local` variables defined in a
|
||||
different translation unit, even if they don't need dynamic
|
||||
initialization. Dynamic initialization and destruction of
|
||||
namespace-scoped thread local variables also has the same ordering
|
||||
problems as for ordinary namespace-scoped variables.
|
||||
|
||||
### nullptr
|
||||
|
||||
Prefer `nullptr`
|
||||
([n2431](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf))
|
||||
to `NULL`. Don't use (constexpr or literal) 0 for pointers.
|
||||
|
||||
For historical reasons there are widespread uses of both `NULL` and of
|
||||
integer 0 as a pointer value.
|
||||
|
||||
### <atomic>
|
||||
|
||||
Do not use facilities provided by the `<atomic>` header
|
||||
([n2427](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html)),
|
||||
([n2752](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm));
|
||||
instead, use the HotSpot `Atomic` class and related facilities.
|
||||
|
||||
Atomic operations in HotSpot code must have semantics which are
|
||||
consistent with those provided by the JDK's compilers for Java. There
|
||||
are platform-specific implementation choices that a C++ compiler might
|
||||
make or change that are outside the scope of the C++ Standard, and
|
||||
might differ from what the Java compilers implement.
|
||||
|
||||
In addition, HotSpot `Atomic` has a concept of "conservative" memory
|
||||
ordering, which may differ from (may be stronger than) sequentially
|
||||
consistent. There are algorithms in HotSpot that are believed to rely
|
||||
on that ordering.
|
||||
|
||||
### Additional Permitted Features
|
||||
|
||||
* `constexpr`
|
||||
([n2235](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf))
|
||||
([n3652](https://isocpp.org/files/papers/N3652.html))
|
||||
|
||||
* Sized deallocation
|
||||
([n3778](https://isocpp.org/files/papers/n3778.html))
|
||||
|
||||
* Variadic templates
|
||||
([n2242](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf))
|
||||
([n2555](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf))
|
||||
|
||||
* Static assertions
|
||||
([n1720](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html))
|
||||
|
||||
* `decltype`
|
||||
([n2343](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf))
|
||||
([n3276](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3276.pdf))
|
||||
|
||||
* Right angle brackets
|
||||
([n1757](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html))
|
||||
|
||||
* Default template arguments for function templates
|
||||
([CWG D226](http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226))
|
||||
|
||||
* Template aliases
|
||||
([n2258](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf))
|
||||
|
||||
* Delegating constructors
|
||||
([n1986](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf))
|
||||
|
||||
* Explicit conversion operators
|
||||
([n2437](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf))
|
||||
|
||||
* Standard Layout Types
|
||||
([n2342](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm))
|
||||
|
||||
* Defaulted and deleted functions
|
||||
([n2346](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm))
|
||||
|
||||
* Dynamic initialization and destruction with concurrency
|
||||
([n2660](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm))
|
||||
|
||||
* `final` virtual specifiers for classes and virtual functions
|
||||
([n2928](http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm)),
|
||||
([n3206](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm)),
|
||||
([n3272](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm))
|
||||
|
||||
* Local and unnamed types as template parameters
|
||||
([n2657](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm))
|
||||
|
||||
### Excluded Features
|
||||
|
||||
* New string and character literals
|
||||
* New character types
|
||||
([n2249](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html))
|
||||
* Unicode string literals
|
||||
([n2442](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm))
|
||||
* Raw string literals
|
||||
([n2442](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm))
|
||||
* Universal character name literals
|
||||
([n2170](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html))
|
||||
|
||||
HotSpot doesn't need any of the new character and string literal
|
||||
types.
|
||||
|
||||
* User-defined literals
|
||||
([n2765](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf)) —
|
||||
User-defined literals should not be added casually, but only
|
||||
through a proposal to add a specific UDL.
|
||||
|
||||
* Inline namespaces
|
||||
([n2535](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm)) —
|
||||
HotSpot makes very limited use of namespaces.
|
||||
|
||||
* `using namespace` directives. In particular, don't use `using
|
||||
namespace std;` to avoid needing to qualify Standard Library names.
|
||||
|
||||
* Propagating exceptions
|
||||
([n2179](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html)) —
|
||||
HotSpot does not permit the use of exceptions, so this feature isn't useful.
|
||||
|
||||
* Avoid namespace-scoped variables with non-constexpr initialization.
|
||||
In particular, avoid variables with types requiring non-trivial
|
||||
initialization or destruction. Initialization order problems can be
|
||||
difficult to deal with and lead to surprises, as can destruction
|
||||
ordering. HotSpot doesn't generally try to cleanup on exit, and
|
||||
running destructors at exit can also lead to problems.
|
||||
|
||||
* `[[deprecated]]` attribute
|
||||
([n3760](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3760.html)) —
|
||||
Not relevant in HotSpot code.
|
||||
|
||||
* Avoid most operator overloading, preferring named functions. When
|
||||
operator overloading is used, ensure the semantics conform to the
|
||||
normal expected behavior of the operation.
|
||||
|
||||
* Avoid most implicit conversion constructors and (implicit or explicit)
|
||||
conversion operators. (Note that conversion to `bool` isn't needed
|
||||
in HotSpot code because of the "no implicit boolean" guideline.)
|
||||
|
||||
* Avoid covariant return types.
|
||||
|
||||
* Avoid `goto` statements.
|
||||
|
||||
### Undecided Features
|
||||
|
||||
This list is incomplete; it serves to explicitly call out some
|
||||
features that have not yet been discussed.
|
||||
|
||||
* `overrides` virtual specifiers for virtual functions
|
||||
([n3272](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm))
|
||||
|
||||
* Trailing return type syntax for functions
|
||||
([n2541](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm))
|
||||
|
||||
* Variable templates
|
||||
([n3651](https://isocpp.org/files/papers/N3651.pdf))
|
||||
|
||||
* Member initializers and aggregates
|
||||
([n3653](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3653.html))
|
||||
|
||||
* `[[noreturn]]` attribute
|
||||
([n2761](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf))
|
||||
|
||||
* Rvalue references and move semantics
|
||||
|
||||
* Lambdas
|
||||
|
||||
|
||||
[ADL]: https://en.cppreference.com/w/cpp/language/adl
|
||||
"Argument Dependent Lookup"
|
||||
|
||||
[ODR]: https://en.cppreference.com/w/cpp/language/definition
|
||||
"One Definition Rule"
|
||||
|
||||
[RAII]: https://en.cppreference.com/w/cpp/language/raii
|
||||
"Resource Acquisition Is Initialization"
|
||||
|
||||
[RTTI]: https://en.wikipedia.org/wiki/Run-time_type_information
|
||||
"Runtime Type Information"
|
||||
|
||||
[SFINAE]: https://en.cppreference.com/w/cpp/language/sfinae
|
||||
"Substitution Failure Is Not An Error"
|
||||
223
doc/hotspot-unit-tests.html
Normal file
223
doc/hotspot-unit-tests.html
Normal file
@@ -0,0 +1,223 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
<title>Native/Unit Test Development Guidelines</title>
|
||||
<style type="text/css">
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
span.underline{text-decoration: underline;}
|
||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||||
</style>
|
||||
<link rel="stylesheet" href="../make/data/docs-resources/resources/jdk-default.css" />
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<header id="title-block-header">
|
||||
<h1 class="title">Native/Unit Test Development Guidelines</h1>
|
||||
</header>
|
||||
<nav id="TOC">
|
||||
<ul>
|
||||
<li><a href="#good-test-properties">Good test properties</a><ul>
|
||||
<li><a href="#lightness">Lightness</a></li>
|
||||
<li><a href="#isolation">Isolation</a></li>
|
||||
<li><a href="#atomicity-and-self-containment">Atomicity and self-containment</a></li>
|
||||
<li><a href="#repeatability">Repeatability</a></li>
|
||||
<li><a href="#informativeness">Informativeness</a></li>
|
||||
<li><a href="#testing-instead-of-visiting">Testing instead of visiting</a></li>
|
||||
<li><a href="#nearness">Nearness</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#asserts">Asserts</a><ul>
|
||||
<li><a href="#several-checks">Several checks</a></li>
|
||||
<li><a href="#first-parameter-is-expected-value">First parameter is expected value</a></li>
|
||||
<li><a href="#floating-point-comparison">Floating-point comparison</a></li>
|
||||
<li><a href="#c-string-comparison">C string comparison</a></li>
|
||||
<li><a href="#error-messages">Error messages</a></li>
|
||||
<li><a href="#uncluttered-output">Uncluttered output</a></li>
|
||||
<li><a href="#failures-propagation">Failures propagation</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#naming-and-grouping">Naming and Grouping</a><ul>
|
||||
<li><a href="#test-group-names">Test group names</a></li>
|
||||
<li><a href="#filename">Filename</a></li>
|
||||
<li><a href="#file-location">File location</a></li>
|
||||
<li><a href="#test-names">Test names</a></li>
|
||||
<li><a href="#fixture-classes">Fixture classes</a></li>
|
||||
<li><a href="#friend-classes">Friend classes</a></li>
|
||||
<li><a href="#oscpu-specific-tests">OS/CPU specific tests</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#miscellaneous">Miscellaneous</a><ul>
|
||||
<li><a href="#hotspot-style">Hotspot style</a></li>
|
||||
<li><a href="#codetest-metrics">Code/test metrics</a></li>
|
||||
<li><a href="#access-to-non-public-members">Access to non-public members</a></li>
|
||||
<li><a href="#death-tests">Death tests</a></li>
|
||||
<li><a href="#external-flags">External flags</a></li>
|
||||
<li><a href="#test-specific-flags">Test-specific flags</a></li>
|
||||
<li><a href="#flag-restoring">Flag restoring</a></li>
|
||||
<li><a href="#googletest-documentation">GoogleTest documentation</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#todo">TODO</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<p>The purpose of these guidelines is to establish a shared vision on what kind of native tests and how we want to develop them for Hotspot using GoogleTest. Hence these guidelines include style items as well as test approach items.</p>
|
||||
<p>First section of this document describes properties of good tests which are common for almost all types of test regardless of language, framework, etc. Further sections provide recommendations to achieve those properties and other HotSpot and/or GoogleTest specific guidelines.</p>
|
||||
<h2 id="good-test-properties">Good test properties</h2>
|
||||
<h3 id="lightness">Lightness</h3>
|
||||
<p>Use the most lightweight type of tests.</p>
|
||||
<p>In Hotspot, there are 3 different types of tests regarding their dependency on a JVM, each next level is slower than previous</p>
|
||||
<ul>
|
||||
<li><p><code>TEST</code> : a test does not depend on a JVM</p></li>
|
||||
<li><p><code>TEST_VM</code> : a test does depend on an initialized JVM, but are supposed not to break a JVM, i.e. leave it in a workable state.</p></li>
|
||||
<li><p><code>TEST_OTHER_VM</code> : a test depends on a JVM and requires a freshly initialized JVM or leaves a JVM in non-workable state</p></li>
|
||||
</ul>
|
||||
<h3 id="isolation">Isolation</h3>
|
||||
<p>Tests have to be isolated: not to have visible side-effects, influences on other tests results.</p>
|
||||
<p>Results of one test should not depend on test execution order, other tests, otherwise it is becoming almost impossible to find out why a test failed. Due to hotspot-specific, it is not so easy to get a full isolation, e.g. we share an initialized JVM between all <code>TEST_VM</code> tests, so if your test changes JVM's state too drastically and does not change it back, you had better consider <code>TEST_OTHER_VM</code>.</p>
|
||||
<h3 id="atomicity-and-self-containment">Atomicity and self-containment</h3>
|
||||
<p>Tests should be <em>atomic</em> and <em>self-contained</em> at the same time.</p>
|
||||
<p>One test should check a particular part of a class, subsystem, functionality, etc. Then it is quite easy to determine what parts of a product are broken basing on test failures. On the other hand, a test should test that part more-or-less entirely, because when one sees a test <code>FooTest::bar</code>, they assume all aspects of bar from <code>Foo</code> are tested.</p>
|
||||
<p>However, it is impossible to cover all aspects even of a method, not to mention a subsystem. In such cases, it is recommended to have several tests, one for each aspect of a thing under test. For example one test to tests how <code>Foo::bar</code> works if an argument is <code>null</code>, another test to test how it works if an argument is acceptable but <code>Foo</code> is not in the right state to accept it and so on. This helps not only to make tests atomic, self-contained but also makes test name self-descriptive (discussed in more details in <a href="#test-names">Test names</a>).</p>
|
||||
<h3 id="repeatability">Repeatability</h3>
|
||||
<p>Tests have to be repeatable.</p>
|
||||
<p>Reproducibility is very crucial for a test. No one likes sporadic test failures, they are hard to investigate, fix and verify a fix.</p>
|
||||
<p>In some cases, it is quite hard to write a 100% repeatable test, since besides a test there can be other moving parts, e.g. in case of <code>TEST_VM</code> there are several concurrently running threads. Despite this, we should try to make a test as reproducible as possible.</p>
|
||||
<h3 id="informativeness">Informativeness</h3>
|
||||
<p>In case of a failure, a test should be as <em>informative</em> as possible.</p>
|
||||
<p>Having more information about a test failure than just compared values can be very useful for failure troubleshooting, it can reduce or even completely eliminate debugging hours. This is even more important in case of not 100% reproducible failures.</p>
|
||||
<p>Achieving this property, one can easily make a test too verbose, so it will be really hard to find useful information in the ocean of useless information. Hence they should not only think about how to provide <a href="#error-messages">good information</a>, but also <a href="#uncluttered-output">when to do it</a>.</p>
|
||||
<h3 id="testing-instead-of-visiting">Testing instead of visiting</h3>
|
||||
<p>Tests should <em>test</em>.</p>
|
||||
<p>It is not enough just to "visit" some code, a test should check that code does that it has to do, compare return values with expected values, check that desired side effects are done, and undesired are not, and so on. In other words, a test should contain at least one GoogleTest assertion and do not rely on JVM asserts.</p>
|
||||
<p>Generally speaking to write a good test, one should create a model of the system under tests, a model of possible bugs (or bugs which one wants to find) and design tests using those models.</p>
|
||||
<h3 id="nearness">Nearness</h3>
|
||||
<p>Prefer having checks inside test code.</p>
|
||||
<p>Not only does having test logic outside, e.g. verification method, depending on asserts in product code contradict with several items above but also decreases test’s readability and stability. It is much easier to understand that a test is testing when all testing logic is located inside a test or nearby in shared test libraries. As a rule of thumb, the closer a check to a test, the better.</p>
|
||||
<h2 id="asserts">Asserts</h2>
|
||||
<h3 id="several-checks">Several checks</h3>
|
||||
<p>Prefer <code>EXPECT</code> over <code>ASSERT</code> if possible.</p>
|
||||
<p>This is related to the <a href="#informativeness">informativeness</a> property of tests, information for other checks can help to better localize a defect’s root-cause. One should use <code>ASSERT</code> if it is impossible to continue test execution or if it does not make much sense. Later in the text, <code>EXPECT</code> forms will be used to refer to both <code>ASSERT/EXPECT</code>.</p>
|
||||
<p>When it is possible to make several different checks, but impossible to continue test execution if at least one check fails, you can use <code>::testing::Test::HasNonfatalFailure()</code> function. The recommended way to express that is <code>ASSERT_FALSE(::testing::Test::HasNonfatalFailure())</code>. Besides making it clear why a test is aborted, it also allows you to provide more information about a failure.</p>
|
||||
<h3 id="first-parameter-is-expected-value">First parameter is expected value</h3>
|
||||
<p>In all equality assertions, expected values should be passed as the first parameter.</p>
|
||||
<p>This convention is adopted by GoogleTest, and there is a slight difference in how GoogleTest treats parameters, the most important one is <code>null</code> detection. Due to different reasons, <code>null</code> detection is enabled only for the first parameter, that is to said <code>EXPECT_EQ(NULL, object)</code> checks that object is <code>null</code>, while <code>EXPECT_EQ(object, NULL)</code> checks that object equals to <code>NULL</code>, GoogleTest is very strict regarding types of compared values so the latter will generates a compile-time error.</p>
|
||||
<h3 id="floating-point-comparison">Floating-point comparison</h3>
|
||||
<p>Use floating-point special macros to compare <code>float/double</code> values.</p>
|
||||
<p>Because of floating-point number representations and round-off errors, regular equality comparison will not return true in most cases. There are special <code>EXPECT_FLOAT_EQ/EXPECT_DOUBLE_EQ</code> assertions which check that the distance between compared values is not more than 4 ULPs, there is also <code>EXPECT_NEAR(v1, v2, eps)</code> which checks that the absolute value of the difference between <code>v1</code> and <code>v2</code> is not greater than <code>eps</code>.</p>
|
||||
<h3 id="c-string-comparison">C string comparison</h3>
|
||||
<p>Use string special macros for C strings comparisons.</p>
|
||||
<p><code>EXPECT_EQ</code> just compares pointers’ values, which is hardly what one wants comparing C strings. GoogleTest provides <code>EXPECT_STREQ</code> and <code>EXPECT_STRNE</code> macros to compare C string contents. There are also case-insensitive versions <code>EXPECT_STRCASEEQ</code>, <code>EXPECT_STRCASENE</code>.</p>
|
||||
<h3 id="error-messages">Error messages</h3>
|
||||
<p>Provide informative, but not too verbose error messages.</p>
|
||||
<p>All GoogleTest asserts print compared expressions and their values, so there is no need to have them in error messages. Asserts print only compared values, they do not print any of interim variables, e.g. <code>ASSERT_TRUE((val1 == val2 && isFail(foo(8)) || i == 18)</code> prints only one value. If you use some complex predicates, please consider <code>EXPECT_PRED*</code> or <code>EXPECT_FORMAT_PRED</code> assertions family, they check that a predicate returns true/success and print out all parameters values.</p>
|
||||
<p>However in some cases, default information is not enough, a commonly used example is an assert inside a loop, GoogleTest will not print iteration values (unless it is an assert's parameter). Other demonstrative examples are printing error code and a corresponding error message; printing internal states which might have an impact on results. One should add this information to assert message using <code><<</code> operator.</p>
|
||||
<h3 id="uncluttered-output">Uncluttered output</h3>
|
||||
<p>Print information only if it is needed.</p>
|
||||
<p>Too verbose tests which print all information even if they pass are very bad practice. They just pollute output, so it becomes harder to find useful information. In order not print information till it is really needed, one should consider saving it to a temporary buffer and pass to an assert. <a href="https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/shared/test_memset_with_concurrent_readers.cpp" class="uri">https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/shared/test_memset_with_concurrent_readers.cpp</a> has a good example how to do that.</p>
|
||||
<h3 id="failures-propagation">Failures propagation</h3>
|
||||
<p>Wrap a subroutine call into <code>EXPECT_NO_FATAL_FAILURE</code> macro to propagate failures.</p>
|
||||
<p><code>ASSERT</code> and <code>FAIL</code> abort only the current function, so if you have them in a subroutine, a test will not be aborted after the subroutine even if <code>ASSERT</code> or <code>FAIL</code> fails. You should call such subroutines in <code>ASSERT_NO_FATAL_FAILURE</code> macro to propagate fatal failures and abort a test. <code>(EXPECT|ASSERT)_NO_FATAL_FAILURE</code> can also be used to provide more information.</p>
|
||||
<p>Due to obvious reasons, there are no <code>(EXPECT|ASSERT)_NO_NONFATAL_FAILURE</code> macros. However, if you need to check if a subroutine generated a nonfatal failure (failed an <code>EXPECT</code>), you can use <code>::testing::Test::HasNonfatalFailure</code> function, or <code>::testing::Test::HasFailure</code> function to check if a subroutine generated any failures, see <a href="#several-checks">Several checks</a>.</p>
|
||||
<h2 id="naming-and-grouping">Naming and Grouping</h2>
|
||||
<h3 id="test-group-names">Test group names</h3>
|
||||
<p>Test group names should be in CamelCase, start and end with a letter. A test group should be named after tested class, functionality, subsystem, etc.</p>
|
||||
<p>This naming scheme helps to find tests, filter them and simplifies test failure analysis. For example, class <code>Foo</code> - test group <code>Foo</code>, compiler logging subsystem - test group <code>CompilerLogging</code>, G1 GC — test group <code>G1GC</code>, and so forth.</p>
|
||||
<h3 id="filename">Filename</h3>
|
||||
<p>A test file must have <code>test_</code> prefix and <code>.cpp</code> suffix.</p>
|
||||
<p>Both are actually requirements from the current build system to recognize your tests.</p>
|
||||
<h3 id="file-location">File location</h3>
|
||||
<p>Test file location should reflect a location of the tested part of the product.</p>
|
||||
<ul>
|
||||
<li><p>All unit tests for a class from <code>foo/bar/baz.cpp</code> should be placed <code>foo/bar/test_baz.cpp</code> in <code>hotspot/test/native/</code> directory. Having all tests for a class in one file is a common practice for unit tests, it helps to see all existing tests at once, share functions and/or resources without losing encapsulation.</p></li>
|
||||
<li><p>For tests which test more than one class, directory hierarchy should be the same as product hierarchy, and file name should reflect the name of the tested subsystem/functionality. For example, if a sub-system under tests belongs to <code>gc/g1</code>, tests should be placed in <code>gc/g1</code> directory.</p></li>
|
||||
</ul>
|
||||
<p>Please note that framework prepends directory name to a test group name. For example, if <code>TEST(foo, check_this)</code> and <code>TEST(bar, check_that)</code> are defined in <code>hotspot/test/native/gc/shared/test_foo.cpp</code> file, they will be reported as <code>gc/shared/foo::check_this</code> and <code>gc/shared/bar::check_that</code>.</p>
|
||||
<h3 id="test-names">Test names</h3>
|
||||
<p>Test names should be in small_snake_case, start and end with a letter. A test name should reflect that a test checks.</p>
|
||||
<p>Such naming makes tests self-descriptive and helps a lot during the whole test life cycle. It is easy to do test planning, test inventory, to see what things are not tested, to review tests, to analyze test failures, to evolve a test, etc. For example <code>foo_return_0_if_name_is_null</code> is better than <code>foo_sanity</code> or <code>foo_basic</code> or just <code>foo</code>, <code>humongous_objects_can_not_be_moved_by_young_gc</code> is better than <code>ho_young_gc</code>.</p>
|
||||
<p>Actually using underscore is against GoogleTest project convention, because it can lead to illegal identifiers, however, this is too strict. Restricting usage of underscore for test names only and prohibiting test name starts or ends with an underscore are enough to be safe.</p>
|
||||
<h3 id="fixture-classes">Fixture classes</h3>
|
||||
<p>Fixture classes should be named after tested classes, subsystems, etc (follow <a href="#test-group-names">Test group names rule</a>) and have <code>Test</code> suffix to prevent class name conflicts.</p>
|
||||
<h3 id="friend-classes">Friend classes</h3>
|
||||
<p>All test purpose friends should have either <code>Test</code> or <code>Testable</code> suffix.</p>
|
||||
<p>It greatly simplifies understanding of friendship’s purpose and allows statically check that private members are not exposed unexpectedly. Having <code>FooTest</code> as a friend of <code>Foo</code> without any comments will be understood as a necessary evil to get testability.</p>
|
||||
<h3 id="oscpu-specific-tests">OS/CPU specific tests</h3>
|
||||
<p>Guard OS/CPU specific tests by <code>#ifdef</code> and have OS/CPU name in filename.</p>
|
||||
<p>For the time being, we do not support separate directories for OS, CPU, OS-CPU specific tests, in case we will have lots of such tests, we will change directory layout and build system to support that in the same way it is done in hotspot.</p>
|
||||
<h2 id="miscellaneous">Miscellaneous</h2>
|
||||
<h3 id="hotspot-style">Hotspot style</h3>
|
||||
<p>Abide the norms and rules accepted in Hotspot style guide.</p>
|
||||
<p>Tests are a part of Hotspot, so everything (if applicable) we use for Hotspot, should be used for tests as well. Those guidelines cover test-specific things.</p>
|
||||
<h3 id="codetest-metrics">Code/test metrics</h3>
|
||||
<p>Coverage information and other code/test metrics are quite useful to decide what tests should be written, what tests should be improved and what can be removed.</p>
|
||||
<p>For unit tests, widely used and well-known coverage metric is branch coverage, which provides good quality of tests with relatively easy test development process. For other levels of testing, branch coverage is not as good, and one should consider others metrics, e.g. transaction flow coverage, data flow coverage.</p>
|
||||
<h3 id="access-to-non-public-members">Access to non-public members</h3>
|
||||
<p>Use explicit friend class to get access to non-public members.</p>
|
||||
<p>We do not use GoogleTest macro to declare friendship relation, because, from our point of view, it is less clear than an explicit declaration.</p>
|
||||
<p>Declaring a test fixture class as a friend class of a tested test is the easiest and the clearest way to get access. However, it has some disadvantages, here is some of them:</p>
|
||||
<ul>
|
||||
<li>Each test has to be declared as a friend</li>
|
||||
<li>Subclasses do not inheritance friendship relation</li>
|
||||
</ul>
|
||||
<p>In other words, it is harder to share code between tests. Hence if you want to share code or expect it to be useful in other tests, you should consider making members in a tested class protected and introduce a shared test-only class which expose those members via public functions, or even making members publicly accessible right away in a product class. If it is not an option to change members visibility, one can create a friend class which exposes members.</p>
|
||||
<h3 id="death-tests">Death tests</h3>
|
||||
<p>You can not use death tests inside <code>TEST_OTHER_VM</code> and <code>TEST_VM_ASSERT*</code>.</p>
|
||||
<p>We tried to make Hotspot-GoogleTest integration as transparent as possible, however, due to the current implementation of <code>TEST_OTHER_VM</code> and <code>TEST_VM_ASSERT*</code> tests, you cannot use death test functionality in them. These tests are implemented as GoogleTest death tests, and GoogleTest does not allow to have a death test inside another death test.</p>
|
||||
<h3 id="external-flags">External flags</h3>
|
||||
<p>Passing external flags to a tested JVM is not supported.</p>
|
||||
<p>The rationality of such design decision is to simplify both tests and a test framework and to avoid failures related to incompatible flags combination till there is a good solution for that. However there are cases when one wants to test a JVM with specific flags combination, <code>_JAVA_OPTIONS</code> environment variable can be used to do that. Flags from <code>_JAVA_OPTIONS</code> will be used in <code>TEST_VM</code>, <code>TEST_OTHER_VM</code> and <code>TEST_VM_ASSERT*</code> tests.</p>
|
||||
<h3 id="test-specific-flags">Test-specific flags</h3>
|
||||
<p>Passing flags to a tested JVM in <code>TEST_OTHER_VM</code> and <code>TEST_VM_ASSERT*</code> should be possible, but is not implemented yet.</p>
|
||||
<p>Facility to pass test-specific flags is needed for system, regression or other types of tests which require a fully initialized JVM in some particular configuration, e.g. with Serial GC selected. There is no support for such tests now, however, there is a plan to add that in upcoming releases.</p>
|
||||
<p>For now, if a test depends on flags values, it should have <code>if (!<flag>) { return }</code> guards in the very beginning and <code>@requires</code> comment similar to jtreg <code>@requires</code> directive right before test macros. <a href="https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp" class="uri">https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp</a> ha an example of this temporary workaround. It is important to follow that pattern as it allows us to easily find all such tests and update them as soon as there is an implementation of flag passing facility.</p>
|
||||
<p>In long-term, we expect jtreg to support GoogleTest tests as first class citizens, that is to say, jtreg will parse <span class="citation" data-cites="requires">@requires</span> comments and filter out inapplicable tests.</p>
|
||||
<h3 id="flag-restoring">Flag restoring</h3>
|
||||
<p>Restore changed flags.</p>
|
||||
<p>It is quite common for tests to configure JVM in a certain way changing flags’ values. GoogleTest provides two ways to set up environment before a test and restore it afterward: using either constructor and destructor or <code>SetUp</code> and <code>TearDown</code> functions. Both ways require to use a test fixture class, which sometimes is too wordy. The simpler facilities like <code>FLAG_GUARD</code> macro or <code>*FlagSetting</code> classes could be used in such cases to restore/set values.</p>
|
||||
<p>Caveats:</p>
|
||||
<ul>
|
||||
<li><p>Changing a flag’s value could break the invariants between flags' values and hence could lead to unexpected/unsupported JVM state.</p></li>
|
||||
<li><p><code>FLAG_SET_*</code> macros can change more than one flag (in order to maintain invariants) so it is hard to predict what flags will be changed and it makes restoring all changed flags a nontrivial task. Thus in case one uses <code>FLAG_SET_*</code> macros, they should use <code>TEST_OTHER_VM</code> test type.</p></li>
|
||||
</ul>
|
||||
<h3 id="googletest-documentation">GoogleTest documentation</h3>
|
||||
<p>In case you have any questions regarding GoogleTest itself, its asserts, test declaration macros, other macros, etc, please consult its documentation.</p>
|
||||
<h2 id="todo">TODO</h2>
|
||||
<p>Although this document provides guidelines on the most important parts of test development using GTest, it still misses a few items:</p>
|
||||
<ul>
|
||||
<li><p>Examples, esp for <a href="#access-to-non-public-members">access to non-public members</a></p></li>
|
||||
<li>test types: purpose, drawbacks, limitation
|
||||
<ul>
|
||||
<li><code>TEST_VM</code></li>
|
||||
<li><code>TEST_VM_F</code></li>
|
||||
<li><code>TEST_OTHER_VM</code></li>
|
||||
<li><code>TEST_VM_ASSERT</code></li>
|
||||
<li><code>TEST_VM_ASSERT_MSG</code></li>
|
||||
</ul></li>
|
||||
<li>Miscellaneous
|
||||
<ul>
|
||||
<li>Test libraries
|
||||
<ul>
|
||||
<li>where to place</li>
|
||||
<li>how to write</li>
|
||||
<li>how to use</li>
|
||||
</ul></li>
|
||||
<li>test your tests
|
||||
<ul>
|
||||
<li>how to run tests in random order</li>
|
||||
<li>how to run only specific tests</li>
|
||||
<li>how to run each test separately</li>
|
||||
<li>check that a test can find bugs it is supposed to by introducing them</li>
|
||||
</ul></li>
|
||||
<li>mocks/stubs/dependency injection</li>
|
||||
<li>setUp/tearDown
|
||||
<ul>
|
||||
<li>vs c-tor/d-tor</li>
|
||||
<li>empty test to test them</li>
|
||||
</ul></li>
|
||||
<li>internal (declared in .cpp) struct/classes</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
451
doc/hotspot-unit-tests.md
Normal file
451
doc/hotspot-unit-tests.md
Normal file
@@ -0,0 +1,451 @@
|
||||
% Native/Unit Test Development Guidelines
|
||||
|
||||
The purpose of these guidelines is to establish a shared vision on
|
||||
what kind of native tests and how we want to develop them for Hotspot
|
||||
using GoogleTest. Hence these guidelines include style items as well
|
||||
as test approach items.
|
||||
|
||||
First section of this document describes properties of good tests
|
||||
which are common for almost all types of test regardless of language,
|
||||
framework, etc. Further sections provide recommendations to achieve
|
||||
those properties and other HotSpot and/or GoogleTest specific
|
||||
guidelines.
|
||||
|
||||
## Good test properties
|
||||
|
||||
### Lightness
|
||||
|
||||
Use the most lightweight type of tests.
|
||||
|
||||
In Hotspot, there are 3 different types of tests regarding their
|
||||
dependency on a JVM, each next level is slower than previous
|
||||
|
||||
* `TEST` : a test does not depend on a JVM
|
||||
|
||||
* `TEST_VM` : a test does depend on an initialized JVM, but are
|
||||
supposed not to break a JVM, i.e. leave it in a workable state.
|
||||
|
||||
* `TEST_OTHER_VM` : a test depends on a JVM and requires a freshly
|
||||
initialized JVM or leaves a JVM in non-workable state
|
||||
|
||||
### Isolation
|
||||
|
||||
Tests have to be isolated: not to have visible side-effects,
|
||||
influences on other tests results.
|
||||
|
||||
Results of one test should not depend on test execution order, other
|
||||
tests, otherwise it is becoming almost impossible to find out why a
|
||||
test failed. Due to hotspot-specific, it is not so easy to get a full
|
||||
isolation, e.g. we share an initialized JVM between all `TEST_VM` tests,
|
||||
so if your test changes JVM's state too drastically and does not
|
||||
change it back, you had better consider `TEST_OTHER_VM`.
|
||||
|
||||
### Atomicity and self-containment
|
||||
|
||||
Tests should be *atomic* and *self-contained* at the same time.
|
||||
|
||||
One test should check a particular part of a class, subsystem,
|
||||
functionality, etc. Then it is quite easy to determine what parts of a
|
||||
product are broken basing on test failures. On the other hand, a test
|
||||
should test that part more-or-less entirely, because when one sees a
|
||||
test `FooTest::bar`, they assume all aspects of bar from `Foo` are tested.
|
||||
|
||||
However, it is impossible to cover all aspects even of a method, not
|
||||
to mention a subsystem. In such cases, it is recommended to have
|
||||
several tests, one for each aspect of a thing under test. For example
|
||||
one test to tests how `Foo::bar` works if an argument is `null`, another
|
||||
test to test how it works if an argument is acceptable but `Foo` is not
|
||||
in the right state to accept it and so on. This helps not only to make
|
||||
tests atomic, self-contained but also makes test name self-descriptive
|
||||
(discussed in more details in [Test names](#test-names)).
|
||||
|
||||
### Repeatability
|
||||
|
||||
Tests have to be repeatable.
|
||||
|
||||
Reproducibility is very crucial for a test. No one likes sporadic test
|
||||
failures, they are hard to investigate, fix and verify a fix.
|
||||
|
||||
In some cases, it is quite hard to write a 100% repeatable test, since
|
||||
besides a test there can be other moving parts, e.g. in case of
|
||||
`TEST_VM` there are several concurrently running threads. Despite this,
|
||||
we should try to make a test as reproducible as possible.
|
||||
|
||||
### Informativeness
|
||||
|
||||
In case of a failure, a test should be as *informative* as possible.
|
||||
|
||||
Having more information about a test failure than just compared values
|
||||
can be very useful for failure troubleshooting, it can reduce or even
|
||||
completely eliminate debugging hours. This is even more important in
|
||||
case of not 100% reproducible failures.
|
||||
|
||||
Achieving this property, one can easily make a test too verbose, so it
|
||||
will be really hard to find useful information in the ocean of useless
|
||||
information. Hence they should not only think about how to provide
|
||||
[good information](#error-messages), but also
|
||||
[when to do it](#uncluttered-output).
|
||||
|
||||
### Testing instead of visiting
|
||||
|
||||
Tests should *test*.
|
||||
|
||||
It is not enough just to "visit" some code, a test should check that
|
||||
code does that it has to do, compare return values with expected
|
||||
values, check that desired side effects are done, and undesired are
|
||||
not, and so on. In other words, a test should contain at least one
|
||||
GoogleTest assertion and do not rely on JVM asserts.
|
||||
|
||||
Generally speaking to write a good test, one should create a model of
|
||||
the system under tests, a model of possible bugs (or bugs which one
|
||||
wants to find) and design tests using those models.
|
||||
|
||||
### Nearness
|
||||
|
||||
Prefer having checks inside test code.
|
||||
|
||||
Not only does having test logic outside, e.g. verification method,
|
||||
depending on asserts in product code contradict with several items
|
||||
above but also decreases test’s readability and stability. It is much
|
||||
easier to understand that a test is testing when all testing logic is
|
||||
located inside a test or nearby in shared test libraries. As a rule of
|
||||
thumb, the closer a check to a test, the better.
|
||||
|
||||
## Asserts
|
||||
|
||||
### Several checks
|
||||
|
||||
Prefer `EXPECT` over `ASSERT` if possible.
|
||||
|
||||
This is related to the [informativeness](#informativeness) property of
|
||||
tests, information for other checks can help to better localize a
|
||||
defect’s root-cause. One should use `ASSERT` if it is impossible to
|
||||
continue test execution or if it does not make much sense. Later in
|
||||
the text, `EXPECT` forms will be used to refer to both
|
||||
`ASSERT/EXPECT`.
|
||||
|
||||
When it is possible to make several different checks, but impossible
|
||||
to continue test execution if at least one check fails, you can
|
||||
use `::testing::Test::HasNonfatalFailure()` function. The recommended
|
||||
way to express that is
|
||||
`ASSERT_FALSE(::testing::Test::HasNonfatalFailure())`. Besides making it
|
||||
clear why a test is aborted, it also allows you to provide more
|
||||
information about a failure.
|
||||
|
||||
### First parameter is expected value
|
||||
|
||||
In all equality assertions, expected values should be passed as the
|
||||
first parameter.
|
||||
|
||||
This convention is adopted by GoogleTest, and there is a slight
|
||||
difference in how GoogleTest treats parameters, the most important one
|
||||
is `null` detection. Due to different reasons, `null` detection is enabled
|
||||
only for the first parameter, that is to said `EXPECT_EQ(NULL, object)`
|
||||
checks that object is `null`, while `EXPECT_EQ(object, NULL)` checks that
|
||||
object equals to `NULL`, GoogleTest is very strict regarding types of
|
||||
compared values so the latter will generates a compile-time error.
|
||||
|
||||
### Floating-point comparison
|
||||
|
||||
Use floating-point special macros to compare `float/double` values.
|
||||
|
||||
Because of floating-point number representations and round-off errors,
|
||||
regular equality comparison will not return true in most cases. There
|
||||
are special `EXPECT_FLOAT_EQ/EXPECT_DOUBLE_EQ` assertions which check
|
||||
that the distance between compared values is not more than 4 ULPs,
|
||||
there is also `EXPECT_NEAR(v1, v2, eps)` which checks that the absolute
|
||||
value of the difference between `v1` and `v2` is not greater than `eps`.
|
||||
|
||||
### C string comparison
|
||||
|
||||
Use string special macros for C strings comparisons.
|
||||
|
||||
`EXPECT_EQ` just compares pointers’ values, which is hardly what one
|
||||
wants comparing C strings. GoogleTest provides `EXPECT_STREQ` and
|
||||
`EXPECT_STRNE` macros to compare C string contents. There are also
|
||||
case-insensitive versions `EXPECT_STRCASEEQ`, `EXPECT_STRCASENE`.
|
||||
|
||||
### Error messages
|
||||
|
||||
Provide informative, but not too verbose error messages.
|
||||
|
||||
All GoogleTest asserts print compared expressions and their values, so
|
||||
there is no need to have them in error messages. Asserts print only
|
||||
compared values, they do not print any of interim variables, e.g.
|
||||
`ASSERT_TRUE((val1 == val2 && isFail(foo(8)) || i == 18)` prints only
|
||||
one value. If you use some complex predicates, please consider
|
||||
`EXPECT_PRED*` or `EXPECT_FORMAT_PRED` assertions family, they check that
|
||||
a predicate returns true/success and print out all parameters values.
|
||||
|
||||
However in some cases, default information is not enough, a commonly
|
||||
used example is an assert inside a loop, GoogleTest will not print
|
||||
iteration values (unless it is an assert's parameter). Other
|
||||
demonstrative examples are printing error code and a corresponding
|
||||
error message; printing internal states which might have an impact on
|
||||
results. One should add this information to assert message using `<<`
|
||||
operator.
|
||||
|
||||
### Uncluttered output
|
||||
|
||||
Print information only if it is needed.
|
||||
|
||||
Too verbose tests which print all information even if they pass are
|
||||
very bad practice. They just pollute output, so it becomes harder to
|
||||
find useful information. In order not print information till it is
|
||||
really needed, one should consider saving it to a temporary buffer and
|
||||
pass to an assert.
|
||||
<https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/shared/test_memset_with_concurrent_readers.cpp>
|
||||
has a good example how to do that.
|
||||
|
||||
### Failures propagation
|
||||
|
||||
Wrap a subroutine call into `EXPECT_NO_FATAL_FAILURE` macro to
|
||||
propagate failures.
|
||||
|
||||
`ASSERT` and `FAIL` abort only the current function, so if you have them
|
||||
in a subroutine, a test will not be aborted after the subroutine even
|
||||
if `ASSERT` or `FAIL` fails. You should call such subroutines in
|
||||
`ASSERT_NO_FATAL_FAILURE` macro to propagate fatal failures and abort a
|
||||
test. `(EXPECT|ASSERT)_NO_FATAL_FAILURE` can also be used to provide
|
||||
more information.
|
||||
|
||||
Due to obvious reasons, there are no
|
||||
`(EXPECT|ASSERT)_NO_NONFATAL_FAILURE` macros. However, if you need to
|
||||
check if a subroutine generated a nonfatal failure (failed an `EXPECT`),
|
||||
you can use `::testing::Test::HasNonfatalFailure` function,
|
||||
or `::testing::Test::HasFailure` function to check if a subroutine
|
||||
generated any failures, see [Several checks](#several-checks).
|
||||
|
||||
## Naming and Grouping
|
||||
|
||||
### Test group names
|
||||
|
||||
Test group names should be in CamelCase, start and end with a letter.
|
||||
A test group should be named after tested class, functionality,
|
||||
subsystem, etc.
|
||||
|
||||
This naming scheme helps to find tests, filter them and simplifies
|
||||
test failure analysis. For example, class `Foo` - test group `Foo`,
|
||||
compiler logging subsystem - test group `CompilerLogging`, G1 GC — test
|
||||
group `G1GC`, and so forth.
|
||||
|
||||
### Filename
|
||||
|
||||
A test file must have `test_` prefix and `.cpp` suffix.
|
||||
|
||||
Both are actually requirements from the current build system to
|
||||
recognize your tests.
|
||||
|
||||
### File location
|
||||
|
||||
Test file location should reflect a location of the tested part of the product.
|
||||
|
||||
* All unit tests for a class from `foo/bar/baz.cpp` should be placed
|
||||
`foo/bar/test_baz.cpp` in `hotspot/test/native/` directory. Having all
|
||||
tests for a class in one file is a common practice for unit tests, it
|
||||
helps to see all existing tests at once, share functions and/or
|
||||
resources without losing encapsulation.
|
||||
|
||||
* For tests which test more than one class, directory hierarchy should
|
||||
be the same as product hierarchy, and file name should reflect the
|
||||
name of the tested subsystem/functionality. For example, if a
|
||||
sub-system under tests belongs to `gc/g1`, tests should be placed in
|
||||
`gc/g1` directory.
|
||||
|
||||
Please note that framework prepends directory name to a test group
|
||||
name. For example, if `TEST(foo, check_this)` and `TEST(bar, check_that)`
|
||||
are defined in `hotspot/test/native/gc/shared/test_foo.cpp` file, they
|
||||
will be reported as `gc/shared/foo::check_this` and
|
||||
`gc/shared/bar::check_that`.
|
||||
|
||||
### Test names
|
||||
|
||||
Test names should be in small_snake_case, start and end with a letter.
|
||||
A test name should reflect that a test checks.
|
||||
|
||||
Such naming makes tests self-descriptive and helps a lot during the
|
||||
whole test life cycle. It is easy to do test planning, test inventory,
|
||||
to see what things are not tested, to review tests, to analyze test
|
||||
failures, to evolve a test, etc. For example
|
||||
`foo_return_0_if_name_is_null` is better than `foo_sanity` or `foo_basic` or
|
||||
just `foo`, `humongous_objects_can_not_be_moved_by_young_gc` is better
|
||||
than `ho_young_gc`.
|
||||
|
||||
Actually using underscore is against GoogleTest project convention,
|
||||
because it can lead to illegal identifiers, however, this is too
|
||||
strict. Restricting usage of underscore for test names only and
|
||||
prohibiting test name starts or ends with an underscore are enough to
|
||||
be safe.
|
||||
|
||||
### Fixture classes
|
||||
|
||||
Fixture classes should be named after tested classes, subsystems, etc
|
||||
(follow [Test group names rule](#test-group-names)) and have
|
||||
`Test` suffix to prevent class name conflicts.
|
||||
|
||||
### Friend classes
|
||||
|
||||
All test purpose friends should have either `Test` or `Testable` suffix.
|
||||
|
||||
It greatly simplifies understanding of friendship’s purpose and allows
|
||||
statically check that private members are not exposed unexpectedly.
|
||||
Having `FooTest` as a friend of `Foo` without any comments will be
|
||||
understood as a necessary evil to get testability.
|
||||
|
||||
### OS/CPU specific tests
|
||||
|
||||
Guard OS/CPU specific tests by `#ifdef` and have OS/CPU name in filename.
|
||||
|
||||
For the time being, we do not support separate directories for OS,
|
||||
CPU, OS-CPU specific tests, in case we will have lots of such tests,
|
||||
we will change directory layout and build system to support that in
|
||||
the same way it is done in hotspot.
|
||||
|
||||
## Miscellaneous
|
||||
|
||||
### Hotspot style
|
||||
|
||||
Abide the norms and rules accepted in Hotspot style guide.
|
||||
|
||||
Tests are a part of Hotspot, so everything (if applicable) we use for
|
||||
Hotspot, should be used for tests as well. Those guidelines cover
|
||||
test-specific things.
|
||||
|
||||
### Code/test metrics
|
||||
|
||||
Coverage information and other code/test metrics are quite useful to
|
||||
decide what tests should be written, what tests should be improved and
|
||||
what can be removed.
|
||||
|
||||
For unit tests, widely used and well-known coverage metric is branch
|
||||
coverage, which provides good quality of tests with relatively easy
|
||||
test development process. For other levels of testing, branch coverage
|
||||
is not as good, and one should consider others metrics, e.g.
|
||||
transaction flow coverage, data flow coverage.
|
||||
|
||||
### Access to non-public members
|
||||
|
||||
Use explicit friend class to get access to non-public members.
|
||||
|
||||
We do not use GoogleTest macro to declare friendship relation,
|
||||
because, from our point of view, it is less clear than an explicit
|
||||
declaration.
|
||||
|
||||
Declaring a test fixture class as a friend class of a tested test is
|
||||
the easiest and the clearest way to get access. However, it has some
|
||||
disadvantages, here is some of them:
|
||||
|
||||
* Each test has to be declared as a friend
|
||||
* Subclasses do not inheritance friendship relation
|
||||
|
||||
In other words, it is harder to share code between tests. Hence if you
|
||||
want to share code or expect it to be useful in other tests, you
|
||||
should consider making members in a tested class protected and
|
||||
introduce a shared test-only class which expose those members via
|
||||
public functions, or even making members publicly accessible right
|
||||
away in a product class. If it is not an option to change members
|
||||
visibility, one can create a friend class which exposes members.
|
||||
|
||||
### Death tests
|
||||
|
||||
You can not use death tests inside `TEST_OTHER_VM` and `TEST_VM_ASSERT*`.
|
||||
|
||||
We tried to make Hotspot-GoogleTest integration as transparent as
|
||||
possible, however, due to the current implementation of `TEST_OTHER_VM`
|
||||
and `TEST_VM_ASSERT*` tests, you cannot use death test functionality in
|
||||
them. These tests are implemented as GoogleTest death tests, and
|
||||
GoogleTest does not allow to have a death test inside another death
|
||||
test.
|
||||
|
||||
### External flags
|
||||
|
||||
Passing external flags to a tested JVM is not supported.
|
||||
|
||||
The rationality of such design decision is to simplify both tests and
|
||||
a test framework and to avoid failures related to incompatible flags
|
||||
combination till there is a good solution for that. However there are
|
||||
cases when one wants to test a JVM with specific flags combination,
|
||||
`_JAVA_OPTIONS` environment variable can be used to do that. Flags from
|
||||
`_JAVA_OPTIONS` will be used in `TEST_VM`, `TEST_OTHER_VM` and
|
||||
`TEST_VM_ASSERT*` tests.
|
||||
|
||||
### Test-specific flags
|
||||
|
||||
Passing flags to a tested JVM in `TEST_OTHER_VM` and `TEST_VM_ASSERT*`
|
||||
should be possible, but is not implemented yet.
|
||||
|
||||
Facility to pass test-specific flags is needed for system, regression
|
||||
or other types of tests which require a fully initialized JVM in some
|
||||
particular configuration, e.g. with Serial GC selected. There is no
|
||||
support for such tests now, however, there is a plan to add that in
|
||||
upcoming releases.
|
||||
|
||||
For now, if a test depends on flags values, it should have `if
|
||||
(!<flag>) { return }` guards in the very beginning and `@requires`
|
||||
comment similar to jtreg `@requires` directive right before test macros.
|
||||
<https://hg.openjdk.java.net/jdk/jdk/file/tip/test/hotspot/gtest/gc/g1/test_g1IHOPControl.cpp>
|
||||
ha an example of this temporary workaround. It is important to follow
|
||||
that pattern as it allows us to easily find all such tests and update
|
||||
them as soon as there is an implementation of flag passing facility.
|
||||
|
||||
In long-term, we expect jtreg to support GoogleTest tests as first
|
||||
class citizens, that is to say, jtreg will parse @requires comments
|
||||
and filter out inapplicable tests.
|
||||
|
||||
### Flag restoring
|
||||
|
||||
Restore changed flags.
|
||||
|
||||
It is quite common for tests to configure JVM in a certain way
|
||||
changing flags’ values. GoogleTest provides two ways to set up
|
||||
environment before a test and restore it afterward: using either
|
||||
constructor and destructor or `SetUp` and `TearDown` functions. Both ways
|
||||
require to use a test fixture class, which sometimes is too wordy. The
|
||||
simpler facilities like `FLAG_GUARD` macro or `*FlagSetting` classes could
|
||||
be used in such cases to restore/set values.
|
||||
|
||||
Caveats:
|
||||
|
||||
* Changing a flag’s value could break the invariants between flags' values and hence could lead to unexpected/unsupported JVM state.
|
||||
|
||||
* `FLAG_SET_*` macros can change more than one flag (in order to
|
||||
maintain invariants) so it is hard to predict what flags will be
|
||||
changed and it makes restoring all changed flags a nontrivial task.
|
||||
Thus in case one uses `FLAG_SET_*` macros, they should use `TEST_OTHER_VM`
|
||||
test type.
|
||||
|
||||
### GoogleTest documentation
|
||||
|
||||
In case you have any questions regarding GoogleTest itself, its
|
||||
asserts, test declaration macros, other macros, etc, please consult
|
||||
its documentation.
|
||||
|
||||
## TODO
|
||||
|
||||
Although this document provides guidelines on the most important parts
|
||||
of test development using GTest, it still misses a few items:
|
||||
|
||||
* Examples, esp for [access to non-public members](#access-to-non-public-members)
|
||||
|
||||
* test types: purpose, drawbacks, limitation
|
||||
* `TEST_VM`
|
||||
* `TEST_VM_F`
|
||||
* `TEST_OTHER_VM`
|
||||
* `TEST_VM_ASSERT`
|
||||
* `TEST_VM_ASSERT_MSG`
|
||||
|
||||
* Miscellaneous
|
||||
* Test libraries
|
||||
* where to place
|
||||
* how to write
|
||||
* how to use
|
||||
* test your tests
|
||||
* how to run tests in random order
|
||||
* how to run only specific tests
|
||||
* how to run each test separately
|
||||
* check that a test can find bugs it is supposed to by introducing them
|
||||
* mocks/stubs/dependency injection
|
||||
* setUp/tearDown
|
||||
* vs c-tor/d-tor
|
||||
* empty test to test them
|
||||
* internal (declared in .cpp) struct/classes
|
||||
@@ -242,16 +242,6 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
|
||||
)
|
||||
|
||||
JDK_SYMBOLS_BUNDLE_FILES := \
|
||||
$(filter \
|
||||
$(JDK_SYMBOLS_EXCLUDE_PATTERN) \
|
||||
$(SYMBOLS_EXCLUDE_PATTERN) \
|
||||
, \
|
||||
$(filter-out \
|
||||
$(JDK_IMAGE_HOMEDIR)/demo/% %.stripped.pdb \
|
||||
, \
|
||||
$(ALL_JDK_SYMBOLS_FILES) \
|
||||
) \
|
||||
) \
|
||||
$(call FindFiles, $(SYMBOLS_IMAGE_DIR))
|
||||
|
||||
TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_DEMOS_IMAGE_HOMEDIR)/demo/%, \
|
||||
@@ -383,7 +373,7 @@ ifneq ($(filter product-bundles% legacy-bundles, $(MAKECMDGOALS)), )
|
||||
$(eval $(call SetupBundleFile, BUILD_JDK_SYMBOLS_BUNDLE, \
|
||||
BUNDLE_NAME := $(JDK_SYMBOLS_BUNDLE_NAME), \
|
||||
FILES := $(JDK_SYMBOLS_BUNDLE_FILES), \
|
||||
BASE_DIRS := $(JDK_SYMBOLS_IMAGE_DIR) $(wildcard $(SYMBOLS_IMAGE_DIR)), \
|
||||
BASE_DIRS := $(SYMBOLS_IMAGE_DIR), \
|
||||
SUBDIR := $(JDK_BUNDLE_SUBDIR), \
|
||||
UNZIP_DEBUGINFO := true, \
|
||||
))
|
||||
|
||||
@@ -76,6 +76,7 @@ java.datatransfer_COPY += flavormap.properties
|
||||
|
||||
################################################################################
|
||||
|
||||
java.desktop_DISABLED_WARNINGS += missing-explicit-ctor
|
||||
java.desktop_DOCLINT += -Xdoclint:all/protected,-reference \
|
||||
'-Xdoclint/package:java.*,javax.*'
|
||||
java.desktop_COPY += .gif .png .wav .txt .xml .css .pf
|
||||
@@ -298,6 +299,10 @@ java.xml.crypto_CLEAN += .properties
|
||||
|
||||
################################################################################
|
||||
|
||||
jdk.accessibility_DISABLED_WARNINGS += missing-explicit-ctor
|
||||
|
||||
################################################################################
|
||||
|
||||
jdk.charsets_COPY += .dat
|
||||
|
||||
################################################################################
|
||||
@@ -347,10 +352,19 @@ jdk.javadoc_COPY += .xml .css .js .png
|
||||
|
||||
################################################################################
|
||||
|
||||
jdk.jartool_DISABLED_WARNINGS += missing-explicit-ctor
|
||||
jdk.jartool_JAVAC_FLAGS += -XDstringConcat=inline
|
||||
|
||||
################################################################################
|
||||
|
||||
jdk.httpserver_DISABLED_WARNINGS += missing-explicit-ctor
|
||||
|
||||
################################################################################
|
||||
|
||||
jdk.unsupported.desktop_DISABLED_WARNINGS += missing-explicit-ctor
|
||||
|
||||
################################################################################
|
||||
|
||||
# No SCTP implementation on Mac OS X or AIX. These classes should be excluded.
|
||||
SCTP_IMPL_CLASSES = \
|
||||
$(TOPDIR)/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/AssociationChange.java \
|
||||
|
||||
@@ -298,6 +298,8 @@ define SetupApiDocsGenerationBody
|
||||
# Create a string like "-Xdoclint:all,-syntax,-html,..."
|
||||
$1_OPTIONS += -Xdoclint:all,$$(call CommaList, $$(addprefix -, \
|
||||
$$(JAVADOC_DISABLED_DOCLINT)))
|
||||
# Ignore the doclint warnings in the W3C DOM package
|
||||
$1_OPTIONS += -Xdoclint/package:-org.w3c.*
|
||||
|
||||
$1_DOC_TITLE := $$($1_LONG_NAME)<br>Version $$(VERSION_SPECIFICATION) API \
|
||||
Specification
|
||||
|
||||
@@ -238,6 +238,7 @@ endif
|
||||
ALL_JDK_MODULES := $(JDK_MODULES)
|
||||
ALL_JRE_MODULES := $(sort $(JRE_MODULES), $(foreach m, $(JRE_MODULES), \
|
||||
$(call FindTransitiveDepsForModule, $m)))
|
||||
ALL_SYMBOLS_MODULES := $(JDK_MODULES)
|
||||
|
||||
ifeq ($(call isTargetOs, windows), true)
|
||||
LIBS_TARGET_SUBDIR := bin
|
||||
@@ -293,6 +294,7 @@ SetupCopyDebuginfo = \
|
||||
# implementation above.
|
||||
$(call SetupCopyDebuginfo,JDK)
|
||||
$(call SetupCopyDebuginfo,JRE)
|
||||
$(call SetupCopyDebuginfo,SYMBOLS)
|
||||
|
||||
################################################################################
|
||||
|
||||
|
||||
@@ -38,11 +38,8 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
|
||||
MACOSX_PLIST_SRC := $(TOPDIR)/make/data/bundle
|
||||
|
||||
BUNDLE_ID := $(MACOSX_BUNDLE_ID_BASE).$(VERSION_SHORT)
|
||||
BUNDLE_NAME := $(MACOSX_BUNDLE_NAME_BASE) $(VERSION_SHORT)
|
||||
BUNDLE_INFO := $(MACOSX_BUNDLE_NAME_BASE) $(VERSION_STRING)
|
||||
BUNDLE_PLATFORM_VERSION := $(VERSION_FEATURE).$(VERSION_INTERIM)
|
||||
BUNDLE_VERSION := $(VERSION_NUMBER)
|
||||
ifeq ($(COMPANY_NAME), N/A)
|
||||
BUNDLE_VENDOR := UNDEFINED
|
||||
else
|
||||
@@ -75,24 +72,26 @@ ifeq ($(call isTargetOs, macosx), true)
|
||||
SOURCE_FILES := $(MACOSX_PLIST_SRC)/JDK-Info.plist, \
|
||||
OUTPUT_FILE := $(JDK_MACOSX_CONTENTS_DIR)/Info.plist, \
|
||||
REPLACEMENTS := \
|
||||
@@ID@@ => $(BUNDLE_ID).jdk ; \
|
||||
@@ID@@ => $(MACOSX_BUNDLE_ID_BASE).jdk ; \
|
||||
@@NAME@@ => $(BUNDLE_NAME) ; \
|
||||
@@INFO@@ => $(BUNDLE_INFO) ; \
|
||||
@@PLATFORM_VERSION@@ => $(BUNDLE_PLATFORM_VERSION) ; \
|
||||
@@VERSION@@ => $(BUNDLE_VERSION) ; \
|
||||
@@VENDOR@@ => $(BUNDLE_VENDOR) , \
|
||||
@@VERSION@@ => $(VERSION_NUMBER) ; \
|
||||
@@BUILD_VERSION@@ => $(MACOSX_BUNDLE_BUILD_VERSION) ; \
|
||||
@@VENDOR@@ => $(BUNDLE_VENDOR) ; \
|
||||
@@MACOSX_VERSION_MIN@@ => $(MACOSX_VERSION_MIN) , \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTextFileProcessing, BUILD_JRE_PLIST, \
|
||||
SOURCE_FILES := $(MACOSX_PLIST_SRC)/JRE-Info.plist, \
|
||||
OUTPUT_FILE := $(JRE_MACOSX_CONTENTS_DIR)/Info.plist, \
|
||||
REPLACEMENTS := \
|
||||
@@ID@@ => $(BUNDLE_ID).jre ; \
|
||||
@@ID@@ => $(MACOSX_BUNDLE_ID_BASE).jre ; \
|
||||
@@NAME@@ => $(BUNDLE_NAME) ; \
|
||||
@@INFO@@ => $(BUNDLE_INFO) ; \
|
||||
@@PLATFORM_VERSION@@ => $(BUNDLE_PLATFORM_VERSION) ; \
|
||||
@@VERSION@@ => $(BUNDLE_VERSION) ; \
|
||||
@@VENDOR@@ => $(BUNDLE_VENDOR) , \
|
||||
@@VERSION@@ => $(VERSION_NUMBER) ; \
|
||||
@@BUILD_VERSION@@ => $(BUNDLE_BUILD_VERSION) ; \
|
||||
@@VENDOR@@ => $(BUNDLE_VENDOR) ; \
|
||||
@@MACOSX_VERSION_MIN@@ => $(MACOSX_VERSION_MIN) , \
|
||||
))
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/images/_jdk_bundle_attribute_set: $(COPY_JDK_IMAGE)
|
||||
|
||||
@@ -678,7 +678,7 @@ $(eval $(call SetupTarget, test-image-hotspot-jtreg-graal, \
|
||||
DEPS := build-test-hotspot-jtreg-graal, \
|
||||
))
|
||||
|
||||
ifneq ($GTEST_FRAMEWORK_SRC), )
|
||||
ifneq ($(GTEST_FRAMEWORK_SRC), )
|
||||
$(eval $(call SetupTarget, test-image-hotspot-gtest, \
|
||||
MAKEFILE := hotspot/test/GtestImage, \
|
||||
DEPS := hotspot, \
|
||||
|
||||
@@ -172,6 +172,10 @@ define SetupAotModuleBody
|
||||
$1_JAOTC_OPTS += --compile-with-assertions
|
||||
endif
|
||||
|
||||
ifneq ($$(filter -XX:+VerifyOops, $$($1_VM_OPTIONS)), )
|
||||
$1_JAOTC_OPTS += -J-Dgraal.AOTVerifyOops=true
|
||||
endif
|
||||
|
||||
$$($1_AOT_LIB): $$(JDK_UNDER_TEST)/release \
|
||||
$$(call DependOnVariable, $1_JAOTC_OPTS) \
|
||||
$$(call DependOnVariable, JDK_UNDER_TEST)
|
||||
|
||||
@@ -72,7 +72,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_FUNDAMENTAL_TOOLS],
|
||||
UTIL_REQUIRE_PROGS(UNAME, uname)
|
||||
UTIL_REQUIRE_PROGS(UNIQ, uniq)
|
||||
UTIL_REQUIRE_PROGS(WC, wc)
|
||||
UTIL_REQUIRE_PROGS(WHICH, which)
|
||||
UTIL_REQUIRE_PROGS(XARGS, xargs)
|
||||
|
||||
# Then required tools that require some special treatment.
|
||||
|
||||
12
make/autoconf/configure
vendored
12
make/autoconf/configure
vendored
@@ -78,11 +78,11 @@ generated_script="$build_support_dir/generated-configure.sh"
|
||||
###
|
||||
|
||||
autoconf_missing_help() {
|
||||
APT_GET="`which apt-get 2> /dev/null | grep -v '^no apt-get in'`"
|
||||
YUM="`which yum 2> /dev/null | grep -v '^no yum in'`"
|
||||
BREW="`which brew 2> /dev/null | grep -v '^no brew in'`"
|
||||
ZYPPER="`which zypper 2> /dev/null | grep -v '^no zypper in'`"
|
||||
CYGWIN="`which cygpath 2> /dev/null | grep -v '^no cygpath in'`"
|
||||
APT_GET="`type -p apt-get 2> /dev/null`"
|
||||
YUM="`type -p yum 2> /dev/null`"
|
||||
BREW="`type -p brew 2> /dev/null`"
|
||||
ZYPPER="`type -p zypper 2> /dev/null`"
|
||||
CYGWIN="`type -p cygpath 2> /dev/null`"
|
||||
|
||||
if test "x$ZYPPER" != x; then
|
||||
PKGHANDLER_COMMAND="sudo zypper install autoconf"
|
||||
@@ -111,7 +111,7 @@ generate_configure_script() {
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
AUTOCONF="`which autoconf 2> /dev/null | grep -v '^no autoconf in'`"
|
||||
AUTOCONF="`type -p autoconf 2> /dev/null`"
|
||||
if test "x$AUTOCONF" = x; then
|
||||
echo
|
||||
echo "Autoconf is not found on the PATH, and AUTOCONF is not set."
|
||||
|
||||
@@ -218,10 +218,12 @@ AC_DEFUN([FLAGS_SETUP_SYSROOT_FLAGS],
|
||||
# We also need -iframework<path>/System/Library/Frameworks
|
||||
$1SYSROOT_CFLAGS="[$]$1SYSROOT_CFLAGS -iframework [$]$1SYSROOT/System/Library/Frameworks"
|
||||
$1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS -iframework [$]$1SYSROOT/System/Library/Frameworks"
|
||||
# These always need to be set, or we can't find the frameworks embedded in JavaVM.framework
|
||||
# set this here so it doesn't have to be peppered throughout the forest
|
||||
$1SYSROOT_CFLAGS="[$]$1SYSROOT_CFLAGS -F [$]$1SYSROOT/System/Library/Frameworks/JavaVM.framework/Frameworks"
|
||||
$1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS -F [$]$1SYSROOT/System/Library/Frameworks/JavaVM.framework/Frameworks"
|
||||
if test -d "[$]$1SYSROOT/System/Library/Frameworks/JavaVM.framework/Frameworks" ; then
|
||||
# These always need to be set on macOS 10.X, or we can't find the frameworks embedded in JavaVM.framework
|
||||
# set this here so it doesn't have to be peppered throughout the forest
|
||||
$1SYSROOT_CFLAGS="[$]$1SYSROOT_CFLAGS -F [$]$1SYSROOT/System/Library/Frameworks/JavaVM.framework/Frameworks"
|
||||
$1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS -F [$]$1SYSROOT/System/Library/Frameworks/JavaVM.framework/Frameworks"
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST($1SYSROOT_CFLAGS)
|
||||
|
||||
@@ -101,6 +101,8 @@ apt_help() {
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libfontconfig1-dev" ;;
|
||||
freetype)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libfreetype6-dev" ;;
|
||||
harfbuzz)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libharfbuzz-dev" ;;
|
||||
ffi)
|
||||
PKGHANDLER_COMMAND="sudo apt-get install libffi-dev" ;;
|
||||
x11)
|
||||
@@ -124,6 +126,8 @@ zypper_help() {
|
||||
PKGHANDLER_COMMAND="sudo zypper install fontconfig-devel" ;;
|
||||
freetype)
|
||||
PKGHANDLER_COMMAND="sudo zypper install freetype-devel" ;;
|
||||
harfbuzz)
|
||||
PKGHANDLER_COMMAND="sudo zypper install harfbuzz-devel" ;;
|
||||
x11)
|
||||
PKGHANDLER_COMMAND="sudo zypper install libX11-devel libXext-devel libXrender-devel libXrandr-devel libXtst-devel libXt-devel libXi-devel" ;;
|
||||
ccache)
|
||||
@@ -143,6 +147,8 @@ yum_help() {
|
||||
PKGHANDLER_COMMAND="sudo yum install fontconfig-devel" ;;
|
||||
freetype)
|
||||
PKGHANDLER_COMMAND="sudo yum install freetype-devel" ;;
|
||||
harfbuzz)
|
||||
PKGHANDLER_COMMAND="sudo yum install harfbuzz-devel" ;;
|
||||
x11)
|
||||
PKGHANDLER_COMMAND="sudo yum install libXtst-devel libXt-devel libXrender-devel libXrandr-devel libXi-devel" ;;
|
||||
ccache)
|
||||
|
||||
@@ -67,34 +67,6 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
|
||||
AC_SUBST(JDK_RC_PLATFORM_NAME)
|
||||
AC_SUBST(HOTSPOT_VM_DISTRO)
|
||||
|
||||
# Set the MACOSX Bundle Name base
|
||||
AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base],
|
||||
[Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names.
|
||||
@<:@not specified@:>@])])
|
||||
if test "x$with_macosx_bundle_name_base" = xyes; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value])
|
||||
elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base])
|
||||
elif test "x$with_macosx_bundle_name_base" != x; then
|
||||
# Set MACOSX_BUNDLE_NAME_BASE to the configured value.
|
||||
MACOSX_BUNDLE_NAME_BASE="$with_macosx_bundle_name_base"
|
||||
fi
|
||||
AC_SUBST(MACOSX_BUNDLE_NAME_BASE)
|
||||
|
||||
# Set the MACOSX Bundle ID base
|
||||
AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base],
|
||||
[Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs.
|
||||
@<:@not specified@:>@])])
|
||||
if test "x$with_macosx_bundle_id_base" = xyes; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value])
|
||||
elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base])
|
||||
elif test "x$with_macosx_bundle_id_base" != x; then
|
||||
# Set MACOSX_BUNDLE_ID_BASE to the configured value.
|
||||
MACOSX_BUNDLE_ID_BASE="$with_macosx_bundle_id_base"
|
||||
fi
|
||||
AC_SUBST(MACOSX_BUNDLE_ID_BASE)
|
||||
|
||||
# Set the JDK RC name
|
||||
AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name],
|
||||
[Set JDK RC name. This is used for FileDescription and ProductName properties
|
||||
@@ -502,6 +474,60 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
|
||||
VENDOR_VERSION_STRING="$with_vendor_version_string"
|
||||
fi
|
||||
|
||||
# Set the MACOSX Bundle Name base
|
||||
AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base],
|
||||
[Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names.
|
||||
@<:@not specified@:>@])])
|
||||
if test "x$with_macosx_bundle_name_base" = xyes; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value])
|
||||
elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base])
|
||||
elif test "x$with_macosx_bundle_name_base" != x; then
|
||||
# Set MACOSX_BUNDLE_NAME_BASE to the configured value.
|
||||
MACOSX_BUNDLE_NAME_BASE="$with_macosx_bundle_name_base"
|
||||
fi
|
||||
AC_SUBST(MACOSX_BUNDLE_NAME_BASE)
|
||||
|
||||
# Set the MACOSX Bundle ID base
|
||||
AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base],
|
||||
[Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs.
|
||||
@<:@not specified@:>@])])
|
||||
if test "x$with_macosx_bundle_id_base" = xyes; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value])
|
||||
elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base])
|
||||
elif test "x$with_macosx_bundle_id_base" != x; then
|
||||
# Set MACOSX_BUNDLE_ID_BASE to the configured value.
|
||||
MACOSX_BUNDLE_ID_BASE="$with_macosx_bundle_id_base"
|
||||
else
|
||||
# If using the default value, append the VERSION_PRE if there is one
|
||||
# to make it possible to tell official builds apart from developer builds
|
||||
if test "x$VERSION_PRE" != x; then
|
||||
MACOSX_BUNDLE_ID_BASE="$MACOSX_BUNDLE_ID_BASE-$VERSION_PRE"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(MACOSX_BUNDLE_ID_BASE)
|
||||
|
||||
# Set the MACOSX CFBundleVersion field
|
||||
AC_ARG_WITH(macosx-bundle-build-version, [AS_HELP_STRING([--with-macosx-bundle-build-version],
|
||||
[Set the MacOSX Bundle CFBundleVersion field. This key is a machine-readable
|
||||
string composed of one to three period-separated integers and should represent the
|
||||
build version. Defaults to the build number.])])
|
||||
if test "x$with_macosx_bundle_build_version" = xyes; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-build-version must have a value])
|
||||
elif [ ! [[ $with_macosx_bundle_build_version =~ ^[0-9\.]*$ ]] ]; then
|
||||
AC_MSG_ERROR([--with-macosx-bundle-build-version contains non numbers and periods: $with_macosx_bundle_build_version])
|
||||
elif test "x$with_macosx_bundle_build_version" != x; then
|
||||
MACOSX_BUNDLE_BUILD_VERSION="$with_macosx_bundle_build_version"
|
||||
else
|
||||
MACOSX_BUNDLE_BUILD_VERSION="$VERSION_BUILD"
|
||||
# If VERSION_OPT consists of only numbers and periods, add it.
|
||||
if [ [[ $VERSION_OPT =~ ^[0-9\.]+$ ]] ]; then
|
||||
MACOSX_BUNDLE_BUILD_VERSION+=".$VERSION_OPT"
|
||||
fi
|
||||
fi
|
||||
AC_SUBST(MACOSX_BUNDLE_BUILD_VERSION)
|
||||
|
||||
# We could define --with flags for these, if really needed
|
||||
VERSION_CLASSFILE_MAJOR="$DEFAULT_VERSION_CLASSFILE_MAJOR"
|
||||
VERSION_CLASSFILE_MINOR="$DEFAULT_VERSION_CLASSFILE_MINOR"
|
||||
|
||||
@@ -40,6 +40,7 @@ AC_DEFUN_ONCE([LIB_SETUP_BUNDLED_LIBS],
|
||||
LIB_SETUP_LIBPNG
|
||||
LIB_SETUP_ZLIB
|
||||
LIB_SETUP_LCMS
|
||||
LIB_SETUP_HARFBUZZ
|
||||
])
|
||||
|
||||
################################################################################
|
||||
@@ -263,3 +264,43 @@ AC_DEFUN_ONCE([LIB_SETUP_LCMS],
|
||||
AC_SUBST(LCMS_CFLAGS)
|
||||
AC_SUBST(LCMS_LIBS)
|
||||
])
|
||||
|
||||
################################################################################
|
||||
# Setup harfbuzz
|
||||
################################################################################
|
||||
AC_DEFUN_ONCE([LIB_SETUP_HARFBUZZ],
|
||||
[
|
||||
AC_ARG_WITH(harfbuzz, [AS_HELP_STRING([--with-harfbuzz],
|
||||
[use harfbuzz from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])])
|
||||
|
||||
AC_MSG_CHECKING([for which harfbuzz to use])
|
||||
|
||||
DEFAULT_HARFBUZZ=bundled
|
||||
# If user didn't specify, use DEFAULT_HARFBUZZ
|
||||
if test "x${with_harfbuzz}" = "x"; then
|
||||
with_harfbuzz=${DEFAULT_HARFBUZZ}
|
||||
fi
|
||||
|
||||
if test "x${with_harfbuzz}" = "xbundled"; then
|
||||
USE_EXTERNAL_HARFBUZZ=false
|
||||
HARFBUZZ_CFLAGS=""
|
||||
HARFBUZZ_LIBS=""
|
||||
AC_MSG_RESULT([bundled])
|
||||
elif test "x${with_harfbuzz}" = "xsystem"; then
|
||||
AC_MSG_RESULT([system])
|
||||
PKG_CHECK_MODULES([HARFBUZZ], [harfbuzz], [HARFBUZZ_FOUND=yes], [HARFBUZZ_FOUND=no])
|
||||
if test "x${HARFBUZZ_FOUND}" = "xyes"; then
|
||||
# PKG_CHECK_MODULES will set HARFBUZZ_CFLAGS and HARFBUZZ_LIBS
|
||||
USE_EXTERNAL_HARFBUZZ=true
|
||||
else
|
||||
HELP_MSG_MISSING_DEPENDENCY([harfbuzz])
|
||||
AC_MSG_ERROR([--with-harfbuzz=system specified, but no harfbuzz found! $HELP_MSG])
|
||||
fi
|
||||
else
|
||||
AC_MSG_ERROR([Invalid value for --with-harfbuzz: ${with_harfbuzz}, use 'system' or 'bundled'])
|
||||
fi
|
||||
|
||||
AC_SUBST(USE_EXTERNAL_HARFBUZZ)
|
||||
AC_SUBST(HARFBUZZ_CFLAGS)
|
||||
AC_SUBST(HARFBUZZ_LIBS)
|
||||
])
|
||||
|
||||
@@ -170,6 +170,7 @@ COMPANY_NAME:=@COMPANY_NAME@
|
||||
HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@
|
||||
MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@
|
||||
MACOSX_BUNDLE_ID_BASE=@MACOSX_BUNDLE_ID_BASE@
|
||||
MACOSX_BUNDLE_BUILD_VERSION=@MACOSX_BUNDLE_BUILD_VERSION@
|
||||
USERNAME:=@USERNAME@
|
||||
VENDOR_URL:=@VENDOR_URL@
|
||||
VENDOR_URL_BUG:=@VENDOR_URL_BUG@
|
||||
@@ -824,6 +825,10 @@ USE_EXTERNAL_LCMS:=@USE_EXTERNAL_LCMS@
|
||||
LCMS_CFLAGS:=@LCMS_CFLAGS@
|
||||
LCMS_LIBS:=@LCMS_LIBS@
|
||||
|
||||
USE_EXTERNAL_HARFBUZZ:=@USE_EXTERNAL_HARFBUZZ@
|
||||
HARFBUZZ_CFLAGS:=@HARFBUZZ_CFLAGS@
|
||||
HARFBUZZ_LIBS:=@HARFBUZZ_LIBS@
|
||||
|
||||
USE_EXTERNAL_LIBPNG:=@USE_EXTERNAL_LIBPNG@
|
||||
PNG_LIBS:=@PNG_LIBS@
|
||||
PNG_CFLAGS:=@PNG_CFLAGS@
|
||||
|
||||
@@ -902,9 +902,14 @@ AC_DEFUN_ONCE([TOOLCHAIN_SETUP_BUILD_COMPILERS],
|
||||
# FIXME: we should list the discovered compilers as an exclude pattern!
|
||||
# If we do that, we can do this detection before POST_DETECTION, and still
|
||||
# find the build compilers in the tools dir, if needed.
|
||||
UTIL_REQUIRE_PROGS(BUILD_CC, [cl cc gcc])
|
||||
if test "x$OPENJDK_BUILD_OS" = xmacosx; then
|
||||
UTIL_REQUIRE_PROGS(BUILD_CC, [clang cl cc gcc])
|
||||
UTIL_REQUIRE_PROGS(BUILD_CXX, [clang++ cl CC g++])
|
||||
else
|
||||
UTIL_REQUIRE_PROGS(BUILD_CC, [cl cc gcc])
|
||||
UTIL_REQUIRE_PROGS(BUILD_CXX, [cl CC g++])
|
||||
fi
|
||||
UTIL_FIXUP_EXECUTABLE(BUILD_CC)
|
||||
UTIL_REQUIRE_PROGS(BUILD_CXX, [cl CC g++])
|
||||
UTIL_FIXUP_EXECUTABLE(BUILD_CXX)
|
||||
UTIL_PATH_PROGS(BUILD_NM, nm gcc-nm)
|
||||
UTIL_FIXUP_EXECUTABLE(BUILD_NM)
|
||||
|
||||
@@ -601,7 +601,7 @@ AC_DEFUN([UTIL_REQUIRE_BUILTIN_PROGS],
|
||||
UTIL_SETUP_TOOL($1, [AC_PATH_PROGS($1, $2, , $3)])
|
||||
if test "x[$]$1" = x; then
|
||||
AC_MSG_NOTICE([Required tool $2 not found in PATH, checking built-in])
|
||||
if command -v $2 > /dev/null 2>&1; then
|
||||
if type -p $2 > /dev/null 2>&1; then
|
||||
AC_MSG_NOTICE([Found $2 as shell built-in. Using it])
|
||||
$1="$2"
|
||||
else
|
||||
|
||||
@@ -242,7 +242,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_CYGWIN],
|
||||
new_path=`$CYGPATH -u "$path"`
|
||||
|
||||
# Now try to locate executable using which
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
# bat and cmd files are not always considered executable in cygwin causing which
|
||||
# to not find them
|
||||
if test "x$new_path" = x \
|
||||
@@ -258,7 +258,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_CYGWIN],
|
||||
path="$complete"
|
||||
arguments="EOL"
|
||||
new_path=`$CYGPATH -u "$path"`
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
# bat and cmd files are not always considered executable in cygwin causing which
|
||||
# to not find them
|
||||
if test "x$new_path" = x \
|
||||
@@ -324,7 +324,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_MSYS],
|
||||
UTIL_REWRITE_AS_UNIX_PATH(new_path)
|
||||
|
||||
# Now try to locate executable using which
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
|
||||
if test "x$new_path" = x; then
|
||||
# Oops. Which didn't find the executable.
|
||||
@@ -336,7 +336,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_MSYS],
|
||||
new_path="$path"
|
||||
UTIL_REWRITE_AS_UNIX_PATH(new_path)
|
||||
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
# bat and cmd files are not always considered executable in MSYS causing which
|
||||
# to not find them
|
||||
if test "x$new_path" = x \
|
||||
@@ -392,7 +392,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_WSL],
|
||||
|
||||
# Now try to locate executable using which
|
||||
new_path_bak="$new_path"
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
# bat and cmd files are not considered executable in WSL
|
||||
if test "x$new_path" = x \
|
||||
&& test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
|
||||
@@ -409,7 +409,7 @@ AC_DEFUN([UTIL_FIXUP_EXECUTABLE_WSL],
|
||||
new_path="$path"
|
||||
UTIL_REWRITE_AS_UNIX_PATH([new_path])
|
||||
new_path_bak="$new_path"
|
||||
new_path=`$WHICH "$new_path" 2> /dev/null`
|
||||
new_path=`type -p "$new_path" 2> /dev/null`
|
||||
# bat and cmd files are not considered executable in WSL
|
||||
if test "x$new_path" = x \
|
||||
&& test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
|
||||
|
||||
@@ -346,7 +346,7 @@ $(MODULE_DEPS_MAKEFILE): $(MODULE_INFOS) \
|
||||
sub(/\/\*.*\*\//, ""); \
|
||||
gsub(/^ +\*.*/, ""); \
|
||||
gsub(/ /, ""); \
|
||||
gsub(/\r/, ""); \
|
||||
gsub(/\r/, ""); \
|
||||
printf(" %s", $$0) } \
|
||||
END { printf("\n") }' $m && \
|
||||
$(PRINTF) "TRANSITIVE_MODULES_$(call GetModuleNameFromModuleInfo, $m) :=" && \
|
||||
@@ -360,7 +360,7 @@ $(MODULE_DEPS_MAKEFILE): $(MODULE_INFOS) \
|
||||
sub(/\/\*.*\*\//, ""); \
|
||||
gsub(/^ +\*.*/, ""); \
|
||||
gsub(/ /, ""); \
|
||||
gsub(/\r/, ""); \
|
||||
gsub(/\r/, ""); \
|
||||
printf(" %s", $$0) } \
|
||||
END { printf("\n") }' $m \
|
||||
) >> $@ $(NEWLINE))
|
||||
|
||||
@@ -102,12 +102,22 @@ define SetupBuildLauncherBody
|
||||
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
ifeq ($$($1_MACOSX_PRIVILEGED), true)
|
||||
$1_PLIST_FILE := Info-privileged.plist
|
||||
else
|
||||
$1_PLIST_FILE := Info-cmdline.plist
|
||||
$1_PLIST_EXTRA := <key>SecTaskAccess</key><string>allowed</string>
|
||||
endif
|
||||
|
||||
$1_LDFLAGS += -sectcreate __TEXT __info_plist $(MACOSX_PLIST_DIR)/$$($1_PLIST_FILE)
|
||||
$1_PLIST_FILE := $$(SUPPORT_OUTPUTDIR)/native/$$(MODULE)/$1/Info.plist
|
||||
|
||||
$$(eval $$(call SetupTextFileProcessing, BUILD_PLIST_$1, \
|
||||
SOURCE_FILES := $(TOPDIR)/make/data/bundle/cmdline-Info.plist, \
|
||||
OUTPUT_FILE := $$($1_PLIST_FILE), \
|
||||
REPLACEMENTS := \
|
||||
@@ID@@ => $(MACOSX_BUNDLE_ID_BASE).$1 ; \
|
||||
@@VERSION@@ => $(VERSION_NUMBER) ; \
|
||||
@@BUILD_VERSION@@ => $(MACOSX_BUNDLE_BUILD_VERSION) ; \
|
||||
@@EXTRA@@ => $$($1_PLIST_EXTRA), \
|
||||
))
|
||||
|
||||
$1_LDFLAGS += -sectcreate __TEXT __info_plist $$($1_PLIST_FILE)
|
||||
|
||||
ifeq ($(STATIC_BUILD), true)
|
||||
$1_LDFLAGS += -exported_symbols_list \
|
||||
@@ -167,6 +177,8 @@ define SetupBuildLauncherBody
|
||||
$1 += $$(BUILD_LAUNCHER_$1)
|
||||
TARGETS += $$($1)
|
||||
|
||||
$$(BUILD_LAUNCHER_$1): $$(BUILD_PLIST_$1)
|
||||
|
||||
ifeq ($(call isTargetOs, aix), true)
|
||||
$$(BUILD_LAUNCHER_$1): $(call FindStaticLib, java.base, jli_static)
|
||||
endif
|
||||
@@ -175,6 +187,10 @@ define SetupBuildLauncherBody
|
||||
$$(BUILD_LAUNCHER_$1): $(call FindStaticLib, java.base, java, /libjava) \
|
||||
$$($1_WINDOWS_JLI_LIB)
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
$$(BUILD_LAUNCHER_$1): $$($1_PLIST_FILE)
|
||||
endif
|
||||
endef
|
||||
|
||||
################################################################################
|
||||
|
||||
@@ -1062,15 +1062,15 @@ var getJibProfilesDependencies = function (input, common) {
|
||||
|
||||
jcov: {
|
||||
// Until an official build of JCov is available, use custom
|
||||
// build to support classfile version 57.
|
||||
// See CODETOOLS-7902358 for more info.
|
||||
// build to support classfile version 60.
|
||||
// See CODETOOLS-7902734 for more info.
|
||||
// server: "jpg",
|
||||
// product: "jcov",
|
||||
// version: "3.0",
|
||||
// build_number: "b07",
|
||||
// file: "bundles/jcov-3_0.zip",
|
||||
organization: common.organization,
|
||||
revision: "3.0-59-support+1.0",
|
||||
revision: "3.0-60-support+1.0",
|
||||
ext: "zip",
|
||||
environment_name: "JCOV_HOME",
|
||||
},
|
||||
@@ -1339,13 +1339,17 @@ var versionArgs = function(input, common) {
|
||||
"--with-version-pre=" + version_numbers.get("DEFAULT_PROMOTED_VERSION_PRE"),
|
||||
"--without-version-opt");
|
||||
} else if (input.build_type == "ci") {
|
||||
var optString = input.build_id_data.ciBuildNumber;
|
||||
var ciBuildNumber = input.build_id_data.ciBuildNumber;
|
||||
var preString = input.build_id_data.projectName;
|
||||
if (preString == "jdk") {
|
||||
preString = version_numbers.get("DEFAULT_PROMOTED_VERSION_PRE");
|
||||
}
|
||||
args = concat(args, "--with-version-pre=" + preString,
|
||||
"--with-version-opt=" + optString);
|
||||
"--with-version-opt=" + ciBuildNumber);
|
||||
if (input.target_os == "macosx") {
|
||||
args = concat(args, "--with-macosx-bundle-build-version="
|
||||
+ common.build_number + "." + ciBuildNumber);
|
||||
}
|
||||
} else {
|
||||
args = concat(args, "--with-version-opt=" + common.build_id);
|
||||
}
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>@@VERSION@@</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@@VERSION@@</string>
|
||||
<string>@@BUILD_VERSION@@</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>The application is requesting access to the microphone.</string>
|
||||
<key>JavaVM</key>
|
||||
<dict>
|
||||
<key>JVMCapabilities</key>
|
||||
@@ -31,9 +33,9 @@
|
||||
<key>JVMMinimumFrameworkVersion</key>
|
||||
<string>13.2.9</string>
|
||||
<key>JVMMinimumSystemVersion</key>
|
||||
<string>10.6.0</string>
|
||||
<string>@@MACOSX_VERSION_MIN@@</string>
|
||||
<key>JVMPlatformVersion</key>
|
||||
<string>@@PLATFORM_VERSION@@</string>
|
||||
<string>@@VERSION@@</string>
|
||||
<key>JVMVendor</key>
|
||||
<string>@@VENDOR@@</string>
|
||||
<key>JVMVersion</key>
|
||||
|
||||
@@ -17,19 +17,21 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>@@VERSION@@</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>@@VERSION@@</string>
|
||||
<string>@@BUILD_VERSION@@</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>The application is requesting access to the microphone.</string>
|
||||
<key>JavaVM</key>
|
||||
<dict>
|
||||
<key>JVMMinimumFrameworkVersion</key>
|
||||
<string>13.2.9</string>
|
||||
<key>JVMMinimumSystemVersion</key>
|
||||
<string>10.6.0</string>
|
||||
<string>@@MACOSX_VERSION_MIN@@</string>
|
||||
<key>JVMPlatformVersion</key>
|
||||
<string>@@PLATFORM_VERSION@@</string>
|
||||
<string>@@VERSION@@</string>
|
||||
<key>JVMVendor</key>
|
||||
<string>@@VENDOR@@</string>
|
||||
<key>JVMVersion</key>
|
||||
|
||||
@@ -3,12 +3,15 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>net.java.openjdk.cmd</string>
|
||||
<string>@@ID@@</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>@@VERSION@@</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<string>@@BUILD_VERSION@@</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>The application is requesting access to the microphone.</string>
|
||||
@@EXTRA@@
|
||||
</dict>
|
||||
</plist>
|
||||
43
make/data/cacerts/entrustrootcag4
Normal file
43
make/data/cacerts/entrustrootcag4
Normal file
@@ -0,0 +1,43 @@
|
||||
Owner: CN=Entrust Root Certification Authority - G4, OU="(c) 2015 Entrust, Inc. - for authorized use only", OU=See www.entrust.net/legal-terms, O="Entrust, Inc.", C=US
|
||||
Issuer: CN=Entrust Root Certification Authority - G4, OU="(c) 2015 Entrust, Inc. - for authorized use only", OU=See www.entrust.net/legal-terms, O="Entrust, Inc.", C=US
|
||||
Serial number: d9b5437fafa9390f000000005565ad58
|
||||
Valid from: Wed May 27 11:11:16 GMT 2015 until: Sun Dec 27 11:41:16 GMT 2037
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
|
||||
gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
|
||||
Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
|
||||
MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
|
||||
BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
|
||||
MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
|
||||
MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
|
||||
c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
|
||||
bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
|
||||
Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
|
||||
AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
|
||||
2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
|
||||
T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
|
||||
5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
|
||||
C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
|
||||
DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
|
||||
wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
|
||||
2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
|
||||
nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
|
||||
dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
|
||||
N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
|
||||
c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
|
||||
VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
|
||||
5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
|
||||
Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
|
||||
hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
|
||||
B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
|
||||
AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
|
||||
H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
|
||||
b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
|
||||
2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
|
||||
IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
|
||||
5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
|
||||
n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
|
||||
-----END CERTIFICATE-----
|
||||
23
make/data/cacerts/sslrooteccca
Normal file
23
make/data/cacerts/sslrooteccca
Normal file
@@ -0,0 +1,23 @@
|
||||
Owner: CN=SSL.com Root Certification Authority ECC, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Issuer: CN=SSL.com Root Certification Authority ECC, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Serial number: 75e6dfcbc1685ba8
|
||||
Valid from: Fri Feb 12 18:14:03 GMT 2016 until: Tue Feb 12 18:14:03 GMT 2041
|
||||
Signature algorithm name: SHA256withECDSA
|
||||
Subject Public Key Algorithm: 384-bit EC key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
|
||||
VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
|
||||
U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
|
||||
aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz
|
||||
WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0
|
||||
b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS
|
||||
b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
|
||||
BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI
|
||||
7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg
|
||||
CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD
|
||||
VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T
|
||||
kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+
|
||||
gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
|
||||
-----END CERTIFICATE-----
|
||||
41
make/data/cacerts/sslrootevrsaca
Normal file
41
make/data/cacerts/sslrootevrsaca
Normal file
@@ -0,0 +1,41 @@
|
||||
Owner: CN=SSL.com EV Root Certification Authority RSA R2, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Issuer: CN=SSL.com EV Root Certification Authority RSA R2, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Serial number: 56b629cd34bc78f6
|
||||
Valid from: Wed May 31 18:14:37 GMT 2017 until: Fri May 30 18:14:37 GMT 2042
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
|
||||
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
|
||||
CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy
|
||||
MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G
|
||||
A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD
|
||||
DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
|
||||
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq
|
||||
M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf
|
||||
OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa
|
||||
4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9
|
||||
HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR
|
||||
aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA
|
||||
b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ
|
||||
Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV
|
||||
PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO
|
||||
pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu
|
||||
UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY
|
||||
MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
|
||||
HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4
|
||||
9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW
|
||||
s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5
|
||||
Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg
|
||||
cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM
|
||||
79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz
|
||||
/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt
|
||||
ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm
|
||||
Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK
|
||||
QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ
|
||||
w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi
|
||||
S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07
|
||||
mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
|
||||
-----END CERTIFICATE-----
|
||||
41
make/data/cacerts/sslrootrsaca
Normal file
41
make/data/cacerts/sslrootrsaca
Normal file
@@ -0,0 +1,41 @@
|
||||
Owner: CN=SSL.com Root Certification Authority RSA, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Issuer: CN=SSL.com Root Certification Authority RSA, O=SSL Corporation, L=Houston, ST=Texas, C=US
|
||||
Serial number: 7b2c9bd316803299
|
||||
Valid from: Fri Feb 12 17:39:39 GMT 2016 until: Tue Feb 12 17:39:39 GMT 2041
|
||||
Signature algorithm name: SHA256withRSA
|
||||
Subject Public Key Algorithm: 4096-bit RSA key
|
||||
Version: 3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
|
||||
BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
|
||||
DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
|
||||
Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz
|
||||
OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
|
||||
dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
|
||||
bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R
|
||||
xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX
|
||||
qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC
|
||||
C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3
|
||||
6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh
|
||||
/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF
|
||||
YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E
|
||||
JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc
|
||||
US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8
|
||||
ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm
|
||||
+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi
|
||||
M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
|
||||
HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G
|
||||
A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV
|
||||
cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc
|
||||
Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs
|
||||
PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/
|
||||
q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0
|
||||
cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr
|
||||
a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I
|
||||
H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y
|
||||
K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu
|
||||
nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf
|
||||
oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
|
||||
Ic2wBlX7Jz9TkHCpBB5XJ7k=
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@@ -50,7 +50,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036
|
||||
LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-MRU929-\
|
||||
MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
|
||||
NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
|
||||
PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
|
||||
PKR586-PLN985-PTE620-PYG600-QAR634-ROL642-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
|
||||
SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
|
||||
SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\
|
||||
TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\
|
||||
@@ -588,7 +588,7 @@ ZW=ZWL
|
||||
|
||||
minor0=\
|
||||
ADP-BEF-BIF-BYB-BYR-CLP-DJF-ESP-GNF-\
|
||||
GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
|
||||
GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-ROL-RWF-\
|
||||
TPE-TRL-UGX-UYI-VND-VUV-XAF-XOF-XPF
|
||||
minor3=\
|
||||
BHD-IQD-JOD-KWD-LYD-OMR-TND
|
||||
|
||||
@@ -69,6 +69,9 @@ class name java/lang/Math
|
||||
method name absExact descriptor (I)I flags 9
|
||||
method name absExact descriptor (J)J flags 9
|
||||
|
||||
class name java/lang/NullPointerException
|
||||
method name fillInStackTrace descriptor ()Ljava/lang/Throwable; flags 21
|
||||
|
||||
class name java/lang/Short
|
||||
header extends java/lang/Number implements java/lang/Comparable,java/lang/constant/Constable flags 31 signature Ljava/lang/Number;Ljava/lang/Comparable<Ljava/lang/Short;>;Ljava/lang/constant/Constable;
|
||||
method name describeConstable descriptor ()Ljava/util/Optional; flags 1 signature ()Ljava/util/Optional<Ljava/lang/constant/DynamicConstantDesc<Ljava/lang/Short;>;>;
|
||||
|
||||
@@ -129,6 +129,12 @@ ifeq ($(call check-jvm-feature, compiler2), true)
|
||||
$d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH).ad \
|
||||
)))
|
||||
|
||||
ifeq ($(HOTSPOT_TARGET_CPU_ARCH), aarch64)
|
||||
AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \
|
||||
$d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/$(HOTSPOT_TARGET_CPU_ARCH)_sve.ad \
|
||||
)))
|
||||
endif
|
||||
|
||||
ifeq ($(call check-jvm-feature, shenandoahgc), true)
|
||||
AD_SRC_FILES += $(call uniq, $(wildcard $(foreach d, $(AD_SRC_ROOTS), \
|
||||
$d/cpu/$(HOTSPOT_TARGET_CPU_ARCH)/gc/shenandoah/shenandoah_$(HOTSPOT_TARGET_CPU).ad \
|
||||
|
||||
@@ -250,14 +250,14 @@ ifneq ($(GENERATE_COMPILE_COMMANDS_ONLY), true)
|
||||
|
||||
define SetupOperatorNewDeleteCheck
|
||||
$1.op_check: $1
|
||||
if [ -n "`$(NM) $$< | $(GREP) $(addprefix -e , $(MANGLED_SYMS)) \
|
||||
| $(GREP) $(UNDEF_PATTERN)`" ]; then \
|
||||
$(ECHO) "$$<: Error: Use of global operators new and delete is not allowed in Hotspot:"; \
|
||||
$(NM) $$< | $(CXXFILT) | $(EGREP) '$(DEMANGLED_REGEXP)' | $(GREP) $(UNDEF_PATTERN); \
|
||||
$(ECHO) "See: $(TOPDIR)/make/hotspot/lib/CompileJvm.gmk"; \
|
||||
$$(call ExecuteWithLog, $1.op_check, \
|
||||
$$(NM) $$< 2>&1 | $$(GREP) $$(addprefix -e , $$(MANGLED_SYMS)) | $$(GREP) $$(UNDEF_PATTERN) > $1.op_check || true)
|
||||
if [ -s $1.op_check ]; then \
|
||||
$$(ECHO) "$$(notdir $$<): Error: Use of global operators new and delete is not allowed in Hotspot:"; \
|
||||
$$(NM) $$< | $$(CXXFILT) | $$(EGREP) '$$(DEMANGLED_REGEXP)' | $$(GREP) $$(UNDEF_PATTERN); \
|
||||
$$(ECHO) "See: $$(TOPDIR)/make/hotspot/lib/CompileJvm.gmk"; \
|
||||
exit 1; \
|
||||
fi
|
||||
$(TOUCH) $$@
|
||||
|
||||
TARGETS += $1.op_check
|
||||
endef
|
||||
|
||||
@@ -116,8 +116,11 @@ endif
|
||||
ifneq ($(call check-jvm-feature, cds), true)
|
||||
JVM_CFLAGS_FEATURES += -DINCLUDE_CDS=0
|
||||
JVM_EXCLUDE_FILES += \
|
||||
archiveBuilder.cpp \
|
||||
archiveUtils.cpp \
|
||||
classListParser.cpp \
|
||||
classLoaderExt.cpp \
|
||||
dumpAllocStats.cpp \
|
||||
dynamicArchive.cpp \
|
||||
filemap.cpp \
|
||||
heapShared.cpp \
|
||||
@@ -126,8 +129,7 @@ ifneq ($(call check-jvm-feature, cds), true)
|
||||
metaspaceShared_$(HOTSPOT_TARGET_CPU_ARCH).cpp \
|
||||
sharedClassUtil.cpp \
|
||||
sharedPathsMiscInfo.cpp \
|
||||
systemDictionaryShared.cpp \
|
||||
#
|
||||
systemDictionaryShared.cpp
|
||||
endif
|
||||
|
||||
ifneq ($(call check-jvm-feature, nmt), true)
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#
|
||||
|
||||
JVM_handle_linux_signal
|
||||
JVM_IsUseContainerSupport
|
||||
numa_error
|
||||
numa_warn
|
||||
sysThreadAvailableStackWithSlack
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Configure cpptools IntelliSense
|
||||
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
|
||||
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++03",
|
||||
"C_Cpp.default.cppStandard": "c++14",
|
||||
"C_Cpp.default.compilerPath": "{{COMPILER}}",
|
||||
|
||||
// Configure ccls
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Configure cpptools IntelliSense
|
||||
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
|
||||
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++03",
|
||||
"C_Cpp.default.cppStandard": "c++14",
|
||||
"C_Cpp.default.compilerPath": "{{COMPILER}}",
|
||||
|
||||
// Configure clangd
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Configure cpptools IntelliSense
|
||||
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
|
||||
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++03",
|
||||
"C_Cpp.default.cppStandard": "c++14",
|
||||
"C_Cpp.default.compilerPath": "{{COMPILER}}",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Configure cpptools IntelliSense
|
||||
"C_Cpp.intelliSenseCachePath": "{{OUTPUTDIR}}/.vscode",
|
||||
"C_Cpp.default.compileCommands": "{{OUTPUTDIR}}/compile_commands.json",
|
||||
"C_Cpp.default.cppStandard": "c++03",
|
||||
"C_Cpp.default.cppStandard": "c++14",
|
||||
"C_Cpp.default.compilerPath": "{{COMPILER}}",
|
||||
|
||||
// Configure RTags
|
||||
|
||||
@@ -157,7 +157,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJIMAGE, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LIBS_unix := -ljvm -ldl $(LIBCXX), \
|
||||
LIBS_macosx := -lc++, \
|
||||
LIBS_windows := jvm.lib, \
|
||||
))
|
||||
|
||||
|
||||
@@ -71,6 +71,10 @@ ifeq ($(FREETYPE_TO_USE), system)
|
||||
LEGAL_EXCLUDES += freetype.md
|
||||
endif
|
||||
|
||||
ifeq ($(USE_EXTERNAL_HARFBUZZ), true)
|
||||
LEGAL_EXCLUDES += harfbuzz.md
|
||||
endif
|
||||
|
||||
$(eval $(call SetupCopyLegalFiles, COPY_LEGAL, \
|
||||
EXCLUDES := $(LEGAL_EXCLUDES), \
|
||||
))
|
||||
|
||||
@@ -432,82 +432,87 @@ endif
|
||||
|
||||
###########################################################################
|
||||
|
||||
HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN -DHAVE_ROUND
|
||||
ifeq ($(USE_EXTERNAL_HARFBUZZ), true)
|
||||
LIBHARFBUZZ_LIBS := $(HARFBUZZ_LIBS)
|
||||
else
|
||||
HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN -DHAVE_ROUND
|
||||
|
||||
# This is better than adding EXPORT_ALL_SYMBOLS
|
||||
ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
|
||||
HARFBUZZ_CFLAGS += -DHB_EXTERN=__attribute__\(\(visibility\(\"default\"\)\)\)
|
||||
else ifeq ($(TOOLCHAIN_TYPE), microsoft)
|
||||
HARFBUZZ_CFLAGS += -DHB_EXTERN=__declspec\(dllexport\)
|
||||
endif
|
||||
# This is better than adding EXPORT_ALL_SYMBOLS
|
||||
ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
|
||||
HARFBUZZ_CFLAGS += -DHB_EXTERN=__attribute__\(\(visibility\(\"default\"\)\)\)
|
||||
else ifeq ($(TOOLCHAIN_TYPE), microsoft)
|
||||
HARFBUZZ_CFLAGS += -DHB_EXTERN=__declspec\(dllexport\)
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, windows), false)
|
||||
HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \
|
||||
ifeq ($(call isTargetOs, windows), false)
|
||||
HARFBUZZ_CFLAGS += -DGETPAGESIZE -DHAVE_MPROTECT -DHAVE_PTHREAD \
|
||||
-DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \
|
||||
-DHB_NO_PRAGMA_GCC_DIAGNOSTIC
|
||||
endif
|
||||
ifeq ($(call isTargetOs, linux macosx), true)
|
||||
HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES
|
||||
endif
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
HARFBUZZ_CFLAGS += -DHAVE_CORETEXT
|
||||
endif
|
||||
ifeq ($(call isTargetOs, macosx), false)
|
||||
LIBHARFBUZZ_EXCLUDE_FILES += harfbuzz/hb-coretext.cc
|
||||
endif
|
||||
# hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
|
||||
LIBHARFBUZZ_EXCLUDE_FILES += harfbuzz/hb-ft.cc
|
||||
endif
|
||||
ifeq ($(call isTargetOs, linux macosx), true)
|
||||
HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES
|
||||
endif
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
HARFBUZZ_CFLAGS += -DHAVE_CORETEXT
|
||||
endif
|
||||
ifeq ($(call isTargetOs, macosx), false)
|
||||
LIBHARFBUZZ_EXCLUDE_FILES += libharfbuzz/hb-coretext.cc
|
||||
endif
|
||||
# hb-ft.cc is not presently needed, and requires freetype 2.4.2 or later.
|
||||
LIBHARFBUZZ_EXCLUDE_FILES += libharfbuzz/hb-ft.cc
|
||||
|
||||
LIBHARFBUZZ_CFLAGS += $(HARFBUZZ_CFLAGS)
|
||||
LIBHARFBUZZ_CFLAGS += $(HARFBUZZ_CFLAGS)
|
||||
|
||||
# For use by libfontmanager:
|
||||
ifeq ($(call isTargetOs, windows), true)
|
||||
LIBHARFBUZZ_LIBS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libharfbuzz/harfbuzz.lib
|
||||
else
|
||||
LIBHARFBUZZ_LIBS := -lharfbuzz
|
||||
endif
|
||||
# For use by libfontmanager:
|
||||
ifeq ($(call isTargetOs, windows), true)
|
||||
LIBHARFBUZZ_LIBS := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libharfbuzz/harfbuzz.lib
|
||||
else
|
||||
LIBHARFBUZZ_LIBS := -lharfbuzz
|
||||
endif
|
||||
|
||||
LIBHARFBUZZ_EXTRA_HEADER_DIRS := \
|
||||
LIBHARFBUZZ_EXTRA_HEADER_DIRS := \
|
||||
libharfbuzz/hb-ucdn \
|
||||
#
|
||||
|
||||
LIBHARFBUZZ_OPTIMIZATION := HIGH
|
||||
LIBHARFBUZZ_OPTIMIZATION := HIGH
|
||||
|
||||
LIBHARFBUZZ_CFLAGS += $(X_CFLAGS) -DLE_STANDALONE -DHEADLESS
|
||||
LIBHARFBUZZ_CFLAGS += $(X_CFLAGS) -DLE_STANDALONE -DHEADLESS
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBHARFBUZZ, \
|
||||
NAME := harfbuzz, \
|
||||
EXCLUDE_FILES := $(LIBHARFBUZZ_EXCLUDE_FILES), \
|
||||
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \
|
||||
CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \
|
||||
OPTIMIZATION := $(LIBHARFBUZZ_OPTIMIZATION), \
|
||||
CFLAGS_windows = -DCC_NOEX, \
|
||||
EXTRA_HEADER_DIRS := $(LIBHARFBUZZ_EXTRA_HEADER_DIRS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc := type-limits missing-field-initializers strict-aliasing, \
|
||||
DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBHARFBUZZ, \
|
||||
NAME := harfbuzz, \
|
||||
EXCLUDE_FILES := $(LIBHARFBUZZ_EXCLUDE_FILES), \
|
||||
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
|
||||
CFLAGS := $(CFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \
|
||||
CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBHARFBUZZ_CFLAGS), \
|
||||
OPTIMIZATION := $(LIBHARFBUZZ_OPTIMIZATION), \
|
||||
CFLAGS_windows = -DCC_NOEX, \
|
||||
EXTRA_HEADER_DIRS := $(LIBHARFBUZZ_EXTRA_HEADER_DIRS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc := type-limits missing-field-initializers strict-aliasing, \
|
||||
DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \
|
||||
maybe-uninitialized class-memaccess, \
|
||||
DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
|
||||
DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
|
||||
tautological-constant-out-of-range-compare int-to-pointer-cast \
|
||||
undef missing-field-initializers, \
|
||||
DISABLED_WARNINGS_microsoft := 4267 4244 4090 4146 4334 4819 4101 4068 4805 4138, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
DISABLED_WARNINGS_microsoft := 4267 4244 4090 4146 4334 4819 4101 4068 4805 4138, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
|
||||
LDFLAGS_aix := -Wl$(COMMA)-berok, \
|
||||
LIBS := $(BUILD_LIBHARFBUZZ), \
|
||||
LIBS_unix := $(LIBM) $(LIBCXX), \
|
||||
LIBS_macosx := -framework CoreText -framework CoreFoundation -framework CoreGraphics, \
|
||||
LIBS_windows := user32.lib, \
|
||||
))
|
||||
LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
|
||||
LDFLAGS_aix := -Wl$(COMMA)-berok, \
|
||||
LIBS := $(BUILD_LIBHARFBUZZ), \
|
||||
LIBS_unix := $(LIBM) $(LIBCXX), \
|
||||
LIBS_macosx := -framework CoreText -framework CoreFoundation -framework CoreGraphics, \
|
||||
LIBS_windows := user32.lib, \
|
||||
))
|
||||
|
||||
ifeq ($(FREETYPE_TO_USE), bundled)
|
||||
$(BUILD_LIBHARFBUZZ): $(BUILD_LIBFREETYPE)
|
||||
endif
|
||||
|
||||
TARGETS += $(BUILD_LIBHARFBUZZ)
|
||||
|
||||
ifeq ($(FREETYPE_TO_USE), bundled)
|
||||
$(BUILD_LIBHARFBUZZ): $(BUILD_LIBFREETYPE)
|
||||
endif
|
||||
|
||||
TARGETS += $(BUILD_LIBHARFBUZZ)
|
||||
|
||||
###########################################################################
|
||||
|
||||
LIBFONTMANAGER_EXTRA_HEADER_DIRS := \
|
||||
@@ -561,9 +566,6 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
|
||||
CFLAGS_windows = -DCC_NOEX, \
|
||||
EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \
|
||||
WARNINGS_AS_ERRORS_xlc := false, \
|
||||
DISABLED_WARNINGS_gcc := sign-compare unused-function, \
|
||||
DISABLED_WARNINGS_clang := sign-compare, \
|
||||
DISABLED_WARNINGS_microsoft := 4018 4146 4244 4996, \
|
||||
LDFLAGS := $(subst -Xlinker -z -Xlinker defs,, \
|
||||
$(subst -Wl$(COMMA)-z$(COMMA)defs,,$(LDFLAGS_JDKLIB))) $(LDFLAGS_CXX_JDK) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
@@ -576,7 +578,11 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \
|
||||
$(WIN_AWT_LIB), \
|
||||
))
|
||||
|
||||
$(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT) $(BUILD_LIBHARFBUZZ)
|
||||
$(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT)
|
||||
|
||||
ifeq ($(USE_EXTERNAL_HARFBUZZ), false)
|
||||
$(BUILD_LIBFONTMANAGER): $(BUILD_LIBHARFBUZZ)
|
||||
endif
|
||||
|
||||
ifeq ($(call isTargetOs, macosx), true)
|
||||
$(BUILD_LIBFONTMANAGER): $(call FindLib, $(MODULE), awt_lwawt)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
@@ -120,7 +120,7 @@ $(CLASSES):
|
||||
mkdirs: $(DIST) $(CLASSES)
|
||||
|
||||
$(CLASSES)/j2dbench/%.class: $(SOURCEPATH)/j2dbench/%.java
|
||||
javac -g:none -source 1.6 -target 1.6 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
|
||||
javac -g:none -source 1.7 -target 1.7 -d $(CLASSES) -sourcepath $(SOURCEPATH) $<
|
||||
|
||||
clean:
|
||||
rm -rf $(CLASSES)
|
||||
|
||||
@@ -20,8 +20,9 @@ Minimum requirements
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The benchmark requires at least jdk1.4 to compile and run. Note that
|
||||
source/target is set to 1.6 in the makefile and build.xml, because of
|
||||
support in jdk 9 compiler.
|
||||
source/target is set to 1.7 in the makefile and build.xml, because of
|
||||
support in jdk 14 compiler. To check compatibility with jdk1.4 you can
|
||||
use "-source 1.4 -target 1.4" options and jdk1.7.
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
How To Compile
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
@@ -49,7 +49,7 @@
|
||||
<target name="compile" depends="init"
|
||||
description="compile the source " >
|
||||
<!-- Compile the java code from ${src} into ${build} -->
|
||||
<javac debug="off" source="1.6" target="1.6" srcdir="${src}" destdir="${build}"/>
|
||||
<javac debug="off" source="1.7" target="1.7" srcdir="${src}" destdir="${build}"/>
|
||||
</target>
|
||||
|
||||
<target name="run" depends="dist"
|
||||
|
||||
@@ -8,8 +8,11 @@ global.env.testtime=2500
|
||||
global.results.workunits=units
|
||||
global.results.timeunits=sec
|
||||
global.results.ratio=unitspersec
|
||||
global.dest.screen=disabled
|
||||
global.dest.offscreen=disabled
|
||||
global.dest.frame.defaultframe=disabled
|
||||
global.dest.frame.transframe=disabled
|
||||
global.dest.frame.shapedframe=disabled
|
||||
global.dest.frame.shapedtransframe=disabled
|
||||
global.dest.compatimg.compatimg=disabled
|
||||
global.dest.compatimg.opqcompatimg=disabled
|
||||
global.dest.compatimg.bmcompatimg=disabled
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -40,9 +40,11 @@
|
||||
|
||||
package j2dbench;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.Component;
|
||||
import java.awt.Frame;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.BufferedImage;
|
||||
@@ -50,11 +52,14 @@ import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.WritableRaster;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import j2dbench.tests.GraphicsTests;
|
||||
import j2dbench.tests.ImageTests;
|
||||
|
||||
public abstract class Destinations extends Option.Enable {
|
||||
public static Group.EnableSet destroot;
|
||||
public static Group frameroot;
|
||||
public static Group bufimgdestroot;
|
||||
public static Group compatimgdestroot;
|
||||
public static Group volimgdestroot;
|
||||
@@ -63,9 +68,22 @@ public abstract class Destinations extends Option.Enable {
|
||||
destroot = new Group.EnableSet(TestEnvironment.globaloptroot,
|
||||
"dest", "Output Destination Options");
|
||||
|
||||
new Screen();
|
||||
new OffScreen();
|
||||
|
||||
frameroot = new Group.EnableSet(destroot, "frame", "Output to Frame");
|
||||
frameroot.setHorizontal();
|
||||
|
||||
new Screen(false, false);
|
||||
if (ImageTests.hasOpacityWindow) {
|
||||
new Screen(true, false);
|
||||
}
|
||||
if (ImageTests.hasShapedWindow) {
|
||||
new Screen(false, true);
|
||||
}
|
||||
if (ImageTests.hasShapedWindow && ImageTests.hasOpacityWindow) {
|
||||
new Screen(true, true);
|
||||
}
|
||||
|
||||
if (GraphicsTests.hasGraphics2D) {
|
||||
if (ImageTests.hasCompatImage) {
|
||||
compatimgdestroot =
|
||||
@@ -129,17 +147,95 @@ public abstract class Destinations extends Option.Enable {
|
||||
public abstract void setDestination(TestEnvironment env);
|
||||
|
||||
public static class Screen extends Destinations {
|
||||
public Screen() {
|
||||
super(destroot, "screen", "Output to Screen", false);
|
||||
|
||||
private boolean opacity;
|
||||
private boolean shaped;
|
||||
|
||||
public Screen(boolean opacity, boolean shaped) {
|
||||
super(frameroot, getDescription(opacity,shaped),
|
||||
getLongDescription(opacity,shaped), false);
|
||||
this.opacity = opacity;
|
||||
this.shaped = shaped;
|
||||
}
|
||||
|
||||
private static String getDescription(boolean opacity, boolean shaped){
|
||||
if (opacity && shaped) {
|
||||
return "shapedtransframe";
|
||||
}
|
||||
if (shaped) {
|
||||
return "shapedframe";
|
||||
}
|
||||
if (opacity) {
|
||||
return "transframe";
|
||||
}
|
||||
return "defaultframe";
|
||||
}
|
||||
|
||||
private static String getLongDescription(boolean opacity, boolean shaped){
|
||||
if (opacity && shaped) {
|
||||
return "Translucent and Shaped";
|
||||
}
|
||||
if (shaped) {
|
||||
return "Shaped";
|
||||
}
|
||||
if (opacity) {
|
||||
return "Translucent";
|
||||
}
|
||||
return "Default";
|
||||
}
|
||||
|
||||
public String getModifierValueName(Object val) {
|
||||
return "Screen";
|
||||
if (opacity && shaped) {
|
||||
return "Translucent and Shaped Frame";
|
||||
}
|
||||
if (shaped) {
|
||||
return "Shaped Frame";
|
||||
}
|
||||
if (opacity) {
|
||||
return "Translucent Frame";
|
||||
}
|
||||
return "Default Frame";
|
||||
}
|
||||
|
||||
public void setDestination(TestEnvironment env) {
|
||||
env.setTestImage(null);
|
||||
}
|
||||
|
||||
public void modifyTest(TestEnvironment env) {
|
||||
setDestination(env);
|
||||
Frame frame = (Frame) SwingUtilities.getWindowAncestor(env.comp);
|
||||
if (frame != null && (opacity || shaped)) {
|
||||
frame.dispose();
|
||||
frame.setUndecorated(true);
|
||||
int w = frame.getWidth();
|
||||
int h = frame.getHeight();
|
||||
if (shaped) {
|
||||
Polygon p = new Polygon();
|
||||
p.addPoint(0, 0);
|
||||
p.addPoint(w, 0);
|
||||
p.addPoint(0, h);
|
||||
p.addPoint(w, h);
|
||||
p.addPoint(0, 0);
|
||||
frame.setShape(p);
|
||||
}
|
||||
if (opacity) {
|
||||
frame.setOpacity(0.5f);
|
||||
}
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
public void restoreTest(TestEnvironment env) {
|
||||
env.setTestImage(null);
|
||||
Frame frame = (Frame) SwingUtilities.getWindowAncestor(env.comp);
|
||||
if (frame != null && (opacity || shaped)) {
|
||||
frame.dispose();
|
||||
frame.setShape(null);
|
||||
frame.setOpacity(1);
|
||||
frame.setUndecorated(false);
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class OffScreen extends Destinations {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -40,6 +40,8 @@
|
||||
|
||||
package j2dbench;
|
||||
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
@@ -780,7 +782,10 @@ public class J2DBench {
|
||||
f.getContentPane().add(p, BorderLayout.SOUTH);
|
||||
f.pack();
|
||||
f.setLocationRelativeTo(null);
|
||||
f.show();
|
||||
Rectangle usable = GraphicsEnvironment.getLocalGraphicsEnvironment()
|
||||
.getMaximumWindowBounds().intersection(f.getBounds());
|
||||
f.setBounds(usable);
|
||||
f.setVisible(true);
|
||||
}
|
||||
|
||||
public static void runTests(boolean showresults) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -53,7 +53,9 @@ import java.awt.Canvas;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Window;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ByteLookupTable;
|
||||
@@ -79,6 +81,8 @@ import javax.swing.JComponent;
|
||||
public abstract class ImageTests extends GraphicsTests {
|
||||
public static boolean hasVolatileImage;
|
||||
public static boolean hasTransparentVolatileImage;
|
||||
public static boolean hasShapedWindow;
|
||||
public static boolean hasOpacityWindow;
|
||||
public static boolean hasCompatImage;
|
||||
|
||||
static {
|
||||
@@ -96,6 +100,16 @@ public abstract class ImageTests extends GraphicsTests {
|
||||
hasTransparentVolatileImage = true;
|
||||
} catch (NoSuchMethodError e) {
|
||||
}
|
||||
try {
|
||||
new Window(null).setShape(new Rectangle());
|
||||
hasShapedWindow = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
new Window(null).setOpacity(0.5f);
|
||||
hasOpacityWindow = true;
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
|
||||
static Group imageroot;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -184,7 +184,7 @@ abstract class InputImageTests extends InputTests {
|
||||
String klass = spi.getClass().getName();
|
||||
String format = spi.getFormatNames()[0].toLowerCase();
|
||||
String suffix = spi.getFileSuffixes()[0].toLowerCase();
|
||||
if (suffix == null || suffix.isEmpty()) {
|
||||
if (suffix == null || suffix.equals("")) {
|
||||
suffix = format;
|
||||
}
|
||||
String shortName;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -143,7 +143,7 @@ abstract class OutputImageTests extends OutputTests {
|
||||
String klass = spi.getClass().getName();
|
||||
String format = spi.getFormatNames()[0].toLowerCase();
|
||||
String suffix = spi.getFileSuffixes()[0].toLowerCase();
|
||||
if (suffix == null || suffix.isEmpty()) {
|
||||
if (suffix == null || suffix.equals("")) {
|
||||
suffix = format;
|
||||
}
|
||||
String shortName;
|
||||
|
||||
@@ -68,6 +68,49 @@ class GeneralRegisterOrSp(Register):
|
||||
else:
|
||||
return self.astr("r")
|
||||
|
||||
class SVEVectorRegister(FloatRegister):
|
||||
def __str__(self):
|
||||
return self.astr("z")
|
||||
|
||||
class SVEPRegister(Register):
|
||||
def __str__(self):
|
||||
return self.astr("p")
|
||||
|
||||
def generate(self):
|
||||
self.number = random.randint(0, 15)
|
||||
return self
|
||||
|
||||
class SVEGoverningPRegister(Register):
|
||||
def __str__(self):
|
||||
return self.astr("p")
|
||||
def generate(self):
|
||||
self.number = random.randint(0, 7)
|
||||
return self
|
||||
|
||||
class RegVariant(object):
|
||||
def __init__(self, low, high):
|
||||
self.number = random.randint(low, high)
|
||||
|
||||
def astr(self):
|
||||
nameMap = {
|
||||
0: ".b",
|
||||
1: ".h",
|
||||
2: ".s",
|
||||
3: ".d",
|
||||
4: ".q"
|
||||
}
|
||||
return nameMap.get(self.number)
|
||||
|
||||
def cstr(self):
|
||||
nameMap = {
|
||||
0: "__ B",
|
||||
1: "__ H",
|
||||
2: "__ S",
|
||||
3: "__ D",
|
||||
4: "__ Q"
|
||||
}
|
||||
return nameMap.get(self.number)
|
||||
|
||||
class FloatZero(Operand):
|
||||
|
||||
def __str__(self):
|
||||
@@ -82,7 +125,10 @@ class OperandFactory:
|
||||
'w' : GeneralRegister,
|
||||
's' : FloatRegister,
|
||||
'd' : FloatRegister,
|
||||
'z' : FloatZero}
|
||||
'z' : FloatZero,
|
||||
'p' : SVEPRegister,
|
||||
'P' : SVEGoverningPRegister,
|
||||
'Z' : SVEVectorRegister}
|
||||
|
||||
@classmethod
|
||||
def create(cls, mode):
|
||||
@@ -741,6 +787,9 @@ class LoadStoreOp(InstructionWithModes):
|
||||
|
||||
regMode = FloatRegister if isFloat else GeneralRegister
|
||||
self.reg = regMode().generate()
|
||||
kindStr = Address.kindToStr(self.kind);
|
||||
if (not isFloat) and (kindStr is "pre" or kindStr is "post"):
|
||||
(self.reg.number, self.adr.base.number) = random.sample(range(31), 2)
|
||||
return self
|
||||
|
||||
def cstr(self):
|
||||
@@ -777,6 +826,14 @@ class LoadStorePairOp(InstructionWithModes):
|
||||
self.reg = [OperandFactory.create(self.mode).generate()
|
||||
for i in range(self.numRegs)]
|
||||
self.base = OperandFactory.create('x').generate()
|
||||
kindStr = Address.kindToStr(self.kind);
|
||||
if kindStr is "pre" or kindStr is "post":
|
||||
if self._name.startswith("ld"):
|
||||
(self.reg[0].number, self.reg[1].number, self.base.number) = random.sample(range(31), 3)
|
||||
if self._name.startswith("st"):
|
||||
self.base.number = random.choice(list(set(range(31)) - set([self.reg[0].number, self.reg[1].number])))
|
||||
elif self._name.startswith("ld"):
|
||||
(self.reg[0].number, self.reg[1].number) = random.sample(range(31), 2)
|
||||
return self
|
||||
|
||||
def astr(self):
|
||||
@@ -828,6 +885,100 @@ class FloatInstruction(Instruction):
|
||||
% tuple([Instruction.astr(self)] +
|
||||
[(self.reg[i].astr(self.modes[i])) for i in range(self.numRegs)]))
|
||||
|
||||
class SVEVectorOp(Instruction):
|
||||
def __init__(self, args):
|
||||
name = args[0]
|
||||
regTypes = args[1]
|
||||
regs = []
|
||||
for c in regTypes:
|
||||
regs.append(OperandFactory.create(c).generate())
|
||||
self.reg = regs
|
||||
self.numRegs = len(regs)
|
||||
if regTypes[0] != "p" and regTypes[1] == 'P':
|
||||
self._isPredicated = True
|
||||
self._merge = "/m"
|
||||
else:
|
||||
self._isPredicated = False
|
||||
self._merge =""
|
||||
|
||||
self._bitwiseop = False
|
||||
if name[0] == 'f':
|
||||
self._width = RegVariant(2, 3)
|
||||
elif not self._isPredicated and (name == "and" or name == "eor" or name == "orr"):
|
||||
self._width = RegVariant(3, 3)
|
||||
self._bitwiseop = True
|
||||
else:
|
||||
self._width = RegVariant(0, 3)
|
||||
if len(args) > 2:
|
||||
self._dnm = args[2]
|
||||
else:
|
||||
self._dnm = None
|
||||
Instruction.__init__(self, name)
|
||||
|
||||
def cstr(self):
|
||||
formatStr = "%s%s" + ''.join([", %s" for i in range(0, self.numRegs)] + [");"])
|
||||
if self._bitwiseop:
|
||||
width = []
|
||||
formatStr = "%s%s" + ''.join([", %s" for i in range(1, self.numRegs)] + [");"])
|
||||
else:
|
||||
width = [self._width.cstr()]
|
||||
return (formatStr
|
||||
% tuple(["__ sve_" + self._name + "("] +
|
||||
[str(self.reg[0])] +
|
||||
width +
|
||||
[str(self.reg[i]) for i in range(1, self.numRegs)]))
|
||||
def astr(self):
|
||||
formatStr = "%s%s" + ''.join([", %s" for i in range(1, self.numRegs)])
|
||||
if self._dnm == 'dn':
|
||||
formatStr += ", %s"
|
||||
dnReg = [str(self.reg[0]) + self._width.astr()]
|
||||
else:
|
||||
dnReg = []
|
||||
|
||||
if self._isPredicated:
|
||||
restRegs = [str(self.reg[1]) + self._merge] + dnReg + [str(self.reg[i]) + self._width.astr() for i in range(2, self.numRegs)]
|
||||
else:
|
||||
restRegs = dnReg + [str(self.reg[i]) + self._width.astr() for i in range(1, self.numRegs)]
|
||||
return (formatStr
|
||||
% tuple([Instruction.astr(self)] +
|
||||
[str(self.reg[0]) + self._width.astr()] +
|
||||
restRegs))
|
||||
def generate(self):
|
||||
return self
|
||||
|
||||
class SVEReductionOp(Instruction):
|
||||
def __init__(self, args):
|
||||
name = args[0]
|
||||
lowRegType = args[1]
|
||||
self.reg = []
|
||||
Instruction.__init__(self, name)
|
||||
self.reg.append(OperandFactory.create('s').generate())
|
||||
self.reg.append(OperandFactory.create('P').generate())
|
||||
self.reg.append(OperandFactory.create('Z').generate())
|
||||
self._width = RegVariant(lowRegType, 3)
|
||||
def cstr(self):
|
||||
return "__ sve_%s(%s, %s, %s, %s);" % (self.name(),
|
||||
str(self.reg[0]),
|
||||
self._width.cstr(),
|
||||
str(self.reg[1]),
|
||||
str(self.reg[2]))
|
||||
def astr(self):
|
||||
if self.name() == "uaddv":
|
||||
dstRegName = "d" + str(self.reg[0].number)
|
||||
else:
|
||||
dstRegName = self._width.astr()[1] + str(self.reg[0].number)
|
||||
formatStr = "%s %s, %s, %s"
|
||||
if self.name() == "fadda":
|
||||
formatStr += ", %s"
|
||||
moreReg = [dstRegName]
|
||||
else:
|
||||
moreReg = []
|
||||
return formatStr % tuple([self.name()] +
|
||||
[dstRegName] +
|
||||
[str(self.reg[1])] +
|
||||
moreReg +
|
||||
[str(self.reg[2]) + self._width.astr()])
|
||||
|
||||
class LdStSIMDOp(Instruction):
|
||||
def __init__(self, args):
|
||||
self._name, self.regnum, self.arrangement, self.addresskind = args
|
||||
@@ -865,6 +1016,37 @@ class LdStSIMDOp(Instruction):
|
||||
def aname(self):
|
||||
return self._name
|
||||
|
||||
class SHA512SIMDOp(Instruction):
|
||||
|
||||
def generate(self):
|
||||
if (self._name == 'sha512su0'):
|
||||
self.reg = [FloatRegister().generate(), FloatRegister().generate()]
|
||||
else:
|
||||
self.reg = [FloatRegister().generate(), FloatRegister().generate(),
|
||||
FloatRegister().generate()]
|
||||
return self
|
||||
|
||||
def cstr(self):
|
||||
if (self._name == 'sha512su0'):
|
||||
return (super(SHA512SIMDOp, self).cstr()
|
||||
+ ('%s, __ T2D, %s);' % (self.reg[0], self.reg[1])))
|
||||
else:
|
||||
return (super(SHA512SIMDOp, self).cstr()
|
||||
+ ('%s, __ T2D, %s, %s);' % (self.reg[0], self.reg[1], self.reg[2])))
|
||||
|
||||
def astr(self):
|
||||
if (self._name == 'sha512su0'):
|
||||
return (super(SHA512SIMDOp, self).astr()
|
||||
+ ('\t%s.2D, %s.2D' % (self.reg[0].astr("v"), self.reg[1].astr("v"))))
|
||||
elif (self._name == 'sha512su1'):
|
||||
return (super(SHA512SIMDOp, self).astr()
|
||||
+ ('\t%s.2D, %s.2D, %s.2D' % (self.reg[0].astr("v"),
|
||||
self.reg[1].astr("v"), self.reg[2].astr("v"))))
|
||||
else:
|
||||
return (super(SHA512SIMDOp, self).astr()
|
||||
+ ('\t%s, %s, %s.2D' % (self.reg[0].astr("q"),
|
||||
self.reg[1].astr("q"), self.reg[2].astr("v"))))
|
||||
|
||||
class LSEOp(Instruction):
|
||||
def __init__(self, args):
|
||||
self._name, self.asmname, self.size, self.suffix = args
|
||||
@@ -941,6 +1123,8 @@ def generate(kind, names):
|
||||
|
||||
outfile = open("aarch64ops.s", "w")
|
||||
|
||||
random.seed(0)
|
||||
|
||||
print "// BEGIN Generated code -- do not edit"
|
||||
print "// Generated by aarch64-asmtest.py"
|
||||
|
||||
@@ -1100,6 +1284,8 @@ generate(LdStSIMDOp, [["ld1", 1, "8B", Address.base_only],
|
||||
["ld4r", 4, "2S", Address.post_reg],
|
||||
])
|
||||
|
||||
generate(SHA512SIMDOp, ["sha512h", "sha512h2", "sha512su0", "sha512su1"])
|
||||
|
||||
generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);", "ccmn\txzr, xzr, #3, LE"],
|
||||
["ccmnw", "__ ccmnw(zr, zr, 5u, Assembler::EQ);", "ccmn\twzr, wzr, #5, EQ"],
|
||||
["ccmp", "__ ccmp(zr, 1, 4u, Assembler::NE);", "ccmp\txzr, 1, #4, NE"],
|
||||
@@ -1114,7 +1300,42 @@ generate(SpecialCases, [["ccmn", "__ ccmn(zr, zr, 3u, Assembler::LE);",
|
||||
["mov", "__ mov(v1, __ T2S, 1, zr);", "mov\tv1.s[1], wzr"],
|
||||
["mov", "__ mov(v1, __ T4H, 2, zr);", "mov\tv1.h[2], wzr"],
|
||||
["mov", "__ mov(v1, __ T8B, 3, zr);", "mov\tv1.b[3], wzr"],
|
||||
["ld1", "__ ld1(v31, v0, __ T2D, Address(__ post(r1, r0)));", "ld1\t{v31.2d, v0.2d}, [x1], x0"]])
|
||||
["ld1", "__ ld1(v31, v0, __ T2D, Address(__ post(r1, r0)));", "ld1\t{v31.2d, v0.2d}, [x1], x0"],
|
||||
# SVE instructions
|
||||
["cpy", "__ sve_cpy(z0, __ S, p0, v1);", "mov\tz0.s, p0/m, s1"],
|
||||
["inc", "__ sve_inc(r0, __ S);", "incw\tx0"],
|
||||
["dec", "__ sve_dec(r1, __ H);", "dech\tx1"],
|
||||
["lsl", "__ sve_lsl(z0, __ B, z1, 7);", "lsl\tz0.b, z1.b, #7"],
|
||||
["lsl", "__ sve_lsl(z21, __ H, z1, 15);", "lsl\tz21.h, z1.h, #15"],
|
||||
["lsl", "__ sve_lsl(z0, __ S, z1, 31);", "lsl\tz0.s, z1.s, #31"],
|
||||
["lsl", "__ sve_lsl(z0, __ D, z1, 63);", "lsl\tz0.d, z1.d, #63"],
|
||||
["lsr", "__ sve_lsr(z0, __ B, z1, 7);", "lsr\tz0.b, z1.b, #7"],
|
||||
["asr", "__ sve_asr(z0, __ H, z11, 15);", "asr\tz0.h, z11.h, #15"],
|
||||
["lsr", "__ sve_lsr(z30, __ S, z1, 31);", "lsr\tz30.s, z1.s, #31"],
|
||||
["asr", "__ sve_asr(z0, __ D, z1, 63);", "asr\tz0.d, z1.d, #63"],
|
||||
["addvl", "__ sve_addvl(sp, r0, 31);", "addvl\tsp, x0, #31"],
|
||||
["addpl", "__ sve_addpl(r1, sp, -32);", "addpl\tx1, sp, -32"],
|
||||
["cntp", "__ sve_cntp(r8, __ B, p0, p1);", "cntp\tx8, p0, p1.b"],
|
||||
["dup", "__ sve_dup(z0, __ B, 127);", "dup\tz0.b, 127"],
|
||||
["dup", "__ sve_dup(z1, __ H, -128);", "dup\tz1.h, -128"],
|
||||
["dup", "__ sve_dup(z2, __ S, 32512);", "dup\tz2.s, 32512"],
|
||||
["dup", "__ sve_dup(z7, __ D, -32768);", "dup\tz7.d, -32768"],
|
||||
["ld1b", "__ sve_ld1b(z0, __ B, p0, Address(sp));", "ld1b\t{z0.b}, p0/z, [sp]"],
|
||||
["ld1h", "__ sve_ld1h(z10, __ H, p1, Address(sp, -8));", "ld1h\t{z10.h}, p1/z, [sp, #-8, MUL VL]"],
|
||||
["ld1w", "__ sve_ld1w(z20, __ S, p2, Address(r0, 7));", "ld1w\t{z20.s}, p2/z, [x0, #7, MUL VL]"],
|
||||
["ld1b", "__ sve_ld1b(z30, __ B, p3, Address(sp, r8));", "ld1b\t{z30.b}, p3/z, [sp, x8]"],
|
||||
["ld1w", "__ sve_ld1w(z0, __ S, p4, Address(sp, r28));", "ld1w\t{z0.s}, p4/z, [sp, x28, LSL #2]"],
|
||||
["ld1d", "__ sve_ld1d(z11, __ D, p5, Address(r0, r1));", "ld1d\t{z11.d}, p5/z, [x0, x1, LSL #3]"],
|
||||
["st1b", "__ sve_st1b(z22, __ B, p6, Address(sp));", "st1b\t{z22.b}, p6, [sp]"],
|
||||
["st1b", "__ sve_st1b(z31, __ B, p7, Address(sp, -8));", "st1b\t{z31.b}, p7, [sp, #-8, MUL VL]"],
|
||||
["st1w", "__ sve_st1w(z0, __ S, p1, Address(r0, 7));", "st1w\t{z0.s}, p1, [x0, #7, MUL VL]"],
|
||||
["st1b", "__ sve_st1b(z0, __ B, p2, Address(sp, r1));", "st1b\t{z0.b}, p2, [sp, x1]"],
|
||||
["st1h", "__ sve_st1h(z0, __ H, p3, Address(sp, r8));", "st1h\t{z0.h}, p3, [sp, x8, LSL #1]"],
|
||||
["st1d", "__ sve_st1d(z0, __ D, p4, Address(r0, r18));", "st1d\t{z0.d}, p4, [x0, x18, LSL #3]"],
|
||||
["ldr", "__ sve_ldr(z0, Address(sp));", "ldr\tz0, [sp]"],
|
||||
["ldr", "__ sve_ldr(z31, Address(sp, -256));", "ldr\tz31, [sp, #-256, MUL VL]"],
|
||||
["str", "__ sve_str(z8, Address(r8, 255));", "str\tz8, [x8, #255, MUL VL]"],
|
||||
])
|
||||
|
||||
print "\n// FloatImmediateOp"
|
||||
for float in ("2.0", "2.125", "4.0", "4.25", "8.0", "8.5", "16.0", "17.0", "0.125",
|
||||
@@ -1139,6 +1360,49 @@ for size in ("x", "w"):
|
||||
["ldumin", "ldumin", size, suffix],
|
||||
["ldumax", "ldumax", size, suffix]]);
|
||||
|
||||
generate(SVEVectorOp, [["add", "ZZZ"],
|
||||
["sub", "ZZZ"],
|
||||
["fadd", "ZZZ"],
|
||||
["fmul", "ZZZ"],
|
||||
["fsub", "ZZZ"],
|
||||
["abs", "ZPZ"],
|
||||
["add", "ZPZ", "dn"],
|
||||
["asr", "ZPZ", "dn"],
|
||||
["cnt", "ZPZ"],
|
||||
["lsl", "ZPZ", "dn"],
|
||||
["lsr", "ZPZ", "dn"],
|
||||
["mul", "ZPZ", "dn"],
|
||||
["neg", "ZPZ"],
|
||||
["not", "ZPZ"],
|
||||
["smax", "ZPZ", "dn"],
|
||||
["smin", "ZPZ", "dn"],
|
||||
["sub", "ZPZ", "dn"],
|
||||
["fabs", "ZPZ"],
|
||||
["fadd", "ZPZ", "dn"],
|
||||
["fdiv", "ZPZ", "dn"],
|
||||
["fmax", "ZPZ", "dn"],
|
||||
["fmin", "ZPZ", "dn"],
|
||||
["fmul", "ZPZ", "dn"],
|
||||
["fneg", "ZPZ"],
|
||||
["frintm", "ZPZ"],
|
||||
["frintn", "ZPZ"],
|
||||
["frintp", "ZPZ"],
|
||||
["fsqrt", "ZPZ"],
|
||||
["fsub", "ZPZ", "dn"],
|
||||
["fmla", "ZPZZ"],
|
||||
["fmls", "ZPZZ"],
|
||||
["fnmla", "ZPZZ"],
|
||||
["fnmls", "ZPZZ"],
|
||||
["mla", "ZPZZ"],
|
||||
["mls", "ZPZZ"],
|
||||
["and", "ZZZ"],
|
||||
["eor", "ZZZ"],
|
||||
["orr", "ZZZ"],
|
||||
])
|
||||
|
||||
generate(SVEReductionOp, [["andv", 0], ["orv", 0], ["eorv", 0], ["smaxv", 0], ["sminv", 0],
|
||||
["fminv", 2], ["fmaxv", 2], ["fadda", 2], ["uaddv", 0]])
|
||||
|
||||
print "\n __ bind(forth);"
|
||||
outfile.write("forth:\n")
|
||||
|
||||
@@ -1147,8 +1411,8 @@ outfile.close()
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# compile for 8.1 because of lse atomics
|
||||
subprocess.check_call([AARCH64_AS, "-march=armv8.1-a", "aarch64ops.s", "-o", "aarch64ops.o"])
|
||||
# compile for sve with 8.1 and sha2 because of lse atomics and sha512 crypto extension.
|
||||
subprocess.check_call([AARCH64_AS, "-march=armv8.1-a+sha2+sve", "aarch64ops.s", "-o", "aarch64ops.o"])
|
||||
|
||||
print
|
||||
print "/*",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1637
src/hotspot/cpu/aarch64/aarch64_sve.ad
Normal file
1637
src/hotspot/cpu/aarch64/aarch64_sve.ad
Normal file
File diff suppressed because it is too large
Load Diff
767
src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
Normal file
767
src/hotspot/cpu/aarch64/aarch64_sve_ad.m4
Normal file
@@ -0,0 +1,767 @@
|
||||
//
|
||||
// Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
// Copyright (c) 2020, Arm Limited. All rights reserved.
|
||||
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
//
|
||||
// This code is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU General Public License version 2 only, as
|
||||
// published by the Free Software Foundation.
|
||||
//
|
||||
// This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// version 2 for more details (a copy is included in the LICENSE file that
|
||||
// accompanied this code).
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License version
|
||||
// 2 along with this work; if not, write to the Free Software Foundation,
|
||||
// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
//
|
||||
// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
//
|
||||
//
|
||||
|
||||
dnl Generate the warning
|
||||
// This file is automatically generated by running "m4 aarch64_sve_ad.m4". Do not edit ----
|
||||
dnl
|
||||
|
||||
// AArch64 SVE Architecture Description File
|
||||
|
||||
dnl
|
||||
dnl OPERAND_VMEMORYA_IMMEDIATE_OFFSET($1, $2, $3 )
|
||||
dnl OPERAND_VMEMORYA_IMMEDIATE_OFFSET(imm_type_abbr, imm_type, imm_len)
|
||||
define(`OPERAND_VMEMORYA_IMMEDIATE_OFFSET', `
|
||||
operand vmemA_imm$1Offset$3()
|
||||
%{
|
||||
predicate(Address::offset_ok_for_sve_immed(n->get_$2(), $3,
|
||||
Matcher::scalable_vector_reg_size(T_BYTE)));
|
||||
match(Con$1);
|
||||
|
||||
op_cost(0);
|
||||
format %{ %}
|
||||
interface(CONST_INTER);
|
||||
%}')
|
||||
dnl
|
||||
// 4 bit signed offset -- for predicated load/store
|
||||
OPERAND_VMEMORYA_IMMEDIATE_OFFSET(I, int, 4)
|
||||
OPERAND_VMEMORYA_IMMEDIATE_OFFSET(L, long, 4)
|
||||
dnl
|
||||
dnl OPERAND_VMEMORYA_INDIRECT_OFFSET($1, $2 )
|
||||
dnl OPERAND_VMEMORYA_INDIRECT_OFFSET(imm_type_abbr, imm_len)
|
||||
define(`OPERAND_VMEMORYA_INDIRECT_OFFSET', `
|
||||
operand vmemA_indOff$1$2(iRegP reg, vmemA_imm$1Offset$2 off)
|
||||
%{
|
||||
constraint(ALLOC_IN_RC(ptr_reg));
|
||||
match(AddP reg off);
|
||||
op_cost(0);
|
||||
format %{ "[$reg, $off, MUL VL]" %}
|
||||
interface(MEMORY_INTER) %{
|
||||
base($reg);
|
||||
`index'(0xffffffff);
|
||||
scale(0x0);
|
||||
disp($off);
|
||||
%}
|
||||
%}')
|
||||
dnl
|
||||
OPERAND_VMEMORYA_INDIRECT_OFFSET(I, 4)
|
||||
OPERAND_VMEMORYA_INDIRECT_OFFSET(L, 4)
|
||||
|
||||
opclass vmemA(indirect, vmemA_indOffI4, vmemA_indOffL4);
|
||||
|
||||
source_hpp %{
|
||||
bool op_sve_supported(int opcode);
|
||||
%}
|
||||
|
||||
source %{
|
||||
|
||||
static inline BasicType vector_element_basic_type(const MachNode* n) {
|
||||
const TypeVect* vt = n->bottom_type()->is_vect();
|
||||
return vt->element_basic_type();
|
||||
}
|
||||
|
||||
static inline BasicType vector_element_basic_type(const MachNode* use, const MachOper* opnd) {
|
||||
int def_idx = use->operand_index(opnd);
|
||||
Node* def = use->in(def_idx);
|
||||
const TypeVect* vt = def->bottom_type()->is_vect();
|
||||
return vt->element_basic_type();
|
||||
}
|
||||
|
||||
typedef void (C2_MacroAssembler::* sve_mem_insn_predicate)(FloatRegister Rt, Assembler::SIMD_RegVariant T,
|
||||
PRegister Pg, const Address &adr);
|
||||
|
||||
// Predicated load/store, with optional ptrue to all elements of given predicate register.
|
||||
static void loadStoreA_predicate(C2_MacroAssembler masm, bool is_store,
|
||||
FloatRegister reg, PRegister pg, BasicType bt,
|
||||
int opcode, Register base, int index, int size, int disp) {
|
||||
sve_mem_insn_predicate insn;
|
||||
Assembler::SIMD_RegVariant type;
|
||||
int esize = type2aelembytes(bt);
|
||||
if (index == -1) {
|
||||
assert(size == 0, "unsupported address mode: scale size = %d", size);
|
||||
switch(esize) {
|
||||
case 1:
|
||||
insn = is_store ? &C2_MacroAssembler::sve_st1b : &C2_MacroAssembler::sve_ld1b;
|
||||
type = Assembler::B;
|
||||
break;
|
||||
case 2:
|
||||
insn = is_store ? &C2_MacroAssembler::sve_st1h : &C2_MacroAssembler::sve_ld1h;
|
||||
type = Assembler::H;
|
||||
break;
|
||||
case 4:
|
||||
insn = is_store ? &C2_MacroAssembler::sve_st1w : &C2_MacroAssembler::sve_ld1w;
|
||||
type = Assembler::S;
|
||||
break;
|
||||
case 8:
|
||||
insn = is_store ? &C2_MacroAssembler::sve_st1d : &C2_MacroAssembler::sve_ld1d;
|
||||
type = Assembler::D;
|
||||
break;
|
||||
default:
|
||||
assert(false, "unsupported");
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
(masm.*insn)(reg, type, pg, Address(base, disp / Matcher::scalable_vector_reg_size(T_BYTE)));
|
||||
} else {
|
||||
assert(false, "unimplemented");
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
bool op_sve_supported(int opcode) {
|
||||
switch (opcode) {
|
||||
case Op_MulAddVS2VI:
|
||||
// No multiply reduction instructions
|
||||
case Op_MulReductionVD:
|
||||
case Op_MulReductionVF:
|
||||
case Op_MulReductionVI:
|
||||
case Op_MulReductionVL:
|
||||
// Others
|
||||
case Op_Extract:
|
||||
case Op_ExtractB:
|
||||
case Op_ExtractC:
|
||||
case Op_ExtractD:
|
||||
case Op_ExtractF:
|
||||
case Op_ExtractI:
|
||||
case Op_ExtractL:
|
||||
case Op_ExtractS:
|
||||
case Op_ExtractUB:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
definitions %{
|
||||
int_def SVE_COST (200, 200);
|
||||
%}
|
||||
|
||||
|
||||
dnl
|
||||
dnl ELEMENT_SHORT_CHART($1, $2)
|
||||
dnl ELEMENT_SHORT_CHART(etype, node)
|
||||
define(`ELEMENT_SHORT_CHAR',`ifelse(`$1', `T_SHORT',
|
||||
`($2->bottom_type()->is_vect()->element_basic_type() == T_SHORT ||
|
||||
($2->bottom_type()->is_vect()->element_basic_type() == T_CHAR))',
|
||||
`($2->bottom_type()->is_vect()->element_basic_type() == $1)')')
|
||||
dnl
|
||||
|
||||
// All SVE instructions
|
||||
|
||||
// vector load/store
|
||||
|
||||
// Use predicated vector load/store
|
||||
instruct loadV(vReg dst, vmemA mem) %{
|
||||
predicate(UseSVE > 0 && n->as_LoadVector()->memory_size() >= 16);
|
||||
match(Set dst (LoadVector mem));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_ldr $dst, $mem\t # vector (sve)" %}
|
||||
ins_encode %{
|
||||
FloatRegister dst_reg = as_FloatRegister($dst$$reg);
|
||||
loadStoreA_predicate(C2_MacroAssembler(&cbuf), false, dst_reg, ptrue,
|
||||
vector_element_basic_type(this), $mem->opcode(),
|
||||
as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
instruct storeV(vReg src, vmemA mem) %{
|
||||
predicate(UseSVE > 0 && n->as_StoreVector()->memory_size() >= 16);
|
||||
match(Set mem (StoreVector mem src));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_str $mem, $src\t # vector (sve)" %}
|
||||
ins_encode %{
|
||||
FloatRegister src_reg = as_FloatRegister($src$$reg);
|
||||
loadStoreA_predicate(C2_MacroAssembler(&cbuf), true, src_reg, ptrue,
|
||||
vector_element_basic_type(this, $src), $mem->opcode(),
|
||||
as_Register($mem$$base), $mem$$index, $mem$$scale, $mem$$disp);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
dnl
|
||||
dnl UNARY_OP_TRUE_PREDICATE_ETYPE($1, $2, $3, $4, $5, %6 )
|
||||
dnl UNARY_OP_TRUE_PREDICATE_ETYPE(insn_name, op_name, element_type, size, min_vec_len, insn)
|
||||
define(`UNARY_OP_TRUE_PREDICATE_ETYPE', `
|
||||
instruct $1(vReg dst, vReg src) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $5 &&
|
||||
n->bottom_type()->is_vect()->element_basic_type() == $3);
|
||||
match(Set dst ($2 src));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$6 $dst, $src\t# vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ $6(as_FloatRegister($dst$$reg), __ $4,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector abs
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsB, AbsVB, T_BYTE, B, 16, sve_abs)
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsS, AbsVS, T_SHORT, H, 8, sve_abs)
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsI, AbsVI, T_INT, S, 4, sve_abs)
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsL, AbsVL, T_LONG, D, 2, sve_abs)
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsF, AbsVF, T_FLOAT, S, 4, sve_fabs)
|
||||
UNARY_OP_TRUE_PREDICATE_ETYPE(vabsD, AbsVD, T_DOUBLE, D, 2, sve_fabs)
|
||||
dnl
|
||||
dnl BINARY_OP_UNPREDICATED($1, $2 $3, $4 $5 )
|
||||
dnl BINARY_OP_UNPREDICATED(insn_name, op_name, size, min_vec_len, insn)
|
||||
define(`BINARY_OP_UNPREDICATED', `
|
||||
instruct $1(vReg dst, vReg src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $4);
|
||||
match(Set dst ($2 src1 src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$5 $dst, $src1, $src2\t # vector (sve) ($3)" %}
|
||||
ins_encode %{
|
||||
__ $5(as_FloatRegister($dst$$reg), __ $3,
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector add
|
||||
BINARY_OP_UNPREDICATED(vaddB, AddVB, B, 16, sve_add)
|
||||
BINARY_OP_UNPREDICATED(vaddS, AddVS, H, 8, sve_add)
|
||||
BINARY_OP_UNPREDICATED(vaddI, AddVI, S, 4, sve_add)
|
||||
BINARY_OP_UNPREDICATED(vaddL, AddVL, D, 2, sve_add)
|
||||
BINARY_OP_UNPREDICATED(vaddF, AddVF, S, 4, sve_fadd)
|
||||
BINARY_OP_UNPREDICATED(vaddD, AddVD, D, 2, sve_fadd)
|
||||
dnl
|
||||
dnl BINARY_OP_UNSIZED($1, $2, $3, $4 )
|
||||
dnl BINARY_OP_UNSIZED(insn_name, op_name, min_vec_len, insn)
|
||||
define(`BINARY_OP_UNSIZED', `
|
||||
instruct $1(vReg dst, vReg src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length_in_bytes() >= $3);
|
||||
match(Set dst ($2 src1 src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$4 $dst, $src1, $src2\t# vector (sve)" %}
|
||||
ins_encode %{
|
||||
__ $4(as_FloatRegister($dst$$reg),
|
||||
as_FloatRegister($src1$$reg),
|
||||
as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector and
|
||||
BINARY_OP_UNSIZED(vand, AndV, 16, sve_and)
|
||||
|
||||
// vector or
|
||||
BINARY_OP_UNSIZED(vor, OrV, 16, sve_orr)
|
||||
|
||||
// vector xor
|
||||
BINARY_OP_UNSIZED(vxor, XorV, 16, sve_eor)
|
||||
dnl
|
||||
dnl VDIVF($1, $2 , $3 )
|
||||
dnl VDIVF(name_suffix, size, min_vec_len)
|
||||
define(`VDIVF', `
|
||||
instruct vdiv$1(vReg dst_src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (DivV$1 dst_src1 src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fdiv $dst_src1, $dst_src1, $src2\t# vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_fdiv(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector float div
|
||||
VDIVF(F, S, 4)
|
||||
VDIVF(D, D, 2)
|
||||
|
||||
dnl
|
||||
dnl BINARY_OP_TRUE_PREDICATE_ETYPE($1, $2, $3, $4, $5, $6 )
|
||||
dnl BINARY_OP_TRUE_PREDICATE_ETYPE(insn_name, op_name, element_type, size, min_vec_len, insn)
|
||||
define(`BINARY_OP_TRUE_PREDICATE_ETYPE', `
|
||||
instruct $1(vReg dst_src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $5 &&
|
||||
n->bottom_type()->is_vect()->element_basic_type() == $3);
|
||||
match(Set dst_src1 ($2 dst_src1 src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$6 $dst_src1, $dst_src1, $src2\t # vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ $6(as_FloatRegister($dst_src1$$reg), __ $4,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector max
|
||||
BINARY_OP_TRUE_PREDICATE_ETYPE(vmaxF, MaxV, T_FLOAT, S, 4, sve_fmax)
|
||||
BINARY_OP_TRUE_PREDICATE_ETYPE(vmaxD, MaxV, T_DOUBLE, D, 2, sve_fmax)
|
||||
BINARY_OP_TRUE_PREDICATE_ETYPE(vminF, MinV, T_FLOAT, S, 4, sve_fmin)
|
||||
BINARY_OP_TRUE_PREDICATE_ETYPE(vminD, MinV, T_DOUBLE, D, 2, sve_fmin)
|
||||
|
||||
dnl
|
||||
dnl VFMLA($1 $2 $3 )
|
||||
dnl VFMLA(name_suffix, size, min_vec_len)
|
||||
define(`VFMLA', `
|
||||
// dst_src1 = dst_src1 + src2 * src3
|
||||
instruct vfmla$1(vReg dst_src1, vReg src2, vReg src3) %{
|
||||
predicate(UseFMA && UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (FmaV$1 dst_src1 (Binary src2 src3)));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fmla $dst_src1, $src2, $src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_fmla(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector fmla
|
||||
VFMLA(F, S, 4)
|
||||
VFMLA(D, D, 2)
|
||||
|
||||
dnl
|
||||
dnl VFMLS($1 $2 $3 )
|
||||
dnl VFMLS(name_suffix, size, min_vec_len)
|
||||
define(`VFMLS', `
|
||||
// dst_src1 = dst_src1 + -src2 * src3
|
||||
// dst_src1 = dst_src1 + src2 * -src3
|
||||
instruct vfmls$1(vReg dst_src1, vReg src2, vReg src3) %{
|
||||
predicate(UseFMA && UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (FmaV$1 dst_src1 (Binary (NegV$1 src2) src3)));
|
||||
match(Set dst_src1 (FmaV$1 dst_src1 (Binary src2 (NegV$1 src3))));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fmls $dst_src1, $src2, $src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_fmls(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector fmls
|
||||
VFMLS(F, S, 4)
|
||||
VFMLS(D, D, 2)
|
||||
|
||||
dnl
|
||||
dnl VFNMLA($1 $2 $3 )
|
||||
dnl VFNMLA(name_suffix, size, min_vec_len)
|
||||
define(`VFNMLA', `
|
||||
// dst_src1 = -dst_src1 + -src2 * src3
|
||||
// dst_src1 = -dst_src1 + src2 * -src3
|
||||
instruct vfnmla$1(vReg dst_src1, vReg src2, vReg src3) %{
|
||||
predicate(UseFMA && UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (FmaV$1 (NegV$1 dst_src1) (Binary (NegV$1 src2) src3)));
|
||||
match(Set dst_src1 (FmaV$1 (NegV$1 dst_src1) (Binary src2 (NegV$1 src3))));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fnmla $dst_src1, $src2, $src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_fnmla(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector fnmla
|
||||
VFNMLA(F, S, 4)
|
||||
VFNMLA(D, D, 2)
|
||||
|
||||
dnl
|
||||
dnl VFNMLS($1 $2 $3 )
|
||||
dnl VFNMLS(name_suffix, size, min_vec_len)
|
||||
define(`VFNMLS', `
|
||||
// dst_src1 = -dst_src1 + src2 * src3
|
||||
instruct vfnmls$1(vReg dst_src1, vReg src2, vReg src3) %{
|
||||
predicate(UseFMA && UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (FmaV$1 (NegV$1 dst_src1) (Binary src2 src3)));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fnmls $dst_src1, $src2, $src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_fnmls(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector fnmls
|
||||
VFNMLS(F, S, 4)
|
||||
VFNMLS(D, D, 2)
|
||||
|
||||
dnl
|
||||
dnl VMLA($1 $2 $3 )
|
||||
dnl VMLA(name_suffix, size, min_vec_len)
|
||||
define(`VMLA', `
|
||||
// dst_src1 = dst_src1 + src2 * src3
|
||||
instruct vmla$1(vReg dst_src1, vReg src2, vReg src3)
|
||||
%{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (AddV$1 dst_src1 (MulV$1 src2 src3)));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_mla $dst_src1, src2, src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_mla(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector mla
|
||||
VMLA(B, B, 16)
|
||||
VMLA(S, H, 8)
|
||||
VMLA(I, S, 4)
|
||||
VMLA(L, D, 2)
|
||||
|
||||
dnl
|
||||
dnl VMLS($1 $2 $3 )
|
||||
dnl VMLS(name_suffix, size, min_vec_len)
|
||||
define(`VMLS', `
|
||||
// dst_src1 = dst_src1 - src2 * src3
|
||||
instruct vmls$1(vReg dst_src1, vReg src2, vReg src3)
|
||||
%{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $3);
|
||||
match(Set dst_src1 (SubV$1 dst_src1 (MulV$1 src2 src3)));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_mls $dst_src1, src2, src3\t # vector (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_mls(as_FloatRegister($dst_src1$$reg), __ $2,
|
||||
ptrue, as_FloatRegister($src2$$reg), as_FloatRegister($src3$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector mls
|
||||
VMLS(B, B, 16)
|
||||
VMLS(S, H, 8)
|
||||
VMLS(I, S, 4)
|
||||
VMLS(L, D, 2)
|
||||
|
||||
dnl
|
||||
dnl BINARY_OP_TRUE_PREDICATE($1, $2, $3, $4, $5 )
|
||||
dnl BINARY_OP_TRUE_PREDICATE(insn_name, op_name, size, min_vec_len, insn)
|
||||
define(`BINARY_OP_TRUE_PREDICATE', `
|
||||
instruct $1(vReg dst_src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $4);
|
||||
match(Set dst_src1 ($2 dst_src1 src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$5 $dst_src1, $dst_src1, $src2\t # vector (sve) ($3)" %}
|
||||
ins_encode %{
|
||||
__ $5(as_FloatRegister($dst_src1$$reg), __ $3,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector mul
|
||||
BINARY_OP_TRUE_PREDICATE(vmulB, MulVB, B, 16, sve_mul)
|
||||
BINARY_OP_TRUE_PREDICATE(vmulS, MulVS, H, 8, sve_mul)
|
||||
BINARY_OP_TRUE_PREDICATE(vmulI, MulVI, S, 4, sve_mul)
|
||||
BINARY_OP_TRUE_PREDICATE(vmulL, MulVL, D, 2, sve_mul)
|
||||
BINARY_OP_UNPREDICATED(vmulF, MulVF, S, 4, sve_fmul)
|
||||
BINARY_OP_UNPREDICATED(vmulD, MulVD, D, 2, sve_fmul)
|
||||
|
||||
dnl
|
||||
dnl UNARY_OP_TRUE_PREDICATE($1, $2, $3, $4, $5 )
|
||||
dnl UNARY_OP_TRUE_PREDICATE(insn_name, op_name, size, min_vec_bytes, insn)
|
||||
define(`UNARY_OP_TRUE_PREDICATE', `
|
||||
instruct $1(vReg dst, vReg src) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length_in_bytes() >= $4);
|
||||
match(Set dst ($2 src));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$5 $dst, $src\t# vector (sve) ($3)" %}
|
||||
ins_encode %{
|
||||
__ $5(as_FloatRegister($dst$$reg), __ $3,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector fneg
|
||||
UNARY_OP_TRUE_PREDICATE(vnegF, NegVF, S, 16, sve_fneg)
|
||||
UNARY_OP_TRUE_PREDICATE(vnegD, NegVD, D, 16, sve_fneg)
|
||||
|
||||
// popcount vector
|
||||
|
||||
instruct vpopcountI(vReg dst, vReg src) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= 4);
|
||||
match(Set dst (PopCountVI src));
|
||||
format %{ "sve_cnt $dst, $src\t# vector (sve) (S)\n\t" %}
|
||||
ins_encode %{
|
||||
__ sve_cnt(as_FloatRegister($dst$$reg), __ S, ptrue, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
|
||||
dnl
|
||||
dnl REDUCE_ADD($1, $2, $3, $4, $5, $6, $7 )
|
||||
dnl REDUCE_ADD(insn_name, op_name, reg_dst, reg_src, size, elem_type, insn1)
|
||||
define(`REDUCE_ADD', `
|
||||
instruct $1($3 dst, $4 src1, vReg src2, vRegD tmp) %{
|
||||
predicate(UseSVE > 0 && n->in(2)->bottom_type()->is_vect()->length_in_bytes() >= 16 &&
|
||||
ELEMENT_SHORT_CHAR($6, n->in(2)));
|
||||
match(Set dst ($2 src1 src2));
|
||||
effect(TEMP_DEF dst, TEMP tmp);
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_uaddv $tmp, $src2\t# vector (sve) ($5)\n\t"
|
||||
"umov $dst, $tmp, $5, 0\n\t"
|
||||
"$7 $dst, $dst, $src1\t # add reduction $5" %}
|
||||
ins_encode %{
|
||||
__ sve_uaddv(as_FloatRegister($tmp$$reg), __ $5,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
__ umov($dst$$Register, as_FloatRegister($tmp$$reg), __ $5, 0);
|
||||
__ $7($dst$$Register, $dst$$Register, $src1$$Register);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
dnl REDUCE_ADDF($1, $2, $3, $4 )
|
||||
dnl REDUCE_ADDF(insn_name, op_name, reg_dst, size)
|
||||
define(`REDUCE_ADDF', `
|
||||
instruct $1($3 src1_dst, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->in(2)->bottom_type()->is_vect()->length_in_bytes() >= 16);
|
||||
match(Set src1_dst ($2 src1_dst src2));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_fadda $src1_dst, $src1_dst, $src2\t# vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ sve_fadda(as_FloatRegister($src1_dst$$reg), __ $4,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
// vector add reduction
|
||||
REDUCE_ADD(reduce_addI, AddReductionVI, iRegINoSp, iRegIorL2I, S, T_INT, addw)
|
||||
REDUCE_ADD(reduce_addL, AddReductionVL, iRegLNoSp, iRegL, D, T_LONG, add)
|
||||
REDUCE_ADDF(reduce_addF, AddReductionVF, vRegF, S)
|
||||
REDUCE_ADDF(reduce_addD, AddReductionVD, vRegD, D)
|
||||
|
||||
dnl
|
||||
dnl REDUCE_FMINMAX($1, $2, $3, $4, $5 )
|
||||
dnl REDUCE_FMINMAX(min_max, name_suffix, element_type, size, reg_src_dst)
|
||||
define(`REDUCE_FMINMAX', `
|
||||
instruct reduce_$1$2($5 dst, $5 src1, vReg src2) %{
|
||||
predicate(UseSVE > 0 && n->in(2)->bottom_type()->is_vect()->element_basic_type() == $3 &&
|
||||
n->in(2)->bottom_type()->is_vect()->length_in_bytes() >= 16);
|
||||
match(Set dst (translit($1, `m', `M')ReductionV src1 src2));
|
||||
ins_cost(INSN_COST);
|
||||
effect(TEMP_DEF dst);
|
||||
format %{ "sve_f$1v $dst, $src2 # vector (sve) (S)\n\t"
|
||||
"f$1s $dst, $dst, $src1\t # $1 reduction $2" %}
|
||||
ins_encode %{
|
||||
__ sve_f$1v(as_FloatRegister($dst$$reg), __ $4,
|
||||
ptrue, as_FloatRegister($src2$$reg));
|
||||
__ f`$1'translit($4, `SD', `sd')(as_FloatRegister($dst$$reg), as_FloatRegister($dst$$reg), as_FloatRegister($src1$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
// vector max reduction
|
||||
REDUCE_FMINMAX(max, F, T_FLOAT, S, vRegF)
|
||||
REDUCE_FMINMAX(max, D, T_DOUBLE, D, vRegD)
|
||||
|
||||
// vector min reduction
|
||||
REDUCE_FMINMAX(min, F, T_FLOAT, S, vRegF)
|
||||
REDUCE_FMINMAX(min, D, T_DOUBLE, D, vRegD)
|
||||
|
||||
// vector Math.rint, floor, ceil
|
||||
|
||||
instruct vroundD(vReg dst, vReg src, immI rmode) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= 2 &&
|
||||
n->bottom_type()->is_vect()->element_basic_type() == T_DOUBLE);
|
||||
match(Set dst (RoundDoubleModeV src rmode));
|
||||
format %{ "sve_frint $dst, $src, $rmode\t# vector (sve) (D)" %}
|
||||
ins_encode %{
|
||||
switch ($rmode$$constant) {
|
||||
case RoundDoubleModeNode::rmode_rint:
|
||||
__ sve_frintn(as_FloatRegister($dst$$reg), __ D,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
break;
|
||||
case RoundDoubleModeNode::rmode_floor:
|
||||
__ sve_frintm(as_FloatRegister($dst$$reg), __ D,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
break;
|
||||
case RoundDoubleModeNode::rmode_ceil:
|
||||
__ sve_frintp(as_FloatRegister($dst$$reg), __ D,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
break;
|
||||
}
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}
|
||||
dnl
|
||||
dnl REPLICATE($1, $2, $3, $4, $5 )
|
||||
dnl REPLICATE(insn_name, op_name, reg_src, size, min_vec_len)
|
||||
define(`REPLICATE', `
|
||||
instruct $1(vReg dst, $3 src) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $5);
|
||||
match(Set dst ($2 src));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_dup $dst, $src\t# vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ sve_dup(as_FloatRegister($dst$$reg), __ $4, as_Register($src$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
dnl REPLICATE_IMM8($1, $2, $3, $4, $5 )
|
||||
dnl REPLICATE_IMM8(insn_name, op_name, imm_type, size, min_vec_len)
|
||||
define(`REPLICATE_IMM8', `
|
||||
instruct $1(vReg dst, $3 con) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $5);
|
||||
match(Set dst ($2 con));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_dup $dst, $con\t# vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ sve_dup(as_FloatRegister($dst$$reg), __ $4, $con$$constant);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
dnl FREPLICATE($1, $2, $3, $4, $5 )
|
||||
dnl FREPLICATE(insn_name, op_name, reg_src, size, min_vec_len)
|
||||
define(`FREPLICATE', `
|
||||
instruct $1(vReg dst, $3 src) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $5);
|
||||
match(Set dst ($2 src));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "sve_cpy $dst, $src\t# vector (sve) ($4)" %}
|
||||
ins_encode %{
|
||||
__ sve_cpy(as_FloatRegister($dst$$reg), __ $4,
|
||||
ptrue, as_FloatRegister($src$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector replicate
|
||||
REPLICATE(replicateB, ReplicateB, iRegIorL2I, B, 16)
|
||||
REPLICATE(replicateS, ReplicateS, iRegIorL2I, H, 8)
|
||||
REPLICATE(replicateI, ReplicateI, iRegIorL2I, S, 4)
|
||||
REPLICATE(replicateL, ReplicateL, iRegL, D, 2)
|
||||
|
||||
REPLICATE_IMM8(replicateB_imm8, ReplicateB, immI8, B, 16)
|
||||
REPLICATE_IMM8(replicateS_imm8, ReplicateS, immI8_shift8, H, 8)
|
||||
REPLICATE_IMM8(replicateI_imm8, ReplicateI, immI8_shift8, S, 4)
|
||||
REPLICATE_IMM8(replicateL_imm8, ReplicateL, immL8_shift8, D, 2)
|
||||
|
||||
FREPLICATE(replicateF, ReplicateF, vRegF, S, 4)
|
||||
FREPLICATE(replicateD, ReplicateD, vRegD, D, 2)
|
||||
dnl
|
||||
dnl VSHIFT_TRUE_PREDICATE($1, $2, $3, $4, $5 )
|
||||
dnl VSHIFT_TRUE_PREDICATE(insn_name, op_name, size, min_vec_len, insn)
|
||||
define(`VSHIFT_TRUE_PREDICATE', `
|
||||
instruct $1(vReg dst, vReg shift) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $4);
|
||||
match(Set dst ($2 dst shift));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$5 $dst, $dst, $shift\t# vector (sve) ($3)" %}
|
||||
ins_encode %{
|
||||
__ $5(as_FloatRegister($dst$$reg), __ $3,
|
||||
ptrue, as_FloatRegister($shift$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
dnl VSHIFT_IMM_UNPREDICATE($1, $2, $3, $4, $5 )
|
||||
dnl VSHIFT_IMM_UNPREDICATE(insn_name, op_name, size, min_vec_len, insn)
|
||||
define(`VSHIFT_IMM_UNPREDICATE', `
|
||||
instruct $1(vReg dst, vReg src, immI shift) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $4);
|
||||
match(Set dst ($2 src shift));
|
||||
ins_cost(SVE_COST);
|
||||
format %{ "$5 $dst, $src, $shift\t# vector (sve) ($3)" %}
|
||||
ins_encode %{
|
||||
int con = (int)$shift$$constant;dnl
|
||||
ifelse(eval(index(`$1', `vasr') == 0 || index(`$1', `vlsr') == 0), 1, `
|
||||
if (con == 0) {
|
||||
__ sve_orr(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg),
|
||||
as_FloatRegister($src$$reg));
|
||||
return;
|
||||
}')dnl
|
||||
ifelse(eval(index(`$1', `vasr') == 0), 1, `ifelse(eval(index(`$3', `B') == 0), 1, `
|
||||
if (con >= 8) con = 7;')ifelse(eval(index(`$3', `H') == 0), 1, `
|
||||
if (con >= 16) con = 15;')')dnl
|
||||
ifelse(eval((index(`$1', `vlsl') == 0 || index(`$1', `vlsr') == 0) && (index(`$3', `B') == 0 || index(`$3', `H') == 0)), 1, `
|
||||
if (con >= 8) {
|
||||
__ sve_eor(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg),
|
||||
as_FloatRegister($src$$reg));
|
||||
return;
|
||||
}')
|
||||
__ $5(as_FloatRegister($dst$$reg), __ $3,
|
||||
as_FloatRegister($src$$reg), con);
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
dnl
|
||||
dnl VSHIFT_COUNT($1, $2, $3, $4 )
|
||||
dnl VSHIFT_COUNT(insn_name, size, min_vec_len, type)
|
||||
define(`VSHIFT_COUNT', `
|
||||
instruct $1(vReg dst, iRegIorL2I cnt) %{
|
||||
predicate(UseSVE > 0 && n->as_Vector()->length() >= $3 &&
|
||||
ELEMENT_SHORT_CHAR($4, n));
|
||||
match(Set dst (LShiftCntV cnt));
|
||||
match(Set dst (RShiftCntV cnt));
|
||||
format %{ "sve_dup $dst, $cnt\t# vector shift count (sve) ($2)" %}
|
||||
ins_encode %{
|
||||
__ sve_dup(as_FloatRegister($dst$$reg), __ $2, as_Register($cnt$$reg));
|
||||
%}
|
||||
ins_pipe(pipe_slow);
|
||||
%}')dnl
|
||||
|
||||
// vector shift
|
||||
VSHIFT_TRUE_PREDICATE(vasrB, RShiftVB, B, 16, sve_asr)
|
||||
VSHIFT_TRUE_PREDICATE(vasrS, RShiftVS, H, 8, sve_asr)
|
||||
VSHIFT_TRUE_PREDICATE(vasrI, RShiftVI, S, 4, sve_asr)
|
||||
VSHIFT_TRUE_PREDICATE(vasrL, RShiftVL, D, 2, sve_asr)
|
||||
VSHIFT_TRUE_PREDICATE(vlslB, LShiftVB, B, 16, sve_lsl)
|
||||
VSHIFT_TRUE_PREDICATE(vlslS, LShiftVS, H, 8, sve_lsl)
|
||||
VSHIFT_TRUE_PREDICATE(vlslI, LShiftVI, S, 4, sve_lsl)
|
||||
VSHIFT_TRUE_PREDICATE(vlslL, LShiftVL, D, 2, sve_lsl)
|
||||
VSHIFT_TRUE_PREDICATE(vlsrB, URShiftVB, B, 16, sve_lsr)
|
||||
VSHIFT_TRUE_PREDICATE(vlsrS, URShiftVS, H, 8, sve_lsr)
|
||||
VSHIFT_TRUE_PREDICATE(vlsrI, URShiftVI, S, 4, sve_lsr)
|
||||
VSHIFT_TRUE_PREDICATE(vlsrL, URShiftVL, D, 2, sve_lsr)
|
||||
VSHIFT_IMM_UNPREDICATE(vasrB_imm, RShiftVB, B, 16, sve_asr)
|
||||
VSHIFT_IMM_UNPREDICATE(vasrS_imm, RShiftVS, H, 8, sve_asr)
|
||||
VSHIFT_IMM_UNPREDICATE(vasrI_imm, RShiftVI, S, 4, sve_asr)
|
||||
VSHIFT_IMM_UNPREDICATE(vasrL_imm, RShiftVL, D, 2, sve_asr)
|
||||
VSHIFT_IMM_UNPREDICATE(vlsrB_imm, URShiftVB, B, 16, sve_lsr)
|
||||
VSHIFT_IMM_UNPREDICATE(vlsrS_imm, URShiftVS, H, 8, sve_lsr)
|
||||
VSHIFT_IMM_UNPREDICATE(vlsrI_imm, URShiftVI, S, 4, sve_lsr)
|
||||
VSHIFT_IMM_UNPREDICATE(vlsrL_imm, URShiftVL, D, 2, sve_lsr)
|
||||
VSHIFT_IMM_UNPREDICATE(vlslB_imm, LShiftVB, B, 16, sve_lsl)
|
||||
VSHIFT_IMM_UNPREDICATE(vlslS_imm, LShiftVS, H, 8, sve_lsl)
|
||||
VSHIFT_IMM_UNPREDICATE(vlslI_imm, LShiftVI, S, 4, sve_lsl)
|
||||
VSHIFT_IMM_UNPREDICATE(vlslL_imm, LShiftVL, D, 2, sve_lsl)
|
||||
VSHIFT_COUNT(vshiftcntB, B, 16, T_BYTE)
|
||||
VSHIFT_COUNT(vshiftcntS, H, 8, T_SHORT)
|
||||
VSHIFT_COUNT(vshiftcntI, S, 4, T_INT)
|
||||
VSHIFT_COUNT(vshiftcntL, D, 2, T_LONG)
|
||||
|
||||
// vector sqrt
|
||||
UNARY_OP_TRUE_PREDICATE(vsqrtF, SqrtVF, S, 16, sve_fsqrt)
|
||||
UNARY_OP_TRUE_PREDICATE(vsqrtD, SqrtVD, D, 16, sve_fsqrt)
|
||||
|
||||
// vector sub
|
||||
BINARY_OP_UNPREDICATED(vsubB, SubVB, B, 16, sve_sub)
|
||||
BINARY_OP_UNPREDICATED(vsubS, SubVS, H, 8, sve_sub)
|
||||
BINARY_OP_UNPREDICATED(vsubI, SubVI, S, 4, sve_sub)
|
||||
BINARY_OP_UNPREDICATED(vsubL, SubVL, D, 2, sve_sub)
|
||||
BINARY_OP_UNPREDICATED(vsubF, SubVF, S, 4, sve_fsub)
|
||||
BINARY_OP_UNPREDICATED(vsubD, SubVD, D, 2, sve_fsub)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -136,7 +136,20 @@ void AbstractInterpreter::layout_activation(Method* method,
|
||||
// interpreter_frame_sender_sp interpreter_frame_sender_sp is
|
||||
// the original sp of the caller (the unextended_sp) and
|
||||
// sender_sp is fp+8/16 (32bit/64bit) XXX
|
||||
intptr_t* locals = interpreter_frame->sender_sp() + max_locals - 1;
|
||||
//
|
||||
// The interpreted method entry on AArch64 aligns SP to 16 bytes
|
||||
// before generating the fixed part of the activation frame. So there
|
||||
// may be a gap between the locals block and the saved sender SP. For
|
||||
// an interpreted caller we need to recreate this gap and exactly
|
||||
// align the incoming parameters with the caller's temporary
|
||||
// expression stack. For other types of caller frame it doesn't
|
||||
// matter.
|
||||
intptr_t* locals;
|
||||
if (caller->is_interpreted_frame()) {
|
||||
locals = caller->interpreter_frame_last_sp() + caller_actual_parameters - 1;
|
||||
} else {
|
||||
locals = interpreter_frame->sender_sp() + max_locals - 1;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
if (caller->is_interpreted_frame()) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -139,6 +139,9 @@ REGISTER_DECLARATION(Register, rdispatch, r21);
|
||||
// Java stack pointer
|
||||
REGISTER_DECLARATION(Register, esp, r20);
|
||||
|
||||
// Preserved predicate register with all elements set TRUE.
|
||||
REGISTER_DECLARATION(PRegister, ptrue, p7);
|
||||
|
||||
#define assert_cond(ARG1) assert(ARG1, #ARG1)
|
||||
|
||||
namespace asm_util {
|
||||
@@ -273,6 +276,14 @@ public:
|
||||
f(r->encoding_nocheck(), lsb + 4, lsb);
|
||||
}
|
||||
|
||||
void prf(PRegister r, int lsb) {
|
||||
f(r->encoding_nocheck(), lsb + 3, lsb);
|
||||
}
|
||||
|
||||
void pgrf(PRegister r, int lsb) {
|
||||
f(r->encoding_nocheck(), lsb + 2, lsb);
|
||||
}
|
||||
|
||||
unsigned get(int msb = 31, int lsb = 0) {
|
||||
int nbits = msb - lsb + 1;
|
||||
unsigned mask = ((1U << nbits) - 1) << lsb;
|
||||
@@ -380,9 +391,15 @@ class Address {
|
||||
: _base(r), _index(noreg), _offset(0), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, int o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, int64_t o)
|
||||
Address(Register r, long o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, uint64_t o)
|
||||
Address(Register r, long long o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, unsigned int o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, unsigned long o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
Address(Register r, unsigned long long o)
|
||||
: _base(r), _index(noreg), _offset(o), _mode(base_plus_offset), _target(0) { }
|
||||
#ifdef ASSERT
|
||||
Address(Register r, ByteSize disp)
|
||||
@@ -554,13 +571,18 @@ class Address {
|
||||
|
||||
void lea(MacroAssembler *, Register) const;
|
||||
|
||||
static bool offset_ok_for_immed(int64_t offset, int shift) {
|
||||
unsigned mask = (1 << shift) - 1;
|
||||
if (offset < 0 || offset & mask) {
|
||||
return (uabs(offset) < (1 << (20 - 12))); // Unscaled offset
|
||||
} else {
|
||||
return ((offset >> shift) < (1 << (21 - 10 + 1))); // Scaled, unsigned offset
|
||||
static bool offset_ok_for_immed(int64_t offset, uint shift);
|
||||
|
||||
static bool offset_ok_for_sve_immed(long offset, int shift, int vl /* sve vector length */) {
|
||||
if (offset % vl == 0) {
|
||||
// Convert address offset into sve imm offset (MUL VL).
|
||||
int sve_offset = offset / vl;
|
||||
if (((-(1 << (shift - 1))) <= sve_offset) && (sve_offset < (1 << (shift - 1)))) {
|
||||
// sve_offset can be encoded
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -685,6 +707,12 @@ public:
|
||||
void rf(FloatRegister reg, int lsb) {
|
||||
current->rf(reg, lsb);
|
||||
}
|
||||
void prf(PRegister reg, int lsb) {
|
||||
current->prf(reg, lsb);
|
||||
}
|
||||
void pgrf(PRegister reg, int lsb) {
|
||||
current->pgrf(reg, lsb);
|
||||
}
|
||||
void fixed(unsigned value, unsigned mask) {
|
||||
current->fixed(value, mask);
|
||||
}
|
||||
@@ -2014,6 +2042,21 @@ public:
|
||||
#undef INSN
|
||||
#undef INSN1
|
||||
|
||||
// Floating-point compare. 3-registers versions (scalar).
|
||||
#define INSN(NAME, sz, e) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn, FloatRegister Vm) { \
|
||||
starti; \
|
||||
f(0b01111110, 31, 24), f(e, 23), f(sz, 22), f(1, 21), rf(Vm, 16); \
|
||||
f(0b111011, 15, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
} \
|
||||
|
||||
INSN(facged, 1, 0); // facge-double
|
||||
INSN(facges, 0, 0); // facge-single
|
||||
INSN(facgtd, 1, 1); // facgt-double
|
||||
INSN(facgts, 0, 1); // facgt-single
|
||||
|
||||
#undef INSN
|
||||
|
||||
// Floating-point Move (immediate)
|
||||
private:
|
||||
unsigned pack(double value);
|
||||
@@ -2379,6 +2422,30 @@ public:
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm) { \
|
||||
starti; \
|
||||
assert(T == T2D, "arrangement must be T2D"); \
|
||||
f(0b11001110011, 31, 21), rf(Vm, 16), f(opc, 15, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(sha512h, 0b100000);
|
||||
INSN(sha512h2, 0b100001);
|
||||
INSN(sha512su1, 0b100010);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn) { \
|
||||
starti; \
|
||||
assert(T == T2D, "arrangement must be T2D"); \
|
||||
f(opc, 31, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(sha512su0, 0b1100111011000000100000);
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn) { \
|
||||
starti; \
|
||||
@@ -2435,13 +2502,18 @@ public:
|
||||
f(sidx<<(int)T, 14, 11), f(1, 10), rf(Vn, 5), rf(Vd, 0);
|
||||
}
|
||||
|
||||
void umov(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) {
|
||||
starti;
|
||||
f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21);
|
||||
f(((idx<<1)|1)<<(int)T, 20, 16), f(0b001111, 15, 10);
|
||||
rf(Vn, 5), rf(Rd, 0);
|
||||
#define INSN(NAME, op) \
|
||||
void NAME(Register Rd, FloatRegister Vn, SIMD_RegVariant T, int idx) { \
|
||||
starti; \
|
||||
f(0, 31), f(T==D ? 1:0, 30), f(0b001110000, 29, 21); \
|
||||
f(((idx<<1)|1)<<(int)T, 20, 16), f(op, 15, 10); \
|
||||
rf(Vn, 5), rf(Rd, 0); \
|
||||
}
|
||||
|
||||
INSN(umov, 0b001111);
|
||||
INSN(smov, 0b001011);
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc, opc2, isSHR) \
|
||||
void NAME(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, int shift){ \
|
||||
starti; \
|
||||
@@ -2471,6 +2543,20 @@ public:
|
||||
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, opc, opc2, isSHR) \
|
||||
void NAME(FloatRegister Vd, FloatRegister Vn, int shift){ \
|
||||
starti; \
|
||||
int encodedShift = isSHR ? 128 - shift : 64 + shift; \
|
||||
f(0b01, 31, 30), f(opc, 29), f(0b111110, 28, 23), \
|
||||
f(encodedShift, 22, 16); f(opc2, 15, 10), rf(Vn, 5), rf(Vd, 0); \
|
||||
}
|
||||
|
||||
INSN(shld, 0, 0b010101, /* isSHR = */ false);
|
||||
INSN(sshrd, 0, 0b000001, /* isSHR = */ true);
|
||||
INSN(ushrd, 1, 0b000001, /* isSHR = */ true);
|
||||
|
||||
#undef INSN
|
||||
|
||||
private:
|
||||
void _ushll(FloatRegister Vd, SIMD_Arrangement Ta, FloatRegister Vn, SIMD_Arrangement Tb, int shift) {
|
||||
starti;
|
||||
@@ -2659,7 +2745,7 @@ public:
|
||||
|
||||
#undef INSN
|
||||
|
||||
void ext(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index)
|
||||
void ext(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister Vm, int index)
|
||||
{
|
||||
starti;
|
||||
assert(T == T8B || T == T16B, "invalid arrangement");
|
||||
@@ -2669,6 +2755,292 @@ void ext(FloatRegister Vd, SIMD_Arrangement T, FloatRegister Vn, FloatRegister V
|
||||
f(0, 10), rf(Vn, 5), rf(Vd, 0);
|
||||
}
|
||||
|
||||
// SVE arithmetics - unpredicated
|
||||
#define INSN(NAME, opcode) \
|
||||
void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \
|
||||
starti; \
|
||||
assert(T != Q, "invalid register variant"); \
|
||||
f(0b00000100, 31, 24), f(T, 23, 22), f(1, 21), \
|
||||
rf(Zm, 16), f(0, 15, 13), f(opcode, 12, 10), rf(Zn, 5), rf(Zd, 0); \
|
||||
}
|
||||
INSN(sve_add, 0b000);
|
||||
INSN(sve_sub, 0b001);
|
||||
#undef INSN
|
||||
|
||||
// SVE floating-point arithmetic - unpredicated
|
||||
#define INSN(NAME, opcode) \
|
||||
void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, FloatRegister Zm) { \
|
||||
starti; \
|
||||
assert(T == S || T == D, "invalid register variant"); \
|
||||
f(0b01100101, 31, 24), f(T, 23, 22), f(0, 21), \
|
||||
rf(Zm, 16), f(0, 15, 13), f(opcode, 12, 10), rf(Zn, 5), rf(Zd, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_fadd, 0b000);
|
||||
INSN(sve_fmul, 0b010);
|
||||
INSN(sve_fsub, 0b001);
|
||||
#undef INSN
|
||||
|
||||
private:
|
||||
void sve_predicate_reg_insn(unsigned op24, unsigned op13,
|
||||
FloatRegister Zd_or_Vd, SIMD_RegVariant T,
|
||||
PRegister Pg, FloatRegister Zn_or_Vn) {
|
||||
starti;
|
||||
f(op24, 31, 24), f(T, 23, 22), f(op13, 21, 13);
|
||||
pgrf(Pg, 10), rf(Zn_or_Vn, 5), rf(Zd_or_Vd, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// SVE integer arithmetics - predicate
|
||||
#define INSN(NAME, op1, op2) \
|
||||
void NAME(FloatRegister Zdn_or_Zd_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Znm_or_Vn) { \
|
||||
assert(T != Q, "invalid register variant"); \
|
||||
sve_predicate_reg_insn(op1, op2, Zdn_or_Zd_or_Vd, T, Pg, Znm_or_Vn); \
|
||||
}
|
||||
|
||||
INSN(sve_abs, 0b00000100, 0b010110101); // vector abs, unary
|
||||
INSN(sve_add, 0b00000100, 0b000000000); // vector add
|
||||
INSN(sve_andv, 0b00000100, 0b011010001); // bitwise and reduction to scalar
|
||||
INSN(sve_asr, 0b00000100, 0b010000100); // vector arithmetic shift right
|
||||
INSN(sve_cnt, 0b00000100, 0b011010101) // count non-zero bits
|
||||
INSN(sve_cpy, 0b00000101, 0b100000100); // copy scalar to each active vector element
|
||||
INSN(sve_eorv, 0b00000100, 0b011001001); // bitwise xor reduction to scalar
|
||||
INSN(sve_lsl, 0b00000100, 0b010011100); // vector logical shift left
|
||||
INSN(sve_lsr, 0b00000100, 0b010001100); // vector logical shift right
|
||||
INSN(sve_mul, 0b00000100, 0b010000000); // vector mul
|
||||
INSN(sve_neg, 0b00000100, 0b010111101); // vector neg, unary
|
||||
INSN(sve_not, 0b00000100, 0b011110101); // bitwise invert vector, unary
|
||||
INSN(sve_orv, 0b00000100, 0b011000001); // bitwise or reduction to scalar
|
||||
INSN(sve_smax, 0b00000100, 0b001000000); // signed maximum vectors
|
||||
INSN(sve_smaxv, 0b00000100, 0b001000001); // signed maximum reduction to scalar
|
||||
INSN(sve_smin, 0b00000100, 0b001010000); // signed minimum vectors
|
||||
INSN(sve_sminv, 0b00000100, 0b001010001); // signed minimum reduction to scalar
|
||||
INSN(sve_sub, 0b00000100, 0b000001000); // vector sub
|
||||
INSN(sve_uaddv, 0b00000100, 0b000001001); // unsigned add reduction to scalar
|
||||
#undef INSN
|
||||
|
||||
// SVE floating-point arithmetics - predicate
|
||||
#define INSN(NAME, op1, op2) \
|
||||
void NAME(FloatRegister Zd_or_Zdn_or_Vd, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn_or_Zm) { \
|
||||
assert(T == S || T == D, "invalid register variant"); \
|
||||
sve_predicate_reg_insn(op1, op2, Zd_or_Zdn_or_Vd, T, Pg, Zn_or_Zm); \
|
||||
}
|
||||
|
||||
INSN(sve_fabs, 0b00000100, 0b011100101);
|
||||
INSN(sve_fadd, 0b01100101, 0b000000100);
|
||||
INSN(sve_fadda, 0b01100101, 0b011000001); // add strictly-ordered reduction to scalar Vd
|
||||
INSN(sve_fdiv, 0b01100101, 0b001101100);
|
||||
INSN(sve_fmax, 0b01100101, 0b000110100); // floating-point maximum
|
||||
INSN(sve_fmaxv, 0b01100101, 0b000110001); // floating-point maximum recursive reduction to scalar
|
||||
INSN(sve_fmin, 0b01100101, 0b000111100); // floating-point minimum
|
||||
INSN(sve_fminv, 0b01100101, 0b000111001); // floating-point minimum recursive reduction to scalar
|
||||
INSN(sve_fmul, 0b01100101, 0b000010100);
|
||||
INSN(sve_fneg, 0b00000100, 0b011101101);
|
||||
INSN(sve_frintm, 0b01100101, 0b000010101); // floating-point round to integral value, toward minus infinity
|
||||
INSN(sve_frintn, 0b01100101, 0b000000101); // floating-point round to integral value, nearest with ties to even
|
||||
INSN(sve_frintp, 0b01100101, 0b000001101); // floating-point round to integral value, toward plus infinity
|
||||
INSN(sve_fsqrt, 0b01100101, 0b001101101);
|
||||
INSN(sve_fsub, 0b01100101, 0b000001100);
|
||||
#undef INSN
|
||||
|
||||
// SVE multiple-add/sub - predicated
|
||||
#define INSN(NAME, op0, op1, op2) \
|
||||
void NAME(FloatRegister Zda, SIMD_RegVariant T, PRegister Pg, FloatRegister Zn, FloatRegister Zm) { \
|
||||
starti; \
|
||||
assert(T != Q, "invalid size"); \
|
||||
f(op0, 31, 24), f(T, 23, 22), f(op1, 21), rf(Zm, 16); \
|
||||
f(op2, 15, 13), pgrf(Pg, 10), rf(Zn, 5), rf(Zda, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_fmla, 0b01100101, 1, 0b000); // floating-point fused multiply-add: Zda = Zda + Zn * Zm
|
||||
INSN(sve_fmls, 0b01100101, 1, 0b001); // floating-point fused multiply-subtract: Zda = Zda + -Zn * Zm
|
||||
INSN(sve_fnmla, 0b01100101, 1, 0b010); // floating-point negated fused multiply-add: Zda = -Zda + -Zn * Zm
|
||||
INSN(sve_fnmls, 0b01100101, 1, 0b011); // floating-point negated fused multiply-subtract: Zda = -Zda + Zn * Zm
|
||||
INSN(sve_mla, 0b00000100, 0, 0b010); // multiply-add: Zda = Zda + Zn*Zm
|
||||
INSN(sve_mls, 0b00000100, 0, 0b011); // multiply-subtract: Zda = Zda + -Zn*Zm
|
||||
#undef INSN
|
||||
|
||||
// SVE bitwise logical - unpredicated
|
||||
#define INSN(NAME, opc) \
|
||||
void NAME(FloatRegister Zd, FloatRegister Zn, FloatRegister Zm) { \
|
||||
starti; \
|
||||
f(0b00000100, 31, 24), f(opc, 23, 22), f(1, 21), \
|
||||
rf(Zm, 16), f(0b001100, 15, 10), rf(Zn, 5), rf(Zd, 0); \
|
||||
}
|
||||
INSN(sve_and, 0b00);
|
||||
INSN(sve_eor, 0b10);
|
||||
INSN(sve_orr, 0b01);
|
||||
#undef INSN
|
||||
|
||||
// SVE shift immediate - unpredicated
|
||||
#define INSN(NAME, opc, isSHR) \
|
||||
void NAME(FloatRegister Zd, SIMD_RegVariant T, FloatRegister Zn, int shift) { \
|
||||
starti; \
|
||||
/* The encodings for the tszh:tszl:imm3 fields (bits 23:22 20:19 18:16) \
|
||||
* for shift right is calculated as: \
|
||||
* 0001 xxx B, shift = 16 - UInt(tszh:tszl:imm3) \
|
||||
* 001x xxx H, shift = 32 - UInt(tszh:tszl:imm3) \
|
||||
* 01xx xxx S, shift = 64 - UInt(tszh:tszl:imm3) \
|
||||
* 1xxx xxx D, shift = 128 - UInt(tszh:tszl:imm3) \
|
||||
* for shift left is calculated as: \
|
||||
* 0001 xxx B, shift = UInt(tszh:tszl:imm3) - 8 \
|
||||
* 001x xxx H, shift = UInt(tszh:tszl:imm3) - 16 \
|
||||
* 01xx xxx S, shift = UInt(tszh:tszl:imm3) - 32 \
|
||||
* 1xxx xxx D, shift = UInt(tszh:tszl:imm3) - 64 \
|
||||
*/ \
|
||||
assert(T != Q, "Invalid register variant"); \
|
||||
if (isSHR) { \
|
||||
assert(((1 << (T + 3)) >= shift) && (shift > 0) , "Invalid shift value"); \
|
||||
} else { \
|
||||
assert(((1 << (T + 3)) > shift) && (shift >= 0) , "Invalid shift value"); \
|
||||
} \
|
||||
int cVal = (1 << ((T + 3) + (isSHR ? 1 : 0))); \
|
||||
int encodedShift = isSHR ? cVal - shift : cVal + shift; \
|
||||
int tszh = encodedShift >> 5; \
|
||||
int tszl_imm = encodedShift & 0x1f; \
|
||||
f(0b00000100, 31, 24); \
|
||||
f(tszh, 23, 22), f(1,21), f(tszl_imm, 20, 16); \
|
||||
f(0b100, 15, 13), f(opc, 12, 10), rf(Zn, 5), rf(Zd, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_asr, 0b100, /* isSHR = */ true);
|
||||
INSN(sve_lsl, 0b111, /* isSHR = */ false);
|
||||
INSN(sve_lsr, 0b101, /* isSHR = */ true);
|
||||
#undef INSN
|
||||
|
||||
private:
|
||||
|
||||
// Scalar base + immediate index
|
||||
void sve_ld_st1(FloatRegister Zt, Register Xn, int imm, PRegister Pg,
|
||||
SIMD_RegVariant T, int op1, int type, int op2) {
|
||||
starti;
|
||||
assert_cond(T >= type);
|
||||
f(op1, 31, 25), f(type, 24, 23), f(T, 22, 21);
|
||||
f(0, 20), sf(imm, 19, 16), f(op2, 15, 13);
|
||||
pgrf(Pg, 10), srf(Xn, 5), rf(Zt, 0);
|
||||
}
|
||||
|
||||
// Scalar base + scalar index
|
||||
void sve_ld_st1(FloatRegister Zt, Register Xn, Register Xm, PRegister Pg,
|
||||
SIMD_RegVariant T, int op1, int type, int op2) {
|
||||
starti;
|
||||
assert_cond(T >= type);
|
||||
f(op1, 31, 25), f(type, 24, 23), f(T, 22, 21);
|
||||
rf(Xm, 16), f(op2, 15, 13);
|
||||
pgrf(Pg, 10), srf(Xn, 5), rf(Zt, 0);
|
||||
}
|
||||
|
||||
void sve_ld_st1(FloatRegister Zt, PRegister Pg,
|
||||
SIMD_RegVariant T, const Address &a,
|
||||
int op1, int type, int imm_op2, int scalar_op2) {
|
||||
switch (a.getMode()) {
|
||||
case Address::base_plus_offset:
|
||||
sve_ld_st1(Zt, a.base(), a.offset(), Pg, T, op1, type, imm_op2);
|
||||
break;
|
||||
case Address::base_plus_offset_reg:
|
||||
sve_ld_st1(Zt, a.base(), a.index(), Pg, T, op1, type, scalar_op2);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// SVE load/store - predicated
|
||||
#define INSN(NAME, op1, type, imm_op2, scalar_op2) \
|
||||
void NAME(FloatRegister Zt, SIMD_RegVariant T, PRegister Pg, const Address &a) { \
|
||||
assert(T != Q, "invalid register variant"); \
|
||||
sve_ld_st1(Zt, Pg, T, a, op1, type, imm_op2, scalar_op2); \
|
||||
}
|
||||
|
||||
INSN(sve_ld1b, 0b1010010, 0b00, 0b101, 0b010);
|
||||
INSN(sve_st1b, 0b1110010, 0b00, 0b111, 0b010);
|
||||
INSN(sve_ld1h, 0b1010010, 0b01, 0b101, 0b010);
|
||||
INSN(sve_st1h, 0b1110010, 0b01, 0b111, 0b010);
|
||||
INSN(sve_ld1w, 0b1010010, 0b10, 0b101, 0b010);
|
||||
INSN(sve_st1w, 0b1110010, 0b10, 0b111, 0b010);
|
||||
INSN(sve_ld1d, 0b1010010, 0b11, 0b101, 0b010);
|
||||
INSN(sve_st1d, 0b1110010, 0b11, 0b111, 0b010);
|
||||
#undef INSN
|
||||
|
||||
// SVE load/store - unpredicated
|
||||
#define INSN(NAME, op1) \
|
||||
void NAME(FloatRegister Zt, const Address &a) { \
|
||||
starti; \
|
||||
assert(a.index() == noreg, "invalid address variant"); \
|
||||
f(op1, 31, 29), f(0b0010110, 28, 22), sf(a.offset() >> 3, 21, 16), \
|
||||
f(0b010, 15, 13), f(a.offset() & 0x7, 12, 10), srf(a.base(), 5), rf(Zt, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_ldr, 0b100); // LDR (vector)
|
||||
INSN(sve_str, 0b111); // STR (vector)
|
||||
#undef INSN
|
||||
|
||||
#define INSN(NAME, op) \
|
||||
void NAME(Register Xd, Register Xn, int imm6) { \
|
||||
starti; \
|
||||
f(0b000001000, 31, 23), f(op, 22, 21); \
|
||||
srf(Xn, 16), f(0b01010, 15, 11), sf(imm6, 10, 5), srf(Xd, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_addvl, 0b01);
|
||||
INSN(sve_addpl, 0b11);
|
||||
#undef INSN
|
||||
|
||||
// SVE inc/dec register by element count
|
||||
#define INSN(NAME, op) \
|
||||
void NAME(Register Xdn, SIMD_RegVariant T, unsigned imm4 = 1, int pattern = 0b11111) { \
|
||||
starti; \
|
||||
assert(T != Q, "invalid size"); \
|
||||
f(0b00000100,31, 24), f(T, 23, 22), f(0b11, 21, 20); \
|
||||
f(imm4 - 1, 19, 16), f(0b11100, 15, 11), f(op, 10), f(pattern, 9, 5), rf(Xdn, 0); \
|
||||
}
|
||||
|
||||
INSN(sve_inc, 0);
|
||||
INSN(sve_dec, 1);
|
||||
#undef INSN
|
||||
|
||||
// SVE predicate count
|
||||
void sve_cntp(Register Xd, SIMD_RegVariant T, PRegister Pg, PRegister Pn) {
|
||||
starti;
|
||||
assert(T != Q, "invalid size");
|
||||
f(0b00100101, 31, 24), f(T, 23, 22), f(0b10000010, 21, 14);
|
||||
prf(Pg, 10), f(0, 9), prf(Pn, 5), rf(Xd, 0);
|
||||
}
|
||||
|
||||
// SVE dup scalar
|
||||
void sve_dup(FloatRegister Zd, SIMD_RegVariant T, Register Rn) {
|
||||
starti;
|
||||
assert(T != Q, "invalid size");
|
||||
f(0b00000101, 31, 24), f(T, 23, 22), f(0b100000001110, 21, 10);
|
||||
srf(Rn, 5), rf(Zd, 0);
|
||||
}
|
||||
|
||||
// SVE dup imm
|
||||
void sve_dup(FloatRegister Zd, SIMD_RegVariant T, int imm8) {
|
||||
starti;
|
||||
assert(T != Q, "invalid size");
|
||||
int sh = 0;
|
||||
if (imm8 <= 127 && imm8 >= -128) {
|
||||
sh = 0;
|
||||
} else if (T != B && imm8 <= 32512 && imm8 >= -32768 && (imm8 & 0xff) == 0) {
|
||||
sh = 1;
|
||||
imm8 = (imm8 >> 8);
|
||||
} else {
|
||||
guarantee(false, "invalid immediate");
|
||||
}
|
||||
f(0b00100101, 31, 24), f(T, 23, 22), f(0b11100011, 21, 14);
|
||||
f(sh, 13), sf(imm8, 12, 5), rf(Zd, 0);
|
||||
}
|
||||
|
||||
void sve_ptrue(PRegister pd, SIMD_RegVariant esize, int pattern = 0b11111) {
|
||||
starti;
|
||||
f(0b00100101, 31, 24), f(esize, 23, 22), f(0b011000111000, 21, 10);
|
||||
f(pattern, 9, 5), f(0b0, 4), prf(pd, 0);
|
||||
}
|
||||
|
||||
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
|
||||
}
|
||||
|
||||
|
||||
@@ -30,4 +30,16 @@
|
||||
#include "asm/codeBuffer.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
|
||||
|
||||
inline bool Address::offset_ok_for_immed(int64_t offset, uint shift) {
|
||||
uint mask = (1 << shift) - 1;
|
||||
if (offset < 0 || (offset & mask) != 0) {
|
||||
// Unscaled signed offset, encoded in a signed imm9 field.
|
||||
return Assembler::is_simm9(offset);
|
||||
} else {
|
||||
// Scaled unsigned offset, encoded in an unsigned imm12:_ field.
|
||||
return Assembler::is_uimm12(offset >> shift);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_ASSEMBLER_AARCH64_INLINE_HPP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -58,7 +58,7 @@ enum {
|
||||
|
||||
pd_nof_cpu_regs_linearscan = 32, // number of registers visible to linear scan
|
||||
pd_nof_fpu_regs_linearscan = pd_nof_fpu_regs_frame_map, // number of registers visible to linear scan
|
||||
pd_nof_xmm_regs_linearscan = 0, // like sparc we don't have any of these
|
||||
pd_nof_xmm_regs_linearscan = 0, // don't have vector registers
|
||||
pd_first_cpu_reg = 0,
|
||||
pd_last_cpu_reg = 16,
|
||||
pd_first_byte_reg = 0,
|
||||
|
||||
@@ -211,6 +211,19 @@ Address LIR_Assembler::as_Address_lo(LIR_Address* addr) {
|
||||
// FIXME: This needs to be much more clever. See x86.
|
||||
}
|
||||
|
||||
// Ensure a valid Address (base + offset) to a stack-slot. If stack access is
|
||||
// not encodable as a base + (immediate) offset, generate an explicit address
|
||||
// calculation to hold the address in a temporary register.
|
||||
Address LIR_Assembler::stack_slot_address(int index, uint size, Register tmp, int adjust) {
|
||||
precond(size == 4 || size == 8);
|
||||
Address addr = frame_map()->address_for_slot(index, adjust);
|
||||
precond(addr.getMode() == Address::base_plus_offset);
|
||||
precond(addr.base() == sp);
|
||||
precond(addr.offset() > 0);
|
||||
uint mask = size - 1;
|
||||
assert((addr.offset() & mask) == 0, "scaled offsets only");
|
||||
return __ legitimize_address(addr, size, tmp);
|
||||
}
|
||||
|
||||
void LIR_Assembler::osr_entry() {
|
||||
offsets()->set_value(CodeOffsets::OSR_Entry, code_offset());
|
||||
@@ -735,32 +748,38 @@ void LIR_Assembler::reg2reg(LIR_Opr src, LIR_Opr dest) {
|
||||
}
|
||||
|
||||
void LIR_Assembler::reg2stack(LIR_Opr src, LIR_Opr dest, BasicType type, bool pop_fpu_stack) {
|
||||
precond(src->is_register() && dest->is_stack());
|
||||
|
||||
uint const c_sz32 = sizeof(uint32_t);
|
||||
uint const c_sz64 = sizeof(uint64_t);
|
||||
|
||||
if (src->is_single_cpu()) {
|
||||
int index = dest->single_stack_ix();
|
||||
if (is_reference_type(type)) {
|
||||
__ str(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix()));
|
||||
__ str(src->as_register(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
__ verify_oop(src->as_register());
|
||||
} else if (type == T_METADATA || type == T_DOUBLE || type == T_ADDRESS) {
|
||||
__ str(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix()));
|
||||
__ str(src->as_register(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
} else {
|
||||
__ strw(src->as_register(), frame_map()->address_for_slot(dest->single_stack_ix()));
|
||||
__ strw(src->as_register(), stack_slot_address(index, c_sz32, rscratch1));
|
||||
}
|
||||
|
||||
} else if (src->is_double_cpu()) {
|
||||
Address dest_addr_LO = frame_map()->address_for_slot(dest->double_stack_ix(), lo_word_offset_in_bytes);
|
||||
int index = dest->double_stack_ix();
|
||||
Address dest_addr_LO = stack_slot_address(index, c_sz64, rscratch1, lo_word_offset_in_bytes);
|
||||
__ str(src->as_register_lo(), dest_addr_LO);
|
||||
|
||||
} else if (src->is_single_fpu()) {
|
||||
Address dest_addr = frame_map()->address_for_slot(dest->single_stack_ix());
|
||||
__ strs(src->as_float_reg(), dest_addr);
|
||||
int index = dest->single_stack_ix();
|
||||
__ strs(src->as_float_reg(), stack_slot_address(index, c_sz32, rscratch1));
|
||||
|
||||
} else if (src->is_double_fpu()) {
|
||||
Address dest_addr = frame_map()->address_for_slot(dest->double_stack_ix());
|
||||
__ strd(src->as_double_reg(), dest_addr);
|
||||
int index = dest->double_stack_ix();
|
||||
__ strd(src->as_double_reg(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -845,30 +864,34 @@ void LIR_Assembler::reg2mem(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch
|
||||
|
||||
|
||||
void LIR_Assembler::stack2reg(LIR_Opr src, LIR_Opr dest, BasicType type) {
|
||||
assert(src->is_stack(), "should not call otherwise");
|
||||
assert(dest->is_register(), "should not call otherwise");
|
||||
precond(src->is_stack() && dest->is_register());
|
||||
|
||||
uint const c_sz32 = sizeof(uint32_t);
|
||||
uint const c_sz64 = sizeof(uint64_t);
|
||||
|
||||
if (dest->is_single_cpu()) {
|
||||
int index = src->single_stack_ix();
|
||||
if (is_reference_type(type)) {
|
||||
__ ldr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()));
|
||||
__ ldr(dest->as_register(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
__ verify_oop(dest->as_register());
|
||||
} else if (type == T_METADATA || type == T_ADDRESS) {
|
||||
__ ldr(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()));
|
||||
__ ldr(dest->as_register(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
} else {
|
||||
__ ldrw(dest->as_register(), frame_map()->address_for_slot(src->single_stack_ix()));
|
||||
__ ldrw(dest->as_register(), stack_slot_address(index, c_sz32, rscratch1));
|
||||
}
|
||||
|
||||
} else if (dest->is_double_cpu()) {
|
||||
Address src_addr_LO = frame_map()->address_for_slot(src->double_stack_ix(), lo_word_offset_in_bytes);
|
||||
int index = src->double_stack_ix();
|
||||
Address src_addr_LO = stack_slot_address(index, c_sz64, rscratch1, lo_word_offset_in_bytes);
|
||||
__ ldr(dest->as_register_lo(), src_addr_LO);
|
||||
|
||||
} else if (dest->is_single_fpu()) {
|
||||
Address src_addr = frame_map()->address_for_slot(src->single_stack_ix());
|
||||
__ ldrs(dest->as_float_reg(), src_addr);
|
||||
int index = src->single_stack_ix();
|
||||
__ ldrs(dest->as_float_reg(), stack_slot_address(index, c_sz32, rscratch1));
|
||||
|
||||
} else if (dest->is_double_fpu()) {
|
||||
Address src_addr = frame_map()->address_for_slot(src->double_stack_ix());
|
||||
__ ldrd(dest->as_double_reg(), src_addr);
|
||||
int index = src->double_stack_ix();
|
||||
__ ldrd(dest->as_double_reg(), stack_slot_address(index, c_sz64, rscratch1));
|
||||
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
@@ -2049,7 +2072,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
|
||||
}
|
||||
|
||||
|
||||
/* Currently, vtable-dispatch is only enabled for sparc platforms */
|
||||
/* vtable-dispatch is not enabled for aarch64 platform*/
|
||||
void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@@ -2085,6 +2108,13 @@ void LIR_Assembler::throw_op(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmit
|
||||
|
||||
// get current pc information
|
||||
// pc is only needed if the method has an exception handler, the unwind code does not need it.
|
||||
if (compilation()->debug_info_recorder()->last_pc_offset() == __ offset()) {
|
||||
// As no instructions have been generated yet for this LIR node it's
|
||||
// possible that an oop map already exists for the current offset.
|
||||
// In that case insert an dummy NOP here to ensure all oop map PCs
|
||||
// are unique. See JDK-8237483.
|
||||
__ nop();
|
||||
}
|
||||
int pc_for_athrow_offset = __ offset();
|
||||
InternalAddress pc_for_athrow(__ pc());
|
||||
__ adr(exceptionPC->as_register(), pc_for_athrow);
|
||||
|
||||
@@ -45,10 +45,12 @@ friend class ArrayCopyStub;
|
||||
|
||||
bool is_literal_address(LIR_Address* addr);
|
||||
|
||||
// When we need to use something other than rscratch1 use this
|
||||
// method.
|
||||
// When we need to use something other than rscratch1 use this method.
|
||||
Address as_Address(LIR_Address* addr, Register tmp);
|
||||
|
||||
// Ensure we have a valid Address (base+offset) to a stack-slot.
|
||||
Address stack_slot_address(int index, uint shift, Register tmp, int adjust = 0);
|
||||
|
||||
// Record the type of the receiver in ReceiverTypeData
|
||||
void type_profile_helper(Register mdo,
|
||||
ciMethodData *md, ciProfileData *data,
|
||||
|
||||
@@ -291,7 +291,7 @@ void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr bas
|
||||
}
|
||||
|
||||
|
||||
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) {
|
||||
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result, LIR_Opr tmp) {
|
||||
|
||||
if (is_power_of_2(c - 1)) {
|
||||
__ shift_left(left, exact_log2(c - 1), tmp);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -48,7 +48,7 @@ LIR_Opr LIR_OprFact::double_fpu(int reg1, int reg2) {
|
||||
void LIR_Address::verify() const {
|
||||
assert(base()->is_cpu_register(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_double_cpu() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
}
|
||||
#endif // PRODUCT
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -73,11 +73,18 @@ int C1_MacroAssembler::lock_object(Register hdr, Register obj, Register disp_hdr
|
||||
// save object being locked into the BasicObjectLock
|
||||
str(obj, Address(disp_hdr, BasicObjectLock::obj_offset_in_bytes()));
|
||||
|
||||
null_check_offset = offset();
|
||||
|
||||
if (DiagnoseSyncOnPrimitiveWrappers != 0) {
|
||||
load_klass(hdr, obj);
|
||||
ldrw(hdr, Address(hdr, Klass::access_flags_offset()));
|
||||
tstw(hdr, JVM_ACC_IS_BOX_CLASS);
|
||||
br(Assembler::NE, slow_case);
|
||||
}
|
||||
|
||||
if (UseBiasedLocking) {
|
||||
assert(scratch != noreg, "should have scratch register at this point");
|
||||
null_check_offset = biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
|
||||
} else {
|
||||
null_check_offset = offset();
|
||||
biased_locking_enter(disp_hdr, obj, hdr, scratch, false, done, &slow_case);
|
||||
}
|
||||
|
||||
// Load object header
|
||||
|
||||
@@ -46,7 +46,7 @@ define_pd_global(intx, CompileThreshold, 10000);
|
||||
|
||||
define_pd_global(intx, OnStackReplacePercentage, 140);
|
||||
define_pd_global(intx, ConditionalMoveLimit, 3);
|
||||
define_pd_global(intx, FLOATPRESSURE, 64);
|
||||
define_pd_global(intx, FLOATPRESSURE, 32);
|
||||
define_pd_global(intx, FreqInlineSize, 325);
|
||||
define_pd_global(intx, MinJumpTableSize, 10);
|
||||
define_pd_global(intx, INTPRESSURE, 24);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -50,7 +50,7 @@
|
||||
// [padding ]
|
||||
|
||||
// [methodData ] = mdp() mdx_offset
|
||||
// [methodOop ] = method() method_offset
|
||||
// [Method ] = method() method_offset
|
||||
|
||||
// [last esp ] = last_sp() last_sp_offset
|
||||
// [old stack pointer ] (sender_sp) sender_sp_offset
|
||||
@@ -61,6 +61,7 @@
|
||||
// [last sp ]
|
||||
// [oop temp ] (only for native calls)
|
||||
|
||||
// [padding ] (to preserve machine SP alignment)
|
||||
// [locals and parameters ]
|
||||
// <- sender sp
|
||||
// ------------------------------ Asm interpreter ----------------------------------------
|
||||
|
||||
@@ -431,8 +431,12 @@ void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, Z
|
||||
ZSetupArguments setup_arguments(masm, stub);
|
||||
__ mov(rscratch1, stub->slow_path());
|
||||
__ blr(rscratch1);
|
||||
if (UseSVE > 0) {
|
||||
// Reinitialize the ptrue predicate register, in case the external runtime
|
||||
// call clobbers ptrue reg, as we may return to SVE compiled code.
|
||||
__ reinitialize_ptrue();
|
||||
}
|
||||
}
|
||||
|
||||
// Stub exit
|
||||
__ b(*stub->continuation());
|
||||
}
|
||||
|
||||
@@ -99,6 +99,9 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
"Avoid generating unaligned memory accesses") \
|
||||
product(bool, UseLSE, false, \
|
||||
"Use LSE instructions") \
|
||||
product(uint, UseSVE, 0, \
|
||||
"Highest supported SVE instruction set version") \
|
||||
range(0, 2) \
|
||||
product(bool, UseBlockZeroing, true, \
|
||||
"Use DC ZVA for block zeroing") \
|
||||
product(intx, BlockZeroingLowLimit, 256, \
|
||||
|
||||
@@ -725,6 +725,13 @@ void InterpreterMacroAssembler::lock_object(Register lock_reg)
|
||||
// Load object pointer into obj_reg %c_rarg3
|
||||
ldr(obj_reg, Address(lock_reg, obj_offset));
|
||||
|
||||
if (DiagnoseSyncOnPrimitiveWrappers != 0) {
|
||||
load_klass(tmp, obj_reg);
|
||||
ldrw(tmp, Address(tmp, Klass::access_flags_offset()));
|
||||
tstw(tmp, JVM_ACC_IS_BOX_CLASS);
|
||||
br(Assembler::NE, slow_case);
|
||||
}
|
||||
|
||||
if (UseBiasedLocking) {
|
||||
biased_locking_enter(lock_reg, obj_reg, swap_reg, tmp, false, done, &slow_case);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -39,7 +39,7 @@ class JNITypes : AllStatic {
|
||||
// I.e., they are functionally 'push' operations if they have a 'pos'
|
||||
// formal parameter. Note that jlong's and jdouble's are written
|
||||
// _in reverse_ of the order in which they appear in the interpreter
|
||||
// stack. This is because call stubs (see stubGenerator_sparc.cpp)
|
||||
// stack. This is because call stubs (see stubGenerator_arm.cpp)
|
||||
// reverse the argument list constructed by JavaCallArguments (see
|
||||
// javaCalls.hpp).
|
||||
|
||||
|
||||
@@ -389,7 +389,7 @@ void MacroAssembler::far_call(Address entry, CodeBuffer *cbuf, Register tmp) {
|
||||
assert(CodeCache::find_blob(entry.target()) != NULL,
|
||||
"destination of far call not found in code cache");
|
||||
if (far_branches()) {
|
||||
uintptr_t offset;
|
||||
uint64_t offset;
|
||||
// We can use ADRP here because we know that the total size of
|
||||
// the code cache cannot exceed 2Gb.
|
||||
adrp(tmp, entry, offset);
|
||||
@@ -407,7 +407,7 @@ void MacroAssembler::far_jump(Address entry, CodeBuffer *cbuf, Register tmp) {
|
||||
assert(CodeCache::find_blob(entry.target()) != NULL,
|
||||
"destination of far call not found in code cache");
|
||||
if (far_branches()) {
|
||||
uintptr_t offset;
|
||||
uint64_t offset;
|
||||
// We can use ADRP here because we know that the total size of
|
||||
// the code cache cannot exceed 2Gb.
|
||||
adrp(tmp, entry, offset);
|
||||
@@ -444,14 +444,14 @@ void MacroAssembler::reserved_stack_check() {
|
||||
bind(no_reserved_zone_enabling);
|
||||
}
|
||||
|
||||
int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
Register obj_reg,
|
||||
Register swap_reg,
|
||||
Register tmp_reg,
|
||||
bool swap_reg_contains_mark,
|
||||
Label& done,
|
||||
Label* slow_case,
|
||||
BiasedLockingCounters* counters) {
|
||||
void MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
Register obj_reg,
|
||||
Register swap_reg,
|
||||
Register tmp_reg,
|
||||
bool swap_reg_contains_mark,
|
||||
Label& done,
|
||||
Label* slow_case,
|
||||
BiasedLockingCounters* counters) {
|
||||
assert(UseBiasedLocking, "why call this otherwise?");
|
||||
assert_different_registers(lock_reg, obj_reg, swap_reg);
|
||||
|
||||
@@ -471,9 +471,7 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
// pointers to allow age to be placed into low bits
|
||||
// First check to see whether biasing is even enabled for this object
|
||||
Label cas_label;
|
||||
int null_check_offset = -1;
|
||||
if (!swap_reg_contains_mark) {
|
||||
null_check_offset = offset();
|
||||
ldr(swap_reg, mark_addr);
|
||||
}
|
||||
andr(tmp_reg, swap_reg, markWord::biased_lock_mask_in_place);
|
||||
@@ -601,8 +599,6 @@ int MacroAssembler::biased_locking_enter(Register lock_reg,
|
||||
}
|
||||
|
||||
bind(cas_label);
|
||||
|
||||
return null_check_offset;
|
||||
}
|
||||
|
||||
void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
|
||||
@@ -1503,11 +1499,11 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) {
|
||||
#ifndef PRODUCT
|
||||
{
|
||||
char buffer[64];
|
||||
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64);
|
||||
snprintf(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64);
|
||||
block_comment(buffer);
|
||||
}
|
||||
#endif
|
||||
assert(imm64 < (1ul << 48), "48-bit overflow in address constant");
|
||||
assert(imm64 < (1ull << 48), "48-bit overflow in address constant");
|
||||
movz(r, imm64 & 0xffff);
|
||||
imm64 >>= 16;
|
||||
movk(r, imm64 & 0xffff, 16);
|
||||
@@ -2121,9 +2117,16 @@ int MacroAssembler::pop(unsigned int bitset, Register stack) {
|
||||
}
|
||||
|
||||
// Push lots of registers in the bit set supplied. Don't push sp.
|
||||
// Return the number of words pushed
|
||||
// Return the number of dwords pushed
|
||||
int MacroAssembler::push_fp(unsigned int bitset, Register stack) {
|
||||
int words_pushed = 0;
|
||||
bool use_sve = false;
|
||||
int sve_vector_size_in_bytes = 0;
|
||||
|
||||
#ifdef COMPILER2
|
||||
use_sve = Matcher::supports_scalable_vector();
|
||||
sve_vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
|
||||
#endif
|
||||
|
||||
// Scan bitset to accumulate register pairs
|
||||
unsigned char regs[32];
|
||||
@@ -2138,9 +2141,19 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SVE
|
||||
if (use_sve && sve_vector_size_in_bytes > 16) {
|
||||
sub(stack, stack, sve_vector_size_in_bytes * count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
sve_str(as_FloatRegister(regs[i]), Address(stack, i));
|
||||
}
|
||||
return count * sve_vector_size_in_bytes / 8;
|
||||
}
|
||||
|
||||
// NEON
|
||||
if (count == 1) {
|
||||
strq(as_FloatRegister(regs[0]), Address(pre(stack, -wordSize * 2)));
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool odd = (count & 1) == 1;
|
||||
@@ -2161,12 +2174,19 @@ int MacroAssembler::push_fp(unsigned int bitset, Register stack) {
|
||||
}
|
||||
|
||||
assert(words_pushed == count, "oops, pushed(%d) != count(%d)", words_pushed, count);
|
||||
return count;
|
||||
return count * 2;
|
||||
}
|
||||
|
||||
// Return the number of dwords poped
|
||||
int MacroAssembler::pop_fp(unsigned int bitset, Register stack) {
|
||||
int words_pushed = 0;
|
||||
bool use_sve = false;
|
||||
int sve_vector_size_in_bytes = 0;
|
||||
|
||||
#ifdef COMPILER2
|
||||
use_sve = Matcher::supports_scalable_vector();
|
||||
sve_vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
|
||||
#endif
|
||||
// Scan bitset to accumulate register pairs
|
||||
unsigned char regs[32];
|
||||
int count = 0;
|
||||
@@ -2180,9 +2200,19 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SVE
|
||||
if (use_sve && sve_vector_size_in_bytes > 16) {
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
sve_ldr(as_FloatRegister(regs[i]), Address(stack, i));
|
||||
}
|
||||
add(stack, stack, sve_vector_size_in_bytes * count);
|
||||
return count * sve_vector_size_in_bytes / 8;
|
||||
}
|
||||
|
||||
// NEON
|
||||
if (count == 1) {
|
||||
ldrq(as_FloatRegister(regs[0]), Address(post(stack, wordSize * 2)));
|
||||
return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool odd = (count & 1) == 1;
|
||||
@@ -2203,7 +2233,7 @@ int MacroAssembler::pop_fp(unsigned int bitset, Register stack) {
|
||||
|
||||
assert(words_pushed == count, "oops, pushed(%d) != count(%d)", words_pushed, count);
|
||||
|
||||
return count;
|
||||
return count * 2;
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
@@ -2583,43 +2613,43 @@ void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[])
|
||||
#endif
|
||||
if (os::message_box(msg, "Execution stopped, print registers?")) {
|
||||
ttyLocker ttyl;
|
||||
tty->print_cr(" pc = 0x%016lx", pc);
|
||||
tty->print_cr(" pc = 0x%016" PRIx64, pc);
|
||||
#ifndef PRODUCT
|
||||
tty->cr();
|
||||
findpc(pc);
|
||||
tty->cr();
|
||||
#endif
|
||||
tty->print_cr(" r0 = 0x%016lx", regs[0]);
|
||||
tty->print_cr(" r1 = 0x%016lx", regs[1]);
|
||||
tty->print_cr(" r2 = 0x%016lx", regs[2]);
|
||||
tty->print_cr(" r3 = 0x%016lx", regs[3]);
|
||||
tty->print_cr(" r4 = 0x%016lx", regs[4]);
|
||||
tty->print_cr(" r5 = 0x%016lx", regs[5]);
|
||||
tty->print_cr(" r6 = 0x%016lx", regs[6]);
|
||||
tty->print_cr(" r7 = 0x%016lx", regs[7]);
|
||||
tty->print_cr(" r8 = 0x%016lx", regs[8]);
|
||||
tty->print_cr(" r9 = 0x%016lx", regs[9]);
|
||||
tty->print_cr("r10 = 0x%016lx", regs[10]);
|
||||
tty->print_cr("r11 = 0x%016lx", regs[11]);
|
||||
tty->print_cr("r12 = 0x%016lx", regs[12]);
|
||||
tty->print_cr("r13 = 0x%016lx", regs[13]);
|
||||
tty->print_cr("r14 = 0x%016lx", regs[14]);
|
||||
tty->print_cr("r15 = 0x%016lx", regs[15]);
|
||||
tty->print_cr("r16 = 0x%016lx", regs[16]);
|
||||
tty->print_cr("r17 = 0x%016lx", regs[17]);
|
||||
tty->print_cr("r18 = 0x%016lx", regs[18]);
|
||||
tty->print_cr("r19 = 0x%016lx", regs[19]);
|
||||
tty->print_cr("r20 = 0x%016lx", regs[20]);
|
||||
tty->print_cr("r21 = 0x%016lx", regs[21]);
|
||||
tty->print_cr("r22 = 0x%016lx", regs[22]);
|
||||
tty->print_cr("r23 = 0x%016lx", regs[23]);
|
||||
tty->print_cr("r24 = 0x%016lx", regs[24]);
|
||||
tty->print_cr("r25 = 0x%016lx", regs[25]);
|
||||
tty->print_cr("r26 = 0x%016lx", regs[26]);
|
||||
tty->print_cr("r27 = 0x%016lx", regs[27]);
|
||||
tty->print_cr("r28 = 0x%016lx", regs[28]);
|
||||
tty->print_cr("r30 = 0x%016lx", regs[30]);
|
||||
tty->print_cr("r31 = 0x%016lx", regs[31]);
|
||||
tty->print_cr(" r0 = 0x%016" PRIx64, regs[0]);
|
||||
tty->print_cr(" r1 = 0x%016" PRIx64, regs[1]);
|
||||
tty->print_cr(" r2 = 0x%016" PRIx64, regs[2]);
|
||||
tty->print_cr(" r3 = 0x%016" PRIx64, regs[3]);
|
||||
tty->print_cr(" r4 = 0x%016" PRIx64, regs[4]);
|
||||
tty->print_cr(" r5 = 0x%016" PRIx64, regs[5]);
|
||||
tty->print_cr(" r6 = 0x%016" PRIx64, regs[6]);
|
||||
tty->print_cr(" r7 = 0x%016" PRIx64, regs[7]);
|
||||
tty->print_cr(" r8 = 0x%016" PRIx64, regs[8]);
|
||||
tty->print_cr(" r9 = 0x%016" PRIx64, regs[9]);
|
||||
tty->print_cr("r10 = 0x%016" PRIx64, regs[10]);
|
||||
tty->print_cr("r11 = 0x%016" PRIx64, regs[11]);
|
||||
tty->print_cr("r12 = 0x%016" PRIx64, regs[12]);
|
||||
tty->print_cr("r13 = 0x%016" PRIx64, regs[13]);
|
||||
tty->print_cr("r14 = 0x%016" PRIx64, regs[14]);
|
||||
tty->print_cr("r15 = 0x%016" PRIx64, regs[15]);
|
||||
tty->print_cr("r16 = 0x%016" PRIx64, regs[16]);
|
||||
tty->print_cr("r17 = 0x%016" PRIx64, regs[17]);
|
||||
tty->print_cr("r18 = 0x%016" PRIx64, regs[18]);
|
||||
tty->print_cr("r19 = 0x%016" PRIx64, regs[19]);
|
||||
tty->print_cr("r20 = 0x%016" PRIx64, regs[20]);
|
||||
tty->print_cr("r21 = 0x%016" PRIx64, regs[21]);
|
||||
tty->print_cr("r22 = 0x%016" PRIx64, regs[22]);
|
||||
tty->print_cr("r23 = 0x%016" PRIx64, regs[23]);
|
||||
tty->print_cr("r24 = 0x%016" PRIx64, regs[24]);
|
||||
tty->print_cr("r25 = 0x%016" PRIx64, regs[25]);
|
||||
tty->print_cr("r26 = 0x%016" PRIx64, regs[26]);
|
||||
tty->print_cr("r27 = 0x%016" PRIx64, regs[27]);
|
||||
tty->print_cr("r28 = 0x%016" PRIx64, regs[28]);
|
||||
tty->print_cr("r30 = 0x%016" PRIx64, regs[30]);
|
||||
tty->print_cr("r31 = 0x%016" PRIx64, regs[31]);
|
||||
BREAKPOINT;
|
||||
}
|
||||
}
|
||||
@@ -2651,23 +2681,39 @@ void MacroAssembler::pop_call_clobbered_registers_except(RegSet exclude) {
|
||||
pop(RegSet::range(r0, r18) - RegSet::of(rscratch1, rscratch2) - exclude, sp);
|
||||
}
|
||||
|
||||
void MacroAssembler::push_CPU_state(bool save_vectors) {
|
||||
int step = (save_vectors ? 8 : 4) * wordSize;
|
||||
void MacroAssembler::push_CPU_state(bool save_vectors, bool use_sve,
|
||||
int sve_vector_size_in_bytes) {
|
||||
push(0x3fffffff, sp); // integer registers except lr & sp
|
||||
mov(rscratch1, -step);
|
||||
sub(sp, sp, step);
|
||||
for (int i = 28; i >= 4; i -= 4) {
|
||||
st1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2),
|
||||
as_FloatRegister(i+3), save_vectors ? T2D : T1D, Address(post(sp, rscratch1)));
|
||||
if (save_vectors && use_sve && sve_vector_size_in_bytes > 16) {
|
||||
sub(sp, sp, sve_vector_size_in_bytes * FloatRegisterImpl::number_of_registers);
|
||||
for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++) {
|
||||
sve_str(as_FloatRegister(i), Address(sp, i));
|
||||
}
|
||||
} else {
|
||||
int step = (save_vectors ? 8 : 4) * wordSize;
|
||||
mov(rscratch1, -step);
|
||||
sub(sp, sp, step);
|
||||
for (int i = 28; i >= 4; i -= 4) {
|
||||
st1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2),
|
||||
as_FloatRegister(i+3), save_vectors ? T2D : T1D, Address(post(sp, rscratch1)));
|
||||
}
|
||||
st1(v0, v1, v2, v3, save_vectors ? T2D : T1D, sp);
|
||||
}
|
||||
st1(v0, v1, v2, v3, save_vectors ? T2D : T1D, sp);
|
||||
}
|
||||
|
||||
void MacroAssembler::pop_CPU_state(bool restore_vectors) {
|
||||
int step = (restore_vectors ? 8 : 4) * wordSize;
|
||||
for (int i = 0; i <= 28; i += 4)
|
||||
ld1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2),
|
||||
as_FloatRegister(i+3), restore_vectors ? T2D : T1D, Address(post(sp, step)));
|
||||
void MacroAssembler::pop_CPU_state(bool restore_vectors, bool use_sve,
|
||||
int sve_vector_size_in_bytes) {
|
||||
if (restore_vectors && use_sve && sve_vector_size_in_bytes > 16) {
|
||||
for (int i = FloatRegisterImpl::number_of_registers - 1; i >= 0; i--) {
|
||||
sve_ldr(as_FloatRegister(i), Address(sp, i));
|
||||
}
|
||||
add(sp, sp, sve_vector_size_in_bytes * FloatRegisterImpl::number_of_registers);
|
||||
} else {
|
||||
int step = (restore_vectors ? 8 : 4) * wordSize;
|
||||
for (int i = 0; i <= 28; i += 4)
|
||||
ld1(as_FloatRegister(i), as_FloatRegister(i+1), as_FloatRegister(i+2),
|
||||
as_FloatRegister(i+3), restore_vectors ? T2D : T1D, Address(post(sp, step)));
|
||||
}
|
||||
pop(0x3fffffff, sp); // integer registers except lr & sp
|
||||
}
|
||||
|
||||
@@ -2716,6 +2762,21 @@ Address MacroAssembler::spill_address(int size, int offset, Register tmp)
|
||||
return Address(base, offset);
|
||||
}
|
||||
|
||||
Address MacroAssembler::sve_spill_address(int sve_reg_size_in_bytes, int offset, Register tmp) {
|
||||
assert(offset >= 0, "spill to negative address?");
|
||||
|
||||
Register base = sp;
|
||||
|
||||
// An immediate offset in the range 0 to 255 which is multiplied
|
||||
// by the current vector or predicate register size in bytes.
|
||||
if (offset % sve_reg_size_in_bytes == 0 && offset < ((1<<8)*sve_reg_size_in_bytes)) {
|
||||
return Address(base, offset / sve_reg_size_in_bytes);
|
||||
}
|
||||
|
||||
add(tmp, base, offset);
|
||||
return Address(tmp);
|
||||
}
|
||||
|
||||
// Checks whether offset is aligned.
|
||||
// Returns true if it is, else false.
|
||||
bool MacroAssembler::merge_alignment_check(Register base,
|
||||
@@ -5225,3 +5286,24 @@ void MacroAssembler::cache_wbsync(bool is_pre) {
|
||||
membar(Assembler::AnyAny);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::verify_sve_vector_length() {
|
||||
Label verify_ok;
|
||||
assert(UseSVE > 0, "should only be used for SVE");
|
||||
movw(rscratch1, zr);
|
||||
sve_inc(rscratch1, B);
|
||||
subsw(zr, rscratch1, VM_Version::get_initial_sve_vector_length());
|
||||
br(EQ, verify_ok);
|
||||
stop("Error: SVE vector length has changed since jvm startup");
|
||||
bind(verify_ok);
|
||||
}
|
||||
|
||||
void MacroAssembler::verify_ptrue() {
|
||||
Label verify_ok;
|
||||
assert(UseSVE > 0, "should only be used for SVE");
|
||||
sve_cntp(rscratch1, B, ptrue, ptrue); // get true elements count.
|
||||
sve_dec(rscratch1, B);
|
||||
cbz(rscratch1, verify_ok);
|
||||
stop("Error: the preserved predicate register (p7) elements are not all true");
|
||||
bind(verify_ok);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef CPU_AARCH64_MACROASSEMBLER_AARCH64_HPP
|
||||
#define CPU_AARCH64_MACROASSEMBLER_AARCH64_HPP
|
||||
|
||||
#include "asm/assembler.hpp"
|
||||
#include "asm/assembler.inline.hpp"
|
||||
#include "oops/compressedOops.hpp"
|
||||
#include "utilities/powerOfTwo.hpp"
|
||||
|
||||
@@ -111,15 +111,11 @@ class MacroAssembler: public Assembler {
|
||||
// tmp_reg must be supplied and must not be rscratch1 or rscratch2
|
||||
// Optional slow case is for implementations (interpreter and C1) which branch to
|
||||
// slow case directly. Leaves condition codes set for C2's Fast_Lock node.
|
||||
// Returns offset of first potentially-faulting instruction for null
|
||||
// check info (currently consumed only by C1). If
|
||||
// swap_reg_contains_mark is true then returns -1 as it is assumed
|
||||
// the calling code has already passed any potential faults.
|
||||
int biased_locking_enter(Register lock_reg, Register obj_reg,
|
||||
Register swap_reg, Register tmp_reg,
|
||||
bool swap_reg_contains_mark,
|
||||
Label& done, Label* slow_case = NULL,
|
||||
BiasedLockingCounters* counters = NULL);
|
||||
void biased_locking_enter(Register lock_reg, Register obj_reg,
|
||||
Register swap_reg, Register tmp_reg,
|
||||
bool swap_reg_contains_mark,
|
||||
Label& done, Label* slow_case = NULL,
|
||||
BiasedLockingCounters* counters = NULL);
|
||||
void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done);
|
||||
|
||||
|
||||
@@ -493,31 +489,20 @@ public:
|
||||
// now mov instructions for loading absolute addresses and 32 or
|
||||
// 64 bit integers
|
||||
|
||||
inline void mov(Register dst, address addr)
|
||||
{
|
||||
mov_immediate64(dst, (uint64_t)addr);
|
||||
}
|
||||
inline void mov(Register dst, address addr) { mov_immediate64(dst, (uint64_t)addr); }
|
||||
|
||||
inline void mov(Register dst, uint64_t imm64)
|
||||
{
|
||||
mov_immediate64(dst, imm64);
|
||||
}
|
||||
inline void mov(Register dst, int imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
inline void mov(Register dst, long imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
inline void mov(Register dst, long long imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
inline void mov(Register dst, unsigned int imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
inline void mov(Register dst, unsigned long imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
inline void mov(Register dst, unsigned long long imm64) { mov_immediate64(dst, (uint64_t)imm64); }
|
||||
|
||||
inline void movw(Register dst, uint32_t imm32)
|
||||
{
|
||||
mov_immediate32(dst, imm32);
|
||||
}
|
||||
|
||||
inline void mov(Register dst, int64_t l)
|
||||
{
|
||||
mov(dst, (uint64_t)l);
|
||||
}
|
||||
|
||||
inline void mov(Register dst, int i)
|
||||
{
|
||||
mov(dst, (int64_t)i);
|
||||
}
|
||||
|
||||
void mov(Register dst, RegisterOrConstant src) {
|
||||
if (src.is_register())
|
||||
mov(dst, src.as_register());
|
||||
@@ -888,8 +873,10 @@ public:
|
||||
|
||||
DEBUG_ONLY(void verify_heapbase(const char* msg);)
|
||||
|
||||
void push_CPU_state(bool save_vectors = false);
|
||||
void pop_CPU_state(bool restore_vectors = false) ;
|
||||
void push_CPU_state(bool save_vectors = false, bool use_sve = false,
|
||||
int sve_vector_size_in_bytes = 0);
|
||||
void pop_CPU_state(bool restore_vectors = false, bool use_sve = false,
|
||||
int sve_vector_size_in_bytes = 0);
|
||||
|
||||
// Round up to a power of two
|
||||
void round_to(Register reg, int modulus);
|
||||
@@ -969,6 +956,11 @@ public:
|
||||
|
||||
Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
|
||||
|
||||
void verify_sve_vector_length();
|
||||
void reinitialize_ptrue() {
|
||||
sve_ptrue(ptrue, B);
|
||||
}
|
||||
void verify_ptrue();
|
||||
|
||||
// Debugging
|
||||
|
||||
@@ -1318,6 +1310,7 @@ private:
|
||||
// Returns an address on the stack which is reachable with a ldr/str of size
|
||||
// Uses rscratch2 if the address is not directly reachable
|
||||
Address spill_address(int size, int offset, Register tmp=rscratch2);
|
||||
Address sve_spill_address(int sve_reg_size_in_bytes, int offset, Register tmp=rscratch2);
|
||||
|
||||
bool merge_alignment_check(Register base, size_t size, int64_t cur_offset, int64_t prev_offset) const;
|
||||
|
||||
@@ -1341,6 +1334,9 @@ public:
|
||||
void spill(FloatRegister Vx, SIMD_RegVariant T, int offset) {
|
||||
str(Vx, T, spill_address(1 << (int)T, offset));
|
||||
}
|
||||
void spill_sve_vector(FloatRegister Zx, int offset, int vector_reg_size_in_bytes) {
|
||||
sve_str(Zx, sve_spill_address(vector_reg_size_in_bytes, offset));
|
||||
}
|
||||
void unspill(Register Rx, bool is64, int offset) {
|
||||
if (is64) {
|
||||
ldr(Rx, spill_address(8, offset));
|
||||
@@ -1351,6 +1347,9 @@ public:
|
||||
void unspill(FloatRegister Vx, SIMD_RegVariant T, int offset) {
|
||||
ldr(Vx, T, spill_address(1 << (int)T, offset));
|
||||
}
|
||||
void unspill_sve_vector(FloatRegister Zx, int offset, int vector_reg_size_in_bytes) {
|
||||
sve_ldr(Zx, sve_spill_address(vector_reg_size_in_bytes, offset));
|
||||
}
|
||||
void spill_copy128(int src_offset, int dst_offset,
|
||||
Register tmp1=rscratch1, Register tmp2=rscratch2) {
|
||||
if (src_offset < 512 && (src_offset & 7) == 0 &&
|
||||
@@ -1364,7 +1363,15 @@ public:
|
||||
spill(tmp1, true, dst_offset+8);
|
||||
}
|
||||
}
|
||||
|
||||
void spill_copy_sve_vector_stack_to_stack(int src_offset, int dst_offset,
|
||||
int sve_vec_reg_size_in_bytes) {
|
||||
assert(sve_vec_reg_size_in_bytes % 16 == 0, "unexpected sve vector reg size");
|
||||
for (int i = 0; i < sve_vec_reg_size_in_bytes / 16; i++) {
|
||||
spill_copy128(src_offset, dst_offset);
|
||||
src_offset += 16;
|
||||
dst_offset += 16;
|
||||
}
|
||||
}
|
||||
void cache_wb(Address line);
|
||||
void cache_wbsync(bool is_pre);
|
||||
};
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
// Table with p(r) polynomial coefficients
|
||||
// and table representation of logarithm values (hi and low parts)
|
||||
__attribute__ ((aligned(64))) juint _L_tbl[] =
|
||||
ATTRIBUTE_ALIGNED(64) juint _L_tbl[] =
|
||||
{
|
||||
// coefficients of p(r) polynomial:
|
||||
// _coeff[]
|
||||
|
||||
@@ -53,7 +53,7 @@ class NativeCall;
|
||||
class NativeInstruction {
|
||||
friend class Relocation;
|
||||
friend bool is_NativeCallTrampolineStub_at(address);
|
||||
public:
|
||||
public:
|
||||
enum {
|
||||
instruction_size = 4
|
||||
};
|
||||
@@ -62,12 +62,16 @@ class NativeInstruction {
|
||||
return uint_at(0);
|
||||
}
|
||||
|
||||
bool is_blr() const { return (encoding() & 0xff9ffc1f) == 0xd61f0000; } // blr(register) or br(register)
|
||||
bool is_adr_aligned() const { return (encoding() & 0xff000000) == 0x10000000; } // adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
|
||||
bool is_blr() const {
|
||||
// blr(register) or br(register)
|
||||
return (encoding() & 0xff9ffc1f) == 0xd61f0000;
|
||||
}
|
||||
bool is_adr_aligned() const {
|
||||
// adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
|
||||
return (encoding() & 0xff000000) == 0x10000000;
|
||||
}
|
||||
|
||||
inline bool is_nop();
|
||||
inline bool is_illegal();
|
||||
inline bool is_return();
|
||||
bool is_jump();
|
||||
bool is_general_jump();
|
||||
inline bool is_jump_or_nop();
|
||||
@@ -78,29 +82,25 @@ class NativeInstruction {
|
||||
bool is_sigill_zombie_not_entrant();
|
||||
bool is_stop();
|
||||
|
||||
protected:
|
||||
address addr_at(int offset) const { return address(this) + offset; }
|
||||
protected:
|
||||
address addr_at(int offset) const { return address(this) + offset; }
|
||||
|
||||
s_char sbyte_at(int offset) const { return *(s_char*) addr_at(offset); }
|
||||
u_char ubyte_at(int offset) const { return *(u_char*) addr_at(offset); }
|
||||
s_char sbyte_at(int offset) const { return *(s_char*)addr_at(offset); }
|
||||
u_char ubyte_at(int offset) const { return *(u_char*)addr_at(offset); }
|
||||
jint int_at(int offset) const { return *(jint*)addr_at(offset); }
|
||||
juint uint_at(int offset) const { return *(juint*)addr_at(offset); }
|
||||
address ptr_at(int offset) const { return *(address*)addr_at(offset); }
|
||||
oop oop_at(int offset) const { return *(oop*)addr_at(offset); }
|
||||
|
||||
jint int_at(int offset) const { return *(jint*) addr_at(offset); }
|
||||
juint uint_at(int offset) const { return *(juint*) addr_at(offset); }
|
||||
|
||||
address ptr_at(int offset) const { return *(address*) addr_at(offset); }
|
||||
|
||||
oop oop_at (int offset) const { return *(oop*) addr_at(offset); }
|
||||
|
||||
|
||||
void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; }
|
||||
void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; }
|
||||
void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; }
|
||||
void set_ptr_at (int offset, address ptr) { *(address*) addr_at(offset) = ptr; }
|
||||
void set_oop_at (int offset, oop o) { *(oop*) addr_at(offset) = o; }
|
||||
void set_char_at(int offset, char c) { *addr_at(offset) = (u_char)c; }
|
||||
void set_int_at(int offset, jint i) { *(jint*)addr_at(offset) = i; }
|
||||
void set_uint_at(int offset, jint i) { *(juint*)addr_at(offset) = i; }
|
||||
void set_ptr_at(int offset, address ptr) { *(address*)addr_at(offset) = ptr; }
|
||||
void set_oop_at(int offset, oop o) { *(oop*)addr_at(offset) = o; }
|
||||
|
||||
void wrote(int offset);
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
inline friend NativeInstruction* nativeInstruction_at(address address);
|
||||
|
||||
@@ -146,7 +146,7 @@ inline NativeInstruction* nativeInstruction_at(address address) {
|
||||
}
|
||||
|
||||
// The natural type of an AArch64 instruction is uint32_t
|
||||
inline NativeInstruction* nativeInstruction_at(uint32_t *address) {
|
||||
inline NativeInstruction* nativeInstruction_at(uint32_t* address) {
|
||||
return (NativeInstruction*)address;
|
||||
}
|
||||
|
||||
@@ -171,17 +171,15 @@ public:
|
||||
address plt_c2i_stub() const;
|
||||
void set_stub_to_clean();
|
||||
|
||||
void reset_to_plt_resolve_call();
|
||||
void set_destination_mt_safe(address dest);
|
||||
void reset_to_plt_resolve_call();
|
||||
void set_destination_mt_safe(address dest);
|
||||
|
||||
void verify() const;
|
||||
};
|
||||
|
||||
inline NativePltCall* nativePltCall_at(address address) {
|
||||
NativePltCall* call = (NativePltCall*) address;
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
NativePltCall* call = (NativePltCall*)address;
|
||||
DEBUG_ONLY(call->verify());
|
||||
return call;
|
||||
}
|
||||
|
||||
@@ -196,7 +194,7 @@ inline NativeCall* nativeCall_at(address address);
|
||||
// DSO calls, etc.).
|
||||
|
||||
class NativeCall: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
enum Aarch64_specific_constants {
|
||||
instruction_size = 4,
|
||||
instruction_offset = 0,
|
||||
@@ -204,14 +202,14 @@ class NativeCall: public NativeInstruction {
|
||||
return_address_offset = 4
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(return_address_offset); }
|
||||
int displacement() const { return (int_at(displacement_offset) << 6) >> 4; }
|
||||
address displacement_address() const { return addr_at(displacement_offset); }
|
||||
address return_address() const { return addr_at(return_address_offset); }
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(return_address_offset); }
|
||||
int displacement() const { return (int_at(displacement_offset) << 6) >> 4; }
|
||||
address displacement_address() const { return addr_at(displacement_offset); }
|
||||
address return_address() const { return addr_at(return_address_offset); }
|
||||
address destination() const;
|
||||
|
||||
void set_destination(address dest) {
|
||||
void set_destination(address dest) {
|
||||
int offset = dest - instruction_address();
|
||||
unsigned int insn = 0b100101 << 26;
|
||||
assert((offset & 3) == 0, "should be");
|
||||
@@ -221,9 +219,8 @@ class NativeCall: public NativeInstruction {
|
||||
set_int_at(displacement_offset, insn);
|
||||
}
|
||||
|
||||
void verify_alignment() { ; }
|
||||
void verify();
|
||||
void print();
|
||||
void verify_alignment() { ; }
|
||||
void verify();
|
||||
|
||||
// Creation
|
||||
inline friend NativeCall* nativeCall_at(address address);
|
||||
@@ -269,32 +266,29 @@ class NativeCall: public NativeInstruction {
|
||||
|
||||
inline NativeCall* nativeCall_at(address address) {
|
||||
NativeCall* call = (NativeCall*)(address - NativeCall::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(call->verify());
|
||||
return call;
|
||||
}
|
||||
|
||||
inline NativeCall* nativeCall_before(address return_address) {
|
||||
NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset);
|
||||
#ifdef ASSERT
|
||||
call->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(call->verify());
|
||||
return call;
|
||||
}
|
||||
|
||||
// An interface for accessing/manipulating native mov reg, imm instructions.
|
||||
// (used to manipulate inlined 64-bit data calls, etc.)
|
||||
class NativeMovConstReg: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
enum Aarch64_specific_constants {
|
||||
instruction_size = 3 * 4, // movz, movk, movk. See movptr().
|
||||
instruction_offset = 0,
|
||||
displacement_offset = 0,
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const {
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
|
||||
address next_instruction_address() const {
|
||||
if (nativeInstruction_at(instruction_address())->is_movz())
|
||||
// Assume movz, movk, movk
|
||||
return addr_at(instruction_size);
|
||||
@@ -307,7 +301,7 @@ class NativeMovConstReg: public NativeInstruction {
|
||||
}
|
||||
|
||||
intptr_t data() const;
|
||||
void set_data(intptr_t x);
|
||||
void set_data(intptr_t x);
|
||||
|
||||
void flush() {
|
||||
if (! maybe_cpool_ref(instruction_address())) {
|
||||
@@ -315,8 +309,8 @@ class NativeMovConstReg: public NativeInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
void verify();
|
||||
void print();
|
||||
void verify();
|
||||
void print();
|
||||
|
||||
// Creation
|
||||
inline friend NativeMovConstReg* nativeMovConstReg_at(address address);
|
||||
@@ -325,29 +319,23 @@ class NativeMovConstReg: public NativeInstruction {
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_at(address address) {
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
|
||||
inline NativeMovConstReg* nativeMovConstReg_before(address address) {
|
||||
NativeMovConstReg* test = (NativeMovConstReg*)(address - NativeMovConstReg::instruction_size - NativeMovConstReg::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
|
||||
class NativeMovConstRegPatching: public NativeMovConstReg {
|
||||
private:
|
||||
friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
|
||||
private:
|
||||
friend NativeMovConstRegPatching* nativeMovConstRegPatching_at(address address) {
|
||||
NativeMovConstRegPatching* test = (NativeMovConstRegPatching*)(address - instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// An interface for accessing/manipulating native moves of the form:
|
||||
@@ -374,7 +362,7 @@ class NativeMovRegMem: public NativeInstruction {
|
||||
next_instruction_offset = 4
|
||||
};
|
||||
|
||||
public:
|
||||
public:
|
||||
// helper
|
||||
int instruction_start() const { return instruction_offset; }
|
||||
|
||||
@@ -382,30 +370,32 @@ class NativeMovRegMem: public NativeInstruction {
|
||||
|
||||
int num_bytes_to_end_of_patch() const { return instruction_offset + instruction_size; }
|
||||
|
||||
int offset() const;
|
||||
int offset() const;
|
||||
|
||||
void set_offset(int x);
|
||||
void set_offset(int x);
|
||||
|
||||
void add_offset_in_bytes(int add_offset) { set_offset ( ( offset() + add_offset ) ); }
|
||||
void add_offset_in_bytes(int add_offset) {
|
||||
set_offset(offset() + add_offset);
|
||||
}
|
||||
|
||||
void verify();
|
||||
void print ();
|
||||
|
||||
private:
|
||||
inline friend NativeMovRegMem* nativeMovRegMem_at (address address);
|
||||
private:
|
||||
inline friend NativeMovRegMem* nativeMovRegMem_at(address address);
|
||||
};
|
||||
|
||||
inline NativeMovRegMem* nativeMovRegMem_at (address address) {
|
||||
inline NativeMovRegMem* nativeMovRegMem_at(address address) {
|
||||
NativeMovRegMem* test = (NativeMovRegMem*)(address - NativeMovRegMem::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
test->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(test->verify());
|
||||
return test;
|
||||
}
|
||||
|
||||
class NativeMovRegMemPatching: public NativeMovRegMem {
|
||||
private:
|
||||
friend NativeMovRegMemPatching* nativeMovRegMemPatching_at (address address) {Unimplemented(); return 0; }
|
||||
private:
|
||||
friend NativeMovRegMemPatching* nativeMovRegMemPatching_at(address address) {
|
||||
Unimplemented();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
// An interface for accessing/manipulating native leal instruction of form:
|
||||
@@ -419,10 +409,8 @@ class NativeLoadAddress: public NativeInstruction {
|
||||
next_instruction_offset = 4
|
||||
};
|
||||
|
||||
public:
|
||||
public:
|
||||
void verify();
|
||||
void print ();
|
||||
|
||||
};
|
||||
|
||||
// adrp x16, #page
|
||||
@@ -441,7 +429,7 @@ public:
|
||||
address next_instruction_address() const { return return_address(); }
|
||||
intptr_t data() const;
|
||||
void set_data(intptr_t data) {
|
||||
intptr_t *addr = (intptr_t *) got_address();
|
||||
intptr_t* addr = (intptr_t*)got_address();
|
||||
*addr = data;
|
||||
}
|
||||
|
||||
@@ -451,15 +439,13 @@ private:
|
||||
};
|
||||
|
||||
inline NativeLoadGot* nativeLoadGot_at(address addr) {
|
||||
NativeLoadGot* load = (NativeLoadGot*) addr;
|
||||
#ifdef ASSERT
|
||||
load->verify();
|
||||
#endif
|
||||
NativeLoadGot* load = (NativeLoadGot*)addr;
|
||||
DEBUG_ONLY(load->verify());
|
||||
return load;
|
||||
}
|
||||
|
||||
class NativeJump: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4,
|
||||
instruction_offset = 0,
|
||||
@@ -467,8 +453,8 @@ class NativeJump: public NativeInstruction {
|
||||
next_instruction_offset = 4
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(instruction_size); }
|
||||
address instruction_address() const { return addr_at(instruction_offset); }
|
||||
address next_instruction_address() const { return addr_at(instruction_size); }
|
||||
address jump_destination() const;
|
||||
void set_jump_destination(address dest);
|
||||
|
||||
@@ -486,9 +472,7 @@ class NativeJump: public NativeInstruction {
|
||||
|
||||
inline NativeJump* nativeJump_at(address address) {
|
||||
NativeJump* jump = (NativeJump*)(address - NativeJump::instruction_offset);
|
||||
#ifdef ASSERT
|
||||
jump->verify();
|
||||
#endif
|
||||
DEBUG_ONLY(jump->verify());
|
||||
return jump;
|
||||
}
|
||||
|
||||
@@ -511,7 +495,7 @@ public:
|
||||
|
||||
inline NativeGeneralJump* nativeGeneralJump_at(address address) {
|
||||
NativeGeneralJump* jump = (NativeGeneralJump*)(address);
|
||||
debug_only(jump->verify();)
|
||||
DEBUG_ONLY(jump->verify());
|
||||
return jump;
|
||||
}
|
||||
|
||||
@@ -529,46 +513,47 @@ public:
|
||||
address next_instruction_address() const { return addr_at(instruction_size); }
|
||||
bool is_GotJump() const;
|
||||
|
||||
void set_jump_destination(address dest) {
|
||||
address* got = (address *)got_address();
|
||||
void set_jump_destination(address dest) {
|
||||
address* got = (address*)got_address();
|
||||
*got = dest;
|
||||
}
|
||||
};
|
||||
|
||||
inline NativeGotJump* nativeGotJump_at(address addr) {
|
||||
NativeGotJump* jump = (NativeGotJump*)(addr);
|
||||
DEBUG_ONLY(jump->verify());
|
||||
return jump;
|
||||
}
|
||||
|
||||
class NativePopReg : public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
// Insert a pop instruction
|
||||
static void insert(address code_pos, Register reg);
|
||||
};
|
||||
|
||||
|
||||
class NativeIllegalInstruction: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
// Insert illegal opcode as specific address
|
||||
static void insert(address code_pos);
|
||||
};
|
||||
|
||||
// return instruction that does not pop values of the stack
|
||||
class NativeReturn: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
};
|
||||
|
||||
// return instruction that does pop values of the stack
|
||||
class NativeReturnX: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
};
|
||||
|
||||
// Simple test vs memory
|
||||
class NativeTstRegMem: public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
};
|
||||
|
||||
inline bool NativeInstruction::is_nop() {
|
||||
inline bool NativeInstruction::is_nop() {
|
||||
uint32_t insn = *(uint32_t*)addr_at(0);
|
||||
return insn == 0xd503201f;
|
||||
}
|
||||
@@ -598,7 +583,7 @@ inline bool NativeInstruction::is_jump_or_nop() {
|
||||
|
||||
// Call trampoline stubs.
|
||||
class NativeCallTrampolineStub : public NativeInstruction {
|
||||
public:
|
||||
public:
|
||||
|
||||
enum AArch64_specific_constants {
|
||||
instruction_size = 4 * 4,
|
||||
@@ -607,7 +592,7 @@ class NativeCallTrampolineStub : public NativeInstruction {
|
||||
next_instruction_offset = 4 * 4
|
||||
};
|
||||
|
||||
address destination(nmethod *nm = NULL) const;
|
||||
address destination(nmethod* nm = NULL) const;
|
||||
void set_destination(address new_destination);
|
||||
ptrdiff_t destination_offset() const;
|
||||
};
|
||||
@@ -617,7 +602,7 @@ inline bool is_NativeCallTrampolineStub_at(address addr) {
|
||||
// ldr xscratch1, L
|
||||
// br xscratch1
|
||||
// L:
|
||||
uint32_t *i = (uint32_t *)addr;
|
||||
uint32_t* i = (uint32_t*)addr;
|
||||
return i[0] == 0x58000048 && i[1] == 0xd61f0100;
|
||||
}
|
||||
|
||||
@@ -632,7 +617,7 @@ public:
|
||||
void set_kind(int order_kind) { Instruction_aarch64::patch(addr_at(0), 11, 8, order_kind); }
|
||||
};
|
||||
|
||||
inline NativeMembar *NativeMembar_at(address addr) {
|
||||
inline NativeMembar* NativeMembar_at(address addr) {
|
||||
assert(nativeInstruction_at(addr)->is_Membar(), "no membar found");
|
||||
return (NativeMembar*)addr;
|
||||
}
|
||||
@@ -686,8 +671,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
inline NativeLdSt *NativeLdSt_at(address addr) {
|
||||
inline NativeLdSt* NativeLdSt_at(address addr) {
|
||||
assert(nativeInstruction_at(addr)->is_Imm_LdSt(), "no immediate load/store found");
|
||||
return (NativeLdSt*)addr;
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_NATIVEINST_AARCH64_HPP
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -33,8 +33,6 @@
|
||||
// This is the hook for finding a register in an "well-known" location,
|
||||
// such as a register block of a predetermined format.
|
||||
// Since there is none, we just return NULL.
|
||||
// See registerMap_sparc.hpp for an example of grabbing registers
|
||||
// from register save areas of a standard layout.
|
||||
address pd_location(VMReg reg) const {return NULL;}
|
||||
|
||||
// no PD state to clear or copy:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -33,6 +33,9 @@ const int ConcreteRegisterImpl::max_fpr
|
||||
= ConcreteRegisterImpl::max_gpr +
|
||||
FloatRegisterImpl::number_of_registers * FloatRegisterImpl::max_slots_per_register;
|
||||
|
||||
const int ConcreteRegisterImpl::max_pr
|
||||
= ConcreteRegisterImpl::max_fpr + PRegisterImpl::number_of_registers;
|
||||
|
||||
const char* RegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
"c_rarg0", "c_rarg1", "c_rarg2", "c_rarg3", "c_rarg4", "c_rarg5", "c_rarg6", "c_rarg7",
|
||||
@@ -54,3 +57,11 @@ const char* FloatRegisterImpl::name() const {
|
||||
};
|
||||
return is_valid() ? names[encoding()] : "noreg";
|
||||
}
|
||||
|
||||
const char* PRegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
"p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7",
|
||||
"p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15"
|
||||
};
|
||||
return is_valid() ? names[encoding()] : "noreg";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -129,9 +129,10 @@ class FloatRegisterImpl: public AbstractRegisterImpl {
|
||||
public:
|
||||
enum {
|
||||
number_of_registers = 32,
|
||||
max_slots_per_register = 4,
|
||||
max_slots_per_register = 8,
|
||||
save_slots_per_register = 2,
|
||||
extra_save_slots_per_register = max_slots_per_register - save_slots_per_register
|
||||
slots_per_neon_register = 4,
|
||||
extra_save_slots_per_neon_register = slots_per_neon_register - save_slots_per_register
|
||||
};
|
||||
|
||||
// construction
|
||||
@@ -187,6 +188,88 @@ CONSTANT_REGISTER_DECLARATION(FloatRegister, v29 , (29));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v30 , (30));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, v31 , (31));
|
||||
|
||||
// SVE vector registers, shared with the SIMD&FP v0-v31. Vn maps to Zn[127:0].
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z0 , ( 0));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z1 , ( 1));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z2 , ( 2));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z3 , ( 3));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z4 , ( 4));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z5 , ( 5));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z6 , ( 6));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z7 , ( 7));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z8 , ( 8));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z9 , ( 9));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z10 , (10));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z11 , (11));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z12 , (12));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z13 , (13));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z14 , (14));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z15 , (15));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z16 , (16));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z17 , (17));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z18 , (18));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z19 , (19));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z20 , (20));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z21 , (21));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z22 , (22));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z23 , (23));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z24 , (24));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z25 , (25));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z26 , (26));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z27 , (27));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z28 , (28));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z29 , (29));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z30 , (30));
|
||||
CONSTANT_REGISTER_DECLARATION(FloatRegister, z31 , (31));
|
||||
|
||||
|
||||
class PRegisterImpl;
|
||||
typedef PRegisterImpl* PRegister;
|
||||
inline PRegister as_PRegister(int encoding) {
|
||||
return (PRegister)(intptr_t)encoding;
|
||||
}
|
||||
|
||||
// The implementation of predicate registers for the architecture
|
||||
class PRegisterImpl: public AbstractRegisterImpl {
|
||||
public:
|
||||
enum {
|
||||
number_of_registers = 16,
|
||||
max_slots_per_register = 1
|
||||
};
|
||||
|
||||
// construction
|
||||
inline friend PRegister as_PRegister(int encoding);
|
||||
|
||||
VMReg as_VMReg();
|
||||
|
||||
// derived registers, offsets, and addresses
|
||||
PRegister successor() const { return as_PRegister(encoding() + 1); }
|
||||
|
||||
// accessors
|
||||
int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; }
|
||||
int encoding_nocheck() const { return (intptr_t)this; }
|
||||
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
|
||||
const char* name() const;
|
||||
};
|
||||
|
||||
// The predicate registers of SVE.
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p0, ( 0));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p1, ( 1));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p2, ( 2));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p3, ( 3));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p4, ( 4));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p5, ( 5));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p6, ( 6));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p7, ( 7));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p8, ( 8));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p9, ( 9));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p10, (10));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p11, (11));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p12, (12));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p13, (13));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p14, (14));
|
||||
CONSTANT_REGISTER_DECLARATION(PRegister, p15, (15));
|
||||
|
||||
// Need to know the total number of registers of all sorts for SharedInfo.
|
||||
// Define a class that exports it.
|
||||
class ConcreteRegisterImpl : public AbstractRegisterImpl {
|
||||
@@ -199,12 +282,14 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl {
|
||||
|
||||
number_of_registers = (RegisterImpl::max_slots_per_register * RegisterImpl::number_of_registers +
|
||||
FloatRegisterImpl::max_slots_per_register * FloatRegisterImpl::number_of_registers +
|
||||
PRegisterImpl::max_slots_per_register * PRegisterImpl::number_of_registers +
|
||||
1) // flags
|
||||
};
|
||||
|
||||
// added to make it compile
|
||||
static const int max_gpr;
|
||||
static const int max_fpr;
|
||||
static const int max_pr;
|
||||
};
|
||||
|
||||
// A set of registers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -154,3 +154,55 @@ REGISTER_DEFINITION(Register, rthread);
|
||||
REGISTER_DEFINITION(Register, rheapbase);
|
||||
|
||||
REGISTER_DEFINITION(Register, r31_sp);
|
||||
|
||||
REGISTER_DEFINITION(FloatRegister, z0);
|
||||
REGISTER_DEFINITION(FloatRegister, z1);
|
||||
REGISTER_DEFINITION(FloatRegister, z2);
|
||||
REGISTER_DEFINITION(FloatRegister, z3);
|
||||
REGISTER_DEFINITION(FloatRegister, z4);
|
||||
REGISTER_DEFINITION(FloatRegister, z5);
|
||||
REGISTER_DEFINITION(FloatRegister, z6);
|
||||
REGISTER_DEFINITION(FloatRegister, z7);
|
||||
REGISTER_DEFINITION(FloatRegister, z8);
|
||||
REGISTER_DEFINITION(FloatRegister, z9);
|
||||
REGISTER_DEFINITION(FloatRegister, z10);
|
||||
REGISTER_DEFINITION(FloatRegister, z11);
|
||||
REGISTER_DEFINITION(FloatRegister, z12);
|
||||
REGISTER_DEFINITION(FloatRegister, z13);
|
||||
REGISTER_DEFINITION(FloatRegister, z14);
|
||||
REGISTER_DEFINITION(FloatRegister, z15);
|
||||
REGISTER_DEFINITION(FloatRegister, z16);
|
||||
REGISTER_DEFINITION(FloatRegister, z17);
|
||||
REGISTER_DEFINITION(FloatRegister, z18);
|
||||
REGISTER_DEFINITION(FloatRegister, z19);
|
||||
REGISTER_DEFINITION(FloatRegister, z20);
|
||||
REGISTER_DEFINITION(FloatRegister, z21);
|
||||
REGISTER_DEFINITION(FloatRegister, z22);
|
||||
REGISTER_DEFINITION(FloatRegister, z23);
|
||||
REGISTER_DEFINITION(FloatRegister, z24);
|
||||
REGISTER_DEFINITION(FloatRegister, z25);
|
||||
REGISTER_DEFINITION(FloatRegister, z26);
|
||||
REGISTER_DEFINITION(FloatRegister, z27);
|
||||
REGISTER_DEFINITION(FloatRegister, z28);
|
||||
REGISTER_DEFINITION(FloatRegister, z29);
|
||||
REGISTER_DEFINITION(FloatRegister, z30);
|
||||
REGISTER_DEFINITION(FloatRegister, z31);
|
||||
|
||||
REGISTER_DEFINITION(PRegister, p0);
|
||||
REGISTER_DEFINITION(PRegister, p1);
|
||||
REGISTER_DEFINITION(PRegister, p2);
|
||||
REGISTER_DEFINITION(PRegister, p3);
|
||||
REGISTER_DEFINITION(PRegister, p4);
|
||||
REGISTER_DEFINITION(PRegister, p5);
|
||||
REGISTER_DEFINITION(PRegister, p6);
|
||||
REGISTER_DEFINITION(PRegister, p7);
|
||||
REGISTER_DEFINITION(PRegister, p8);
|
||||
REGISTER_DEFINITION(PRegister, p9);
|
||||
REGISTER_DEFINITION(PRegister, p10);
|
||||
REGISTER_DEFINITION(PRegister, p11);
|
||||
REGISTER_DEFINITION(PRegister, p12);
|
||||
REGISTER_DEFINITION(PRegister, p13);
|
||||
REGISTER_DEFINITION(PRegister, p14);
|
||||
REGISTER_DEFINITION(PRegister, p15);
|
||||
|
||||
REGISTER_DEFINITION(PRegister, ptrue);
|
||||
|
||||
@@ -115,11 +115,28 @@ class RegisterSaver {
|
||||
};
|
||||
|
||||
OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_frame_words, int* total_frame_words, bool save_vectors) {
|
||||
bool use_sve = false;
|
||||
int sve_vector_size_in_bytes = 0;
|
||||
int sve_vector_size_in_slots = 0;
|
||||
|
||||
#ifdef COMPILER2
|
||||
use_sve = Matcher::supports_scalable_vector();
|
||||
sve_vector_size_in_bytes = Matcher::scalable_vector_reg_size(T_BYTE);
|
||||
sve_vector_size_in_slots = Matcher::scalable_vector_reg_size(T_FLOAT);
|
||||
#endif
|
||||
|
||||
#if COMPILER2_OR_JVMCI
|
||||
if (save_vectors) {
|
||||
int vect_words = 0;
|
||||
int extra_save_slots_per_register = 0;
|
||||
// Save upper half of vector registers
|
||||
int vect_words = FloatRegisterImpl::number_of_registers * FloatRegisterImpl::extra_save_slots_per_register /
|
||||
VMRegImpl::slots_per_word;
|
||||
if (use_sve) {
|
||||
extra_save_slots_per_register = sve_vector_size_in_slots - FloatRegisterImpl::save_slots_per_register;
|
||||
} else {
|
||||
extra_save_slots_per_register = FloatRegisterImpl::extra_save_slots_per_neon_register;
|
||||
}
|
||||
vect_words = FloatRegisterImpl::number_of_registers * extra_save_slots_per_register /
|
||||
VMRegImpl::slots_per_word;
|
||||
additional_frame_words += vect_words;
|
||||
}
|
||||
#else
|
||||
@@ -138,7 +155,7 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_
|
||||
|
||||
// Save Integer and Float registers.
|
||||
__ enter();
|
||||
__ push_CPU_state(save_vectors);
|
||||
__ push_CPU_state(save_vectors, use_sve, sve_vector_size_in_bytes);
|
||||
|
||||
// Set an oopmap for the call site. This oopmap will map all
|
||||
// oop-registers and debug-info registers as callee-saved. This
|
||||
@@ -162,8 +179,13 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_
|
||||
|
||||
for (int i = 0; i < FloatRegisterImpl::number_of_registers; i++) {
|
||||
FloatRegister r = as_FloatRegister(i);
|
||||
int sp_offset = save_vectors ? (FloatRegisterImpl::max_slots_per_register * i) :
|
||||
(FloatRegisterImpl::save_slots_per_register * i);
|
||||
int sp_offset = 0;
|
||||
if (save_vectors) {
|
||||
sp_offset = use_sve ? (sve_vector_size_in_slots * i) :
|
||||
(FloatRegisterImpl::slots_per_neon_register * i);
|
||||
} else {
|
||||
sp_offset = FloatRegisterImpl::save_slots_per_register * i;
|
||||
}
|
||||
oop_map->set_callee_saved(VMRegImpl::stack2reg(sp_offset),
|
||||
r->as_VMReg());
|
||||
}
|
||||
@@ -172,10 +194,15 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm, int additional_
|
||||
}
|
||||
|
||||
void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_vectors) {
|
||||
#if !COMPILER2_OR_JVMCI
|
||||
#ifdef COMPILER2
|
||||
__ pop_CPU_state(restore_vectors, Matcher::supports_scalable_vector(),
|
||||
Matcher::scalable_vector_reg_size(T_BYTE));
|
||||
#else
|
||||
#if !INCLUDE_JVMCI
|
||||
assert(!restore_vectors, "vectors are generated only by C2 and JVMCI");
|
||||
#endif
|
||||
__ pop_CPU_state(restore_vectors);
|
||||
#endif
|
||||
__ leave();
|
||||
|
||||
}
|
||||
@@ -823,7 +850,7 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
}
|
||||
|
||||
// On 64 bit we will store integer like items to the stack as
|
||||
// 64 bits items (sparc abi) even though java would only store
|
||||
// 64 bits items (Aarch64 abi) even though java would only store
|
||||
// 32bits for a parameter. On 32bit it will simply be 32 bits
|
||||
// So this routine will do 32->32 on 32bit and 32->64 on 64bit
|
||||
static void move32_64(MacroAssembler* masm, VMRegPair src, VMRegPair dst) {
|
||||
@@ -1842,6 +1869,11 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
// Force this write out before the read below
|
||||
__ dmb(Assembler::ISH);
|
||||
|
||||
if (UseSVE > 0) {
|
||||
// Make sure that jni code does not change SVE vector length.
|
||||
__ verify_sve_vector_length();
|
||||
}
|
||||
|
||||
// check for safepoint operation in progress and/or pending suspend requests
|
||||
Label safepoint_in_progress, safepoint_in_progress_done;
|
||||
{
|
||||
@@ -2774,6 +2806,12 @@ SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_t
|
||||
__ maybe_isb();
|
||||
__ membar(Assembler::LoadLoad | Assembler::LoadStore);
|
||||
|
||||
if (UseSVE > 0 && save_vectors) {
|
||||
// Reinitialize the ptrue predicate register, in case the external runtime
|
||||
// call clobbers ptrue reg, as we may return to SVE compiled code.
|
||||
__ reinitialize_ptrue();
|
||||
}
|
||||
|
||||
__ ldr(rscratch1, Address(rthread, Thread::pending_exception_offset()));
|
||||
__ cbz(rscratch1, noException);
|
||||
|
||||
|
||||
@@ -488,6 +488,11 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address,
|
||||
SharedRuntime::exception_handler_for_return_address),
|
||||
rthread, c_rarg1);
|
||||
if (UseSVE > 0 ) {
|
||||
// Reinitialize the ptrue predicate register, in case the external runtime
|
||||
// call clobbers ptrue reg, as we may return to SVE compiled code.
|
||||
__ reinitialize_ptrue();
|
||||
}
|
||||
// we should not really care that lr is no longer the callee
|
||||
// address. we saved the value the handler needs in r19 so we can
|
||||
// just copy it to r3. however, the C2 handler will push its own
|
||||
@@ -3125,6 +3130,172 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
// Arguments:
|
||||
//
|
||||
// Inputs:
|
||||
// c_rarg0 - byte[] source+offset
|
||||
// c_rarg1 - int[] SHA.state
|
||||
// c_rarg2 - int offset
|
||||
// c_rarg3 - int limit
|
||||
//
|
||||
address generate_sha512_implCompress(bool multi_block, const char *name) {
|
||||
static const uint64_t round_consts[80] = {
|
||||
0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL,
|
||||
0xE9B5DBA58189DBBCL, 0x3956C25BF348B538L, 0x59F111F1B605D019L,
|
||||
0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L, 0xD807AA98A3030242L,
|
||||
0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L,
|
||||
0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L,
|
||||
0xC19BF174CF692694L, 0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L,
|
||||
0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L, 0x2DE92C6F592B0275L,
|
||||
0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L,
|
||||
0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL,
|
||||
0xBF597FC7BEEF0EE4L, 0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L,
|
||||
0x06CA6351E003826FL, 0x142929670A0E6E70L, 0x27B70A8546D22FFCL,
|
||||
0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL,
|
||||
0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L,
|
||||
0x92722C851482353BL, 0xA2BFE8A14CF10364L, 0xA81A664BBC423001L,
|
||||
0xC24B8B70D0F89791L, 0xC76C51A30654BE30L, 0xD192E819D6EF5218L,
|
||||
0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L,
|
||||
0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L,
|
||||
0x34B0BCB5E19B48A8L, 0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL,
|
||||
0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L, 0x748F82EE5DEFB2FCL,
|
||||
0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL,
|
||||
0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L,
|
||||
0xC67178F2E372532BL, 0xCA273ECEEA26619CL, 0xD186B8C721C0C207L,
|
||||
0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L, 0x06F067AA72176FBAL,
|
||||
0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL,
|
||||
0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL,
|
||||
0x431D67C49C100D4CL, 0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL,
|
||||
0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L
|
||||
};
|
||||
|
||||
// Double rounds for sha512.
|
||||
#define sha512_dround(dr, i0, i1, i2, i3, i4, rc0, rc1, in0, in1, in2, in3, in4) \
|
||||
if (dr < 36) \
|
||||
__ ld1(v##rc1, __ T2D, __ post(rscratch2, 16)); \
|
||||
__ addv(v5, __ T2D, v##rc0, v##in0); \
|
||||
__ ext(v6, __ T16B, v##i2, v##i3, 8); \
|
||||
__ ext(v5, __ T16B, v5, v5, 8); \
|
||||
__ ext(v7, __ T16B, v##i1, v##i2, 8); \
|
||||
__ addv(v##i3, __ T2D, v##i3, v5); \
|
||||
if (dr < 32) { \
|
||||
__ ext(v5, __ T16B, v##in3, v##in4, 8); \
|
||||
__ sha512su0(v##in0, __ T2D, v##in1); \
|
||||
} \
|
||||
__ sha512h(v##i3, __ T2D, v6, v7); \
|
||||
if (dr < 32) \
|
||||
__ sha512su1(v##in0, __ T2D, v##in2, v5); \
|
||||
__ addv(v##i4, __ T2D, v##i1, v##i3); \
|
||||
__ sha512h2(v##i3, __ T2D, v##i1, v##i0); \
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", name);
|
||||
address start = __ pc();
|
||||
|
||||
Register buf = c_rarg0;
|
||||
Register state = c_rarg1;
|
||||
Register ofs = c_rarg2;
|
||||
Register limit = c_rarg3;
|
||||
|
||||
__ stpd(v8, v9, __ pre(sp, -64));
|
||||
__ stpd(v10, v11, Address(sp, 16));
|
||||
__ stpd(v12, v13, Address(sp, 32));
|
||||
__ stpd(v14, v15, Address(sp, 48));
|
||||
|
||||
Label sha512_loop;
|
||||
|
||||
// load state
|
||||
__ ld1(v8, v9, v10, v11, __ T2D, state);
|
||||
|
||||
// load first 4 round constants
|
||||
__ lea(rscratch1, ExternalAddress((address)round_consts));
|
||||
__ ld1(v20, v21, v22, v23, __ T2D, __ post(rscratch1, 64));
|
||||
|
||||
__ BIND(sha512_loop);
|
||||
// load 128B of data into v12..v19
|
||||
__ ld1(v12, v13, v14, v15, __ T2D, __ post(buf, 64));
|
||||
__ ld1(v16, v17, v18, v19, __ T2D, __ post(buf, 64));
|
||||
__ rev64(v12, __ T16B, v12);
|
||||
__ rev64(v13, __ T16B, v13);
|
||||
__ rev64(v14, __ T16B, v14);
|
||||
__ rev64(v15, __ T16B, v15);
|
||||
__ rev64(v16, __ T16B, v16);
|
||||
__ rev64(v17, __ T16B, v17);
|
||||
__ rev64(v18, __ T16B, v18);
|
||||
__ rev64(v19, __ T16B, v19);
|
||||
|
||||
__ mov(rscratch2, rscratch1);
|
||||
|
||||
__ mov(v0, __ T16B, v8);
|
||||
__ mov(v1, __ T16B, v9);
|
||||
__ mov(v2, __ T16B, v10);
|
||||
__ mov(v3, __ T16B, v11);
|
||||
|
||||
sha512_dround( 0, 0, 1, 2, 3, 4, 20, 24, 12, 13, 19, 16, 17);
|
||||
sha512_dround( 1, 3, 0, 4, 2, 1, 21, 25, 13, 14, 12, 17, 18);
|
||||
sha512_dround( 2, 2, 3, 1, 4, 0, 22, 26, 14, 15, 13, 18, 19);
|
||||
sha512_dround( 3, 4, 2, 0, 1, 3, 23, 27, 15, 16, 14, 19, 12);
|
||||
sha512_dround( 4, 1, 4, 3, 0, 2, 24, 28, 16, 17, 15, 12, 13);
|
||||
sha512_dround( 5, 0, 1, 2, 3, 4, 25, 29, 17, 18, 16, 13, 14);
|
||||
sha512_dround( 6, 3, 0, 4, 2, 1, 26, 30, 18, 19, 17, 14, 15);
|
||||
sha512_dround( 7, 2, 3, 1, 4, 0, 27, 31, 19, 12, 18, 15, 16);
|
||||
sha512_dround( 8, 4, 2, 0, 1, 3, 28, 24, 12, 13, 19, 16, 17);
|
||||
sha512_dround( 9, 1, 4, 3, 0, 2, 29, 25, 13, 14, 12, 17, 18);
|
||||
sha512_dround(10, 0, 1, 2, 3, 4, 30, 26, 14, 15, 13, 18, 19);
|
||||
sha512_dround(11, 3, 0, 4, 2, 1, 31, 27, 15, 16, 14, 19, 12);
|
||||
sha512_dround(12, 2, 3, 1, 4, 0, 24, 28, 16, 17, 15, 12, 13);
|
||||
sha512_dround(13, 4, 2, 0, 1, 3, 25, 29, 17, 18, 16, 13, 14);
|
||||
sha512_dround(14, 1, 4, 3, 0, 2, 26, 30, 18, 19, 17, 14, 15);
|
||||
sha512_dround(15, 0, 1, 2, 3, 4, 27, 31, 19, 12, 18, 15, 16);
|
||||
sha512_dround(16, 3, 0, 4, 2, 1, 28, 24, 12, 13, 19, 16, 17);
|
||||
sha512_dround(17, 2, 3, 1, 4, 0, 29, 25, 13, 14, 12, 17, 18);
|
||||
sha512_dround(18, 4, 2, 0, 1, 3, 30, 26, 14, 15, 13, 18, 19);
|
||||
sha512_dround(19, 1, 4, 3, 0, 2, 31, 27, 15, 16, 14, 19, 12);
|
||||
sha512_dround(20, 0, 1, 2, 3, 4, 24, 28, 16, 17, 15, 12, 13);
|
||||
sha512_dround(21, 3, 0, 4, 2, 1, 25, 29, 17, 18, 16, 13, 14);
|
||||
sha512_dround(22, 2, 3, 1, 4, 0, 26, 30, 18, 19, 17, 14, 15);
|
||||
sha512_dround(23, 4, 2, 0, 1, 3, 27, 31, 19, 12, 18, 15, 16);
|
||||
sha512_dround(24, 1, 4, 3, 0, 2, 28, 24, 12, 13, 19, 16, 17);
|
||||
sha512_dround(25, 0, 1, 2, 3, 4, 29, 25, 13, 14, 12, 17, 18);
|
||||
sha512_dround(26, 3, 0, 4, 2, 1, 30, 26, 14, 15, 13, 18, 19);
|
||||
sha512_dround(27, 2, 3, 1, 4, 0, 31, 27, 15, 16, 14, 19, 12);
|
||||
sha512_dround(28, 4, 2, 0, 1, 3, 24, 28, 16, 17, 15, 12, 13);
|
||||
sha512_dround(29, 1, 4, 3, 0, 2, 25, 29, 17, 18, 16, 13, 14);
|
||||
sha512_dround(30, 0, 1, 2, 3, 4, 26, 30, 18, 19, 17, 14, 15);
|
||||
sha512_dround(31, 3, 0, 4, 2, 1, 27, 31, 19, 12, 18, 15, 16);
|
||||
sha512_dround(32, 2, 3, 1, 4, 0, 28, 24, 12, 0, 0, 0, 0);
|
||||
sha512_dround(33, 4, 2, 0, 1, 3, 29, 25, 13, 0, 0, 0, 0);
|
||||
sha512_dround(34, 1, 4, 3, 0, 2, 30, 26, 14, 0, 0, 0, 0);
|
||||
sha512_dround(35, 0, 1, 2, 3, 4, 31, 27, 15, 0, 0, 0, 0);
|
||||
sha512_dround(36, 3, 0, 4, 2, 1, 24, 0, 16, 0, 0, 0, 0);
|
||||
sha512_dround(37, 2, 3, 1, 4, 0, 25, 0, 17, 0, 0, 0, 0);
|
||||
sha512_dround(38, 4, 2, 0, 1, 3, 26, 0, 18, 0, 0, 0, 0);
|
||||
sha512_dround(39, 1, 4, 3, 0, 2, 27, 0, 19, 0, 0, 0, 0);
|
||||
|
||||
__ addv(v8, __ T2D, v8, v0);
|
||||
__ addv(v9, __ T2D, v9, v1);
|
||||
__ addv(v10, __ T2D, v10, v2);
|
||||
__ addv(v11, __ T2D, v11, v3);
|
||||
|
||||
if (multi_block) {
|
||||
__ add(ofs, ofs, 128);
|
||||
__ cmp(ofs, limit);
|
||||
__ br(Assembler::LE, sha512_loop);
|
||||
__ mov(c_rarg0, ofs); // return ofs
|
||||
}
|
||||
|
||||
__ st1(v8, v9, v10, v11, __ T2D, state);
|
||||
|
||||
__ ldpd(v14, v15, Address(sp, 48));
|
||||
__ ldpd(v12, v13, Address(sp, 32));
|
||||
__ ldpd(v10, v11, Address(sp, 16));
|
||||
__ ldpd(v8, v9, __ post(sp, 64));
|
||||
|
||||
__ ret(lr);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
void generate_safefetch(const char* name, int size, address* entry,
|
||||
address* fault_pc, address* continuation_pc) {
|
||||
@@ -4852,6 +5023,12 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ reset_last_Java_frame(true);
|
||||
__ maybe_isb();
|
||||
|
||||
if (UseSVE > 0) {
|
||||
// Reinitialize the ptrue predicate register, in case the external runtime
|
||||
// call clobbers ptrue reg, as we may return to SVE compiled code.
|
||||
__ reinitialize_ptrue();
|
||||
}
|
||||
|
||||
__ leave();
|
||||
|
||||
// check for pending exceptions
|
||||
@@ -5852,6 +6029,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_sha256_implCompress = generate_sha256_implCompress(false, "sha256_implCompress");
|
||||
StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB");
|
||||
}
|
||||
if (UseSHA512Intrinsics) {
|
||||
StubRoutines::_sha512_implCompress = generate_sha512_implCompress(false, "sha512_implCompress");
|
||||
StubRoutines::_sha512_implCompressMB = generate_sha512_implCompress(true, "sha512_implCompressMB");
|
||||
}
|
||||
|
||||
// generate Adler32 intrinsics code
|
||||
if (UseAdler32Intrinsics) {
|
||||
|
||||
@@ -62,7 +62,7 @@ bool StubRoutines::aarch64::_completed = false;
|
||||
/**
|
||||
* crc_table[] from jdk/src/share/native/java/util/zip/zlib-1.2.5/crc32.h
|
||||
*/
|
||||
juint StubRoutines::aarch64::_crc_table[] ATTRIBUTE_ALIGNED(4096) =
|
||||
ATTRIBUTE_ALIGNED(4096) juint StubRoutines::aarch64::_crc_table[] =
|
||||
{
|
||||
// Table 0
|
||||
0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
|
||||
@@ -289,11 +289,11 @@ juint StubRoutines::aarch64::_crc_table[] ATTRIBUTE_ALIGNED(4096) =
|
||||
};
|
||||
|
||||
// Accumulation coefficients for adler32 upper 16 bits
|
||||
jubyte StubRoutines::aarch64::_adler_table[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) jubyte StubRoutines::aarch64::_adler_table[] = {
|
||||
16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
|
||||
};
|
||||
|
||||
juint StubRoutines::aarch64::_npio2_hw[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) juint StubRoutines::aarch64::_npio2_hw[] = {
|
||||
// first, various coefficient values: 0.5, invpio2, pio2_1, pio2_1t, pio2_2,
|
||||
// pio2_2t, pio2_3, pio2_3t
|
||||
// This is a small optimization wich keeping double[8] values in int[] table
|
||||
@@ -325,7 +325,7 @@ juint StubRoutines::aarch64::_npio2_hw[] __attribute__ ((aligned(64))) = {
|
||||
|
||||
// Coefficients for sin(x) polynomial approximation: S1..S6.
|
||||
// See kernel_sin comments in macroAssembler_aarch64_trig.cpp for details
|
||||
jdouble StubRoutines::aarch64::_dsin_coef[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) jdouble StubRoutines::aarch64::_dsin_coef[] = {
|
||||
-1.66666666666666324348e-01, // 0xBFC5555555555549
|
||||
8.33333333332248946124e-03, // 0x3F8111111110F8A6
|
||||
-1.98412698298579493134e-04, // 0xBF2A01A019C161D5
|
||||
@@ -336,7 +336,7 @@ jdouble StubRoutines::aarch64::_dsin_coef[] __attribute__ ((aligned(64))) = {
|
||||
|
||||
// Coefficients for cos(x) polynomial approximation: C1..C6.
|
||||
// See kernel_cos comments in macroAssembler_aarch64_trig.cpp for details
|
||||
jdouble StubRoutines::aarch64::_dcos_coef[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) jdouble StubRoutines::aarch64::_dcos_coef[] = {
|
||||
4.16666666666666019037e-02, // c0x3FA555555555554C
|
||||
-1.38888888888741095749e-03, // 0xBF56C16C16C15177
|
||||
2.48015872894767294178e-05, // 0x3EFA01A019CB1590
|
||||
@@ -351,7 +351,7 @@ jdouble StubRoutines::aarch64::_dcos_coef[] __attribute__ ((aligned(64))) = {
|
||||
// Converted to double to avoid unnecessary conversion in code
|
||||
// NOTE: table looks like original int table: {0xA2F983, 0x6E4E44,...} with
|
||||
// only (double) conversion added
|
||||
jdouble StubRoutines::aarch64::_two_over_pi[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) jdouble StubRoutines::aarch64::_two_over_pi[] = {
|
||||
(double)0xA2F983, (double)0x6E4E44, (double)0x1529FC, (double)0x2757D1, (double)0xF534DD, (double)0xC0DB62,
|
||||
(double)0x95993C, (double)0x439041, (double)0xFE5163, (double)0xABDEBB, (double)0xC561B7, (double)0x246E3A,
|
||||
(double)0x424DD2, (double)0xE00649, (double)0x2EEA09, (double)0xD1921C, (double)0xFE1DEB, (double)0x1CB129,
|
||||
@@ -366,7 +366,7 @@ jdouble StubRoutines::aarch64::_two_over_pi[] __attribute__ ((aligned(64))) = {
|
||||
};
|
||||
|
||||
// Pi over 2 value
|
||||
jdouble StubRoutines::aarch64::_pio2[] __attribute__ ((aligned(64))) = {
|
||||
ATTRIBUTE_ALIGNED(64) jdouble StubRoutines::aarch64::_pio2[] = {
|
||||
1.57079625129699707031e+00, // 0x3FF921FB40000000
|
||||
7.54978941586159635335e-08, // 0x3E74442D00000000
|
||||
5.39030252995776476554e-15, // 0x3CF8469880000000
|
||||
|
||||
@@ -1372,6 +1372,11 @@ address TemplateInterpreterGenerator::generate_native_entry(bool synchronized) {
|
||||
__ push(dtos);
|
||||
__ push(ltos);
|
||||
|
||||
if (UseSVE > 0) {
|
||||
// Make sure that jni code does not change SVE vector length.
|
||||
__ verify_sve_vector_length();
|
||||
}
|
||||
|
||||
// change thread state
|
||||
__ mov(rscratch1, _thread_in_native_trans);
|
||||
__ lea(rscratch2, Address(rthread, JavaThread::thread_state_offset()));
|
||||
@@ -1580,6 +1585,9 @@ address TemplateInterpreterGenerator::generate_normal_entry(bool synchronized) {
|
||||
|
||||
// Make room for locals
|
||||
__ sub(rscratch1, esp, r3, ext::uxtx, 3);
|
||||
|
||||
// Padding between locals and fixed part of activation frame to ensure
|
||||
// SP is always 16-byte aligned.
|
||||
__ andr(sp, rscratch1, -16);
|
||||
|
||||
// r3 - # of additional locals
|
||||
|
||||
@@ -3286,7 +3286,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
||||
|
||||
const Register method = index; // method must be rmethod
|
||||
assert(method == rmethod,
|
||||
"methodOop must be rmethod for interpreter calling convention");
|
||||
"Method must be rmethod for interpreter calling convention");
|
||||
|
||||
// do the call - the index is actually the method to call
|
||||
// that is, f2 is a vtable index if !is_vfinal, else f2 is a Method*
|
||||
@@ -3309,7 +3309,7 @@ void TemplateTable::invokevirtual_helper(Register index,
|
||||
// profile this call
|
||||
__ profile_virtual_call(r0, rlocals, r3);
|
||||
|
||||
// get target methodOop & entry point
|
||||
// get target Method & entry point
|
||||
__ lookup_virtual_method(r0, index, method);
|
||||
__ profile_arguments_type(r3, method, r4, true);
|
||||
// FIXME -- this looks completely redundant. is it?
|
||||
@@ -3444,7 +3444,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
rmethod, r13,
|
||||
no_such_interface);
|
||||
|
||||
// rmethod,: methodOop to call
|
||||
// rmethod,: Method to call
|
||||
// r2: receiver
|
||||
// Check for abstract method error
|
||||
// Note: This should be done more efficiently via a throw_abstract_method_error
|
||||
@@ -3456,7 +3456,7 @@ void TemplateTable::invokeinterface(int byte_no) {
|
||||
|
||||
// do the call
|
||||
// r2: receiver
|
||||
// rmethod,: methodOop
|
||||
// rmethod,: Method
|
||||
__ jump_from_interpreted(rmethod, r3);
|
||||
__ should_not_reach_here();
|
||||
|
||||
|
||||
@@ -27,16 +27,19 @@
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/stubCodeGenerator.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "utilities/formatBuffer.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
#include OS_HEADER_INLINE(os)
|
||||
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#ifndef HWCAP_AES
|
||||
#define HWCAP_AES (1<<3)
|
||||
@@ -62,6 +65,24 @@
|
||||
#define HWCAP_ATOMICS (1<<8)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_SHA512
|
||||
#define HWCAP_SHA512 (1 << 21)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP_SVE
|
||||
#define HWCAP_SVE (1 << 22)
|
||||
#endif
|
||||
|
||||
#ifndef HWCAP2_SVE2
|
||||
#define HWCAP2_SVE2 (1 << 1)
|
||||
#endif
|
||||
|
||||
#ifndef PR_SVE_GET_VL
|
||||
// For old toolchains which do not have SVE related macros defined.
|
||||
#define PR_SVE_SET_VL 50
|
||||
#define PR_SVE_GET_VL 51
|
||||
#endif
|
||||
|
||||
int VM_Version::_cpu;
|
||||
int VM_Version::_model;
|
||||
int VM_Version::_model2;
|
||||
@@ -69,6 +90,7 @@ int VM_Version::_variant;
|
||||
int VM_Version::_revision;
|
||||
int VM_Version::_stepping;
|
||||
bool VM_Version::_dcpop;
|
||||
int VM_Version::_initial_sve_vector_length;
|
||||
VM_Version::PsrInfo VM_Version::_psr_info = { 0, };
|
||||
|
||||
static BufferBlob* stub_blob;
|
||||
@@ -111,7 +133,6 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void VM_Version::get_processor_features() {
|
||||
_supports_cx8 = true;
|
||||
_supports_atomic_getset4 = true;
|
||||
@@ -162,6 +183,7 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
|
||||
uint64_t auxv = getauxval(AT_HWCAP);
|
||||
uint64_t auxv2 = getauxval(AT_HWCAP2);
|
||||
|
||||
char buf[512];
|
||||
|
||||
@@ -272,6 +294,12 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
}
|
||||
|
||||
if (_cpu == CPU_ARM) {
|
||||
if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) {
|
||||
FLAG_SET_DEFAULT(UseSignumIntrinsic, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (_cpu == CPU_ARM && (_model == 0xd07 || _model2 == 0xd07)) _features |= CPU_STXR_PREFETCH;
|
||||
// If an olde style /proc/cpuinfo (cpu_lines == 1) then if _model is an A57 (0xd07)
|
||||
// we assume the worst and assume we could be on a big little system and have
|
||||
@@ -285,7 +313,10 @@ void VM_Version::get_processor_features() {
|
||||
if (auxv & HWCAP_AES) strcat(buf, ", aes");
|
||||
if (auxv & HWCAP_SHA1) strcat(buf, ", sha1");
|
||||
if (auxv & HWCAP_SHA2) strcat(buf, ", sha256");
|
||||
if (auxv & HWCAP_SHA512) strcat(buf, ", sha512");
|
||||
if (auxv & HWCAP_ATOMICS) strcat(buf, ", lse");
|
||||
if (auxv & HWCAP_SVE) strcat(buf, ", sve");
|
||||
if (auxv2 & HWCAP2_SVE2) strcat(buf, ", sve2");
|
||||
|
||||
_features_string = os::strdup(buf);
|
||||
|
||||
@@ -358,6 +389,11 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseFMA, true);
|
||||
}
|
||||
|
||||
if (UseMD5Intrinsics) {
|
||||
warning("MD5 intrinsics are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseMD5Intrinsics, false);
|
||||
}
|
||||
|
||||
if (auxv & (HWCAP_SHA1 | HWCAP_SHA2)) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, true);
|
||||
@@ -385,7 +421,12 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA512Intrinsics) {
|
||||
if (UseSHA && (auxv & HWCAP_SHA512)) {
|
||||
// Do not auto-enable UseSHA512Intrinsics until it has been fully tested on hardware
|
||||
// if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
|
||||
// FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
|
||||
// }
|
||||
} else if (UseSHA512Intrinsics) {
|
||||
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
@@ -415,6 +456,18 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseBlockZeroing, false);
|
||||
}
|
||||
|
||||
if (auxv & HWCAP_SVE) {
|
||||
if (FLAG_IS_DEFAULT(UseSVE)) {
|
||||
FLAG_SET_DEFAULT(UseSVE, (auxv2 & HWCAP2_SVE2) ? 2 : 1);
|
||||
}
|
||||
if (UseSVE > 0) {
|
||||
_initial_sve_vector_length = prctl(PR_SVE_GET_VL);
|
||||
}
|
||||
} else if (UseSVE > 0) {
|
||||
warning("UseSVE specified, but not supported on current CPU. Disabling SVE.");
|
||||
FLAG_SET_DEFAULT(UseSVE, 0);
|
||||
}
|
||||
|
||||
// This machine allows unaligned memory accesses
|
||||
if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
|
||||
FLAG_SET_DEFAULT(UseUnalignedAccesses, true);
|
||||
@@ -449,6 +502,50 @@ void VM_Version::get_processor_features() {
|
||||
UseMontgomerySquareIntrinsic = true;
|
||||
}
|
||||
|
||||
if (UseSVE > 0) {
|
||||
if (FLAG_IS_DEFAULT(MaxVectorSize)) {
|
||||
MaxVectorSize = _initial_sve_vector_length;
|
||||
} else if (MaxVectorSize < 16) {
|
||||
warning("SVE does not support vector length less than 16 bytes. Disabling SVE.");
|
||||
UseSVE = 0;
|
||||
} else if ((MaxVectorSize % 16) == 0 && is_power_of_2(MaxVectorSize)) {
|
||||
int new_vl = prctl(PR_SVE_SET_VL, MaxVectorSize);
|
||||
_initial_sve_vector_length = new_vl;
|
||||
// If MaxVectorSize is larger than system largest supported SVE vector length, above prctl()
|
||||
// call will set task vector length to the system largest supported value. So, we also update
|
||||
// MaxVectorSize to that largest supported value.
|
||||
if (new_vl < 0) {
|
||||
vm_exit_during_initialization(
|
||||
err_msg("Current system does not support SVE vector length for MaxVectorSize: %d",
|
||||
(int)MaxVectorSize));
|
||||
} else if (new_vl != MaxVectorSize) {
|
||||
warning("Current system only supports max SVE vector length %d. Set MaxVectorSize to %d",
|
||||
new_vl, new_vl);
|
||||
}
|
||||
MaxVectorSize = new_vl;
|
||||
} else {
|
||||
vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize));
|
||||
}
|
||||
}
|
||||
|
||||
if (UseSVE == 0) { // NEON
|
||||
int min_vector_size = 8;
|
||||
int max_vector_size = 16;
|
||||
if (!FLAG_IS_DEFAULT(MaxVectorSize)) {
|
||||
if (!is_power_of_2(MaxVectorSize)) {
|
||||
vm_exit_during_initialization(err_msg("Unsupported MaxVectorSize: %d", (int)MaxVectorSize));
|
||||
} else if (MaxVectorSize < min_vector_size) {
|
||||
warning("MaxVectorSize must be at least %i on this platform", min_vector_size);
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, min_vector_size);
|
||||
} else if (MaxVectorSize > max_vector_size) {
|
||||
warning("MaxVectorSize must be at most %i on this platform", max_vector_size);
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, max_vector_size);
|
||||
}
|
||||
} else {
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 16);
|
||||
}
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(OptoScheduling)) {
|
||||
OptoScheduling = true;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ protected:
|
||||
static int _revision;
|
||||
static int _stepping;
|
||||
static bool _dcpop;
|
||||
static int _initial_sve_vector_length;
|
||||
|
||||
struct PsrInfo {
|
||||
uint32_t dczid_el0;
|
||||
uint32_t ctr_el0;
|
||||
@@ -106,6 +108,7 @@ public:
|
||||
static int cpu_variant() { return _variant; }
|
||||
static int cpu_revision() { return _revision; }
|
||||
static bool supports_dcpop() { return _dcpop; }
|
||||
static int get_initial_sve_vector_length() { return _initial_sve_vector_length; };
|
||||
static ByteSize dczid_el0_offset() { return byte_offset_of(PsrInfo, dczid_el0); }
|
||||
static ByteSize ctr_el0_offset() { return byte_offset_of(PsrInfo, ctr_el0); }
|
||||
static bool is_zva_enabled() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -36,4 +36,8 @@ inline VMReg FloatRegisterImpl::as_VMReg() {
|
||||
ConcreteRegisterImpl::max_gpr);
|
||||
}
|
||||
|
||||
inline VMReg PRegisterImpl::as_VMReg() {
|
||||
return VMRegImpl::as_VMReg(encoding() + ConcreteRegisterImpl::max_fpr);
|
||||
}
|
||||
|
||||
#endif // CPU_AARCH64_VMREG_AARCH64_INLINE_HPP
|
||||
|
||||
@@ -1006,6 +1006,14 @@ const int Matcher::vector_width_in_bytes(BasicType bt) {
|
||||
return MaxVectorSize;
|
||||
}
|
||||
|
||||
const bool Matcher::supports_scalable_vector() {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int Matcher::scalable_vector_reg_size(const BasicType bt) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Vector ideal reg corresponding to specified size in bytes
|
||||
const uint Matcher::vector_ideal_reg(int size) {
|
||||
assert(MaxVectorSize >= size, "");
|
||||
@@ -8869,12 +8877,12 @@ instruct CallLeafNoFPDirect(method meth) %{
|
||||
// Also known as an 'interprocedural jump'.
|
||||
// Target of jump will eventually return to caller.
|
||||
// TailJump below removes the return address.
|
||||
instruct TailCalljmpInd(IPRegP jump_target, inline_cache_regP method_oop) %{
|
||||
match(TailCall jump_target method_oop );
|
||||
instruct TailCalljmpInd(IPRegP jump_target, inline_cache_regP method_ptr) %{
|
||||
match(TailCall jump_target method_ptr);
|
||||
|
||||
ins_cost(CALL_COST);
|
||||
format %{ "MOV Rexception_pc, LR\n\t"
|
||||
"jump $jump_target \t! $method_oop holds method oop" %}
|
||||
"jump $jump_target \t! $method_ptr holds method" %}
|
||||
ins_encode %{
|
||||
__ mov(Rexception_pc, LR); // this is used only to call
|
||||
// StubRoutines::forward_exception_entry()
|
||||
|
||||
@@ -1941,7 +1941,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall *op) {
|
||||
}
|
||||
|
||||
|
||||
/* Currently, vtable-dispatch is only enabled for sparc platforms */
|
||||
/* vtable-dispatch is not enabled for arm platforms */
|
||||
void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ void LIRGenerator::cmp_reg_mem(LIR_Condition condition, LIR_Opr reg, LIR_Opr bas
|
||||
}
|
||||
|
||||
|
||||
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, int c, LIR_Opr result, LIR_Opr tmp) {
|
||||
bool LIRGenerator::strength_reduce_multiply(LIR_Opr left, jint c, LIR_Opr result, LIR_Opr tmp) {
|
||||
assert(left != result, "should be different registers");
|
||||
if (is_power_of_2(c + 1)) {
|
||||
LIR_Address::Scale scale = (LIR_Address::Scale) log2_intptr(c + 1);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -52,12 +52,12 @@ void LIR_Address::verify() const {
|
||||
// be handled by the back-end or will be rejected if not.
|
||||
#ifdef _LP64
|
||||
assert(index()->is_illegal() || index()->is_double_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_LONG || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#else
|
||||
assert(base()->is_single_cpu(), "wrong base operand");
|
||||
assert(index()->is_illegal() || index()->is_single_cpu(), "wrong index operand");
|
||||
assert(base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
assert(base()->type() == T_ADDRESS || base()->type() == T_OBJECT || base()->type() == T_INT || base()->type() == T_METADATA,
|
||||
"wrong type for addresses");
|
||||
#endif
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user